一文带你掌握掌握Golang结构体与方法
来源:脚本之家
时间:2023-05-13 14:47:47 111浏览 收藏
偷偷努力,悄无声息地变强,然后惊艳所有人!哈哈,小伙伴们又来学习啦~今天我将给大家介绍《一文带你掌握掌握Golang结构体与方法》,这篇文章主要会讲到结构体、方法等等知识点,不知道大家对其都有多少了解,下面我们就一起来看一吧!当然,非常希望大家能多多评论,给出合理的建议,我们一起学习,一起进步!
1. Golang 结构体的概念及定义
结构体是 Golang 中一种复合类型,它是由一组具有相同或不同类型的数据字段组成的数据结构。结构体是一种用户自定义类型,它可以被用来封装多个字段,从而实现数据的组合和抽象化。在 Golang 中,结构体是一种非常灵活和扩展性强的类型,它支持嵌套、组合、方法等高级特性。
定义一个结构体的语法如下:
type StructName struct { Field1 Type1 Field2 Type2 // ... }
其中,StructName 是结构体的名称,Field1、Field2 等是结构体的字段名,Type1、Type2 等是结构体的字段类型。可以定义多个字段,字段名和字段类型之间用空格分隔。
下面是一个定义 Person 结构体的例子:
type Person struct { Name string Age int }
在上述代码中,我们定义了一个名为 Person 的结构体,包含两个字段:Name 和 Age。其中,Name 是字符串类型,Age 是整型。
2. Golang 结构体的实例化
在 Golang 中,结构体的实例化有多种方式,包括使用结构体字面量、new 函数、var 关键字和构造函数等。
结构体字面量
结构体字面量是一种简便的方式,用于创建结构体的实例。在使用结构体字面量时,我们需要指定结构体的字段名和字段值,多个字段之间用逗号分隔,整个结构体用花括号括起来。
下面是使用结构体字面量创建 Person 结构体的例子:
p := Person{Name: "Tom", Age: 25}
在上述代码中,我们创建了一个名为 p 的 Person 结构体,并将其初始化为 {Name: "Tom", Age: 25}。其中,Name 字段的值为 "Tom",Age 字段的值为 25。
2.1 new 函数
new 函数是 Golang 中的一个内置函数,它用于创建一个指向新分配的类型为T的零值的指针。在使用 new 函数时,我们需要传递一个类型参数,该参数表示要分配内存的类型。
下面是使用 new 函数创建 Person 结构体的例子:
p := new(Person)
在上述代码中,我们创建了一个名为 p 的 Person 结构体指针。由于使用 new 函数创建的结构体是被初始化为零值的,因此 p 的所有字段值都是默认值。
2.2 var 关键字
var 关键字也可以用于创建结构体的实例。在使用 var 关键字时,我们需要指定变量名和类型,然后用等号将其初始化为结构体字面量。
下面是使用 var 关键字创建 Person 结构体的例子:
var p Person = Person{Name: "Tom", Age: 25}
在上述代码中,我们创建了一个名为 p 的 Person 结构体,并将其初始化为 {Name: "Tom", Age: 25}。由于使用了 var 关键字,因此可以在变量名前面加上类型。
2.3 构造函数
构造函数是一种特殊的函数,它用于创建和初始化结构体的实例。在 Golang 中,构造函数通常以 New 开头,并返回一个指向结构体的指针。
下面是使用构造函数创建 Person 结构体的例子:
func NewPerson(name string, age int) *Person { return &Person{Name: name, Age: age} } p := NewPerson("Tom", 25)
在上述代码中,我们定义了一个名为 NewPerson 的构造函数,它接受两个参数:name 和 age,并返回一个指向Person 结构体的指针。通过调用 NewPerson 函数,我们创建了一个名为 p 的 Person 结构体,并将其初始化为 {Name: "Tom", Age: 25}。
3. Golang 结构体的内嵌与组合
在 Golang 中,结构体的内嵌和组合是实现代码复用和继承的重要手段。结构体的内嵌可以让一个结构体类型包含另一个结构体类型的所有字段和方法,从而实现代码复用。结构体的组合则是通过将一个或多个结构体类型组合在一起,形成一个新的结构体类型,从而实现继承和多态。
3.1 结构体的内嵌
结构体的内嵌是将一个结构体类型嵌套在另一个结构体类型中。在内嵌的结构体中定义的字段和方法都会被继承到外层的结构体中,从而实现代码复用。
下面是一个使用结构体内嵌的例子:
type Address struct { City string State string } type Person struct { Name string Age int Address // 内嵌Address结构体 } func main() { p := Person{ Name: "Tom", Age: 25, Address: Address{ City: "Beijing", State: "China", }, } fmt.Println(p.Name) // Tom fmt.Println(p.Age) // 25 fmt.Println(p.City) // Beijing fmt.Println(p.State) // China }
在上述代码中,我们定义了两个结构体类型:Address 和 Person。其中,Address 结构体包含两个字段:City 和 State;Person 结构体内嵌了 Address 结构体,并添加了两个新字段:Name 和 Age。
通过内嵌 Address 结构体,Person 结构体继承了 Address 结构体的所有字段。因此,我们可以通过 p.City 和p.State 访问 Person 结构体中的 Address 字段。
3.2 结构体的组合
结构体的组合是将一个或多个结构体类型组合在一起,形成一个新的结构体类型。在组合的结构体中,可以重载或扩展组合结构体中的字段和方法,从而实现继承和多态。
下面是一个使用结构体组合的例子:
type Animal struct { Name string } func (a *Animal) Say() { fmt.Printf("%s says: ...\n", a.Name) } type Dog struct { *Animal // 组合Animal结构体 } func (d *Dog) Say() { fmt.Printf("%s says: Woof woof!\n", d.Name) } func main() { a := &Animal{Name: "Unknown"} d := &Dog{Animal: a} a.Say() // Unknown says: ... d.Say() // Unknown says: Woof woof! }
在上述代码中,我们定义了两个结构体类型:Animal 和 Dog。Animal 结构体包含一个字段 Name 和一个方法 Say;Dog 结构体组合了 Animal 结构体,并重载了 Say 方法。
通过组合 Animal 结构体,Dog 结构体继承了 Animal 结构体中的所有字段和方法。在重载 Say 方法时,我们使用了 Name 字段的值,这说明 Dog 结构体继承了 Animal 结构体中的 Name 字段。
3.3 结构体的匿名字段和方法集
在 Golang 中,结构体字段可以被匿名化,这意味着它们的类型可以被直接嵌入到结构体中,而不需要指定字段名。匿名字段的值可以被直接访问,就像结构体中的其他字段一样。
3.3.1 匿名字段
匿名字段和内嵌结构体类似,但它们不会继承字段名和方法。相反,匿名字段的类型被视为字段名,并且可以通过类型名来访问该字段的值。
下面是一个使用匿名字段的例子:
type Person struct { Name string int // 匿名字段 } func main() { p := Person{Name: "Tom", int: 25} fmt.Println(p.Name) // Tom fmt.Println(p.int) // 25 }
在上述代码中,我们定义了一个 Person 结构体类型,它包含了一个 Name 字段和一个匿名的 int 类型字段。通过匿名字段,我们可以直接访问 Person 结构体中的int类型字段,而不需要使用字段名。
3.3.2 方法集
在Golang中,每个结构体类型都有一个方法集,它是该结构体类型上的所有方法的集合。方法集可以被分为两个部分:值方法集和指针方法集。
值方法集包含所有接收者为值类型的方法,而指针方法集包含所有接收者为指针类型的方法。当我们调用结构体类型上的方法时,Golang会自动根据方法集中的接收者类型来确定要传递给方法的接收者值。
在下面的例子中,我们定义了一个Person结构体类型,并在其上定义了一个值方法和一个指针方法:
type Person struct { Name string Age int } func (p Person) GetName() string { return p.Name } func (p *Person) SetAge(age int) { p.Age = age } func main() { p1 := Person{Name: "Tom", Age: 25} fmt.Println(p1.GetName()) // Tom p1.SetAge(30) fmt.Println(p1.Age) // 30 p2 := &Person{Name: "Jack", Age: 35} fmt.Println(p2.GetName()) // Jack p2.SetAge(40) fmt.Println(p2.Age) // 40 }
在上述代码中,我们定义了一个 Person 结构体类型,并在其上定义了一个值方法 GetName 和一个指针方法 SetAge。在调用方法时,Golang 会自动根据方法集中的接收者类型来确定要传递给方法的接收者值。
在调用 p1.GetName 方法时,Golang 会将 p1 作为方法的接收者值传递给 GetName 方法。由于 GetName 方法的接收者类型为值类型,因此 Golang 会将 p1 复制一份,然后将复制的值传递给 GetName 方法。
在调用 p1.SetAge 方法时,Golang 会将 &p1 作为方法的接收者值传递给 SetAge 方法。由于 SetAge 方法的接收者类型为指针类型,因此 Golang 会将 &p1 作为指向 p1 的指针传递给 SetAge 方法。在 SetAge 方法中,我们可以通过指针来修改 p1 结构体中的 Age 字段。
在调用 p2.GetName 方法和 p2.SetAge 方法时,Golang 会自动将 &p2 作为方法的接收者值传递给方法,因为 p2 是一个指向 Person 结构体的指针。
4. Golang 方法的定义和使用
在 Go 语言中,方法是一种特殊的函数,它与某个类型相关联,可以对该类型的实例进行操作。在 Go 语言中,方法的定义方式与函数的定义方式非常相似,唯一的区别在于方法需要在其名称前面加上接收者。下面是一个示例:
type Person struct { name string age int } func (p Person) sayHello() { fmt.Printf("Hello, my name is %s\n", p.name) }
在这个示例中,我们定义了一个名为 “sayHello” 的方法,它与 Person 类型相关联。该方法的接收者为 “p Person”,表示该方法作用于 Person 类型的实例。在方法体中,我们使用了接收者 “p” 的属性 “name” 来输出一段问候语。
5. Golang 方法的接收者
在 Go 语言中,方法的接收者可以是指针类型或值类型。如果使用指针类型作为接收者,则可以在方法中修改结构体的属性值。下面是一个示例:
type Person struct { name string age int } func (p *Person) setAge(newAge int) { p.age = newAge } func main() { p := Person{"Tom", 20} p.setAge(30) fmt.Printf("%s's age is %d\n", p.name, p.age) }
在这个示例中,我们定义了一个名为 “setAge” 的方法,它的接收者为 “p *Person”,表示它接收一个指向 Person类型的指针。在方法体中,我们使用了指针 “p” 的属性 “age” 来修改 Person 结构体的年龄属性。在 main 函数中,我们使用该方法来修改 Person 实例的年龄,并输出修改后的结果。
6. Golang 指针类型的方法
在 Go 语言中,指针类型的方法可以被值类型的实例和指针类型的实例调用。这是因为在调用时,值类型的实例会自动被转换为指针类型的实例。下面是一个示例:
type Person struct { name string age int } func (p *Person) sayHello() { fmt.Printf("Hello, my name is %s\n", p.name) } func main() { p := Person{"Tom", 20} p.sayHello() (&p).sayHello() }
在这个示例中,我们定义了一个名为 “sayHello” 的方法,它的接收者为 “p *Person”,表示它接收一个指向 Person 类型的指针。在 main 函数中,我们定义了一个 Person 实例 “p”,然后分别使用值类型的实例和指针类型的实例来调用 “sayHello” 方法。
7. Golang 方法与接口
在 Go 语言中,方法是接口的实现条件之一。一个类型只有实现了接口定义的所有方法,才能被称为该接口类型的实现类。下面是一个示例:
type Animal interface { Speak() string } type Dog struct{} func (d Dog) Speak() string { return "Woof!" } type Cat struct{} func (c Cat) Speak() string { return "Meow!" } func main() { animals := []Animal{Dog{}, Cat{}} for _, animal := range animals { fmt.Println(animal.Speak()) } }
在这个示例中,我们定义了一个名为 “Animal” 的接口,它包含一个名为 “Speak” 的方法。然后,我们定义了两个类型:“Dog” 和 “Cat”,它们都实现了 “Animal” 接口中定义的 “Speak” 方法。在 main 函数中,我们定义了一个 Animal 类型的切片 “animals”,将 “Dog” 和 “Cat” 实例分别添加到该切片中,并遍历该切片,输出每个实例的 “Speak” 方法的返回值。
8. Golang 结构体和接口的组合
在上面的几个部分中,我们已经介绍了 Golang 结构体和方法的定义和使用,以及接口的设计和实现。在本部分中,我们将探讨 Golang 结构体和接口的组合,即如何使用结构体和接口来实现更加灵活和可扩展的设计。
在 Golang 中,我们可以使用结构体和接口的组合来实现多态。多态是一种面向对象编程中的概念,它允许不同的对象使用同一种接口来实现不同的行为。通过多态,我们可以让不同的对象具有不同的行为,从而实现更加灵活和可扩展的设计。
首先,让我们来看一个简单的例子,说明如何使用结构体和接口的组合来实现多态。假设我们有一个形状接口和两个形状结构体,分别表示矩形和圆形。我们可以定义形状接口如下:
type Shape interface { Area() float64 }
然后,我们可以定义矩形和圆形结构体,实现形状接口中的方法:
type Rectangle struct { Width float64 Height float64 } func (r Rectangle) Area() float64 { return r.Width * r.Height } type Circle struct { Radius float64 } func (c Circle) Area() float64 { return math.Pi * c.Radius * c.Radius }
现在,我们可以定义一个通用的函数,使用形状接口作为参数,计算不同形状的面积:
func CalculateArea(shape Shape) float64 { return shape.Area() }
最后,我们可以使用这个函数来计算不同形状的面积:
rect := Rectangle{Width: 3, Height: 4} circle := Circle{Radius: 5} fmt.Println(CalculateArea(rect)) // 输出 12 fmt.Println(CalculateArea(circle)) // 输出 78.53981633974483
rect := Rectangle{Width: 3, Height: 4} circle := Circle{Radius: 5} fmt.Println(CalculateArea(rect)) // 输出 12 fmt.Println(CalculateArea(circle)) // 输出 78.53981633974483
rect := Rectangle{Width: 3, Height: 4} circle := Circle{Radius: 5} fmt.Println(CalculateArea(rect)) // 输出 12 fmt.Println(CalculateArea(circle)) // 输出 78.53981633974483
通过上面的例子,我们可以看到,使用结构体和接口的组合可以实现多态,从而让不同的对象具有不同的行为。在实际的开发中,我们可以使用这种方法来实现更加灵活和可扩展的设计。
除了上面的例子之外,我们还可以使用结构体和接口的组合来实现更加复杂的设计。例如,我们可以定义一个汽车接口和两个汽车结构体,分别表示轿车和越野车。然后,我们可以定义一个通用的函数,使用汽车接口作为参数,计算不同汽车的油耗。通过这种方法,我们可以实现一个通用的汽车油耗计算器,从而让我们更加灵活地进行汽车设计和开发。
总之,使用结构体和接口的组合可以让我们实现更加灵活和可扩展的设计。通过多态,我们可以让不同的对象使用同一种接口来实现不同的行为,从而让我们的代码更加清晰和易于维护。在实际的开发中,我们可以使用结构体和接口的组合来实现各种复杂的设计,从而让我们的代码更加优雅和高效。
9. Golang 结构体标签
在 Golang 中,我们可以在结构体的字段上添加标签,以便在运行时可以通过反射获取这个字段的元数据。结构体标签是一种可以添加到结构体字段上的元数据,它可以用于描述这个字段的属性、格式等等。
结构体标签的基本语法如下:
type MyStruct struct { FieldName FieldType `tag:"tagValue"` }
其中,FieldName 是结构体的一个字段,FieldType 是这个字段的类型,tagValue 是这个字段的标签值。
例如,我们可以为 Person 结构体的Name字段添加一个 json 标签,用于指定在将结构体编码为 JSON 格式时,这个字段应该使用的名称,代码如下所示:
type Person struct { Name string `json:"name"` Age int `json:"age"` }
这个结构体的 Name 字段被标记为 json:"name",表示在将这个结构体编码为 JSON 格式时,这个字段应该使用name 作为字段名称。
我们可以使用 Golang 内置的反射机制来获取这个结构体字段的标签值,例如,我们可以使用 reflect 包中的 Type和 FieldByName 方法来获取 Person 结构体的 Name 字段的标签值,代码如下所示:
p := Person{Name: "Tom", Age: 18} t := reflect.TypeOf(p) f, _ := t.FieldByName("Name") fmt.Println(f.Tag.Get("json")) // Output: name
这个代码创建了一个名为 p 的 Person 结构体实例,并使用反射机制获取了这个结构体的 Name 字段的 json 标签值。
10. 总结
本文介绍了 Golang 语言中结构体和方法的相关知识。我们从结构体的定义和初始化开始,深入探讨了结构体的成员和匿名字段、方法集以及结构体的嵌套和组合等概念。通过学习本文,你应该能够熟练使用结构体和方法来实现面向对象编程中的各种功能。同时,你也应该能够清晰地理解 Golang 语言中结构体和方法的内部实现原理,从而更好地利用它们来解决实际问题。
如果你对本文所介绍的内容有任何疑问或建议,欢迎在评论区留言,我们将在第一时间给予回复。
文中关于golang的知识介绍,希望对你的学习有所帮助!若是受益匪浅,那就动动鼠标收藏这篇《一文带你掌握掌握Golang结构体与方法》文章吧,也可关注golang学习网公众号了解相关技术文章。
-
438 收藏
-
377 收藏
-
353 收藏
-
125 收藏
-
453 收藏
-
233 收藏
-
322 收藏
-
181 收藏
-
316 收藏
-
244 收藏
-
300 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 507次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习