结构体的定义
结构体也是一种复合类型,通常使用带属性的结构体来表示一个现实中的实体。结构体也是值类型,因此可以通过使用 new 函数来创建。Go语言不是一门传统的面向对象的编程语言,因此 Go 中没有类的概念,也不支持类的面向对象概念。结构体是由零个或多个任意类型的值聚合成的实体,每个值都可以称为结构体的成员。
结构体成员也可以称为“字段”,这些字段有以下特性:
- 字段拥有自己的类型和值;
- 字段名必须唯一;
- 字段的类型也可以是结构体,甚至是字段所在结构体的类型。
type Family struct {
name string
age int
language string
...
}
type Family struct {
name, language string //同一类型的变量可以放在一起声明
age int
...
}
结构体的定义只是一种内存布局的描述,只要当结构体实例化时,才会真正的分配内存空间
结构体的实例化
实例化是指根据结构体内定义的格式创建一份与格式一致的内存区域,结构体实例与实例之间是完全独立的。
在 Go 语言中,有多种实例化结构体的方式:
var a Family //Famlily表示结构体类型, a表示结构体的实例//定义结构体
type Family struct {
name,lang,skill string
age int
}
//实例化结构体
func main() {
//Family是结构体类型,a是结构体的实例
var a Family
a.name = "小马"
a.lang = "zh"
a.age = 18
a.skill = "python"
//打印结构体的属性值
fmt.Println(Family(a))
}
/*
{小马 zh python 18 false}
*/a := new(Animal) //Family表示结构体类型,a表示结构体实例(一个指向 Family 的指针)type Animal struct {
Name string
Age int
Sex string
Comment string
}
func main() {
//使用new函数实例化
a := new(Animal)
a.Name = "Panda"
a.Age = 22
a.Sex = "female"
a.Comment = "功夫熊猫"
//打印指向结构体的指针及其指针地址
fmt.Println(a,&a)
}
/*
&{Panda 22 female 功夫熊猫} 0xc000006028
*/
a := &Book{} //Book表示结构体类型,a表示结构体实例(一个指向Book的指针)type Book struct {
Name string
Author string
Price int
}
func main(){
//实例化
a := &Book{}
a.Name = "三国演义"
a.Author = "罗贯中"
a.Price = 88
fmt.Println(a)
}
/*
&{三国演义 罗贯中 88}
*///声明结构体
type Book struct {
Name string
Author string
Price int
}
//使用函数封装实例化过程,返回*Book指针
func newBook (name string,author string,price int) *Book {
return &Book{
Name: name,
Author:author,
Price:price,
}
}
//调用newBook结构体实例化函数完成实例化
func main(){
fmt.Println(newBook("三国","罗贯中",88))
}
/*
&{三国 罗贯中 88}
*///声明结构体
type Book struct {
Name string
Author string
Price int
Version *Book //不需要初始化,默认输出类型零值,为nil
}
//使用键值对初始化成员变量
func main(){
a := Book{
Name : "三国演义",
Author : "罗贯中",
Price : 88,
}
fmt.Println(a)
}
/*
{三国演义 罗贯中 88 <nil>}
*///声明结构体
type Book struct {
Name string
Author string
Price int
Version *Book
}
//使用键值对初始化成员变量
func main(){
a := Book{ //使用多个值的列表初始化
"金瓶梅",
"未名人",
1998,
nil,
}
fmt.Println(a)
}
/*
{金瓶梅 未名人 1998 <nil>}
*/
初始化匿名结构体
func main(){
//匿名结构体定义,不需要用type定义就可以使用
lala := struct{
name string
age int
}{//匿名结构体初始化(可选)
name:"钓鱼城大学完满主任",
age:18,
}
//打印匿名结构体属性值
fmt.Println(lala.name,lala.age)
}
/*
钓鱼城大学完满主任 18
*/
### 使用匿名结构体(demo)
//构造完满主任函数,传入匿名结构体
func wanmanLeader(wanman *struct{
id,post,name,food string
weight int
}){
//打印匿名结构体类型
fmt.Printf("%T\n",wanman)
}
func main(){
//匿名结构体定义
wanman := &struct{
id,post,name,food string
weight int
}{//匿名结构体初始化
"WM001",
"完满主任",
"Xiaoma",
"米饭",
80,
}
//调用完满主任函数,打印匿名结构体的类型
wanmanLeader(wanman)
//打印信息
fmt.Printf("匿名结构体的属性值:%v\n匿名结构体的内存地址:%v\n",wanman,&wanman)
}
/*
*struct { id string; post string; name string; food string; weight int }
匿名结构体的属性值:&{WM001 完满主任 Xiaoma 米饭 80}
匿名结构体的内存地址:0xc00008a018
*/
### 模拟构造函数重载——多种方式创建和初始化结构体
还记得 C++ 对函数重载的定义是什么吗?指可以有多个同名函数,因此对函数名称进行了重载(它们完成相同的工作,但使用不同的参数列表)。且仅当函数基本上执行相同的任务,但使用不同形式的数据时,才应该使用函数重载,这是C++的用法。
Golang 的类型或者结构体没有构造函数的功能,但依旧可以用结构体初始化来模拟函数重载。请看如下例子,如果使用结构体描述鸭子的特性,根据鸭子的叫声和颜色可以有不同种类的鸭子,那么不同种颜色和叫声就是结构体的字段,同时可以使用颜色和叫声构造不同种类鸭子的实例:
//定义鸭子特性结构体
type Duck struct {
Call string
Color string
}
//用叫声构造函数
func NewDuckByCall (call string)*Duck{
return &Duck{//取地址实例化结构体
Call:call,
}
}
//用颜色构造函数
func NewDuckByColor (color string)*Duck{
return &Duck{//取地址实例化结构体
Color:color,
}
}
NewDuckByCall()NewDuckByColor()
模拟父级构造调用——带有父子关系的结构体
让我们来回顾 C++ 中对于基类和派生类的定义:当创建一个类时,不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称为基类,新建的类称为派生类。
在 Golang 中没有提供构造函数相关的特殊机制,用户根据自己的需求,将参数使用函数传递到结构体构造参数中即可完成构造函数的任务。由于 Go 不是传统的 OOP 语言,也没有类的定义,但是可以用结构体模拟实现类的继承。
例如,小黄鸭是鸭子的一个种类,鸭子是小黄鸭的泛称,同时描述这两种概念时,就是派生小黄鸭派生自鸭子的种类,鸭子是小黄鸭的基类。使用结构体描述小黄鸭与鸭子的关系时,将鸭子(Duck)的结构体内嵌到小黄鸭(littleDuck)中,表示小黄鸭拥有鸭子的特性(相当于派生),然后再使用两个不同的构造函数分别构造出小黄鸭和鸭子的两个实例:
//定义鸭子特性结构体
type Duck struct {
Call string
Color string
}
//派生
type littleDuck struct {
Duck //内嵌鸭子结构体,表示小黄鸭拥有鸭子的特性
}
//构造基类
func NewDuck(call string) *Duck{
return &Duck{
Call: "gaga",
}
}
//构造子类
func NewlittleDuck(color string) *littleDuck {
duck := new(littleDuck) //实例化小黄鸭结构体,此时鸭子也被实例化
duck.Color = color
return duck
}
littleDuckDucklittleDuckDuckDuckNewDuckDuckcallDuckNewlittleDucklittleDuckcolorlittleDuckDucklittleDuckDucklittleDuckDuck
DucklittleDuckDucklittleDuckDuck