如果 Tx 和 T 共享相同的底层类型(忽略结构体 tags), 那么 x 可以显示地转换为 T, 尤其当 Tx 或者 T 不是一个定义类型并且它们的底层类型相同(考虑结构体 tags), 那么 x 可以隐式地转换为 T.
如果 Tx 和 T 具有不同的底层类型, 但 Tx 和 T 都是非定义的指针类型, 并且它们的基类型共享相同的底层类型(忽略结构体 tags), 则 x 可以(并且必须)可以显示地转换为 T.
一般性例子:
package main
funcmain() { // []int, IntSlice and MySlice share // the same underlying type: []int type IntSlice []int type MySlice []int
var s = []int{} var is = IntSlice{} var ms = MySlice{} var x struct{n int`foo`} var y struct{n int`bar`}
// The two lines both fail to compile. /* is = ms ms = is */
// Must use explicit conversions here. is = IntSlice(ms) ms = MySlice(is) x = struct{n int`foo`}(y) y = struct{n int`bar`}(x)
// Implicit conversions are okay here. s = is is = s s = ms ms = s }
指针的例子:
package main
funcmain() { type MyInt int type IntPtr *int type MyIntPtr *MyInt
var pi = new(int) // type is *int var ip IntPtr = pi // ok, same underlying type
// var _ *MyInt = pi // can't convert implicitly var _ = (*MyInt)(pi) // ok, must explicitly
// var _ MyIntPtr = pi // can't convert implicitly // var _ = MyIntPtr(pi) // can't convert explicitly var _ MyIntPtr = (*MyInt)(pi) // ok var _ = MyIntPtr((*MyInt)(pi)) // ok
// var _ MyIntPtr = ip // can't convert implicitly // var _ = MyIntPtr(ip) // can't convert explicitly var _ MyIntPtr = (*MyInt)((*int)(ip)) // ok var _ = MyIntPtr((*MyInt)((*int)(ip))) // ok }
不同零大小的值的地址可能相同也可能不同.
两个零大小值的地址是否相等取决于编译器和编译器版本.
package main
import"fmt"
funcmain() { a := struct{}{} b := struct{}{} x := struct{}{} y := struct{}{} m := [10]struct{}{} n := [10]struct{}{} o := [10]struct{}{} p := [10]struct{}{}
fmt.Println(&x, &y, &o, &p)
// For the standard Go compiler (1.10), // x, y, o and p escape to heap, // but a, b, m and n are allocated on stack.
funcmain() { type P *P var p P p = &p p = **************p }
同样,
切片类型的元素类型可以是切片类型本身,
映射类型的元素类型可以是映射类型本身,
管道类型的元素类型可以是管道类型本身,
函数类型的参数和结果类型可以是函数类型本身.
package main
funcmain() { type S []S type M map[string]M type C chan C type F func(F)F s := S{0:nil} s[0] = s m := M{"Go": nil} m["Go"] = m c := make(C, 3) c <- c; c <- c; c <- c var f F f = func(F)F {return f}
type T struct { x int } func(T)m(){} // T has one method.
type P *T // a defined one-level pointer type. type PP *P // a defined two-level pointer type.
funcmain() { var t T var tp = &t var tpp = &tp var p P = tp var pp PP = &p tp.x = 12// okay p.x = 34// okay pp.x = 56// error: type PP has no field or method x tpp.x = 78// error: type **T has no field or method x)
tp.m() // okay. Type *T also has a "m" method. p.m() // error: type P has no field or method m pp.m() // error: type PP has no field or method m tpp.m() // error: type **T has no field or method m }
容器
嵌套复合字面量可以简化
如果复合字面量嵌套了许多其他复合字面量, 那么这些嵌套复合字面量可以简化为 {…} 形式.
例如, 切片值字面量:
// A slcie value of a type whose element type is *[4]byte. // The element type is a pointer type whose base type is [4]byte. // The pointer base type is an array type whose element type is byte. var heads = []*[4]byte{ &[4]byte{'P', 'N', 'G', ' '}, &[4]byte{'G', 'I', 'F', ' '}, &[4]byte{'J', 'P', 'E', 'G'}, }
type LangCategory struct { dynamic bool strong bool }
// A value of map type whose key type is a struct type and // whose element type is another map type "map[string]int". var _ = map[LangCategory]map[string]int{ LangCategory{true, true}: map[string]int{ "Python": 1991, "Erlang": 1986, }, LangCategory{true, false}: map[string]int{ "JavaScript": 1995, }, LangCategory{false, true}: map[string]int{ "Go": 2009, "Rust": 2010, }, LangCategory{false, false}: map[string]int{ "C": 1972, }, }