struct(結構體)也是一種聚合的數據類型,struct能夠包含多個任意類型的值,這些值被稱爲struct的字段。express
type Person struct {
Name string
Age int
Birthday time.Time
}
複製代碼
結構體字段的首字母標識字段的權限訪問,大寫的包外可訪問,小寫的屬於包內私有變量,僅在該結構體內部使用bash
ts := "2000-01-01 12:00:32"
timeLayout := "2006-01-02 15:04:05" //轉化所需模板
loc, _ := time.LoadLocation("Local") //重要:獲取時區
theTime, _ := time.ParseInLocation(timeLayout, ts, loc) //使用模板在對應時區轉化爲time.time類型
fmt.Println(theTime)
p := Person{Name:"zhanglinpeng",Age: 18, Birthday: theTime,} //最後的,不能少
p2 := new(Persion) //new()函數來建立一個「零值」結構體,全部的字段都被初始化爲相應類型的零值。返回的是結構體指針
zerostruct := struct{}{} //空結構體,字節長度爲0
複製代碼
var apr = struct {
Name string
Age int
}{
Name: "zhanglinpeng",
Age: 13,
}
fmt.Println(apr)
複製代碼
var Student struct {
string
int
}
a := Student{"zhaoll", 19}
複製代碼
注意初始化時的順序不能變函數
type Person struct {
Name string
Age int
Contact struct {
Phone, Email, QQ string
}
}
複製代碼
內嵌匿名結構體的初始化只能經過如下方式實現:ui
var apr = struct {
Name string
Age int
Contact struct {
Phone, Email string
}
}{
Name: "zhanglinpeng",
Age: 13,
}
apr.Contact.Phone = "110"
apr.Contact.Email = "110@qq.com"
fmt.Println(apr)
複製代碼
結構體做爲參數傳遞給函數時,也是值傳遞,若是想修改原始結構體,能夠使用指針spa
func changeName(pr *Person) {
pr.name = "zhanglinpeng"
}
...
changeName(&person)
fmt.Println(person)
複製代碼
能夠使用點操做符獲取屬性值,點操做符還能夠應用在struct指針上。指針
person := &person{Name:"weishihao",Age:14,...}
person.Name = "zhaoyuhao"
複製代碼
var Person struct {
Name string
Age int
}
p1 := Person{Name:"zhaojj", Age: 14}
p2 := Person{Name:"zhaojj", Age: 14}
p3 := Person{Name:"zhaojj", Age: 15}
fmt.Println(p1 == p2) // true
fmt.Println(p1 == p3) // false
複製代碼
type Person struct {
Gender int
}
type teacher struct {
Person
Name string
Age int
}
type student struct {
Person
Name string
Age int
}
t1 := teacher{Name:"mayun", Age: 44, Person: Person{Gender: 0}}
s1 := student{Name: "zhaojj", Age: 12, Person: Person{Gender: 1}}
t1.Name = "yangmi"
s1.Gender = 0
複製代碼
咱們發現,修改「繼承」來的屬性,能夠直接點操做,而不用s1.Person.Gender = 0, 雖然這樣作也是可行的。 若是在嵌入的結構體中存在同名的屬性字段,那麼在訪問不一樣結構體中的屬性字段時,須要指明,好比上述的那種訪問方式。 若是同級別的嵌入結構體存在同名屬性字段,就會報錯。code
咱們只須要在普通函數前面加個接受者(receiver,寫在函數名前面的括號裏面),這樣編譯器就知道這個函數(方法)屬於哪一個struct了。 須要注意的是,由於Go不支持函數重載,因此某個接收者(receiver)的某個方法只能對應一個函數,好比下面的就屬於方法重複。繼承
type A struct {
Name string
}
type B struct {
Name string
}
func (a A) print() {
fmt.Println("function A")
}
func (b B) print() {
fmt.Println("function B")
}
func (b B) print(i int) {
fmt.Println("function B with argument")
}
複製代碼
針對A, B不一樣結構體print是不一樣的方法,因此能夠和平相處,可是針對B結構體,存在兩個同名的print方法,那麼就會報錯。接口
package main
import (
"fmt"
)
type User struct {
Id int
Name string
}
func (u User) displayId() {
fmt.Println(u.Id)
}
func (u *User) displayName() {
fmt.Println(u.Name)
}
func main() {
us := User{Id: 1, Name: "zhao"}
us.displayId() // 1
us.displayName() // zhao
us2 := &User{Id: 2, Name: "qian"}
us2.displayId() // 2
us2.displayName() // qian
}
複製代碼
能夠看出,不管是結構體變量仍是結構體指針變量,都是能夠調用接受者無論是結構體仍是結構體指針的方法。可是,傳遞給接口的時候會有所不一樣編譯器
package main
import (
"fmt"
)
type DisplayInfo interface {
displayId()
displayName()
}
type User struct {
Id int
Name string
}
func (u User) displayId() {
fmt.Println(u.Id)
}
func (u *User) displayName() {
fmt.Println(u.Name)
}
func DisplayUserInfo(ds DisplayInfo) {
ds.displayId()
ds.displayName()
}
func main() {
us := User{Id: 1, Name: "zhao"}
us.displayId()
us.displayName()
us2 := &User{Id: 2, Name: "qian"}
us2.displayId()
us2.displayName()
us3 :=User{Id:3,Name:"sun"} // 若是這裏使用&User{Id:3,Name:"sun"}是能夠運行的
DisplayUserInfo(us3) // cannot use us3 (type User) as type DisplayInfo in argument to DisplayUserInfo
// User does not implement DisplayInfo (displayName method has pointer receiver)
}
複製代碼
錯誤信息中說,User類型沒有實現DisplayInfo接口緣由是displayName方法接受者是指針。可是爲何us3=&User{Id:3,Name:"sun"}
能夠呢?這是由於接受者是指針類型的時候,說明指針指向的結構體實現了接口 接受者是值類型的時候,說明的是結構體自己實現了接口.接受者是T的屬於一個方法集,接受者是*T的是另外一個方法集,該方法及包含接受者是*T和T的。
package main
import "fmt"
type A struct {
Name string
}
type B struct {
Name string
}
func (a A) print() {
a.Name = "FuncA"
fmt.Println("function A")
}
func (b *B) print() {
b.Name = "FuncB"
fmt.Println("function B")
}
func main() {
a := A{}
a.print()
fmt.Println(a.Name) // ""
b := B{}
b.print()
fmt.Println(b.Name) // "FuncB"
}
複製代碼
若是是包外的類型,咱們是沒法綁定方法的。這就是爲何類型別名,沒法將類型上的方法帶到當前的包中的緣由,好比,我在當前包中定義了一個int 類型,那麼int類型上的方法,只有咱們本身去實現
其實有兩種調用方式,上面講的那種官方管它叫method value,還有另外一種調用方式,叫method expression
package main
import "fmt"
type A struct {
Name string
}
func (a *A) print() {
a.Name = "FuncA"
fmt.Println("function A")
}
func main() {
a := A{}
a.print() // method value
(*A).print(&a) // method expression
(&a).print()
}
複製代碼
最後說下訪問權限,由於Go是以大小寫來區分是公有仍是私有,但都是針對包級別的, 因此在包內全部的都能訪問,而方法綁定自己只能綁定包內的類型,因此方法能夠訪問接收者全部成員。
package main
import (
"fmt"
"unsafe"
)
type User struct {
subject [10]byte
}
func main() {
user := new(User)
fmt.Println(user.subject) // [0 0 0 0 0 0 0 0 0 0]
fmt.Println(len(user.subject)) // 10
fmt.Println(reflect.TypeOf(user)) // *main.User
fmt.Println(unsafe.Sizeof(struct{}{})) // 0
}
複製代碼