本文忽略了匿名結構體跟結構體匿名方法,通常做爲開發者不建議去玩這種技巧性但沒實際意義的東西,直接從結構體的值傳遞跟引用傳遞開始編程
一、值傳遞和引用傳遞性能
不管學習哪門語言,都基本會大談特談「值傳遞」和「引用傳遞」的問題,GO語言也免不了俗氣一把,在GO語言中除了切片(slice)、集合(map)、通道(channel)和接口(interface)以外,其它的都是值傳遞,看下面的例子:學習
/*聲明一個結構體*/ type employee struct { name, address string // 姓名、住址 height, weight float64 // 身高、體重 } /*定義方法,該方法入參爲結構體,經過該方法修改結構體成員name的值*/ func modifyAttribute(emp employee) { emp.name = "newer" fmt.Println(emp) } /*測試方法*/ func main() { // 初始化結構體並賦給emp emp := employee{name: "eagle", address: "guangdong", height: 172.0, weight: 75.3} // 修改以前打印結果 fmt.Println(emp) // 調用方法修改name值並打印 modifyAttribute(emp) // 修改以後打印結果 fmt.Println(emp) }
執行並打印出結果測試
從結果上能夠看出雖然在方法modifyAttribute中修改了name,但對於main方法中定義的emp並無形成影響,因此這是一個值傳遞。編碼
C語言之因此通過這麼久的風風雨雨而經久不衰,其緣由之一在於它對內存的操做,對內存的操做就意味着性能的提高,由於對結構體內存地址的操做效率遠高於結構體的複製(別緊張,這裏不講指針,呵呵)指針
接下來咱們把入參由結構體修改成結構體指針code
/*把入參由結構體修改成結構體指針*/ func modifyAttribute(emp *employee) { emp.name = "newer" fmt.Println(emp) } /*測試方法*/ func main() { // 初始化結構體並賦給emp emp := employee{name: "eagle", address: "guangdong", height: 172.0, weight: 75.3} // 修改以前打印結果 fmt.Println(emp) // 調用方法修改name值並打印 modifyAttribute(&emp) // 修改以後打印結果 fmt.Println(emp) }
執行並打印出結果對象
從結果上能夠看出方法的修改影響到了main方法中emp的值,這再也不是值傳遞,而是引用傳遞了 :)blog
二、嵌套結構體接口
因爲結構體的嵌套在具體編碼中常常出現,上節寫的過於倉促,怕沒有解釋清楚,這裏再談一談關於結構體的嵌套問題
/*聲明figure結構體*/ type figure struct { height, weight float64 } /*聲明human結構體,裏面嵌套figure結構體*/ type human struct { name, address string figure }
正如上章所說,結構體在使用以前先進行初始化,比較好理解的初始化方式是:字面值初始化
man := human{} // 初始化human結構體,但不對成員賦值
// 採用字面值進行賦值
man.name = "eagle"
man.address = "guangdong"
man.height = 172 // 或者man.figure.height = 172
man.weight = 75.3 // 或者man.figure.weight = 75.3
這種賦值方式更面向對象化一些,從Java或者C++轉型過來的讀者可能更喜歡一些,但真正編碼過程當中,咱們會常常讀其餘人寫的代碼,他們可能更習慣初始化和賦值一塊進行:
man := human{name:"eagle", address:"guangdong", figure:figure{height:172, weight:75.3}}
請各位稍休息一下,而後重點考慮下面的話:
在human結構體嵌套中,您會發現成員變量name有指定名稱和類型,一樣address也是,但有一個奇葩figure,它究竟是成員名稱?仍是結構體類型呢?
答案是:figure既是成員名稱又是類型,因此在初始化時才採用figure:figure{}的形式初始化。
若您理解了這句話,能夠接着向下看了,不然須要重讀幾遍,再不清楚的話能夠留言給我 :)
三、面向對象
在《【4】GO語言類型和爲類型增長方法》中講到爲類型增長方法,你們融會貫通一下:
// 爲int類型起一個別名Integer type Integer int // 爲類型Integer增長一個新方法LessThan func (a Integer) LessThan (b Integer) bool{ return a < b } // 而後就能夠面向對象編程了 var a Integer = 5 // 定義一個對象a ,其類型爲Integer a.LessThan(8) // 調用對象a的方法LessThan()
再看一下結構體的聲明
// 爲struct類型起一個別名employee type employee struct{ name, address string } // 用方法模擬一個構造器 func newEmployee(name, address string) employee{ return employee{name, address} } // 定義一個修改employee住址的方法 func ModifyAddress(emp *employee){ emp.address = "shenzhen" } // 爲類型employee增長一個比較方法:只要名稱和地址相同,則認爲兩個對象相同 func (src employee) IsEqual(dest employee) bool{ return src.name == dest.name && src.address == dest.address } // 採用面向對象編程的方式使用結構體 // 初始化對象src和dest,且二者賦予相同的值 var src = newEmployee("eagle", "guangdong") var dest = newEmployee("eagle", "guangdong") fmt.Println(src.IsEqual(dest)) // 打印結果爲true // 修改目標的住址 ModifyAddress(&dest) fmt.Println(src.IsEqual(dest)) // 打印結果爲false
好了,到此結構體基本上已介紹完,但還有一些更細節的東西沒有介紹,例如:
採用new的方式初始化結構體
結構體是一種複合類型,因此它能夠和指針結合,本文都沒有深刻涉及
等等