Golang數(shù)據(jù)類型之結構體-上篇
目錄
1、結構體介紹
2、結構體的定義
3、構造結構體實例
4、聲明與初始化
5、屬性的訪問和修改

1、結構體介紹

為什么要有結構體?
數(shù)組只能保存同一種類型的數(shù)據(jù),當需要記錄多種不同類型的數(shù)據(jù),并聚集在一起用來描述復雜的實體時,怎么辦?
結構體就是用于解決這個問題的,結構體是由一系列具有相同類型或不同類型的數(shù)據(jù)構成的數(shù)據(jù)集合,方便容量任意類型的數(shù)據(jù)
結構體的目的就是把數(shù)據(jù)聚集在一起,以便能夠更加便捷的操作這些數(shù)據(jù)
結構體是由一些列屬性組成的復合數(shù)據(jù)類型,每個屬性都具有名稱、類型和值,結構體將屬性組合在一起進行由程序進行處理
結構體和類的概念
go里面沒有類,go用一種特殊的方式,把結構體本身看做一個類
一個成熟的類,具備成員變量和成員函數(shù),結構體本身就有成員變量,再給他綁定上成員函數(shù),就可以了
結構體單例綁定
如下,sayHello()用了指針的方式進行綁定,相當于給結構體綁定了函數(shù),這個結構體等價于對象
唯一的不同點就是如果使用*綁定函數(shù),那么這種對象就是單例的,引用的是同一個結構體
type People struct {
name string
}
func (p People) toString() {
fmt.Println(p.name)
fmt.Printf("p的地址 %p \n", &p)
}
func (p *People) sayHello() {
fmt.Printf("Hello %v \n", p.name)
fmt.Printf("*P的地址 %p \n", p)
}
2、結構體的定義
結構體定義使用struct標識,需要指定其包含的屬性(名和類型),使用關鍵字type和struct來定義一個結構體
結構體的定義格式如下
type 類型名 struct {
字段1 類型1
字段2 類型2
//...
}
以上各個部分的說明如下
類型名:標識自定義結構體的名稱,在同一個包內不能包含重復的類型名 struct{}:表示結構體類型,type 類型名 struct{}可以被理解為將 struct{}結構體定義為類型名的類型 字段 1、字段 2......:表示結構體字段名。結構體中的字段名必須唯一 類型 1、類型 2......:表示結構體各個字段的類型,結構體中的字段可以是任意類型:string、int、float;復合類型:map、slice、channel、struct
在定義結構體時可以為結構體指定結構體名(命名結構體),用于后續(xù)聲明結構體變量使用
type struct_variable_type struct {
member definition
member definition
...
member definition
}
例如 用于描述一個人的特征
如果單獨使用變量描述應該如何描述?
沒有結構體
var (
name string
age int
gender string
weight uint
favoriteColor []string
)
使用結構體
type Person struct {
Name string
Age int
Gender string
Weight uint
FavoriteColor []string
}
type User struct {
ID int
Name string
Birthday string
Addr string
Tel string
Remark string
}
如果某幾個字段類型相同,可以縮寫在同一行:
type Person struct {
Name, City string
Age int
}
可以看出結構體就像一個容器,這個容器里面裝什么自己定義,這也是結構體的特點: 自定義化的程度很高,使用靈活
一旦定義了結構體類型,則它就能用于變量的聲明,語法格式如下
variable_name := struct_variable_type {value1, value2,...}
或
variable_name := struct_variable_type {key1: value1, key2: value2,...}
例如,定義一個名為Book的圖書結構體,并打印出結構體的字段值的示例如下
package main
import "fmt"
type Book struct {
title string
author string
subject string
press string
}
func main() {
// 創(chuàng)建一個新的結構體
fmt.Println(Book{"Go基礎", "ssgeek", "Go語言", "Go語言教程"})
// 也可以使用 key => value 格式
fmt.Println(Book{title: "Go基礎", author: "ssgeek", subject: "Go語言", press: "Go語言教程"})
// 忽略的字段為 0 或 空
fmt.Println(Book{title: "Go基礎", author: "ssgeek"})
}
3、構造結構體實例
定義了struct,就表示定義了一個數(shù)據(jù)結構,或者說數(shù)據(jù)類型,也或者說定義了一個類。總而言之,定義了struct,就具備了成員屬性,就可以作為一個抽象的模板,可以根據(jù)這個抽象模板生成具體的實例,也就是所謂的"對象", 也就是面向對象中的Class---> Object, 如下圖

對應的結構體定義
type Car struct {
Color string // 顏色
Brand string // 品牌
Model string // 型號
}
var car Car // 初始化一個Car實例, car就代表是一輛具體的車(Object)
這里的car就是一個具體的Car實例,它根據(jù)抽象的模板Car構造而出,具有具體的屬性Color、Brand和Model的值,雖然初始化時它的各個字段都是""值。換句話說,car是一個具體的車, 比如福特野馬
struct初始化時,會做默認的賦0初始化,會給它的每個字段根據(jù)它們的數(shù)據(jù)類型賦予對應的0值。例如int類型是數(shù)值0,string類型是"",引用類型是nil等
var car Car
fmt.Printf("%+v", car) // {Color: Brand: Model:}
也可以在聲明的時候直接為成員變量賦值,通常把這個過程稱之為構造結構體的實例, 語法如下:
// 使用{k:v, k:v}這種方式來為結構體的成員賦值
TypeName{filed1: value1, filed2: value2, ...}
// 為了書寫美觀, 通常都把每一個k:v 獨立寫在一行,比如:
TypeName{
file1: value1,
file2: value2,
...
}
一個具體的例子,比如要通過Car構造一個具體的汽車: 福特野馬
// 為了書寫的簡潔,采用簡單聲明的方式, 就像 a := 10 <---> var a int; a = 10
//
var car Car
fmt.Printf("%+v\n", car)
car = Car{ // 當然也可以不然聲明car的類型, 直接使用簡短聲明: car := Car{...}
Color: "yellow", // 黃色
Brand: "ford", // 福特
Model: "yema", //
}
fmt.Printf("%+v\n", car) // {Color:yellow Brand:ford Model:yema}
// 注意,上面最后一個逗號","不能省略,Go會報錯,這個逗號有助于去擴展這個結構
4、聲明與初始化
聲明結構體變量只需要定義變量類型為結構體名,變量中的每個屬性被初始化為對應類型的零值
也可聲明結構體指針變量,此時變量被初始化為nil
遵循所有類型聲明語法: var struct_name struct_type
使用結構體創(chuàng)建的變量叫做對應結構體的實例或者對象
只聲明不初始化
比如下面初始化一個person的實例
// 只聲明
var person Person
var me User
fmt.Printf("%T\n", me) // main.User
可以看到聲明后的結構體的所有屬性都是初始值
var不加等號:初始化零值(對數(shù)值類型來說,零值是 0;對字符串來說,零值是空字符串;對布爾類型,零值是false)
var person Person
fmt.Printf("%+v\n", person)
// {Name: Age:0 Gender: Weight:0 FavoriteColor:[]}
var me3 User = User{}
fmt.Println(me3) // {0 0001-01-01 00:00:00 +0000 UTC }
聲明并初始化
使用字面量初始化結構體值對象
var person Person = Person{
Name: "andy",
Age: 66,
Gender: "male",
Weight: 120,
FavoriteColor: []string{"red", "blue"},
}
fmt.Printf("%+v\n", person)
// {Name:andy Age:66 Gender:male Weight:120 FavoriteColor:[red blue]}
fmt.Printf("%p\n", &person.Name) // 0xc0000ce080 地址相鄰
fmt.Printf("%p\n", &person.Age) // 0xc0000ce090 地址相鄰
var me2 User = User{
1,
"geek",
time.Now().Format("2006-01-02"),
"北京市",
"15588888888",
"這是備注2",
}
fmt.Printf("%v\n", me2) // {1 geek 2021-08-10 北京市 155888888888 這是備注2}
可以在函數(shù)外部使用,可以用來聲明初始化全局變量
注意,上面最后一個逗號","不能省略,Go會報錯,這個逗號有助于去擴展這個結構體
使用短變量聲明
// 變量 := 結構體{賦值}
func TestPerson32(t *testing.T) {
p3 := Person3{
Name: "ssgeek",
Age: 24,
}
fmt.Println(p3)
}
通過屬性名
// 通過屬性名指定,可以省略、無序
var me4 User = User{ID:1, Name: "geek", Birthday: time.Now().Format("2006-01-02"), Addr: "北京市", Tel: "15588888888"}
fmt.Println(me4)
使用 new 函數(shù)進行初始化結構體指針對象
var me5 *User = new(User)
fmt.Printf("%T, %#v, %#v\n", me5, me5, *me5)
使用指針初始化
var me6 *User
fmt.Printf("%T\n", me6) // *main.User
fmt.Printf("%#v\n", me6) // (*main.User)(nil)
var me7 = &User{ID: 2, Name: "geek"}
fmt.Printf("%T\n", me7) // *main.User
5、屬性的訪問和修改
通過結構體對象名.屬性名的方式來訪問和修改對象的屬性值
可以通過結構體指針對象的點操作直接對對象的屬性值進行訪問和修改
// 語法:結構體.成員名
fmt.Println((&person).Name) // andy
fmt.Println(person.Name) // andy
person.Age = 20
fmt.Println(person.Age) // 20
在golang中,訪問結構體成員需要使用點號操作符,點號操作符也被稱為選擇器selector
func main() {
p1 := Person{
Name: "geek",
Age: 9000,
}
fmt.Println(p1.Name, p1.Age)
p1.Age += 1
fmt.Println(p1.Name, p1.Age)
}
See you ~
