Go學習總結筆記(一)

go version 1.13

基礎語法

1. new(T)make(T,args)的區別?

new(T) 返回對應T的指針類型,即*T,指針指向的數據其值爲零值,make(T,args) 只能初始化 slice,map,chan這三種類型,T的初始化值也爲零值,但是返回類型是T類型的引用,而不是指針類型。

2. slice 使用append()函數時,參數爲slice和相同類型的元素時,有啥不同?

slice追加slice時,需要在被追加的slice後面加...,追加元素時而不需要,具體可看下面代碼片斷。

 	s1 := []int{1, 2, 3}
	s2 := []int{4, 5}

	s1 = append(s1, s2...)
	fmt.Println(s1)

	s1 = append(s1, 6, 7)
	fmt.Println(s1)

3. 變量的聲明方式有哪幾種?

有四種。

方式一:var 變量名 變量類型,這種方式變量值爲零值,如下所示:

    var s string
    var i int
	var m map[string]string
	
    fmt.Printf("s:%T,%q,i:%T,%v,m:%T,%v",s,s,i,i,m,m)

代碼輸出結果:s:string,"",i:int,0,m:map[string]string,map[]

方式二: var 變量名 變量類型 = 表達式,表達式指定變量的初始值,如下所示:

    var s1 string = "Hello,王二狗"
    var i1 int = 520
    var s2 []string = []string{"學習","go"}
    
    fmt.Printf("s1:%T,%q,i1:%T,%v,s2:%T,%v\n",s1,s1,i1,i1,s2,s2)

代碼輸出結果:s1:string,"Hello,王二狗",i1:int,520,s2:[]string,[學習 go]

方式三(同時聲明多個變量):var 變量名1,變量名2 = 值1,值2,如下所示:

    var s3,i2 = "Happy",521
    fmt.Printf("s3:%T,%q,i2:%T,%d\n",s3,s3,i2,i2)

代碼輸出結果:s3:string,"Happy",i2:int,521

方式四:變量名 := 值,注意,這種短變量聲明方式只能使用在函數內部,如下所示:

    
    s4 := "技術人的自我修養"
    i3 := 12345
    
    fmt.Printf("s4:%T,%q,i3:%T,%d\n",s4,s4,i3,i3)

代碼輸出結果:s4:string,"技術人的自我修養",i3:int,12345

4. 常量如何聲明?

常量的聲明要使用關鍵字const,常量在聲明的時候必須賦值,方式有兩種。

方式一:const 常量名 = 常量值。

    const s1 = "Happy"
    const i = 1234

方式二:參考代碼片斷。

    const(
        s2 = "編程學習"
        i2 = 2020
    )

5. Go語言中,哪些變量類型可以直接比較,哪些滿足前提條件下可比較,哪些不能比較?

布爾類型(boolean)、整型(integer)、浮點數(float)、複數(complex)、字符串(string)、指針類型(pointer)、通道(channel)、接口類型(interface)可以直接進行比較。

結構體(struct)、數組(array),如果元素都是能直接比較類型,(即元素類型屬於前一類能直接比較的),則對應的結構體和數據也可比較。

切片(slice)、map和函數類型(func)不能進行比較,除非是與nil進行比較。

注意:接口類型雖可直接比較,但如果實現接口的對應類型不能直接進行比較的話,也會引發panic導致程序異常退出,如下代碼所示:

// T 定義的一個演示接口
type T interface {
	hello()
}

// PersonA 演示用結構體
type PersonA struct {
	m map[string]int
}

// PersonB 演示用結構體
type PersonB struct {
}

func (p *PersonA) hello() {
	fmt.Println("hello PersonA")
}

func (p *PersonB) hello() {
	fmt.Println("hello PersonB")
}

func main() {
	var p1 PersonA
	var p2 PersonB
	fmt.Println(p1 == p2)
}

運行以上代碼會提示:invalid operation: p1 == p2 (mismatched types PersonA and PersonB)

Boolean values are comparable. Two boolean values are equal if they are either both true or both false.

Integer values are comparable and ordered, in the usual way.

Floating-point values are comparable and ordered, as defined by the IEEE-754 standard.

Complex values are comparable. Two complex values u and v are equal if both real(u) == real(v) and imag(u) == imag(v).

String values are comparable and ordered, lexically byte-wise.

Pointer values are comparable. Two pointer values are equal if they point to the same variable or if both have value nil. Pointers to distinct zero-size variables may or may not be equal.

Channel values are comparable. Two channel values are equal if they were created by the same call to make or if both have value nil.

Interface values are comparable. Two interface values are equal if they have identical dynamic types and equal dynamic values or if both have value nil.

A comparison of two interface values with identical dynamic types causes a run-time panic if values of that type are not comparable. This behavior applies not only to direct interface value comparisons but also when comparing arrays of interface values or structs with interface-valued fields.

A value x of non-interface type X and a value t of interface type T are comparable when values of type X are comparable and X implements T. They are equal if t's dynamic type is identical to X and t's dynamic value is equal to x.

Struct values are comparable if all their fields are comparable. Two struct values are equal if their corresponding non-blank fields are equal.

Array values are comparable if values of the array element type are comparable. Two array values are equal if their corresponding elements are equal.

Slice, map, and function values are not comparable. However, as a special case, a slice, map, or function value may be compared to the predeclared identifier nil.

Comparison of pointer, channel, and interface values to nil is also allowed and follows from the general rules above.

以上英文片斷出自:https://golang.org/ref/spec#Comparison_operators

6.通過指針變量p訪問成員變量的方式?

// p.name , (*p).name 或 *&p.name
type person struct {
	name string
}

func main() {
	p1 := person{name: "王二狗"}
	p := &p1
	fmt.Printf("%s,%s,%s\n", p.name, (*p).name, *&p.name)
}

7.類型別名與自定義的區別

Go中可用type關鍵字自定義類型,類型別名相當於給類型T取一個別名,別名指向的類型本質上還是屬於T,二者的語法區別如下所示:

// MyInt 自定義類型:MyInt,屬於一個新類型,它具有int的特性
type MyInt int

// MyInt2 類型別名:給int類型取一個別名
type MyInt2 = int

func main() {
	var i int = 1234
	// 編譯不通過,因爲Go是強類型語言,不能直接把int類型的變量賦給MyInt類型,可通過強轉賦值
	//var i1 MyInt = i
	var i1 MyInt = MyInt(i)
	var i2 MyInt2 = i
	fmt.Printf("i1 type:%T,i1=%d,i2 type:%T,i2=%d\n", i1, i1, i2, i2)
}

// 輸出結果:i1 type:main.MyInt,i1=1234,i2 type:int,i2=1234

8.nil可以給哪些類型的變量賦值?

nil 只能給 chanslice,map,interface,func和指針類型賦值。注意:error本質上屬於interface類型,參考源代碼定義,如下:

type error interface {
    Error() string
}

9.說說Go中的init()函數?

  • init()是包的初始化函數,用於程序在執行對應包的代碼前做一些初始化工作;

  • 每個包可以有多個init()函數;

  • 每個包的同一個源碼文件也可以有多個init()函數;

  • 同一個源碼文件的init()函數執行順序沒有明確定義;

  • init()函數不能手工調用,只能在引入包時自動執行;

  • 不同包的init()函數調用關係可參考下圖:

    image-20200525170544881

10.一個接口如果被*T類型的變量實現,T可以賦值給該接口類型嗎?

不能,參考以下代碼:

// Walker 接口
type Walker interface {
	Walk() string
}

// Dog 狗
type Dog struct{}

// Walk 小狗跑
func (d *Dog) Walk() string {
	return "小狗奔跑"
}

func main() {
	var walker Walker
	wangcai := &Dog{}
	fugui := Dog{}

	walker = wangcai
	fmt.Println("旺柴", wangcai.Walk())
	fmt.Println("接口", walker.Walk())

	// walker = fugui 編譯不通過,因爲實現Walker的是 *Dog類型
	walker = &fugui
	// Dog 和 *Dog 都可以調用 Walk()函數
	fmt.Println("富貴", fugui.Walk())
	fmt.Println("接口", walker.Walk())
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章