匿名结构体

标识符直接使用struct部分结构体本身来作为类型,而不是使用type定义的有名字的结构体的标识符。

可以使用 var 、 const 、 := 来定义匿名结构体。

type定义结构体的标识符,可以反复定义其结构体实例,但是匿名结构体是一次性的。

 匿名结构体,只是为了快速方便地得到一个结构体实例,而不是使用结构体创建N个实例。

var Point struct {
 x, y int
} // 定义Point是后面匿名结构体类型的,用零值
fmt.Printf("%#v\n", Point) // 得到的是一个结构体实例
var message = struct {
 id   int
 data string
}{1, "OK"} // 不用零值,初始化
fmt.Printf("%#v\n", message)
student := struct {
 id   int
 name string
}{1, "Tom"} // 短格式定义并初始化
fmt.Printf("%#v\n", student)

 匿名成员

type Point struct {
 x    int
 int  // 字段,匿名成员变量
 bool // 匿名,必须类型不一样才能区分
}
var p1 = Point{1, 2, false}
fmt.Println(p1)
var p2 = Point{x: 20, int: 5, bool: false} // 使用类型名作为字段名
fmt.Println(p2, p1.x, p2.int, p2.bool)

构造函数

Go语言并没有从语言层面为结构体提供什么构造器,但是有时候可以通过一个函数为结构体初始化提供 属性值,从而方便得到一个结构体实例。习惯上,函数命名为 NewXxx 的形式。

package main
import "fmt"
type Animal struct {
 name string
 age  int
}
func NewAnimal(name string, age int) Animal {
 a := Animal{name, age}
 fmt.Printf("%+v, %p\n", a, &a)
 return a
}
func main() {
 a := NewAnimal("Tom", 20)
 fmt.Printf("%+v, %p\n", a, &a)
}

NewAnimal的返回值使用了值拷贝,增加了内存开销,习惯上返回值会采用指针类型,避免实 例的拷贝。

func NewAnimal(name string, age int) *Animal {
 a := Animal{name, age}
 fmt.Printf("%+v, %p\n", a, &a)
 return &a
}

 父子关系构造

 动物类包括猫类,猫属于猫类,猫也属于动物类,某动物一定是动物类,但不能说某动物一定是猫类。 将上例中的Animal结构体,使用匿名成员的方式,嵌入到Cat结构体中

使用结构体嵌套实现类似面向对象父类子类继承(派生)的效果

子结构体使用匿名成员能简化调用父结构体成员

package main
import "fmt"
type Animal struct {
 name string
 age  int
}
type Cat struct {
 Animal // 匿名成员,可以使用类型名作为访问的属性名
 color  string
}
func main() {
 var cat = new(Cat) // Cat实例化,Animal同时被实例化
 fmt.Printf("%#v\n", cat)
 cat.color = "black"     // 子结构体属性
 cat.Animal.name = "Tom" // 完整属性访问
 cat.age = 20            // 简化写法,只有匿名成员才有这种效果
 fmt.Printf("%#v\n", cat)
}

 指针类型receiver

Go语言中,可以为任意类型包括结构体增加方法,形式是 func Receiver 方法名 签名 {函数体} ,这 个receiver类似其他语言中的this或self。

receiver必须是一个类型T实例或者类型T的指针,T不能是指针或接口。

深浅拷贝

  • shadow copy 影子拷贝,也叫浅拷贝。遇到引用类型数据,仅仅复制一个引用而已
  • deep copy 深拷贝,往往会递归复制一定深度

深浅拷贝说的是拷贝过程中是否发生递归拷贝,也就是说如果某个值是一个地址,是只复制这个 地址 ,还是复制地址指向的内容。 值拷贝是深拷贝,地址拷贝是浅拷贝,这种说法是错误的。因为地址拷贝只是拷贝了地址,因此本质上 来讲也是值拷贝。 Go语言中,引用类型实际上拷贝的是标头值,这也是值拷贝,并没有通过标头值中对底层数据结构的指 针指向的内容进行复制,这就是浅拷贝。非引用类型的复制就是值拷贝,也就是再造一个副本,这也是 浅拷贝。因为你不能说对一个整数值在内存中复制出一个副本,就是深的拷贝。像整数类型这样的基本 类型就是一个单独的值,没法深入拷贝,根本没法去讲深入的事儿。 简单讲,大家可以用拷贝文件是否对软链接跟进来理解。直接复制软链接就是浅拷贝,钻进软链接里面 复制其内容就是深拷贝。 复杂数据结构,往往会有嵌套,有时嵌套很深,如果都采用深拷贝,那代价很高,所以,浅拷贝才是语 言普遍采用的方案。

posted on 2023-07-03 16:37  自然洒脱  阅读(16)  评论(0编辑  收藏  举报