网站宽屏可以免费建设网站吗
网站宽屏,可以免费建设网站吗,深圳网站设计招聘网,vs2013网站开发结构体 1. 自定义类型、类型别名1.1. 自定义类型1.2. 类型别名1.3. 类型定义和类型别名的区别 2. 结构体定义3. 结构体初始化4. 指针类型结构体5. 构造函数6. 方法和接收者6.1. 方法定义6.2. 方法调用6.3. 值方法和指针方法6.4. 指针方法使用场景6.5. 任意类型添加方法 7. 结构… 结构体 1. 自定义类型、类型别名1.1. 自定义类型1.2. 类型别名1.3. 类型定义和类型别名的区别 2. 结构体定义3. 结构体初始化4. 指针类型结构体5. 构造函数6. 方法和接收者6.1. 方法定义6.2. 方法调用6.3. 值方法和指针方法6.4. 指针方法使用场景6.5. 任意类型添加方法 7. 结构体成员可见性8. 结构体匿名字段9. 嵌套结构体9.1. 嵌套匿名结构体9.2. 嵌套结构体的字段名冲突 10. 通过嵌套实现“继承”11. 结构体与JSON序列化12. 结构体标签Tag13. 匿名结构体 上一篇字典及其约束
下一篇通道 Go语言中没有“类”的概念也不支持类的“继承”等面向对象的概念它所做的是通过嵌入字段的方式实现了类型之间的组合。Go语言中通过结构体的内嵌再配合接口比面向对象具有更高的扩展性和灵活性。
1. 自定义类型、类型别名
1.1. 自定义类型
通过Type关键字定义。 自定义类型是定义一个全新的类型。可以基于基本类型定义也可以通过struct定义。
// 通过Type关键字的定义MyInt就是一种新的类型它具有int的特性。
type MyInt int1.2. 类型别名
使用 “” 定义type TypeAlias Type 类型别名规定TypeAlias只是Type的别名本质上属于同一个类型。 type intAlias int// 内置别名类型type byte uint8type rune int32type any interface{}1.3. 类型定义和类型别名的区别
//类型定义
type NewInt int//类型别名
type MyInt intfunc main() {var a NewIntvar b MyIntfmt.Printf(type of a:%T\n, a) //type of a:main.NewIntfmt.Printf(type of b:%T\n, b) //type of b:int
}上面代码结果显示 a 的类型是 main.NewInt表示 main 包下定义的 NewInt 类型b 的类型是 int。MyInt 类型只会在代码中存在编译完成时并不会有 MyInt 类型。
2. 结构体定义
结构体是一种自定义类型它是由若干字段组成的。结构体的字段可以是任意类型甚至可以是结构体本身。
通过 struct 关键字定义。
type 类型名 struct {字段名 字段类型字段名 字段类型…
}类型名同一个包内不能重复
字段名同一个结构体内不能重复
字段类型可以是任意类型甚至可以是结构体本身// 定义一个结构体
type Student struct {Name stringAge int
} 3. 结构体初始化
只有当结构体实例化时才会分配内存。也就是必须实例化后才能使用结构体的字段。
未赋值字段初始化为字段类型零值。
var stu Student
fmt.Printf(%#v\n, stu) // main.Student{Name:, Age:0} // 通过点符号(.)访问结构体字段
stu.Name Tom
fmt.Println(stu.Name)使用键值对初始化
stu : Student{Name: 小花, Age: 18}
fmt.Println(stu)使用值的列表初始化简写初始化时不写键只写值 需满足一下条件
必须初始化结构体的所有字段。初始值的填充顺序必须与字段在结构体中的声明顺序一致。该方式不能和键值初始化方式混用。
stu : Student{小明, 16}
fmt.Println(stu)4. 指针类型结构体
初始化方式与值类型结构体相同但使用指针类型进行初始化。
使用 new 关键字实例化
// new
var stu1 new(Student)
fmt.Printf(%T \n, stu1)使用 对结构体进行取址操作相当于 new
stu : Student{}
stu.Name 小明
(*stu).Age 6
fmt.Printf(%#v\n, stu)Go语法糖会适时地为我们进行自动地转译在stu之上之所以我们可以通过stu.Name 小明设置名字是因为 Go语言把它自动转译为了(*stu).Name 小明。
5. 构造函数
Go语言没有构造函数我们可以自己实现。 struct是值类型如果结构体比较复杂的话值拷贝性能开销会比较大所以该构造函数返回的是结构体指针类型。
type Student struct {Name stringAge int
}func NewStudent(name string, age int) *Student {return Student{Name: name, Age: age}
}func main() {stu : NewStudent(小花, 18)fmt.Printf(%#v\n, stu)
}6. 方法和接收者
Go语言中通过struct来实现面向对象可以包含方法方法是结构体的成员函数。
Go语言中的方法Method是一种作用于特定类型变量的函数。这种特定类型变量叫做接收者Receiver。接收者的概念就类似于其他语言中的 this 或者 self。
方法的接收者类型必须是某个自定义的数据类型而且不能是接口类型或接口的指针类型。
函数与方法的区别函数不属于任何类型而方法属于特定的类型。
6.1. 方法定义
方法定义格式如下
func (接收者 变量名) 方法名(参数列表)(返回值列表) {方法体
}例如
type Student struct {Name stringAge int
}func (stu *Student) SayHello(age int) {fmt.Printf(Hello, my name is %s, and %d years old.\n, stu.Name, age)
} 6.2. 方法调用
Go语言方法表达式有两种instance.method(args…) .func(instance, args…)
func main() {stu : Student{Name: Tom,Age: 18,}stu.SayHello(18)// 隐式隐式sSay : stu.SayHellosSay(20)// 显式传递sr : (*Student).SayHellosr(stu, 22)
}6.3. 值方法和指针方法
值方法接收者类型是非指针的自定义数据类型的方法。
指针方法接收者类型是指针的自定义数据类型的方法。
值方法与指针方法区别 接受者类型 值方法的接收者是该方法所属类型值的一个副本在方法内对该副本的修改一般不会体现在原值上除非这个类型本身是某个引用类型slice、map、chan。指针方法的接收者是该方法所属类型值的指针的一个副本在方法内对该副本指向的值进行修改一定会体现在原值上。 方法集合一个自定义数据类型的方法集合中仅包含它的所有值方法而该类型的指针类型的方法集合囊括了所有值方法和所有指针方法。
package mainimport fmttype Student struct {Name stringAge int
}// 指针方法
func (stu *Student) SetName(name string) {stu.Name name
}// 值方法
func (stu Student) SetNameCopy(name string) {stu.Name name
}func main() {stu : Student{小红, 20}stu.SetName(小花)fmt.Println(stu.Name) // 小花stu.SetNameCopy(小明)fmt.Println(stu.Name) // 小花
}6.4. 指针方法使用场景
需要修改接收者中的值接收者是拷贝代价比较大的对象保证一致性如果某个方法使用了指针接收者那么其它方法也应该使用指针方法。
6.5. 任意类型添加方法
Go语言中接收者的类型可以是任何类型不仅仅是结构体任何类型都可以拥有方法。
举个例子我们基于内置的int类型使用type关键字可以定义新的自定义类型然后为我们的自定义类型添加方法。
//MyInt 将int定义为自定义MyInt类型
type MyInt int//SayHello 为MyInt添加一个SayHello的方法
func (m MyInt) SayHello() {fmt.Println(Hello, 我是一个int。)
}func main() {var m MyIntm.SayHello() //Hello, 我是一个int。m 100fmt.Printf(%#v %T\n, m, m) //100 main.MyInt
}7. 结构体成员可见性
Go语言通过首字母的大小写来控制权限。首字母大写包外部可见首字母小写仅包内部可见。
demo/struct.go
package demotype Student struct {Name string // 公共字段Age int score int // 包内字段在包外部不可初始化
}// 公共方法
func (stu *Student) SetName(name string) {stu.Name name
}// 包内方法
func (stu *Student) setScore(score int) {stu.score score
}main.go
package mianimport (demofmt
)func main() {stu : demo.Student{Name: 小花, Age: 18}stu.SetName(小红)stu.setScore(80) // stu.setScore undefined (type *demo.Student has no field or method setScore)fmt.Println(stu)
}8. 结构体匿名字段
结构体允许其成员字段在声明时没有字段名而只有类型那么它就是一个嵌入字段也可以被称为匿名字段。
匿名字段默认采用类型作为字段名结构体要求字段名称必须唯一因此一个结构体中同种类型的匿名字段只能有一个。
type BaseType struct {stringint
}func main() {var b BaseType{}b.int 10fmt.Println(b.int)
}9. 嵌套结构体
一个结构体可以嵌套包含另一个结构体或结构体指针。
type Address struct {Province stringCity string
}type User struct {Name stringGender stringAddress Address
}func main() {user : User{Name: pprof,Gender: 女,Address: Address{Province: 北京,City: 北京,},}fmt.Printf(user%#v\n, use)
}9.1. 嵌套匿名结构体
嵌套结构体字段也可以使用匿名。推荐使用匿名方式嵌套结构体如下所示
type User struct {Name stringGender stringAddress
}func main() {user : User{Name:pprof, Gender:女}user.Address.Province 北京fmt.Printf(user%#v\n, use)
}9.2. 嵌套结构体的字段名冲突
嵌套结构体内部可能存在相同的字段名为了避免歧义需要指定具体的内嵌结构体的字段。
仅匿名内嵌结构体成员可以直接访问。Go直接访问成员匹配规则
结构体成员中含有要访问的成员则匹配结构体成员。结构体成员中没有要访问的成员则在内嵌匿名结构体中继续查找。若同一层级多个内嵌匿名结构体存在同名成员则产生歧义报错。内嵌结构体中未找到要访问的成员若内嵌匿名结构体内还存在内嵌匿名结构体则继续向下查找依此类推。都匹配不到则报错。
package maintype Student struct {Name stringAge intCreateTime stringAddressEmail}type Email struct {Account stringPhone stringCreateTime string
}type Address struct {Name stringProvince stringCity stringCounty stringPhone stringCreateTime string
}func (stu *Student) SetName(name string) {stu.Name name
}func (addr *Address) SetName(name string) {addr.Name name
}func (addr *Address) SetProvince(pro string) {addr.Province pro
}func main() {var stu Student{}// 1. 嵌套结构体重名字段需自定具体路径stu.CreateTime 2023-12-21stu.Address.CreateTime 2023-12-30// 2. 直接访问匿名结构体的字段名当访问结构体成员时会先在结构体中查找该字段找不到再去匿名结构体中查找。stu.Account 123mail.com// 3. 向下查找字段若同一层级出现重名字段则产生歧义需指定具体结构体字段。stu.Phone 123123123 //报错ambiguous selector stu.Phonestu.Address.Phone 123123// 结构体方法处理方式与字段相同stu.SetName(老北京)stu.Address.SetName(小北京)stu.SetProvince(北京市)fmt.Printf(%#v, stu)
}10. 通过嵌套实现“继承”
type Animal struct {name string
}func (a *Animal) move() {fmt.Printf(%s会动\n, a.name)
}type Dog struct {Feet int8*Animal // 通过嵌套匿名结构体实现继承
}func (d *Dog) wang() {fmt.Printf(%s会汪汪汪~\n, d.name)
}func main() {d : Dog{Feet: 4,Animal: Animal{ // 注意嵌套的是结构体指针name: 旺财,},}d.wang() //旺财会汪汪汪~d.move() //旺财会动
}11. 结构体与JSON序列化
package mainimport (encoding/jsonfmt
)type Class struct {Title stringStudents []*Student
}type Student struct {Name stringAge intAddress
}type Address struct {Province stringCity stringCounty string
}func main() {c : Class{Title: 高一12班,Students: make([]*Student, 0, 60),}for i : 1; i 10; i {stu : Student{Name: fmt.Sprintf(Stu_%02d, i),Address: Address{Province: 北京},}c.Students append(c.Students, stu)}// JSON序列化结构体 to JSONdata, err : json.Marshal(c)if err ! nil {fmt.Println(Json marshal failed.)return}fmt.Printf(json:%s\n\n\n, data)// JSON反序列化JSON to 结构体str : {Title:101,Students:[{Name:小明,Age:16,Address:{Province:北京}},{Name:小花,Age:15,Address:{Province:上海}},{Name:小红,Age:16,Address:{Province:广东}}]}c1 : Class{}err json.Unmarshal([]byte(str), c1)if err ! nil {fmt.Println(json unmarshal failed!)return}fmt.Printf(%#v\n, c1)
}12. 结构体标签Tag
Tag 是结构体的元信息可以在运行的时候通过反射的机制读取出来。
结构体Tag在字段的后方定义使用一对反引号()包括起来由一个或多个键值对组成键与值使用冒号分隔值用双引号括起来键值对之间使用一个空格分隔。
具体格式如下
key1:value1 key2:value2 **注意为结构体编写Tag时必须严格遵守键值对的规则。结构体标签的解析代码的容错能力很差一旦格式写错编译和运行时都不会提示任何错误通过反射也无法正确取值。**例如不要在key和value之间添加空格。
在结构体字段的定义中如果字段名与 json 标签不一致则需要在字段名后面添加一个 json 标签如
package mainimport (encoding/jsonfmt
)type Student struct {Id int json:id //通过指定tag实现json序列化该字段时的keyName string json:nameAge int json:- //通过指定tag实现json序列化该字段时忽略该字段Sex string json:name,omitempty // omitempty表示字段为空值时不序列化phone string //私有不能被json包访问
}func main() {stu : Student{Id: 1,Name: 小明,Age: 18,phone: 13333333333,}str, _ : json.Marshal(stu)fmt.Printf(json:%s\n, str) //json:{id:1,name:小明}str2, _ : json.Marshal(Student{Id: 2,Sex: 女,})fmt.Printf(json:%s\n, str2) //json:{id:2,name:,sex:女}
}13. 匿名结构体
在定义一些临时数据结构等场景下可以使用匿名结构体。
package mainimport (fmt
)func main() {var user struct{Name string; Age int}user.Name pprof.cnuser.Age 18fmt.Printf(%#v\n, user)
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/90089.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!