午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

六、golang中的結(jié)構(gòu)體和方法、接口

 F2967527 2019-08-06

結(jié)構(gòu)體:

1、用來自定義復(fù)雜數(shù)據(jù)結(jié)構(gòu)

2、struct里面可以包含多個字段(屬性)

3、struct類型可以定義方法,注意和函數(shù)的區(qū)分

4、strucr類型是值類型

5、struct類型可以嵌套

6、go語言中沒有class類型,只有struct類型

struct聲明:

         type  標(biāo)識符 struct{

                   field1 type

                   field2 type

}

例子:

         type Student struct{

         Name string

         Age  int

         Score int

}

struct中字段訪問,和其他語言一樣,使用點(diǎn)

         例子:

                   var stu Student            //拿結(jié)構(gòu)題定義一個變量

                   stu.Name=”tony”

                   stu.Age=18

                   stu.Score=20

                   fmt.Printf(“name=%s,age=%d,score=%d”,stu.Name,stu.Age,stu.Sore)

struct定義的三種形式    初始化的三種方式

         a、var stu Student

         b、var stu *Student=new(Student)

         c、var stu *Student=&Student{}

其中b和c返回的都是指向結(jié)構(gòu)體的指針,訪問形式如下:

         a、stu.Name、stu.Age  和stu.Score 或者(*stu).Name、 (*stu).Age等

如果是指針形式可以用上面的普通的方式訪問,其實(shí)就自動轉(zhuǎn)化為指針訪問的形式

package mainimport ( 'fmt')type Student struct{ Name string Age int score float32}func main(){ //聲明方式一 var stu Student stu.Name='hua' stu.Age=18 stu.score=80 //聲明方式二 var stu1 *Student =&Student{ Age:20, Name:'hua', } //聲明方式三 var stu3 =Student{ Age:20, Name:'hua', } fmt.Printf(stu1.Name) fmt.Printf(stu3.Name)}

struct內(nèi)存布局

例子:

package mainimport(   'fmt')type Student struct{   Name string   Age int   score float32}func main(){   var stu Student   stu.Name='hua'   stu.Age=18   stu.score=80   fmt.Print(stu)   fmt.Printf('Name:%p\n',&stu.Name)   fmt.Printf('Age:%p\n',&stu.Age)   fmt.Printf('score:%p\n',&stu.score)}{hua 18 80}Name:0xc04204a3a0Age:0xc04204a3b0score:0xc04204a3b8這里int32是4字節(jié),64是8字節(jié)

鏈表的定義:

type Student struct{

         name string

         next* Student

}

每個節(jié)點(diǎn)包含下一個節(jié)點(diǎn)的地址,這樣把所有的節(jié)點(diǎn)串起來,通常把鏈表中的每一個節(jié)點(diǎn)叫做鏈表頭

遍歷到最后一個元素的時候有個特點(diǎn),就是next這個指針指向的是nil,可以從這個特點(diǎn)來判斷是否是鏈表結(jié)束

單鏈表的特點(diǎn):只有一個字段指向后面的結(jié)構(gòu)體

         單鏈表只能從前往后遍歷

雙鏈表的特點(diǎn):有兩個字段,分別指向前面和后面的結(jié)構(gòu)體

         雙鏈表可以雙向遍歷

鏈表操作:

1、生成鏈表及遍歷鏈表操作

package mainimport ( 'fmt')type Student struct{ Name string Age int Score float32 next *Student}func main(){ var head Student head.Name='hua' head.Age=18 head.Score=80 var stu1 Student stu1.Name='stu1' stu1.Age=20 stu1.Score=100 head.next=&stu1 //遍歷 var p *Student=&head //生成p指針,指向head for p!=nil{ //這里p就是head結(jié)構(gòu)體,所以要從第一個遍歷 fmt.Println(*p) p=p.next }}D:\project>go build go_dev / example/example3D:\project>example3.exe{hua 18 80 0xc042078060} 這里第三個值指向的是下一個結(jié)構(gòu)體{stu1 20 100 <nil>}上面的程序不規(guī)范,修改如下:package mainimport ( 'fmt')type Student struct{ Name string Age int Score float32 next *Student}func trans(p *Student){ for p!=nil { //這里p就是head結(jié)構(gòu)體,所以要從第一個遍歷 fmt.Println(*p) p = p.next }}func main(){ var head Student head.Name='hua' head.Age=18 head.Score=80 var stu1 Student stu1.Name='stu1' stu1.Age=20 stu1.Score=100 //這里默認(rèn)第二個鏈表為nil head.next=&stu1 //var p *Student=&head trans(&head) //生成p指針,指向head}

插入鏈表的方法:

1、尾部插入法,就在鏈表的尾部插入結(jié)構(gòu)體代碼如下:package mainimport(   'fmt')type Student struct{   Name string   Age int   Score float32   next *Student}func trans(p *Student){   for p!=nil { //這里p就是head結(jié)構(gòu)體,所以要從第一個遍歷      fmt.Println(*p)      p = p.next   }}func main() {   var head Student   head.Name = 'hua'   head.Age = 18   head.Score = 80   var stu1 Student   stu1.Name = 'stu1'   stu1.Age = 20   stu1.Score = 100   var stu2 Student   stu2.Name='stu2'   stu2.Age=22   stu2.Score=90   head.next=&stu1   stu1.next=&stu2   trans(&head)   }2、尾部循環(huán)插入package mainimport (   'fmt'   'math/rand')type Student struct{   Name string   Age int   Score float32   next *Student}func trans(p *Student){   for p!=nil { //這里p就是head結(jié)構(gòu)體,所以要從第一個遍歷      fmt.Println(*p)      p = p.next   }}//尾部循環(huán)插入數(shù)據(jù)func trans2(tail *Student){   for i:=0;i<10;i++{      stu:=&Student{         Name:fmt.Sprintf('stu%d',i),         Age:rand.Intn(100),         Score:rand.Float32()*100,      }      //注意下面的是指針      tail.next=stu   //鏈表是指向下一個      tail=stu        //更新最后一個鏈表   }}func main(){   var head Student   head.Name='hua'   head.Age=18   head.Score=100      //下面這兩個都是根據(jù)head這個鏈表結(jié)構(gòu)體產(chǎn)生   trans2(&head)   trans(&head)}3、頭部插入1、注意給指針分配內(nèi)存空間2、用指針的方式才可以分配內(nèi)存,如果用變量就不行(牽扯到地址就用指針)package mainimport(   'fmt'   'math/rand')type Student struct{   Name string   Age int   Score float32   next *Student}func trans(p *Student){   for p!=nil{      fmt.Println(*p)      p=p.next   }}func main(){   //因?yàn)檫@是指針,所以要給指針分配空間,下面是給指針分配內(nèi)存空間的兩種方法   //var head *Student=&Student{}   var head *Student=new(Student)   head.Name='hua'   head.Age=18   head.Score=100   //從頭插入   for i:=0;i<10;i++{      stu:=Student{         Name:fmt.Sprintf('stu%d',i),         Age:rand.Intn(100),         Score:rand.Float32()*100,      }      //頭部插入必須要傳遞指針才可以,首先頭部插入一個,鏈表指向第一個,但是插入的鏈表地址被覆蓋      stu.next=head      head=&stu    //指針賦值   }   trans(head)}頭部插入和尾部插入的區(qū)別是頭部插入:需要用指針的方式來插入尾部插入:直接插入就可以了(變量形式插入)優(yōu)化代碼package mainimport(   'fmt'   'math/rand')type Student struct{   Name string   Age int   Score float32   next *Student}//打印函數(shù)func trans(p *Student){   for p!=nil{      fmt.Println(*p)      p=p.next   }}//這里的head是指針變量副本,這里要接受指針的指針,head1 * Student是指針變量的副本func insertHead(head1 **Student){   //從頭插入   for i:=0;i<10;i++ {      stu := Student{         Name:  fmt.Sprintf('stu%d', i),         Age:   rand.Intn(100),         Score: rand.Float32() * 100,      }      //因?yàn)閰?shù)是指針的指針,所以這里要傳遞指針的指針,      stu.next = *head1      *head1 = &stu   }}func main(){   var head *Student=new(Student)   head.Name='hua'   head.Age=18   head.Score=100   //因?yàn)檫@個函數(shù)要改變指針變量的值,所以要傳遞指針的地址進(jìn)去   insertHead(&head)   trans(head)}理解:如下:這里的insertHead中的head1是head的副本,開始head1和head是指向同一個內(nèi)存地址,當(dāng)head1=&stu的時候head1的地址,也就是head的副本的地址就變化了,但是head還是沒有變化的。所以要改變指針的地址,也就是head的地址,這里函數(shù)必須要傳遞指針的指針才可以,在指針的基礎(chǔ)之上多加一個*,func insertHead(head1 **Student){}然后傳遞的時候要傳遞指針的地址,如 insertHead(* head)小結(jié): 要改變指針變量的值,就要傳遞指針的指針進(jìn)去指針還有二級指針,三級指針等

刪除鏈表

刪除指定節(jié)點(diǎn):

思路:

1、遍歷,

2、遍歷當(dāng)前節(jié)點(diǎn)的上個節(jié)點(diǎn)的next等于當(dāng)前節(jié)點(diǎn)的下一個節(jié)點(diǎn),這個節(jié)點(diǎn)就刪除了

3、如果第一次沒有找到,那么就往后移動位置,即當(dāng)前節(jié)點(diǎn)的上級節(jié)點(diǎn)等于當(dāng)前節(jié)點(diǎn),當(dāng)前節(jié)點(diǎn)的下一個節(jié)點(diǎn)賦值給當(dāng)前節(jié)點(diǎn),

4、下面這個代碼是有問題的,主要是這是一個副本。頭部插入會有問題

代碼:

package mainimport ( 'fmt' 'math/rand')type Student struct{ Name string Age int Score float32 next *Student //指向下一個節(jié)點(diǎn)}func trans(p *Student) { for p!=nil{ fmt.Println(*p) p=p.next }}//頭部插入func insertHead(head **Student){ //從頭插入 for i:=0;i<10;i++ { stu := Student{ Name: fmt.Sprintf('stu%d', i), Age: rand.Intn(100), Score: rand.Float32() * 100, } //因?yàn)閰?shù)是指針的指針,所以這里要傳遞指針的指針, stu.next = *head *head = &stu }}func delNode(p * Student){ //臨時變量保存上一個節(jié)點(diǎn) var prev *Student=p /* 遍歷鏈表 1、首先判斷當(dāng)前鏈表節(jié)點(diǎn)是否等于要刪除的鏈表,如果是那么把當(dāng)前鏈表節(jié)點(diǎn)上一個節(jié)點(diǎn)等于 當(dāng)前鏈表節(jié)點(diǎn)的下一個節(jié)點(diǎn) 2、如果沒有找到,那么當(dāng)前鏈表節(jié)點(diǎn)就等于上個節(jié)點(diǎn),當(dāng)前鏈表節(jié)點(diǎn)就指向下個節(jié)點(diǎn),也就是往后移動位置 */ for p!=nil{ if p.Name=='stu6'{ prev.next=p.next break } //如果沒有找到,那么p就等于上個節(jié)點(diǎn),p就指向下個節(jié)點(diǎn) prev=p p=p.next }}func main(){ var head *Student=new(Student) head.Name='hua' head.Age=18 head.Score=100 insertHead(&head) delNode(head) trans(head)}

怎么在上面stu6后面插入一個節(jié)點(diǎn)?

思路:

1、首先生成一個節(jié)點(diǎn),讓這個節(jié)點(diǎn)的下一個節(jié)點(diǎn)等于stu6的下一個節(jié)點(diǎn)

2、再讓stu6的下一個節(jié)點(diǎn)指向插入的這個節(jié)點(diǎn)

package mainimport (   'fmt'   'math/rand')type Student struct{   Name string   Age int   Score float32   next *Student   //指向下一個節(jié)點(diǎn)}func trans(p *Student)  {   for p!=nil{      fmt.Println(*p)      p=p.next   }}//頭部插入func insertHead(head **Student){   //從頭插入   for i:=0;i<10;i++ {      stu := Student{         Name:  fmt.Sprintf('stu%d', i),         Age:   rand.Intn(100),         Score: rand.Float32() * 100,      }      //因?yàn)閰?shù)是指針的指針,所以這里要傳遞指針的指針,      stu.next = *head      *head = &stu   }}func delNode(p * Student){   //臨時變量保存上一個節(jié)點(diǎn)   var prev *Student=p   /*   遍歷鏈表   1、首先判斷當(dāng)前鏈表節(jié)點(diǎn)是否等于要刪除的鏈表,如果是那么把當(dāng)前鏈表節(jié)點(diǎn)上一個節(jié)點(diǎn)等于   當(dāng)前鏈表節(jié)點(diǎn)的下一個節(jié)點(diǎn)   2、如果沒有找到,那么當(dāng)前鏈表節(jié)點(diǎn)就等于上個節(jié)點(diǎn),當(dāng)前鏈表節(jié)點(diǎn)就指向下個節(jié)點(diǎn),也就是往后移動位置   */   for p!=nil{      if p.Name=='stu6'{         prev.next=p.next         break      }      //如果沒有找到,那么p就等于上個節(jié)點(diǎn),p就指向下個節(jié)點(diǎn)      prev=p      p=p.next   }}//在stu5后面插入一個鏈表func addNode(p *Student,newNode * Student){   for p!=nil{      if p.Name=='stu5'{         newNode.next=p.next         p.next=newNode         break      }      p=p.next   }}func main(){   var head *Student=new(Student)   head.Name='hua'   head.Age=18   head.Score=100   insertHead(&head)   delNode(head)   trans(head)   var newNode *Student=new(Student)   newNode.Name='stu1000'   newNode.Age=18   newNode.Score=100   addNode(head,newNode)   trans(head)}

雙向鏈表

         定義  type Student struct{

         Name sring

         next * Student

         prevn * Student

}

如果有兩個指針分別指向前一個節(jié)點(diǎn)和后一個節(jié)點(diǎn),我們叫做雙鏈表

二叉樹

定義:

         type Student struct{

         Name string

         left * Student

         right *Student

}

如果每個節(jié)點(diǎn)有兩個指針分別用來指向左子樹和右子樹,我們把這樣的結(jié)構(gòu)叫做二叉樹

對于二叉樹,要用到廣度優(yōu)先或者深度優(yōu)先的遞歸算法

下面是二叉樹的類型圖,下面的stu2的右邊的孩子也可以是為nil,然后stu3如果沒有孩子就叫做葉子節(jié)點(diǎn),stu02是stu01的子樹

 

代碼:

下面采用遞歸的形式進(jìn)行遍歷二叉樹,下面是深度優(yōu)先的原理

如果要采取廣度優(yōu)先,那么每次遍歷的時候就要把結(jié)果放到隊列里面

前序遍歷:是從根節(jié)點(diǎn)開始遍歷的

package mainimport( 'fmt')//聲明二叉樹type Student struct{ Name string Age int Score float32 left *Student right *Student}func trans(root *Student){ if root==nil{ return } fmt.Println(root) //遞歸遍歷左子樹 trans(root.left) //遞歸然后遍歷右子樹 trans(root.right)}func main(){ //初始化root定點(diǎn) var root *Student=new(Student) root.Name='stu01' root.Age=18 root.Score=100 root.left=nil //初始化 root.right=nil var left1 *Student=new(Student) left1.Name='stu02' left1.Age=19 left1.Score=100 //把這個節(jié)點(diǎn)插入到root的左邊 root.left=left1 var right1 *Student=new(Student) right1.Name='stu04' right1.Age=19 right1.Score=100 //把這個節(jié)點(diǎn)插入到root的右邊 root.right=right1 var left02 *Student=new(Student) left02.Name='stu03' left02.Age=18 left02.Score=100 //把這個節(jié)點(diǎn)插入到left1的左邊 left1.left=left02 trans(root)}/*下面結(jié)果分別是,Name Age Score 然后左邊和右邊的地址&{stu01 18 100 0xc042082090 0xc0420820c0} &{stu02 19 100 0xc0420820f0 <nil>}&{stu03 18 100 <nil> <nil>}&{stu04 19 100 <nil> <nil>}*/中序遍歷:先遍歷左子樹,然后遍歷根節(jié)點(diǎn),然后遍歷右節(jié)點(diǎn)package mainimport( 'fmt')//聲明二叉樹type Student struct{ Name string Age int Score float32 left *Student right *Student}func trans(root *Student){ if root==nil{ return } //中序遍歷 trans(root.left) fmt.Println(root) trans(root.right) /* 結(jié)果 &{stu03 18 100 <nil> <nil>} &{stu02 19 100 0xc0420820f0 <nil>} &{stu01 18 100 0xc042082090 0xc0420820c0} &{stu04 19 100 <nil> <nil>} */}func main(){ //初始化root定點(diǎn) var root *Student=new(Student) root.Name='stu01' root.Age=18 root.Score=100 root.left=nil //初始化 root.right=nil var left1 *Student=new(Student) left1.Name='stu02' left1.Age=19 left1.Score=100 //把這個節(jié)點(diǎn)插入到root的左邊 root.left=left1 var right1 *Student=new(Student) right1.Name='stu04' right1.Age=19 right1.Score=100 //把這個節(jié)點(diǎn)插入到root的右邊 root.right=right1 var left02 *Student=new(Student) left02.Name='stu03' left02.Age=18 left02.Score=100 //把這個節(jié)點(diǎn)插入到left1的左邊 left1.left=left02 trans(root)}后序遍歷:首先遍歷左子樹,然后遍歷右子樹,最后遍歷根節(jié)點(diǎn)package mainimport( 'fmt')//聲明二叉樹type Student struct{ Name string Age int Score float32 left *Student right *Student}func trans(root *Student){ if root==nil{ return } //后序遍歷 trans(root.left) trans(root.right) fmt.Println(root) /* 結(jié)果 &{stu03 18 100 <nil> <nil>} &{stu02 19 100 0xc04206e0f0 <nil>} &{stu04 19 100 <nil> <nil>} &{stu01 18 100 0xc04206e090 0xc04206e0c0} */}func main(){ //初始化root定點(diǎn) var root *Student=new(Student) root.Name='stu01' root.Age=18 root.Score=100 root.left=nil //初始化 root.right=nil var left1 *Student=new(Student) left1.Name='stu02' left1.Age=19 left1.Score=100 //把這個節(jié)點(diǎn)插入到root的左邊 root.left=left1 var right1 *Student=new(Student) right1.Name='stu04' right1.Age=19 right1.Score=100 //把這個節(jié)點(diǎn)插入到root的右邊 root.right=right1 var left02 *Student=new(Student) left02.Name='stu03' left02.Age=18 left02.Score=100 //把這個節(jié)點(diǎn)插入到left1的左邊 left1.left=left02 trans(root)}
View Code

結(jié)構(gòu)體與方法

結(jié)構(gòu)體是用戶單獨(dú)定義的類型,不能和其他類型進(jìn)行強(qiáng)制轉(zhuǎn)換

type Student struct{

         Number int

}

type Stu Student  //alias  別名   type 變量  類型 這個是定義類型的別名

var a Student

a=Student{30}

var b Stu

a=b   //這樣賦值錯誤

a=Student(b)  //這樣才可以

上面這兩個Stu和Student是別名關(guān)系,但是這兩個字段一樣,并不是同一個類型,因?yàn)槭莟ype定義的

如:

package mainimport (   'fmt')type integer intfunc main(){      //賦值給誰呢么類型,就要強(qiáng)制轉(zhuǎn)換成什么類型   var i integer=1000   fmt.Println(i)   var j int=100   //這里i是自定義的類型, j是int類型,所以賦值的時候要強(qiáng)制轉(zhuǎn)換,如下   j=int(i)              //i如果賦值給j應(yīng)該強(qiáng)制轉(zhuǎn)換為int類型   i=integer(j)        //j如果想復(fù)制給i必須轉(zhuǎn)換為integer類型   fmt.Println(i)   fmt.Println(j)}

工廠模式

golang中的struct沒有構(gòu)造函數(shù),一般可以使用工廠模式來解決這個問題

Package model

type student Struct{

Name string

Age  int

}

func NewStudent(name string,age int)*Student{

         return &Student{   //創(chuàng)建實(shí)例

Name:name

Age:age

}

}

Package main

S:new(student)

S:model.NewStudent(“tony”,20)

再次強(qiáng)調(diào)

make用來創(chuàng)建map,slice ,channel

new 用來創(chuàng)建值類型

struct中的tag

我們可以為strct中的每一個字段,協(xié)商一個tag,這個tag可以通過反射機(jī)制獲取到,最常用的場景就是json序列化和反序列化

type student struct{

         Name string  “this is name field” //每個字段寫一個說明,作為這個字段的描述

         Age int      “this is age field”

}

json打包

json.Marshal()

注意:

json打包的時候,

1、必須要把結(jié)構(gòu)體中的字段大寫,才可以

下面是程序聲明打包初始化的兩種方式

package mainimport( 'encoding/json' 'fmt')type Student struct{ Name string `json:'Student_name'` age int `json:'student_age'` score int `json:score`}func main(){ //聲明 var stu Student=Student{ Name:'stu01', age:10, score:100, } data,err:=json.Marshal(stu) //打包,返回值為byte if err!=nil{ fmt.Println('json encode stu faild,err',err) return } fmt.Println(string(data)) //把byte轉(zhuǎn)化成string}//{'Student_name':'stu01'}也可以下面的方式書寫package mainimport( 'encoding/json' 'fmt')type Student struct{ Name string `json:'Student_name'` age int `json:'student_age'` score int `json:score`}func main(){ //初始化 var stu *Student=new(Student) stu.Name='stu01' data,err:=json.Marshal(stu) //打包,返回值為byte if err!=nil{ fmt.Println('json encode stu faild,err',err) return } fmt.Println(string(data)) //把byte轉(zhuǎn)化成string}//{'Student_name':'stu01'}

匿名字段

結(jié)構(gòu)體 中字段可以沒有名字,叫做匿名字段

type Car struct{

         Name string

         Age int

}

type Train struct{

         Car                //匿名字段

         Start time.Time      //有名字段

         int                //匿名字段

}

匿名字段要怎么訪問呢?

package mainimport (   'fmt'   'time')type Cart struct{   name string   age int}type Train struct{   Cart   int   strt time.Time}func main(){   var t Train   //正規(guī)寫法   t.Cart.name='001'   t.Cart.age=11   //上面的正規(guī)寫法可以縮寫成下面的寫法   t.name='001'   t.age=11   t.int=200   fmt.Println(t)}

匿名字段沖突處理

 

對于上面的1這里有優(yōu)先原則:

縮寫形式,如果有兩個結(jié)構(gòu)體中有相同的字段,會優(yōu)先找本身的字段

對于上面的2,必須要手動的指定某個字段才可以,不然會報錯

方法:

golang中的方法是作用在特定類型的變量上,因此自定義類型,都可以有方法,而不僅僅是struct

定義: func (recevier type ) methodName(參數(shù)列表)(返回值列表){}

package mainimport( 'fmt')type Student struct{ Name string Age int Score int sex int}func (p *Student) init(name string,age int,){ p.Name=name p.Age=age fmt.Println(p)}func (p Student) get() Student{ return p}func main(){ var stu Student //由于這里傳遞指針才可以,正規(guī)寫法應(yīng)該是下面 (&stu).init('stu',10) //但是由于go做了優(yōu)化,只有在結(jié)構(gòu)體方法中才可以用下面的方法 stu.init('stu',10) stu1:=stu.get() fmt.Println(stu1)}/*&{stu 10 0 0}&{stu 10 0 0}{stu 10 0 0}*/方法的調(diào)用這里需要注意兩點(diǎn)1、任何自定義類型都有方法2、在注意調(diào)用的時候的方法,注意指針才改變值package mainimport ( 'fmt')type integer intfunc (p integer)print(){ fmt.Println(p)}//這里由于傳遞的是副本,所以無法改變值func (p integer)set(b integer){ p=b}//這里直接傳遞的指針,所以可以改變func (p *integer)get(b integer){ *p=b}func main(){ var a integer a=100 a.print() a.set(1000) a.print() //下面是(&a).get的縮寫形式 a.get(1000) a.print()}

方法的調(diào)用

type A struct{

         a int

}

func (this A)test(){

         fmt.Println(this.a)

}

var t A

t.test()

上面的this就是下面的t,通過上面方法中的參數(shù)this.A就能獲取當(dāng)前結(jié)構(gòu)體中的實(shí)例

方法和函數(shù)的區(qū)別:

1)函數(shù)調(diào)用 :function(variable,參數(shù)列表)

2)‘方法 variable.function(參數(shù)列表)

指針receiver vs值receiver

 本質(zhì)上和函數(shù)的值傳遞和地址傳遞是一樣的

方法的訪問控制,通過大小寫控制

繼承

如果一個struct潛逃了另一個匿名結(jié)構(gòu)體,那么這個結(jié)構(gòu)可以直接訪問匿名結(jié)構(gòu)體的方法,從而實(shí)現(xiàn)了繼承

如:

package mainimport (   'fmt'   'time')type Cart struct{   name string   age int}type Train struct{   Cart   int   strt time.Time   age int}func main(){   var t Train   //正規(guī)寫法   t.Cart.name='001'   t.Cart.age=11   //上面的正規(guī)寫法可以縮寫成下面的寫法   t.name='001'   t.age=11   t.int=200   fmt.Println(t)}這里的Train繼承了Cart,Cart為父類,然后Train里面有Cart的所有的方法

下面是方法的繼承

package mainimport ( 'fmt')type Car struct{ weight int name string}func (p *Car) Run(){ fmt.Println('running')}type Bike struct{ Car lunzi int}type Train struct{ Car}func main(){ var a Bike a.weight=100 a.name='bike' a.lunzi=2 fmt.Println(a) //{{100 bike} 2} a.Run() //running var b Train b.weight=1000 b.name='train' b.Run() //running}這里a和b都繼承了Car父類中的Run方法總結(jié),匿名函數(shù)可以繼承字段也可以繼承方法

組合和匿名函數(shù)

如果一個struct嵌套了另一個匿名結(jié)構(gòu)體,那么這個結(jié)構(gòu)體可以直接訪問匿名結(jié)構(gòu)體的方法,從而實(shí)現(xiàn)了繼承

如果一個struct嵌套了另一個有名結(jié)構(gòu)體,那么這個模式就叫做組合(一個結(jié)構(gòu)體嵌套另一個結(jié)構(gòu)體)

也可以說匿名字段是特殊的組合

package mainimport (   'fmt')type Car struct{   weight int   name string}func (p *Car) Run(){   fmt.Println('running')}type Train struct{   c Car}func main(){   var b Train   b.c.weight=1000   b.c.name='train'   b.c.Run()         //running}如上就是組合

多重繼承

如果一個struct嵌套了多個匿名結(jié)構(gòu)體,那么這個結(jié)構(gòu)可以直接訪問多個匿名結(jié)構(gòu)體的方法,從而實(shí)現(xiàn)了多重繼承

如果沖突的話,就需要帶上結(jié)構(gòu)體的名字來訪問

實(shí)現(xiàn)String()  這是一個接口

如果一個變量實(shí)現(xiàn)了String()這個方法,那么fmt.Println默認(rèn)會調(diào)用變量String()進(jìn)行輸出

go里面只要實(shí)現(xiàn)了接口這個方法,那么就實(shí)現(xiàn)了這個接口,相當(dāng)于鴨子類型

package mainimport ( 'fmt')type Cart struct{ weight int name string}type Train struct{ Cart}func (p *Cart) Run(){ fmt.Println('running')}func (p *Train)String() string{ str:=fmt.Sprintf('name=[%s] weight=[%d]',p.name,p.weight) return str}func main(){ var b Train b.weight=100 b.name='train' b.Run() //這個是字符串的接口所以需要格式化才會調(diào)用這個接口,這個是指針型的 fmt.Printf('%s',&b)}

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多