关于golang:Go基础编程结构体

38次阅读

共计 5060 个字符,预计需要花费 13 分钟才能阅读完成。

构造体 (struct) 是自定义形式造成新的数据类型,构造体是类型中带有成员的复合类型。Go 语言构造体是一种聚合的数据类型,是由零个或多个任意类型的值聚合成的实体。每个值称为构造体的成员。来形容真实世界的实体和实体对应的各种属性。

构造体属性也叫 字段 成员, 每个字段都有名称和类型,每个名称是惟一的。能够是任何类型,如一般类型、复合类型、函数、map、interface、struct 等,所以咱们能够了解为 go 语言中的“类”。

定义

构造体定义形式如下:

type name struct{
     fieldName1 type1
     fieldName2 type2
     ...
}

如下,定义 User 构造体:

type User struct {
     Name string
     age  int
}

实例化

下面定义只是类型,就想是一个 int 一样,须要定义一个类型变量才能够应用,相似 Java 的类。

间接定义变量应用

package main
​
import ("fmt")
​
type User struct {
     Name string
     age  int
}
​
func main() {
     var user1 User // 定义 User 类型变量 user
     var user2 *User // 类型指针,未分配内存,不能间接应用
     fmt.Println(user1, user2) //{0} <nil>
}

定义默认成员变量

var user1 = User{Name: "abc"}
fmt.Println(user1)

func NewUser() *User {return &User{Name:"abc",age:20}
}

应用内建函数 new() 分配内存返回类型变量指针

var user = new(User)
fmt.Println(user) //&{0}

拜访成员

应用 . 来拜访

var user User
user.Name = "abc"
user.age = 20
fmt.Println(user) //{abc 20}

首字母大小写 问题,成员大写示意包外可见(即面向对象的私有属性), 小写包外不可见

零值:构造体的零值是nil

初始值 : 构造体的初始值是非nil 时,各成员对应类型的初始值

空构造体: 空构造体就是没有字段的构造体,空构造体不占内存

package main
​
import (
     "fmt"
     "unsafe"
)
​
func main() {user1 := struct{}{}
     user2 := struct{}{}
     fmt.Printf("%p,%dn", &user1, unsafe.Sizeof(user1)) //0x585218,0
     fmt.Printf("%p,%dn", &user2, unsafe.Sizeof(user2)) //0x585218,0
}

从下面能够看出空构造体内存地址和大小都是一样的。依据这个个性,应用空构造体能够作为信号量,起到信号作用但不占内存。如空构造体类型的chan

匿名构造体

匿名构造体没有类型名称,毋庸通过 type 关键字定义就能够间接应用。

user := struct {Name string}{Name: "abc"}
fmt.Println(user) //{abc}

比拟

如果构造体的全副成员都是 能够比拟 的,且成员的 程序 类型 数量 齐全一样才能够比拟,两个构造体将能够应用 == 或!= 运算符进行比拟。

package main
​
import ("fmt")
​
func main() {
     user1 := struct {Name string}{Name: "abc"}
     user2 := struct {Name string}{Name: "abc"}
     fmt.Println(user1 == user2) //true
}

成员名称不一样

package main
​
import ("fmt")
​
func main() {
     user1 := struct {Name string}{Name: "abc"}
     user2 := struct {name string}{name: "abc"}
     fmt.Println(user1 == user2) //invalid operation: user1 == user2 (mismatched types struct { Name string} and struct {name string})
}

成员数量不一样

package main
​
import ("fmt")
​
func main() {
     user1 := struct {Name string}{Name: "abc"}
     user2 := struct {
     Name string
     age  int
     }{Name: "abc"}
     fmt.Println(user1 == user2) //invalid operation: user1 == user2 (mismatched types struct { Name string} and struct {Name string; age int})
}

成员类型不能比拟

package main
​
import ("fmt")
​
func main() {
     user1 := struct {
     Name string
     m    map[int]int
     }{Name: "abc"}
     user2 := struct {
     Name string
     m    map[int]int
     }{Name: "abc"}
     fmt.Println(user1 == user2) //invalid operation: user1 == user2 (struct containing map[int]int cannot be compared)
}

程序不一样

package main
​
import ("fmt")
​
func main() {
     user1 := struct {
     Name string
     age  int
     }{Name: "abc"}
     user2 := struct {
     age  int
     Name string
     }{Name: "abc"}
     fmt.Println(user1 == user2) //invalid operation: user1 == user2 (mismatched types struct { Name string; age int} and struct {age int; Name string})
}

其实整个构造体就是一个类型(如 int),成员程序、类型这些不一样,整体的构造体就不一样,故对于强类型语言来说就是不能比拟的,对应类型齐全一样还须要留神成员是否是能够比拟,如 slice、map 等

Go 语言没有面向对象这个概念,但能够把构造体看做是一个类,能够实现面向对象的个性,如通过组合和嵌入实现继承

匿名字段

匿名字段是构造体没有显示的名字,是构造体嵌入一个或多个构造体,如上面

B 间接嵌入 A,B 是匿名字段

package main
​
import ("fmt")
​
type A struct {
     Name string
     B
}
type B struct {
     Age int
     Name string
}

拜访成员变量

func main() {var a = A{Name:"a",B:B{Name:"b",Age:20}}
     fmt.Printf("%#vn", a) //main.A{Name:"", B:main.B{Age:0}}
     fmt.Println(a.Name)  //a
     fmt.Println(a.B.Name)  //b
     fmt.Println(a.Age)  //20 
}

只有一个成员名称的状况下,Go 语法糖能够省略嵌入构造体

fmt.Println(a.B.Age) //20
fmt.Println(a.Age)   //20

对应有多个雷同名称的成员,不能省略,因为编译器不晓得是哪个

type C struct {
     A
     B
}
​
func main() {var c = C{A:A{Name:"a"},B:B{Name:"b",Age:20}}
     fmt.Println(c.Name) //ambiguous selector c.Name
}

正确做法是

func main() {var c = C{A:A{Name:"a"},B:B{Name:"b",Age:20}}
     fmt.Println(c.A.Name) //a
     fmt.Println(c.B.Name) //b
}

组合

下面是没有名字的嵌入构造体,还能够给嵌入构造体命名, 拜访必须要带上具体的字段,不能省略。

package main
​
import ("fmt")
​
type A struct {Btype B}
type B struct {
     Age int
     Name string
}
​
func main() {var a = A{Btype:B{Name:"b",Age:20}}
     fmt.Println(a.Name) //.Name undefined (type A has no field or method Name)
}

标签

如上面在字段前面用 包起来的是标签,次要是通过反射来序列化和反序列化,具体由反射章节来讲。

type User struct {
 Id int `json:"id"`
 Account string `json:"account" form:"account"`
 Nickname string `gorm:"nickname" json:"nickname" form:"nickname"`
}

办法

办法个别都是面向对象编程 (OOP) 的一个个性,Go 语言的办法其实与一个值或变量关联的非凡的函数。这个值或变量叫做 接收者

func ([typeName] 接收者) name (param) [return]{}

接收者是自定义的类型

package main
​
import ("fmt")
​
type A struct {} // 构造体
​
type B int  //int
​
func (a A) show()  {fmt.Println("a............")
}
​
func (b B) show()  {fmt.Println("b............")
}
​
func main() {
     var a  A
     var b  B
     a.show()
     b.show()}

接收者不能间接用内置类型

func (c int) show()  {  //cannot define new methods on non-local type int
    fmt.Println("b............")
}

接收者 能够是值类型或指针类型

package main
​
import ("fmt")
​
type A struct {}
​
type B struct {}
​
func (a A) show()  { // 值类型
     fmt.Println("a............")
}
​
func (b *B) show()  { // 指针类型
     fmt.Println("b............")
}
​
func main() {
     var a  A
     var b  B
     a.show()
     b.show()}

对与 B 来说, 上面两种调用形式是等价的,实质上他们都是一样的,b.show()的写法是省略了(&b), 只不过由语法糖来补全

func main() {
     var b  B
     b.show()
     (&b).show()}

办法能够拜访接收者本身的信息,如下

package main
​
import ("fmt")
​
type User struct {
     Id int 
     Account string 
     Nickname string 
}
​
func (u User)show()  {fmt.Println(u.Nickname)
}
​
func main() {var a  = User{Nickname:"测试"} 
     a.show() // 测试}

值类型接收者拷贝类型的全副,批改 不会 影响原数据; 指针拷贝的是地址,批改 影响原数据

package main
​
import ("fmt")
​
type User struct {
     Id int
     Account string
     Nickname string
}
​
func (u User)show()  {fmt.Println(u)
}
func (u User)setName1()  {u.Nickname="值类型"}
​
func (u *User)setName2()  {u.Nickname="指针类型"}
​
func main() {var a  = User{Nickname:"测试"}
     a.setName1()
     a.show()
     a.setName2()
     a.show()}

接受者 类型 自身不能为指针

package main
​
import ("fmt")
​
type A int 
​
type B *int  // 变量类型为指针
​
func (a A) show()  {fmt.Println("a............")
}
​
func (b B) show()  {  //invalid receiver type B (B is a pointer type)
     fmt.Println("b............")
}

办法的参数和返回值这些和函数一样,具体看函数章节

正文完
 0