golang type


參考鏈接 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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM