1、结构体声明
1 2 3 4 | type 结构体名称 struct { field type field type } |
举例:
1 2 3 4 5 | type Dog struct { Name string Age int Color string } |
2、结构体使用
2.1 直接声明
1 | var dog Dog |
2.2 {}
1 2 3 4 5 6 7 8 9 10 | type Dog struct { Name string Age int Color string } func main() { dog := Dog{ "来福" , 3, "白色" } fmt.Printf( "dog=%v\n" , dog) } |
2.3 new()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | type Dog struct { Name string Age int Color string } func main() { dog := new(Dog) // dog是一个指针,因此标准的给字段赋值应该是(*dog).Name = "来福" (*dog).Age = 3 (*dog).Color = "白色" // go设计者为了程序员使用方便,底层会对dog.Name = "来福"进行处理,会给dog加上取值运算(*dog).Name = "来福" dog.Name = "来福" // 等价于(*dog).Name = "来福" dog.Age = 3 // 等价于(*dog).Age = 3 dog.Color = "白色" // 等价于(*dog).Color = "白色" fmt.Printf( "dog=%v\n" , *dog) } |
2.4 &
1 2 3 4 5 6 7 8 9 10 | type Dog struct { Name string Age int Color string } func main() { dog := &Dog{ "来福" , 3, "白色" } fmt.Printf( "dog=%v\n" , *dog) } |
2.5 创建struct实例指定字段值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | type Person struct { Name string Age int } func main() { person := Person{ Name: "Tom" , Age: 18, } personPor := &Person{ Name: "Jack" , Age: 20, } fmt.Println( "person=" , person) fmt.Println( "personPor=" , *personPor) } |
第三种方式和第四种方式返回的是结构体指针,结构体指针访问字段的标准方式应该是:(*结构体指针).字段名,比如(*dog).Name = "来福"
3、方法的声明
1 2 3 4 | func (recevier type ) methodName(参数列表)(返回值列表){ 方法体 return 返回值 } |
参数列表,表示方法输入
recevier type:表示这个方法和type这个类型进行绑定,或者说该方法作用于type类型
recevier type:可以是结构体,也可以说是自定义类型。
recevier就是type类型的一个变量(实例)。
参数列表表示方法的输入
返回值列表,表示返回的值,可以是多个。
方法主体,表示为了实现某一功能代码块
return语句不是必须的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | type Dog struct { Name string Age int Color string } // 给Dog类型绑定一个方法 func (d Dog) Eat(food string) { fmt.Printf( "%v正在吃%v\n" , d.Name, food) } func main() { d := Dog{ Name: "小花" , Age: 3, Color: "花色" , } // 调用方法 d.Eat( "骨头" ) } |
4、函数和方法的区别
调用方式不一样
函数的调用方式:函数名(实参列表)
方法的调用方式:变量.方法名(实参列表)
b. 对于普通函数,接收者是值类型时,不能将指针类型的数据直接传递
c. 对于方法(如struct的方法),接收者为值类型时,可以直接用指针类型的变量调用方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | type Person struct { Name string Age int } func (p Person) test() { p.Name = "Merry" } func (p *Person) test01() { p.Name = "Jack" } func main() { person := Person{ Name: "Tom" , Age: 18, } person.test() fmt.Println( "name=" , person.Name) (&person).test() // 从形式上是传入地址,但本质任然是值拷贝 fmt.Println( "name=" , person.Name) person.test01() // 等价于(&person).test01() 从形式上是传入值类型,但本质任然是地址拷贝 fmt.Println( "name=" , person.Name) (&person).test01() fmt.Println( "name=" , person.Name) } |
输出:
1 2 3 4 | name= Tom name= Tom name= Jack name= Jack |
不管调用形式如何,真正决定是值拷贝还是地址拷贝,看这个方法是和那个类型绑定的
如果是和值类绑定型,比如: (p Person) test(),则是值拷贝
如果是和地址类型绑定,比如:func (p *Person) test01(),则是地址拷贝
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律