Golang通脈之類型定義

自定義類型

在Go語言中有一些基本的數(shù)據(jù)類型,如string、整型浮點(diǎn)型、布爾等數(shù)據(jù)類型, Go語言中可以使用type關(guān)鍵字來定義自定義類型。

type是Go語法里的重要而且常用的關(guān)鍵字,type絕不只是對(duì)應(yīng)于C/C++中的typedef。搞清楚type的使用,就容易理解go語言中的核心概念struct、interface、函數(shù)等的使用。

類型定義

定義結(jié)構(gòu)體

使用type 可以定義結(jié)構(gòu)體類型:

//1、定義結(jié)構(gòu)體
//結(jié)構(gòu)體定義
type person struct {
   name string //注意后面不能有逗號(hào)
   age  int
}

定義接口

使用type 可以定義接口類型:

type USB interface {
    start()
    end()
}

定義其他的新類型

使用type,還可以定義新類型。

語法:

type 類型名 Type

示例代碼:

type myint int
type mystr string

func main() {

     var i1 myint
     var i2 = 100
     i1 = 100
     fmt.Println(i1)
     //i1 = i2 //cannot use i2 (type int) as type myint in assignment
     fmt.Println(i1,i2)
     
     var name mystr
     name = "王二狗"
     var s1 string
     s1 = "李小花"
     fmt.Println(name)
     fmt.Println(s1)
     name = s1 //cannot use s1 (type string) as type mystr in assignment
}

定義函數(shù)的類型

Go語言支持函數(shù)式編程,可以使用高階編程語法。一個(gè)函數(shù)可以作為另一個(gè)函數(shù)的參數(shù),也可以作為另一個(gè)函數(shù)的返回值,那么在定義這個(gè)高階函數(shù)的時(shí)候,如果函數(shù)的類型比較復(fù)雜,可以使用type來定義這個(gè)函數(shù)的類型:

func main() {
     res1 := fun1()
     fmt.Println(res1(10,20))
}


type my_fun  func (int,int)(string)

//fun1()函數(shù)的返回值是my_func類型
func fun1 () my_fun{
    fun := func(a,b int) string {
        s := strconv.Itoa(a) + strconv.Itoa(b)
        return s
    }
    return fun
}

類型別名

類型別名規(guī)定:TypeAlias只是Type的別名,本質(zhì)上TypeAlias與Type是同一個(gè)類型。就像一個(gè)孩子小時(shí)候有小名、乳名,上學(xué)后用學(xué)名,英語老師又會(huì)給他起英文名,但這些名字都指的是他本人。

類型別名是 Go 1.9 版本添加的新功能。主要用于代碼升級(jí)、遷移中類型的兼容性問題。在 C/C++語言中,代碼重構(gòu)升級(jí)可以使用宏快速定義新的一段代碼。Go 語言中沒有選擇加入宏,而是將解決重構(gòu)中最麻煩的類型名變更問題。

type TypeAlias = Type

在 Go 1.9 版本之前的內(nèi)建類型定義的代碼是這樣寫的:

type byte uint8
type rune int32

而在 Go 1.9 版本之后變?yōu)椋?/p>

type byte = uint8
type rune = int32

這個(gè)修改就是配合類型別名而進(jìn)行的修改。

類型定義和類型別名的區(qū)別

類型別名與類型定義表面上看只有一個(gè)等號(hào)的差異,我們通過下面的這段代碼來理解它們之間的區(qū)別。

//類型定義
type NewInt int

//類型別名
type MyInt = int

func main() {
    var a NewInt
    var b MyInt
    
    fmt.Printf("type of a:%T\n", a) //type of a:main.NewInt
    fmt.Printf("type of b:%T\n", b) //type of b:int
}

結(jié)果顯示a的類型是main.NewInt,表示main包下定義的NewInt類型。b的類型是int。MyInt類型只會(huì)在代碼中存在,編譯完成時(shí)并不會(huì)有MyInt類型。

非本地類型不能定義方法

能夠隨意地為各種類型起名字,是否意味著可以在自己包里為這些類型任意添加方法?

// 定義time.Duration的別名為MyDuration
type MyDuration = time.Duration
// 為MyDuration添加一個(gè)函數(shù)
func (m MyDuration) EasySet(a string) { //cannot define new methods on non-local type time.Duration
}
func main() {
}

以上代碼報(bào)錯(cuò)。報(bào)錯(cuò)信息:cannot define new methods on non-local type time.Duration

編譯器提示:不能在一個(gè)非本地的類型 time.Duration 上定義新方法。非本地方法指的就是使用 time.Duration 的代碼所在的包,也就是 main 包。因?yàn)?time.Duration 是在 time 包中定義的,在 main 包中使用。time.Duration 包與 main 包不在同一個(gè)包中,因此不能為不在一個(gè)包中的類型定義方法。

解決這個(gè)問題有下面兩種方法:

  • 將類型別名改為類型定義: type MyDuration time.Duration,也就是將 MyDuration 從別名改為類型。
  • MyDuration 的別名定義放在 time 包中。

在結(jié)構(gòu)體成員嵌入時(shí)使用別名

當(dāng)類型別名作為結(jié)構(gòu)體嵌入的成員時(shí)會(huì)發(fā)生什么情況?

type Person struct {
    name string
}

func (p Person) Show() {
    fmt.Println("Person-->",p.name)
}

//類型別名
type People = Person

type Student struct {
    // 嵌入兩個(gè)結(jié)構(gòu)
    Person
    People
}

func (p People) Show2(){
    fmt.Println("People------>",p.name)
}

func main() {
    //
    var s Student

    //s.name = "王二狗" //ambiguous selector s.name
    s.People.name = "李小花"
    s.Person.name = "王二狗"
    //s.Show() //ambiguous selector s.Show
    s.Person.Show()
    s.People.Show2()
    fmt.Printf("%T,%T\n",s.Person,s.People) //main.Person,main.Person

}

在通過s直接訪問name的時(shí)候,或者s直接調(diào)用Show()方法,因?yàn)閮蓚€(gè)類型都有 name字段和Show() 方法,會(huì)發(fā)生歧義,證明People 的本質(zhì)確實(shí)是Person 類型。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容