GO學習筆記——面向對象編程之結構體(15)

GO是支持面向對象編程的,但是面向對象的三大特性:封裝,繼承,多態,GO只支持封裝,並不支持繼承和多態。學過C++的有沒有感覺在學繼承和多態的時候特別複雜麻煩,那些對象模型特別容易搞混。所以這樣設計也是極好的,簡化了語言。繼承和多態這些功能GO是通過接口來實現的,這在後續會講到。

也是爲了簡化,GO中只有struct,沒有class,也就是說,GO是通過結構體來實現面向對象的,而不是通過類。

所以,面向對象編程,我們先從結構體來說起。


結構體定義

簡單的結構體定義如下

//定義一個單鏈表的節點
type ListNode struct {
	next *ListNode    //單鏈表的next節點
	val int	    //節點的值
}

聲明一個結構體變量

//定義一個單鏈表的節點
type ListNode struct {
	next *ListNode
	val int
}

func main() {
	root := ListNode{val:3}	//next是默認零值nil
	fmt.Println(root)
	root.val = 5	//和其他語言一樣,可以用.來訪問結構體成員
	fmt.Println(root)
}

輸出結果

{<nil> 3}
{<nil> 5}

另外,也可以根據結構體內變量聲明的順序直接定義

func main() {
	root := ListNode{nil,3}
	fmt.Println(root)
}

還可以使用new關鍵字,來爲引用類型的變量開闢空間(指針),因爲GO中對nil指針做取操作也是會報錯的。

func main() {
	root := ListNode{}
	root.next = &ListNode{nil,5}
	root.next.next = new(ListNode)	//new分配空間以後的值爲默認零值
	fmt.Println(root.next.next)
}

另外,注意一下,GO中訪問指針指向的對象的內容不是用->,還是用.,這也是和C++的一個區別,也是GO的一個簡單之處。


結構體沒有構造函數

GO中的結構體沒有構造函數,如上我們在{}中就直接構造了一個結構體變量,但有些時候我們還是想自己來控制結構體構造,這裏就可以創建一個工廠函數來自定義創建結構體。

//自定義的工廠函數
func createListNode(value int) *ListNode{
	return &ListNode{val:value}
}


func main() {
	root := createListNode(3)
	fmt.Println(*root)
}

輸出結果

{<nil> 3}

注意這邊函數中返回的是一個局部變量的地址,在C++中,返回局部變量的地址這種行爲是非常可怕的,這個指針就會是一個野指針。而GO語言中支持這種語法,顯然是有它的道理的。我這邊參考了一篇博客:函數返回局部變量地址,他是這麼說的:

go語言編譯器會自動決定把一個變量放在棧還是放在堆,編譯器會做逃逸分析(escape analysis),當發現變量的作用域沒有跑出函數範圍,就可以在棧上,反之則必須分配在堆。所以不用擔心會不會導致memory leak,因爲GO語言有強大的垃圾回收機制。go語言聲稱這樣可以釋放程序員關於內存的使用限制,更多的讓程序員關注於程序功能邏輯本身。

所以函數內部局部變量,無論是動態new出來的變量還是創建的局部變量,它被分配在堆還是棧,是由編譯器做逃逸分析之後做出的決定

 

所以,說到這裏,來總結一下GO的一個特點:

GO程序員不需要關心定義的這個局部變量具體是在堆上,還是在棧上,即使是new出來的也不一定在堆上,GO編譯器會對該變量做逃逸分析來確定變量的存放位置,即使是在堆上分配了,GO也有垃圾回收機制不用我們去主動釋放空間,作爲程序員我們只要考慮上層的這些邏輯就可以了,不需要關心底層具體的分配問題。

 

上述是題外話了,繼續來討論結構體。


結構體相等性

結構體中的字段如果都是可以比較的,那麼結構體變量之間也是可以比較的;反之,如果結構體中包含了不可以比較的字段,那麼結構體變量之間就是不可以比較的

先來看下如果字段都是可以比較的結構體

type Person struct {
	name string
	age int
}

func main() {
	student1 := Person{"pigff",1}
	student2 := Person{"pigff",1}
	if student1 == student2{
		fmt.Println("兩個變量相等")
	}else{
		fmt.Println("兩個變量不相等")
	}
}

輸出結果

兩個變量相等

再看下包含不可以比較的字段

type Person struct {
	data map[string]int
}

func main() {
	student1 := Person{map[string]int{
		"pigff":1,
	}}
	student2 := Person{map[string]int{
		"pigff":1,
	}}
	if student1 == student2{
		fmt.Println("兩個變量相等")
	}else{
		fmt.Println("兩個變量不相等")
	}
}

程序會在編譯期間報錯

.\main.go:17:14: invalid operation: student1 == student2 (struct containing map[string]int cannot be compared)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章