type Track int
type TrackType []Track
func main() {
tracks := []Track{
1,2,
}
var tracksType TrackType = tracks
var tracks2 []Track = tracksType
fmt.Println(tracksType,tracks2)
}
TrackType是一個新的類型,為什么可以和[]Track相互轉換!!
還有一個問題是,既然type定義的是新類型,那么type HandleFunc func()為什么指名傳遞HandleFunc,但是傳遞一個匿名函數也可用。后來才想明白,func()本來就不是一個類型(準備的說是一個沒有命名的類型,如int這種是有名字的類型所以是命名類型),而使用type給func()定義了一個類型(有了名字),所以能夠進行互換,但是如果再給HandleFunc定一個新類型就不能互換了,如type HandleFunc2 HandleFunc,HandleFunc2和HandleFunc不能互換,因為兩者都是命名類型,那么此時兩者類型就不一樣了。
如func(),數組類型[]int,struct,接口,slice,map,channel指針這些都不是命名類型。
參考下go1.9 新特性 https://github.com/golang/proposal/blob/master/design/18130-type-alias.md:
type Name1 map[string]string
type Name2 map[string]string
type Alias = map[string]string
According to Go assignability, a value of type Name1 is assignable to map[string]string (because the latter is not a named type) but a value of type Name1 is not assignable to Name2 (because both are named types, and the names differ). In this example, because Alias is an alternate spelling for map[string]string, a value of type Name1 is assignable to Alias (because Alias is the same as map[string]string, which is not a named type).
翻譯就是
根據Go可分配性,Name1類型的值可以分配給map [string]字符串(因為后者不是命名類型),但是Name1類型的值不能分配給Name2(因為它們都是命名類型,名稱不同)。在此示例中,由于Alias是map [string]字符串的替代拼寫,Name1類型的值可分配給Alias(因為Alias與map [string]字符串相同,而不是命名類型)。
從以上說明可以得出,對于slice,map[string]int,等類型,因為他們不是命名類型,所以在type MyType []Type的情況下,是可以將[]Type分配給MyType的,并且MyType也可以分配給[]Type。
Go的可分配性
對于賦值而言,以下情況可以將x的值賦給T類型。
- x的類型與T相同
- x的類型和T具有相同的底層類型,并且至少有一個不是定義類型(即有一個是非命名類型)
- T是一個接口,并且x實現了T
- x是一個雙向通道,T是一個通道類型,并且x的類型和T具有相同的底層類型,至少有一個不是定義類型。
- x是nil的時候,可以賦給指針類型,函數類型,slice,map,channel等引用類型和接口類型等
- x是由類型T的值表示的無類型常量。
針對以上的第二條做個解釋,如下代碼示例:
type Func func()
type Func2 Func
func Test1(f Func){
}
func Test2(f Func2){
}
func main(){
m := func(){
}
Test1(m)
Test2(m)
}
上述代碼是可以運行的,其中m的類型是func()非命名類型,但是傳遞Test1和Test2中都可以使用,說明在傳遞的時候func()和Func以及Func2都能互相轉換,其中func()和Func能進行互相賦值好理解,但是為什么func()和Func2也能互相賦值,這個時候看下第二條規則就明白了:x的類型和T具有相同的地底層類型,并且至少有一個不是定義類型(即有一個是非命名類型)
,因為func()和Func2有相同的底層類型,其中func()不是定義類型,所以兩者可以互相賦值。
但是以下代碼無法正確執行,因為m類型是指定的Func,不符合以上任何一條規則,所以不能和Func2進行互相轉換。
func main(){
var m Func = func(){}
Test1(m) //success,因為Func是非命名類型的第一個命名,可互相轉換
Test2(m) // failed,Func和Func2不是同一個類型
}