// 能够两个结果也可一个结果,实现?
v, ok = m[key] // map lookup
v, ok = x.(T) // type assertion
v, ok = <-ch // channel receive
v = m[key] // map查找,失败时返回零值
v = x.(T) // type断言,失败时panic异常
v = <-ch // 管道接收,失败时返回零值(阻塞不算是失败)
复制代码
out := strings[:0] //共享底层数组建立空切片
in := bufio.NewReader(os.Stdin) // io
复制代码
一个命名为S的结构体类型将不能再包含S类型的成员:由于一个聚合的值不能包含它自身。 (该限制一样适应于数组。)可是S类型的结构体能够包含 *S 指针类型的成员json
写做struct{}。它的大小为0 好比用来作控制而非数据信息: chan struct{} 好比用来实现set: map[string]struct{} 若是结构体的所有成员都是能够比较的,那么结构体也是能够比较的,可比较的结构体类型和其余可比较的类型同样,能够用于map的key类型。 须要注意的是Printf函数中%v参数包含的#副词,它表示用和Go语言相似的语法打印值。对于 结构体类型来讲,将包含每一个成员的名字。数组
data, err := json.MarshalIndent(movies, "", " ")
复制代码
func add(x int, y int) int {return x + y}
func sub(x, y int) (z int) { z = x - y; return}
func first(x int, _ int) int { return x }
func zero(int, int) int { return 0 }
复制代码
你可能会偶尔遇到没有函数体的函数声明,这表示该函数不是以Go实现的。这样的声明定义 了函数标识符。函数
package math func Sin(x float64) float //implemented in assembly language 复制代码
可是函数值之间是不可比较的,也不能用函数值做为map的key。工具
func bigSlowOperation() {
defer trace("bigSlowOperation")() // don't forget the
extra parentheses
// ...lots of work…
time.Sleep(10 * time.Second) // simulate slow
operation by sleeping
}
func trace(msg string) func() {
start := time.Now()
log.Printf("enter %s", msg)
return func() {
log.Printf("exit %s (%s)", msg,time.Since(start))
}
}
复制代码
func double(x int) (result int) {
defer func() { fmt.Printf("double(%d) = %d\n", x,result) }()
return x + x
}
_ = double(4)
// Output:
// "double(4) = 8"
func triple(x int) (result int) {
defer func() { result += x }()
return double(x)
}
fmt.Println(triple(4)) // "12"
复制代码
- 当panic异常发生时,程序会中断运行,并当即执行在该goroutine(能够先理解成 线程,在第8章会详细介绍)中被延迟的函数(defer 机制)。
type P *int
func (P) f() { /* ... */ } // compile error: invalid receiver type
复制代码
m = nil
fmt.Println(m.Get("item")) // ""
m.Add("item", "3") // panic: assignment to entry in nil map
复制代码
,内嵌字段会指导编译器去生成额外的包装方法来委托已经声明好的方法:(而不是cat is a animal,是cat has a animal) 内嵌字段,属性方法同层不能存在同一命名的ui
type Point struct{ X, Y float64 }
func (p Point) Add(q Point) Point { return Point{p.X + q.X, p.Y + q.Y} }
func (p Point) Sub(q Point) Point { return Point{p.X - q.X, p.Y - q.Y} }
type Path []Point
func (path Path) TranslateBy(offset Point, add bool) {
var op func(p, q Point) Point if add {
op = Point.Add
} else {
op = Point.Sub
}
for i := range path {
// Call either path[i].Add(offset) or path[i].Sub(offset).
path[i] = op(path[i], offset)
}
复制代码
对于接口,必须是该对象实现了方法,对象的指针实现了没有用url
package flag
// Value is the interface to the value stored in a flag.
type Value interface {
String() string
Set(string) error
}
复制代码
var w io.Writer
w = os.Stdout
w = new(bytes.Buffer)
w = nil
复制代码
非指针时value包含这个对象 注意接口为nil和接口的value值为nil是两个概念spa
接口是能够比较的线程
var w io.Writer
fmt.Printf("%T\n", w) // "<nil>"
w = os.Stdout
fmt.Printf("%T\n", w) // "*os.File"
w = new(bytes.Buffer)
fmt.Printf("%T\n", w) // "*bytes.Buffer"
复制代码
若是断言操做的对象是一个nil接口值,那么不论被断言的类型是什么这个类型断言都会失 败指针
switch x.(type) {
case nil: // ...
case int, uint: // ...
case bool: // ...
case string: // ...
default: // ...
}
复制代码
- Channel还支持close操做,用于关闭channel,随后对基于该channel的任何发送操做都将导 致panic异常。对一个已经被close过的channel之行接收操做依然能够接受到以前已经成功发 送的数据;若是channel中已经没有数据的话讲产生一个零值的数据
- 当一个被关闭的channel中已经发送的数据都被成功接收后,后续的接收操做将再也不阻塞,它们会当即返回一个零值(能够用这个特性,建立一个chan,<-chan 直到close(chan))
package main
import "fmt"
func counter(out chan<- int) {
for x := 0; x < 100; x++ {
out <- x
}
close(out)
}
func squarer(out chan<- int, in <-chan int) {
for v := range in {
out <- v * v
}
close(out)
}
func printer(in <-chan int) {
for v := range in {
fmt.Println(v)
}
}
func main() {
naturals := make(chan int)
squares := make(chan int)
go counter(naturals)
go squarer(squares, naturals)
printer(squares)
}
// range ch 会一直到close(ch)才结束
复制代码
重复关闭一个channel将致使panic异常,视图关闭一个nil值的channel也将致使panic异 常。关闭一个channels还会触发一个广播机制 由于关闭操做只用于断言再也不向channel发送新的数据,因此只有在发送者所在的goroutine才 会调用close函数,所以对一个只接收的channel调用close将是一个编译错误。code
var loadIconsOnce sync.Once
var icons map[string]image.Image
// Concurrency-safe.
func Icon(name string) image.Image {
loadIconsOnce.Do(loadIcons)
return icons[name]
}
> 只要在go build,go run或者go test命令后面加上-race的flag,就会使编译器建立一个你的应
用的“修改”版或者一个附带了可以记录全部运行期对共享变量访问工具的test,而且会记录下
每个读或者写共享变量的goroutine的身份信息
复制代码
Go语言的构建工具对包含internal名字的路径段的包导入路径作了特殊处理。这种包叫internal包,一个internal包只能被和internal目录有同一个父目录的包所导入。例如,net/http/internal/chunked内部包只能被net/http/httputil或net/http包导入,可是不能被net/url包导入。不过net/url包却能够导入net/http/httputil包
咱们能够经过调用reflect.ValueOf(&x).Elem(),来获取任意变量x对应的可取地址的Value