结构体是自定义的数据类型,代表一类事物,
结构体变量(实例)是具体的,实际的,代表一个具体变量
type Cat struct {
Name string
Age int
Color string
Hobby string
}
func main() {
var cat Cat
cat.Name = "小黑"
cat.Age = 34
cat.Color = "黑色"
cat.Hobby = "miao"
}
一、结构体变量内存布局
结构体是值类型
在创建一个结构体变量后,如果没有给字段赋值,都对应一个零值(默认值):
指针、slice和map的零值都是nil,即还没有分配空间
二、创建结构体实例的方式
- 方式一
var person Person
person.name = ""
person.age = 34
- 方式二
var person Person = {}
person.name = ""
person.age = 34
- 方式三
var person *Person = new(Person)
// p3是一个指针,也可person.name = "simon"
go设计者为了简化底层会加上取值符
(*person).name = "simon"
(*person).age = 34
- 方式四
var person *Person = &Person{}
// p3是一个指针
(*person).name = "simon"
(*person).age = 34
- 创建结构体实例时,可以直接指定字段的值
var stu1 Student = Student{"tom", 10}
stu2 := Student{"tom", 10}
// 指针变量
var stu3 *Student = &Student{"xiaomi", 14}
二、结构体使用细节
- 结构体的所有字段在内存中是连续的
- 结构体使用户单独定义的类型,和其他类型进行转换时需要完全相同的字段(名字、个数、类型)
type A struct {
Num int
}
type B struct {
Num int
}
func main() {
var a A
var a B
a = B(b) // 要强制转换
}
- 结构体的每个字段上,可以写一个tag,该tag可以通过反射机制获取,常见场景序列化和反序列化
type Student struct {
Name string `json:"name"`
Age int `json:"age"`
}
三、结构体方法
golang中的方法是作用在指定的数据类型上的
(即:和指定的数据类型绑定),因此自定义类型,都有方法
,而不仅仅是struct
type A struct {
Num int
}
func (a A) test() {
fmt.Println(a.Num)
}
func (a A) test() {} 表示A结构体有一个方法名,方法名为test
(a A) 体现test方法是和A类型绑定的
- 方法调用和传参机制
- 在通过一个变量去调用方法时,其调用机制和函数一样
- 不一样的地方,变量调用方法时,该变量本身也会作为一个参数传递到方法(如果变量是值类型,则进行值拷贝,如果变量是引用类型,则进行地址拷贝)
- 方法注意事项和使用细节
如果程序员希望在方法中,修改结构体变量的值,可以通过结构体指针的方式处理
type Circle struct {
radius float64
}
func (c *Circle) area() float64 {
// c 是指针, 访问字段的方式是(*c).radius
// (*c).radius 等价 c.radius
return 3.14 * (*c).radius * (*c).radius
}
func main() {
var c Circle
c.radius = 5.0
// 编辑器底层作了优化 (&c).area() 等价 c.area()
res := (&c).area()
}
四、继承
结构体可使用嵌套匿名结构体所有的字段和方法,(首字母大小写都可使用)
type A struct {
Name string
age int
}
type B struct {
A // 嵌套匿名结构体A,达到继承
}
func (a *A) hello() {
fmt.Println("你好")
}
func main() {
var b B
b.A.Name = "xiaoming"
b.hello()
}
五、接口
interface类型默认是一个指针(引用类型),如果没初始化就是用,会输出nil。
空接口interface{},没有任何方法,所有类型都实现了空接口,即可把任何类型变量赋值给空接口
type AInterface interface {
test1()
}
type BInterface struct {
test2()
}
type CInterface struct {
AInterface // 继承另一个接口
BInterface
test3()
}
type Stu struct {
}
func (stu Stu) test1() {
}
func (stu Stu) test2() {
}
func (stu Stu) test3() {
}
func main() {
var stu Stu
var a AInterface = stu
a.test1()
}
六、断言
由于接口是一般类型,不知道具体类型,如果要转成具体类型,就需要使用类型断言
func main() {
var t float32
var x interface{}
x = t
y, ok := x.(float32) // 转成float32
if ok == true {
fmt.Println("convert success")
} else {
fmt.Println("convert fail")
}
}