1. 結構體 struct
1.1 概述
Go語言可以通過自定義的形式形成新的類型,結構體是類型中帶有成員的複合類型,Go語言中使用結構體和結構體成員描述 真實世界 的實體和實體對應的各種屬性 ,通過這個描述體現了Go語言中
struct
和class
具有同等地位
結構體成員
是一系列成員變量
構成的,這些成員變量也被稱爲字段
- 字段擁有自己的類型和值
- 一個結構體中字段名必須是唯一的
- 字段的類型可以是結構體
Go語言中結構體可以擁有
方法
並且每種自定義類型都可以擁有自己的方法Go語言中沒有繼承這樣的面向對象特性,只保留了
組合
這個基礎的特性, 組合是形成複合類型的基礎
1.2. 定義結構體
結構體是複合類型,通過
type
定義結構體的定義格式如下:
type 結構體名稱 struct{
字段1 類型
字段2 類型
字段3 類型
...
}
- 結構體名稱 : 標識自定義結構體的名稱 ,在同一包內不能重複
- struct{} : 標識這是個結構體類型
- 字段: 表示結構體中的字段名,在一個結構體中字段名必須是唯一
- 類型: 表示對應的結構體的數據類型,
package main
//定義一個Color的結構體
type Color struct {
R,G,B byte
}
// 定義一個point 結構體
type Point struct {
x int64
y int64
}
// 定義一個Student的結構體
type Student struct {
name string
age int
course []string
score map[string]int
average float32
graduate bool
}
func main(){
}
1.3 實例化結構體
結構體定義只是一種內存佈局的描述,只有當結構體實例化時,纔會真正分配內存,因此只有在結構體實例化之後才能使用結構體中的字段
- 實例化結構體也是創建一個結構體變量
- 訪問結構體中的成員變量通過
.
實現- 實例化一個結構體,要是沒有復,那麼結構體變量中訪問字段的初始值都是默認值
- 對同一個結構體實例化出來的多個結構體變量,這些變量個各不相干,結構體是對內存佈局的描述,每次實例化都是結構體變量分配新的內存
結構體本身是一種類型,所以可以以
var
關鍵字聲明一個變量是結構體的結構體變量,這樣就完成了實例化
package main
import "fmt"
type Student struct {
name string
age int
course []string
score map[string]int
average float32
graduate bool
}
func main() {
// 實例化方式1
var stu1 Student
fmt.Println(stu1)
}
實例化方法2
package main
import "fmt"
type Student struct {
name string
age int
course []string
score map[string]int
average float32
graduate bool
}
func main() {
// 實例化方式2
var stu2 Student = Student{}
fmt.Println(stu2)
}
實例化方法3
Go語言中使用
new
關鍵字對類型進行實例化,結構體在實例化之後會形成結構體指針格式:
ins : = new (T)
int *T = new(T)
package main
import "fmt"
type Student struct {
name string
age int
course []string
score map[string]int
average float32
graduate bool
}
func main() {
// 實例化方式1
var stu3 *Student = new(Student)
fmt.Println(stu3)
}
go run main.go
&{ 0 [] map[] 0 false}
實例化方法4 ,
格式如下:
int := &T{}
var int * T = &T{}
對結構體進行取地址
&
操作,相當於是進行一次new 的實例化操作 ,得到的是結構體指針
package main
import "fmt"
type Student struct {
name string
age int
course []string
score map[string]int
average float32
graduate bool
}
func main() {
// 實例化方法4
var stu4 *Student = &Student{}
fmt.Println(stu4)
}
go run main.go
&{ 0 [] map[] 0 false}
1.4 初始化結構體成員變量
結構體在實例化時,或者之後都可以對其成員變量進行初始化
package main
import "fmt"
type Student struct {
name string
age int
course []string
score map[string]int
average float32
graduate bool
}
func main() {
var stu1 Student
// 結構體變量成員初始化1 訪問結構體字段方式賦值
stu1.name = "張三"
stu1.age = 70
// slice 和 map 都需要make之後才能使用
stu1.course = make([]string,3)
stu1.course[0] = "數學"
stu1.course[1] = "物理"
stu1.course[2] = "化學"
fmt.Println(stu1)
// 結構體變量成員初始化2 鍵值對形式賦值
var stu2 Student = Student{
name:"李四",
age:70,
course:[]string{"語文","地理"},
score: map[string]int{"語文":120,"地理":90},
average:105.0,
graduate:false,
}
fmt.Println(stu2)
// 結構體變量成員初始化3 值列表形式賦值
stu3 := Student{
"王五",
70,
[]string{"音樂","美術"},
map[string]int{"音樂":90,"美術":80},
85.0,
true,
}
fmt.Println(stu3)
}
go run main.go
{張三 70 [數學 物理 化學] map[] 0 false}
{李四 70 [語文 地理] map[地理:90 語文:120] 105 false}
{王五 70 [音樂 美術] map[美術:80 音樂:90] 85 true}
看一訪問結構體成員的例子
結構體指針訪問結構體成員的標準格式是
(*結構體指針).字段名
,例如下面的例子(*stu).name = "趙六"
但是在go語言中也支持
結構體.字段名
如下stu.name = "秦七"
的形式,這是因爲go語言自己做了一個簡化,Go在編譯時將stu.name
轉化成了(*stu).name
package main
import "fmt"
type Student struct {
name string
age int
course []string
score map[string]int
average float32
graduate bool
}
func main() {
var stu *Student = new(Student)
fmt.Println(stu)
// 結構體變量stu是結構體指針那麼訪問結構體成員
(*stu).name = "趙六"
fmt.Println(*stu)
// 一般的方法訪問結構體成員變量
stu.name = "秦七" // (*stu).name = "秦七"
fmt.Println(*stu)
}
go run main.go
&{ 0 [] map[] 0 false}
{趙六 0 [] map[] 0 false}
{秦七 0 [] map[] 0 false}
1.5 結構體變量複製
結構體變量作爲值賦給另外的變量是值拷貝,那麼這兩個結構體變量沒有任何關係
結構體變量也可以將結構體地址賦值給結構體指針變量,這樣就成了地址拷貝
package main
import "fmt"
type Person struct {
name string
age int
}
func main() {
var p1 Person = Person{"張三", 70}
// 結構體值拷貝
p2 := p1
p2.name = "李四"
fmt.Printf("p1 =>addr = %p,value = %v\n", &p1, p1)
fmt.Printf("p2 =>addr = %p,value = %v\n", &p2, p2)
// 結構體地址拷貝
var p3 *Person = &p2
// p3的修改,直接影響p2
p3.name = "王五"
fmt.Printf("p2 =>addr = %p,value = %v\n", &p2, p2)
// p3的值就是p2 的地址,當然p3也有自己的內存地址
fmt.Printf("p3 =>addr = %p,p3 = value = %p\n", &p3, p3)
}
go run main.go
p1 =>addr = 0xc00004a420,value = {張三 70}
p2 =>addr = 0xc00004a440,value = {李四 70}
p2 =>addr = 0xc00004a440,value = {王五 70}
p3 =>addr = 0xc000080020,p3 = value = 0xc00004a440
1.6 匿名結構體
匿名結構體就是沒有結構體名稱的結構體,無需type關鍵字就可以直接使用
使用的不多,此處只是提一下
定義格式和初始化寫法
ins := struct{
字段名1 類型1
字段名2 類型2
字段名3 類型3
...
}{
字段名1 : 值1,
字段名2 : 值2,
字段值3 : 值3,
...
}
package main
import "fmt"
func getType(ins struct {
id int
data string
}) {
fmt.Printf("%T\n", ins)
ins.id = 99
fmt.Println(ins)
}
func main() {
ins := struct {
id int
data string
}{
1,
"hello golang",
}
// 將結構體當做值賦給另外一個變量,值拷貝
ins2 := ins
ins2.id = 2
ins2.data = "hello world"
getType(ins)
getType(ins2)
fmt.Println(ins)
fmt.Printf("%T\n", ins)
}
go run main.go
struct { id int; data string }
{99 hello golang}
struct { id int; data string }
{99 hello world}
{1 hello golang}
struct { id int; data string }
1.7 模擬構造函數
Go語言中沒有進行顯示初始化的值都會使用它自身的默認值,結構體也是如此.Go語言中沒有其他編程語言中的
構造函數
這個概念,那麼結構體的初始化工作可以交給一個全局的構建函數函數來完成,模擬出構造函數
package main
import "fmt"
type Person struct {
name string
nationality string
BloodType byte
}
func NewPerson(name string, nationality string, blood byte) *Person {
return &Person{
name: name,
nationality: nationality,
BloodType: blood,
}
}
func main() {
p1 := NewPerson("張三", "漢族", 'A')
fmt.Printf("%s 是 %s 血型是%c型\n", p1.name, p1.nationality, p1.BloodType)
p2 := NewPerson("李四", "滿族", 'B')
fmt.Printf("%s 是 %s 血型是%c型", p2.name, p2.nationality, p2.BloodType)
}
go run main.go
張三 是 漢族 血型是A型
李四 是 滿族 血型是B型