公有和私有
Go语言中公有和私有的概念是以包为边界的。
- 如果一个标识符可以在除了声明它的包以外的其它包中被访问,即称为导出(公有)标识符。
- 如果一个标识符只能在声明它的包内部被访问,即称为非导出(私有)标识符。
一个标识符是否被导出或者说是公有还是私有,取决于其名称中的首字母是大写还是小写,注意下划线和汉字也算小写。
结构体及其字段可以借助名称首字母的大小写,被单独指定为公有或者私有。
结构体的公/私有属性,与其字段的公/私有属性是独立的,互不影响。
- type drink struct {
Name string // 私有结构体的公有字段
ice bool
}- type Drink struct {
Name string
ice bool // 公有结构体的私有字段
}
指针引用和值引用
结构体变量拥有独立的数据类型,可以内存复制的形式被整体地赋值、传参和从函数中返回,前提是目标变量必须与源变量属于同一种结构体类型
- b := a
一旦赋值完成,b即成 为a的副本,各自拥有独立的内存空间,修改b不会影响到a,修改a也同样不会对b造成任何影响
数组和结构体间的数据传递都是值传递,即内存复制,而切片和映射间的传递则是引用传递,即内存共享,二者之间务必加以严格区分
除了值以外也可以通过指针引用源结构体变量,这时所获得的并非源变量的副本而是其地址,目标变量所引用的就是源变量本身
- b := &a
b是指向a的指针,*b和a是对同一块内存的引用,修改*b就是修改a,反之亦然
// 按值赋值结构体变量
// 以值的方式复制结构体变量,所有字段各自独立
package main
import "fmt"
type drink struct {
name string
ice bool
}
func main() {
a := drink{
name: "Lemonade",
ice: true,
}
b := a // 以赋值的方式初始化了b,值传递
b.ice = false
fmt.Printf("%p %+v\n", &a, a)
// 0xc000056400 {name:Lemonade ice:true} a,b变量内存地址不同
fmt.Printf("%p %+v\n", &b, b)
// 0xc000056420 {name:Lemonade ice:false}
}
// 按引用复制结构体变量
// 以引用的方式复制结构体变量,共享一套字段
package main
import "fmt"
type drink struct {
name string
ice bool
}
func main() {
a := drink{
name: "Lemonade",
ice: true,
}
b := &a // 以取a地址的方式初始化了b,引用传递
b.ice = false
fmt.Printf("%p %+v\n", &a, a)
// 0xc000004440 {name:Lemonade ice:false},a,b变量内存地址相同
fmt.Printf("%p %+v\n", b, *b)
// 0xc000004440 {name:Lemonade ice:false}
}