tft每日頭條

 > 生活

 > go三層架構

go三層架構

生活 更新时间:2024-12-04 10:06:59
Golang構造函數

go三層架構(Go基礎之結構體二)1

Go沒有類似傳統面向對象的構造函數,但是我們可以通過結構體來使用構造函數初始化結構體類型。

我們在使用構造函數要注意struct是值類型如果結構體比較複雜最好返回結構體指針類型,因為值拷貝性能開銷大。

  • 簡單的構造函數

package main import "fmt" type Server struct { address string port int } func NewServer() *Server { return &Server{ address: "localhost", port: 8080, } } func main() { server1 := NewServer() fmt.Println(server1) } // result &{localhost 8080}

  • 如何使用工廠設計模型創建結構體

Go中的工廠模式其實就是包内一個不可直接實例的結構體(結構體名稱首字母小寫即私有結構體),包外不可直接實例化實例,那麼為了解決這個問題可以寫一個包外可調用的函數,通過這個函數實現返回結構體對象。

// main.go 代碼 package main import ( "fmt" "app/model" ) func main(){ p1 := model.NewPerson("jack", 20) age := p.GetAge() fmt.Println(*p1) fmt.Println(age) } // result // {jack 20} // 20 // app/model.go package model type person struct( Name string age int ) func NewPerson(name string,age int) *person{ return &person{ Name: name, age: age, } } func (p *person) GetAge() int{ return p.age }

類型别名和自定義類型

類型别名是Go在1.9版本之後添加的新特性,主要是用在代碼升級、代碼重構和遷移中類型的兼容性。

  • 基本數據類型類型别名

type byte uint8 type rune int32

  • 區别類型别名和自定義類型

類型别名指定類型别名隻是類型的别名。本質上類型的别名和類型是相同的類型,即基本數據類型是相同的。

package main import "fmt" type myInt int type intAlias = int func main() { var a myInt fmt.Printf("a Type: %T, value: %d\n", a, a) var b intAlias fmt.Printf("b Type: %T, value: %d\n", b, b) } // result // a Type: main.myInt, value: 0 // b Type: int, value: 0

通過上面的代碼來看,在表面上類型别名和自定義類型之間隻有相等的符号差異(“ =”),實際上我們可以代碼運行結構看到a的類型是myint而且是main包定義的myInt類型,即生成了新的數據類型,而b的類型是int,則表示intAlias類型僅在代碼中體現而編譯完成之後沒有intAlias類型。

結構體中的方法及接受者

Go 語言支持方法,Go方法類似于 Go 函數,但有一個區别即該方法包含一個接收者參數。通過接受者參數該方法就可以訪問接收者的屬性。這裡接收者表示可以是結構類型或非結構類型,在代碼中創建方法時,接收者和接收者類型必須存在于同一個包中。并且不允許創建接收者類型已在另一個包中定義的方法,包括 int、string 等内置類型。如果這樣做,Go編譯器将給出錯誤。

  • 定義方法的格式

func (接收者變量 接收者類型) 方法名(參數列表) (返回參數) { 函數體 }

  • 值類型(即結構體本身)接收者的方法

使用值類型接受者的方法時無法改變接受者變量的值。

package main import "fmt" type person struct { name, job string age int } func (p person) show() { fmt.Println("Person's Name: ", p.name) fmt.Println("Job: ", p.job) fmt.Println("age:", p.age) } func main() { res := person{ name: "jack", job: "engine", age: 20, } res.show() } // result // Person's Name: jack // Job: engine // age: 20

  • 指針類型(即結構體指針)接受者的方法

結構體指針類型的接收者由一個結構體的指針組成,由于指針的特性,調用方法時修改接收者指針的任意成員變量,在方法結束後,修改都是有效的。

package main import "fmt" type user struct { name, job string age int } func (u *user) SetAge(age int) { u.age = age } func main() { res := user{ name: "jack", job: "engine", age: 19, } fmt.Println("user's name: ", res.name) fmt.Println("user's job: ", res.job) fmt.Println("user's age: ", res.age) u := &res u.SetAge(22) fmt.Println("user's name: ", res.name) fmt.Println("user's job: ", res.job) fmt.Println("user's age: ", res.age) } // result // user's name: jack // user's job: engine // user's age: 19 // user's name: jack // user's job: engine // user's age: 22

  • 非結構體類型添加方法

在 Go 語言中,隻要類型和方法定義存在于同一個包中,就可以創建具有非結構類型接收器的方法。如果不存在同一個包裡,那麼編譯器就會報錯,因為它們是在不同的包中定義的。

package main import "fmt" type data int func (d1 data) multiply(d2 data) data { return d1 * d2 } func main() { value1 := data(20) value2 := data(20) res := value1.multiply(value2) fmt.Println("Final result: ", res) } // result // Final result: 400

重點:什麼時候使用值類型接受者方法,什麼時候使用指針類型接受者方法。

  • 當你需要修改接受者的屬性時
  • 接受者是個複雜結構體時
  • 保持代碼可讀性跟一緻性,意思就是你不能一個方法用了指針類型一個方法用值類型。
結構體的”繼承“

結構體嵌套可以模拟面向對象編程繼承的特性中以下兩種關系:

聚合關系:一個類作為另一個類的屬性,聚合關系一定不能是匿名結構體必須用有名字的結構體作為結構體字段

繼承關系:一個類作為另一個類的子類。子類和父類的關系。匿名結構體字段的形式就是繼承關系

  • 聚合關系(也可以叫組合)

package main import "fmt" type Address struct { province, city string } type Person struct { name string age int address *Address } func main() { p1 := Person{name: "jack", age: 19, address: &Address{province: "Guangdong", city: "Guangzhou"}} fmt.Printf("Name: %s\nAge: %d\nProvince: %s\nCity: %s\n", p1.name, p1.age, p1.address.province, p1.address.city) // 當你修改Person結構體實例化p1的數據時,結構體Address的數據也會發生變化 p1.address.province = "Hunan" p1.address.city = "Changsha" fmt.Printf("Province: %s\nCity:%s\n", p1.address.province, p1.address.city) }

  • 繼承關系

如果一個結構體嵌套了另一個匿名結構體,那麼這個結構體可以直接訪問匿名結構體的方法,從而實現繼承。

package main import "fmt" type Cat struct { age int name string } func (c *Cat) Run() { fmt.Println("Cat Running") } type WhiteCat struct { Cat color string } type BlackCat struct { Cat } func (p *BlackCat) String() string { str := fmt.Sprintf("name=[%s] age=[%d]", p.name, p.age) return str } func main() { var a WhiteCat a.age = 2 a.name = "tom" a.color = "white" fmt.Println(a) a.Run() var b BlackCat b.age = 3 b.name = "rise" b.Run() fmt.Printf("%s", &b) }

注意

結構體嵌套時可能存在相同的屬性名,屬性名重名會導緻屬性名沖突,盡量避免這種情況。

結構體字段的私有屬性和公開屬性

結構體中字段大寫開頭表示可公開訪問的屬性,小寫表示私有屬性(僅在定義當前結構體的包中可訪問)。

結構體标簽(Tag)和JSON序列化

結構體tag是結構體的元信息,可以在運行的時候通過反射的機制讀取出來。 Tag在結構體字段的後方定義,由一對反引号包裹起來。

  • 定義結構體标簽的格式

結構體标簽由一個或多個鍵值對組成。鍵與值使用冒号分隔,值用雙引号括起來。鍵值對之間使用一個空格分隔。

type user struct { Name string `json:name` // 通過指定tag實現json序列化該字段時的key password string // 私有屬性不能被json訪問 }

  • JSON序列化結構體

package main import ( "encoding/json" "fmt" ) type User struct { ID int `json:"id"` Name string `json:"name"` } func main() { u1 := User{ ID: 1, Name: "jack", } data, err := json.Marshal(u1) if err != nil { fmt.Println("json marshal failed!") return } fmt.Printf("json str:%s\n", data) }

  • JSON反序列化結構體(從json中讀取數據為結構體數據)

package main import ( "encoding/json" "fmt" ) type User struct { ID int `json:"id"` Name string `json:"name"` Age int `json:"age"` } func main() { var r User s := `{ "name":"jack", "age":18, "id":1 }` err := json.Unmarshal([]byte(s), &r) if err != nil { fmt.Print(err) } fmt.Printf("結構體轉換為字符串之後的值為:%#v", r) }

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关生活资讯推荐

热门生活资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved