// 可以两个结果也可一个结果,实现?
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 指针类型的成员
写作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) 内嵌字段,属性方法同层不能存在同一命名的
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)
}
复制代码
对于接口,必须是该对象实现了方法,对象的指针实现了没有用
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是两个概念
接口是可以比较的
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将是一个编译错误。
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