這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
go結構體詳解
go 是物件導向語言
封裝
可見度/不可見度 (大寫/小寫)
可重用性
方法的重載
介面
傳統沒,物件導向程式設計語言
資料結構構成一個類
你可以建立一個對象通過類的模板
類中封裝了屬性和方法
go中的類型
Go 類型:基本類型、參考型別、結構類型、自訂類型
Go 語言中,參考型別有 切片、字典(map)、介面、函數類型 以及 通道(chan) 。
結構類型是用來描述一組值的,比如一個人有身高、體重、名字和年齡等,本質上是一種彙總型的資料類型
類型別名 Go 的編譯器不會像 Java 的那樣,幫我們做隱式的類型轉換。
package mainimport "fmt"type foo intfunc main() { var myAge foo myAge = 44 fmt.Printf("%T %v \n", myAge, myAge)}
結構體的初始化
type person struct { first string last string age int}func main() { p1 := person{"James", "Bond", 20} p2 := person{"Miss", "Moneypenny", 18} fmt.Println(p1.first, p1.last, p1.age) fmt.Println(p2.first, p2.last, p2.age)}
struct method 結構體的方法
type person struct { first string last string age int}func (p person) fullName() string { return p.first + p.last}func main() { p1 := person{"James", "Bond", 20} p2 := person{"Miss", "Moneypenny", 18} fmt.Println(p1.fullName()) fmt.Println(p2.fullName())}
組合類別型 嵌入式類型
type person struct { First string Last string Age int}type doubleZero struct { person LicenseToKill bool}func main() { p1 := doubleZero{ person: person{ First: "James", Last: "Bond", Age: 20, }, LicenseToKill: true, } p2 := doubleZero{ person: person{ First: "Miss", Last: "MoneyPenny", Age: 19, }, LicenseToKill: false, } fmt.Println(p1.First, p1.Last, p1.Age, p1.LicenseToKill) fmt.Println(p2.person.First, p2.Last, p2.Age, p2.LicenseToKill)
屬性方法的覆蓋
聲明一個結構體類型的類型,若發生類型嵌套,如果外層沒有內層的屬性和方法則可以直接拿到內層的屬性和方法
如果外層也聲明了一樣的熟悉和方法,則會發生覆蓋,這跟物件導向的重寫類似,在go中嵌套就是傳統物件導向的繼承
結構體的指標
結構體的指標可以改變該結構體的屬性和方法
```go
type person struct {
name string
age int
}
func main() {
p1 := &person{"James", 20}
fmt.Println(p1)
fmt.Printf("%T\n", p1)
fmt.Println(p1.name)
fmt.Println(p1.age)
}
#### 結構體序列化>結構體的屬性要大寫,不然不能夠序列化```gotype person struct { First string Last string Age int notExported int}func main() { p1 := person{"James", "Bond", 20, 007} bs, _ := json.Marshal(p1) fmt.Println(bs) fmt.Printf("%T \n", bs) fmt.Println(string(bs))}
變數範圍
包的變數
var x = 42func main() { fmt.Println(x) foo()}func foo() { fmt.Println(x)}
包變數的範圍及可匯出
在go中 變數或方法名為大寫則意味著可匯出,在同一個包中可以任意使用
// MyName is exported because it starts with a capital lettervar MyName = "Todd"var yourName = "Future Rock Star Programmer"
變數在方法的範圍
func main() { x := 42 fmt.Println(x) foo()}func foo() { // no access to x // this does not compile fmt.Println(x)}
go的變數範圍
go的變數範圍是花括弧確定的,任一變數的範圍只在自身所處的花括弧範圍內
if, for等可以有初始設定式的,其範圍還要高於其後的花括弧一層
閉包
if-else
普通if-else
if a==1{
fmt.Println("a=1")
}
if else 局部變數
if food := "Chocolate"; b { a := true if a { food := "banana" fmt.Println(food) } else { food := "apple" fmt.Println(food) } fmt.Println(food) }
if else else if else
if false { fmt.Println("first print statement") } else if true { fmt.Println("second print statement") } else { fmt.Println("third print statement") }
迴圈
for 迴圈
for i := 0; i <= 100; i++ { fmt.Println(i) }
for range
當用於遍曆數組和切片的時候,range函數返回索引和元素;
當用於遍曆字典的時候,range函數返回字典的鍵和值。
數組
普通數組
var a [23]intfmt.Println(x) fmt.Println(len(x)) fmt.Println(x[42]) x[42] = 777 fmt.Println(x[42])
字面量數組
[3]int [4]int是兩種完全不同的類型
var q [3]int = [3]int{1, 2, 3}var r [3]int = [...]int{1, 2, 4}
切片
mySlice := []int{1, 3, 5, 7, 9, 11}
字典
make與 new的區別
介面
沒有介面的解構體方法
type square struct { side float64}func (z square) area() float64 { return z.side * z.side}func main() { s := square{10} fmt.Println("Area: ", s.area())}
有介面的結構體方法
type square struct { side float64}func (z square) area() float64 { return z.side * z.side}type shape interface { area() float64}func info(z shape) { fmt.Println(z) fmt.Println(z.area())}func main() { s := square{10} fmt.Printf("%T\n",s) info(s)}
錯誤處理
發生錯誤沒有進行異常處理
程式發生異常錯誤 fmt列印
```go
_, err := os.Open("no-file.txt")
if err != nil {
fmt.Println("err happened", err)
}
#### 發生錯誤沒有進行異常處理>程式發生異常錯誤 log列印```go _, err := os.Open("no-file.txt") if err != nil { // fmt.Println("err happened", err) log.Println("err happened", err) // log.Fatalln(err) // panic(err) }
發生錯誤沒有進行異常處理
程式發生異常錯誤 log列印到文本裡面
func init() { nf, err := os.Create("log.txt") if err != nil { fmt.Println(err) } log.SetOutput(nf)}func main() { _, err := os.Open("no-file.txt") if err != nil { // fmt.Println("err happened", err) log.Println("err happened", err) // log.Fatalln(err) // panic(err) }}
異常處理函數
defer 表示永遠在執行完成去執行defer後面的函數
func clean(){ fmt.Println(" do something in clean ")}func main(){ defer clean() fmt.Println("end main")}
defer
(準系統)簡單來講,在defer所在函數執行完所有的代碼之後,會自動執行defer的這個函數。
```go
func main() {
defer second()
first()
}
func first() {
fmt.Println("first")
}
func second() {
fmt.Println("second")
}
first
second
>局部函數```gofunc main() { defer second() defer third() first()}func first() { fmt.Println("first")}func second() { fmt.Println("second")}func third() { fmt.Println("third")}
棧特性
```go
func main() {
defer second()
defer third()
first()
}
func first() {
fmt.Println("first")
}
func second() {
fmt.Println("second")
}
func third() {
fmt.Println("third")
}
>### panic>panic相當於一個運行時異常>遇到panic的時候,會停止當前函數剩下來的語句,但在退出該函數之前,會執行defer的語句>依據函數調用層次,panic依次終止每個函數,直至main()。### recover>recover相當於try-catch的catch部分,使得panic不再傳遞。而defer相當於try-catch-final的final部分。```gofunc main() { f()}func final_print(msg string) { fmt.Println(msg)}func f() { fmt.Println("f.1") g() fmt.Println("f.2")}func g() { defer func() { str := recover() fmt.Println(str) }() defer final_print("g.defer()") fmt.Println("g.1") h() fmt.Println("g.2")}func h() { defer final_print("h.defer()") fmt.Println("h.1") panic("panic in h()") fmt.Println("h.2")}