结构体
package main
import "fmt"
import "encoding/json"
/*
结构体定义方式
type struct_name struct{
变量名 type
}
结构体特征:
1.当字段或者结构体以大写字母开头则表示其为public,引用类型强制为public
2.在创建一个结构体变量后,如果没有给字段赋值,都对应一个零值,引用类型的零值为nil,即没有分配空间,所以当使用这样的字段所以先make才能使用 ,指针则为new
3.结构体是值类型
4.不同结构体变量的字段是独立,互不影响
结构体注意事项和细节:
1.结构体所有字段在内存中是连续的
2.结构体是用户单独定义的类型,和其他类型进行转换是需要有完全相同的字段(名字,个数和类型)
3. 结构体进行type重新定义(相当于取别名),Golang认为是新的数据类型,但是相互间可以强转
4. struct的每个字段上,可以写上一个tag,该tag可以通过反射机制获取,常见的使用场景就是序列化和反序列化
*/
//定义一个Cat类型的结构体,字段有:名字,年龄,颜色
type Cat struct {
Name string `json:"name"`
Age int `json:"age"`
Color string `json:"color"`
}
//定义结构体中的方法 func (变量 type) 方法(参数列表)(返回列表)
//注意cat *Cat是引用传递
func (cat *Cat)eat(food string){
//cat.Name等价于(*cat).Name
fmt.Printf("%s喜欢吃%s",cat.Name,food)
cat.Name="小陈"
}
func main() {
//创建结构体实例四种方式
//第一种 var 变量名 struct_name
var cat1 Cat
cat1.Name = "小白"
cat1.Age = 3
cat1.Color = "白色"
//第二种 变量名:=struct_name{}
cat2 := Cat{"小黑", 4, "黑色"}
//第三种 var 变量名 *struct_name =new (struct_name)
var cat3 *Cat = new(Cat)
(*cat3).Name = "小绿"
(*cat3).Age = 5
(*cat3).Color = "绿色"
//第四种 var 变量名 *struct_name =&struct_name{}
var cat4 *Cat = &Cat{"小蓝", 6, "蓝色"}
fmt.Println(cat1) //{小白 3 白色}
fmt.Println(cat2) //{小黑 4 黑色}
fmt.Println(*cat3) //{小绿 5 绿色}
fmt.Println(*cat4) //{小蓝 6 蓝色}
//struct的每个字段上,可以写上一个tag,该tag可以通过反射机制获取,常见的使用场景就是序列化和反序列化
jsonStr,err :=json.Marshal(cat1)
if err !=nil{
fmt.Println("json 解析错误",err)
}
fmt.Println(string(jsonStr)) //{"name":"小白","age":3,"color":"白色"}
//cat1.eat("鱼")等价于(&cat1).eat("鱼")
cat1.eat("鱼") //小白喜欢吃鱼
fmt.Println(cat1.Name) //小陈
}
结构体在内存分布
结构体特征:
- 当字段或者结构体以大写字母开头则表示其为public,引用类型强制为public
- 在创建一个结构体变量后,如果没有给字段赋值,都对应一个零值,引用类型的零值为nil,即没有分配空间,所以当使用这样的字段所以先make才能使用,指针则为new
- 结构体是值类型
- 不同结构体变量的字段是独立,互不影响
结构体注意事项和细节
-
结构体所有字段在内存中是连续的
-
结构体是用户单独定义的类型,和其他类型进行转换是需要有完全相同的字段(名字,个数和类型)
-
结构体进行type重新定义(相当于取别名),Golang认为是新的数据类型,但是相互间可以强转
-
struct的每个字段上,可以写上一个tag,该tag可以通过反射机制获取,常见的使用场景就是序列化和反序列化
序列化使用场景:
方法注意事项和细节讨论
- 结构体类型是值类型,在方法调用中,遵守值类型的传递机制,是值拷贝传递方式
- 如果程序员希望在方法中,修改结构体变量的值,可以通过结构体指针的方式来处理
- Golang中方法作用在指定的数据类型上的(即:和指定的数据类型绑定),因此自定义类型,都可以有方法,而不仅仅是struct,比如int,flaot32都可以
- 方法的访问范围控制的规则,和函数一样.方法名首字母小写,只能在本包访问,方法首字母大写开头在本包和其他包访问
- 如果一个类型实现String()这个方法,那么fmt.Println默认会调用这个变量的String()进行输出
方法和函数的区别
- 调用方式不一样
函数的调用方式: 函数名(实参列表)
方法的调用方式: 变量.方法名(实参列表) - 对于普通函数,接收者为 值类型时,不能将指针类型的数据直接传递,反之亦然
- 对于方法,接收者为值类型时,可以直接用指针类型的变量调用方法,反过来同样也可以