1. 包(package)
- 包的定義:
package
關鍵字,包名通常是和目錄名一致,可以含有_
但不能含有-
- 一個文件夾就是一個包,文件夾裏存放的都是
.go
文件 - 包的導入:使用
import
關鍵字。
a.包導入路徑是從$GOPATH/src
後面的路徑開始寫起的;
b.可以單行導入,也可以多行導入;
c.可以給導入的包起別名,也可以匿名導入:import _"包的路徑"
。匿名導入的包與其它方式導入的包一樣都會被編譯到可執行文件中。
d. Go不支持循環導入,也不支持導入包不使用的做法。
e.包名爲main
包爲應用程序的入口包,編譯時不包含main包的源代碼時不會得到可執行文件。 - 包中
標識符
(變量名、函數名、結構體名、接口名、常量…)的可見性:標識符首字母大寫表示對外可見。 init()
a. 包導入的時候會自動執行
b. 一個包裏只能有一個init()
c. init()沒有參數也沒有返回值也不能在代碼中主動調用它
d.一般用於做一些初始化操作
e. 多個包中都定義了init()函數,他們的執行順序如下:
2.接口(interface)
在編程中會遇到這樣的情況:我們不關心一個變量是什麼類型,只關心能調用它的什麼方法。這時就會用到接口(interface).接口就是你要實現的方法的清單。
接口是一種類型,一種抽象的類型。
-
接口的定義
Go語言提倡面向接口編程。type 接口類型名 interface{ 方法名1(參數1,參數2...)(返回值1,返回值2...) 方法名2(參數1,參數2...)(返回值1,返回值2...) }
用來給變量\參數\返回值等設置類型。
-
接口的實現
一個變量如果實現了接口中的所有方法,那麼這個變量就實現了這個接口。實現了接口就可以當成這個接口類型的變量。
使用值接收者實現接口與使用指針接收者實現接口的區別?
i.使用值接收者實現接口,結構體類型和結構體指針類型的變量都能存;
ii.指針接收者實現接口只能存結構體指針類型的變量。
實例代碼:type animal interface { move() eat(string) } type cat struct { name string feet int } func (c cat)move(){ fmt.Println("走貓步...") } func (c cat)eat(food string){ fmt.Printf("貓喫%s\n",food) } type chicken struct { feet int8 } func (c chicken)move(){ fmt.Println("雞動~") } func (c chicken)eat(food string){ fmt.Printf("雞喫%s\n",food) } func main() { var a1 animal//定義一個接口類型的變量 bc:=cat{ name:"淘氣", feet:4, } a1=bc fmt.Printf("這時a1的類型是:%T\n",a1) a1.eat("小黃魚") fmt.Println(a1) kfc:=chicken{ feet:2, } a1=kfc fmt.Printf("這時a1的類型是:%T\n",a1) a1.eat("飼料") fmt.Println(a1) }
輸出結果:
這時a1的類型是:main.cat
貓喫小黃魚
{淘氣 4}
這時a1的類型是:main.chicken
雞喫飼料
{2} -
接口變量
實現了一個變量,可以保存所有實現了這個接口的類型的值。 -
空接口:
interface{}
接口中沒有定義任何方法,也就是說任意類型都實現了空接口。任何類型都可以存到空接口變量中,也就是說空接口類型的變量可以存儲任意類型的變量。
空接口的應用:
a. 作爲函數參數:使用空接口實現可以接收任意類型的函數參數。fmt.Println()
b.空接口作爲map的值map[string]interface{}
:使用空接口實現可以保存任意值的字典。 -
接口底層結構
接口底層是有動態類型
和動態值
兩部分組成的。
-
類型斷言:
當想知道接口接收的值具體時什麼類型時,需要使用類型斷言。//使用if判斷 func assign1(a interface{}) { fmt.Printf("%T\n", a) str,ok:=a.(string)//一種類型一種的試 if !ok{ fmt.Println("猜錯了") }else{ fmt.Println("傳進來的是一個字符串:",str) } } //使用switch實現: func assign2(a interface{}) { fmt.Printf("%T\n", a) switch t := a.(type) { case string: fmt.Println("是一個string:", t) case int: fmt.Println("是一個int:", t) case int64: fmt.Println("是一個int64:", t) case bool: fmt.Println("是一個bool:", t) } } func main() { assign1(10) assign2(true) }
int
猜錯了
bool
是一個bool: true -
同一個結構體可以實現多個接口;接口還可以嵌套
//同一個cat結構體可以實現多個接口 //接口還可以嵌套 type animal interface { mover eater } type mover interface { move() } type eater interface { eat(string) } type cat struct { name string feet int } //cat實現了mover接口 func (c cat)move(){ fmt.Println("走貓步...") } //cat實現了eater接口 func (c cat)eat(food string){ fmt.Printf("貓喫%s\n",food) }
需要注意的是:只有當有兩個或兩個以上的具體類型必須以相同的方式進行處理時才需要定義接口,不要爲了接口而寫接口,那樣只會增加不必要的抽象,導致不必要的運行時損耗