结构体
- 结构体除了字段和类型之外, 还存在一个可选的标签(tag)。一般不会使用,但可以通过包
reflect
获取它 - 任何类型都可以有方法,甚至可以是函数类型,不仅仅是结构体
- String()相当于 java中的toString方法
type TagType struct { // tags
field1 bool "An important answer"
field2 string "The name of the thing"
field3 int "How much there are"
}
t=new(T)
和var t T
的区别
t=new(T) 变量t是一个指向T的指针
var t T 称为t是类型T的i个实例
结构体的内存布局
- Go 语言中,结构体和它所包含的数据在内存中是以连续块的形式存在的,即使结构体中嵌套有其他的结构体,这在性能上带来了很大的优势。不像 Java 中的引用类型,一个对象和它里面包含的对象可能会在不同的内存空间中,这点和 Go 语言中的指针很像
下面的例子清晰的说明了这个问题:
结构体工厂创建实例(构造方法)
func NewFile(fd int, name string) *File {
if fd < 0 {
return nil
}
return &File{fd, name}
}
- 如果File是一个结构体类型,那么表达式new(FIle)和&File{}是等价的
强制使用工厂方法
- 将结构体名写成小写,工厂方法为大写,这样使得类型变为了私有的,从而只能通过工厂方法构造
package main
import "matrix"
...
wrong := new(matrix.matrix) // 编译失败(matrix 是私有的)
right := matrix.NewMatrix(...) // 实例化 matrix 的唯一方式
- 使用make()一个结构体变量,会引起发一个编译错误
匿名字段和内嵌结构体
- 结构体可以包含一个或多个匿名(内嵌)字段
- 结构体可以包含内嵌结构体
- 在Go语言中,相比较于继承,组合更受青睐
type innerS struct {
in1 int
in2 int
}
type outerS struct {
b int
c float32
int // anonymous field
innerS //anonymous field
}
func main() {
outer := new(outerS)
outer.b = 6
outer.c = 7.5
outer.int = 60
outer.in1 = 5
outer.in2 = 10
fmt.Printf("outer.b is: %d\n", outer.b)
fmt.Printf("outer.c is: %f\n", outer.c)
fmt.Printf("outer.int is: %d\n", outer.int)
fmt.Printf("outer.in1 is: %d\n", outer.in1)
fmt.Printf("outer.in2 is: %d\n", outer.in2)
// 使用结构体字面量
outer2 := outerS{6, 7.5, 60, innerS{5, 10}}
fmt.Println("outer2 is:", outer2)
}
- 当元素出现命名冲突:
1.外层会覆盖内层的,但是俩者的内存都保留
2.如果俩个命名相同且在同一级,调用时会出错
type A struct {a int}
type B struct {a, b int}
type C struct {A; B}
var c C
type D struct {B; b float32}
var d D
//使用c.a是会出错的,因为不知道是c.A.a还是c.B.a (写成c.A.a正确)
//d.b是外层的float32, d.B.b 则是B中的b
结构体的方法
- 结构体代码和方法的代码可以不放在一起,但是必须在一个包内
- golang是不允许方法重载的(为了语法简单,不出错),但是如果这俩个方法属于不同的结构体是允许的
func (recv receiver_type) methodName(parameter_list) (return_value_list) { ... }
// recv 是这个结构体的实例 也可以使用 this 和 self
不能给基本类型创建方法,且结构体的方法必须在本包(所以不能给系统包创建方法)
解决方法:
- 给该类型起别名,给该类型定义方法
- 将该类型内嵌到一个新的结构体中
但是这个方法只在这个别名类型上有效
函数和方法的区别
函数将变量作为参数:Function1(recv)
方法在变量上被调用:recv.Method1()