參考鏈接 https://blog.csdn.net/tzs919/article/details/53571632
type是golang中非常重要的關鍵字,常見的就是定義結構體,但是其功能遠不止是像c中那樣只定義結構體,在golang中type關鍵字的功能可以說是非常豐富,通過參考相關的文章和源碼,總結如下:
1 定義結構體
type person struct { name string //注意后面不能有逗號 age int }
2 類型定義,相當於定義一個別名
type name string //name類型與string等價 例子: type name string func main() { var myname name = "taozs" //其實就是字符串類型 l := []byte(myname) //字符串轉字節數組 fmt.Println(len(l)) //字節長度 }
ps:定義的新類型(別名),可以用來定義方法,比如,我設置string的別名為name,可以用name定義方法,如下:
type name string func (n name) len() int { return len(n) } func main() { var myname name = "taozs" //其實就是字符串類型 l := []byte(myname) //字符串轉字節數組 fmt.Println(len(l)) //字節長度 fmt.Println(myname.len()) //調用對象的方法 }
3 type定義結構體時,可以內嵌匿名成員
//結構體內嵌匿名成員定義 type person struct { string //直接寫類型,匿名 age int } func main() { //結構體匿名成員初始化 p := person{string: "taozs", age: 18}//可以省略部分字段,如:person{string: "taozs"}。也可以這樣省略字段名:person{“taozs”, 18},但必須寫全了,不可以省略部分字段 //結構體匿名成員訪問 fmt.Println(p.string) //注意不能用強制類型轉換(類型斷言):p.(string) }
當結構體只有唯一一個匿名成員的case時
//結構體內嵌匿名成員定義 type person struct { string } func main() { //結構體匿名成員初始化 p := person{string: "taozs"} //也可這樣:person{"taozs"} //結構體匿名成員訪問 fmt.Println(p.string) //注意不能用強制類型轉換(類型斷言):p.(string) }
4 定義接口類型
這也是最常用的一種,例子如下,不多贅述
//接口定義 type Personer interface { Run() Name() string } //實現接口,注意實現接口的不一定只是結構體,也可以是函數對象,參見下面第5條 type person struct { name string age int } func (person) Run() { fmt.Println("running...") } //接收參數person不可以是指針類型,否則不認為是實現了接口 func (p person) Name() string { return p.name } func main() { //接口類型的變量定義 var p Personer fmt.Println(p) //值<nil> //實例化結構體,並賦值給interface p = person{"taozs", 18} //或者:&person{"taozs", 18} p.Run() fmt.Println(p.Name()) var p2 person = p.(person) //類型斷言,接口類型斷言到具體類型 fmt.Println(p2.age) }
ps:當一個結構體實現了某個接口的所有方法時,才能算是實現了這個接口
//另外,類型斷言返回值也可以有第二個bool值,表示斷言是否成功,如下: if p2, ok := p.(person); ok {//斷言成功ok值為true fmt.Println(ok) fmt.Println(p2.age) }
5 定義函數類型
//以下是定義一個函數類型handler type handler func(name string) int //針對這個函數類型可以再定義方法,如: func (h handler) add(name string) int { return h(name) + 10 }
下面是一個比較全面的例子:
package main import ( "fmt" ) //定義接口 type adder interface { add(string) int } //定義函數類型 type handler func(name string) int //實現函數類型方法 func (h handler) add(name string) int { return h(name) + 10 } //函數參數類型接受實現了adder接口的對象(函數或結構體) func process(a adder) { fmt.Println("process:", a.add("taozs")) } //另一個函數定義 func doubler(name string) int { return len(name) * 2 } //非函數類型 type myint int //實現了adder接口 func (i myint) add(name string) int { return len(name) + int(i) } func main() { //注意要成為函數對象必須顯式定義handler類型 var my handler = func(name string) int { return len(name) } //以下是函數或函數方法的調用 fmt.Println(my("taozs")) //調用函數 fmt.Println(my.add("taozs")) //調用函數對象的方法 fmt.Println(handler(doubler).add("taozs")) //doubler函數顯式轉換成handler函數對象然后調用對象的add方法 //以下是針對接口adder的調用 process(my) //process函數需要adder接口類型參數 process(handler(doubler)) //因為process接受的參數類型是handler,所以這兒要強制轉換 process(myint(8)) //實現adder接口不僅可以是函數也可以是結構體 }
難點:fmt.Println(handler(doubler).add("taozs")) //doubler函數顯式轉換成handler函數對象然后調用對象的add方法
這波操作比較懵逼,首先說下這波操作一下子就能看懂的,看注釋,很明顯,強制類型轉換,doubler函數強制轉換成了handler這種類型,這個操作最后的輸出是20,怎么得來的呢?看add方法的實現:
func (h handler) add(name string) int { return h(name) + 10 }
可以看到,像是聲明某個結構體的方法的方式,這里規定了add屬於handler這個函數類型,可以看到add函數體中有一個h(name),是不是看的有點莫名其妙?其實就像是接口一樣,哪個句柄調用了add方法,就執行哪個句柄。可以看到
fmt.Println(handler(doubler).add("taozs"))
是doubler調用了add,那么這個h(name)就等價於doubler(name),因為這里name="taozs",那么先執行add函數,執行到return這句的時候,執行h(name)即doubler(name),執行結果是len(name)*2 = 10。於是,結果就是20