热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Golang学习——结构体struct(二)

Golang中匿名结构体和匿名字段,结构体嵌套,模拟继承性学习这篇文章也是结构体的学习,不过,如果没有结构体struct基础的话,推荐先看Golang学习——结构体struct(一











Golang中匿名结构体和匿名字段,结构体嵌套,模拟继承性学习

这篇文章也是结构体的学习,不过,如果没有结构体struct基础的话,推荐先看Golang学习——结构体struct(一)。

今天主要记录 匿名结构体和匿名字段,结构体嵌套,模拟继承性


一.匿名结构体和匿名字段

1.匿名结构体

匿名结构体:即没有名字的结构体,在创建匿名结构体时,同时初始化结构体。
实例:

// 没有结构体命名过程, 直接创建一个结构体,并初始化
s2 := struct {
name string
age int
}{}

初始化时必须的, 不然会编译报错。实例中,我未具体初始化,使用了默认值。通常,这个语法在实际开发中使用较少,作为了解即可


2.匿名字段

匿名字段:一个结构体的字段没有字段名

我们定义一个Worker结构体,有两个匿名字段,:

type Worker struct {
string //匿名字段
int
//string 再次定义一个 string 匿名字段时编译报错
}

匿名字段,默认使用数据类型作为名字,那么匿名字段的类型就不能重复,否则会冲突。

通过.操作正常访问字段,如下:

bob := Worker{"Bob", 22}
fmt.Println(bob)
fmt.Println(bob.string)
fmt.Println(bob.int)

输出:

{Bob 22}
Bob
22

在实际开发中几乎没有人会这么写的,但是我们仍然有必要了解一下,为模拟继承性打好基础。


二.结构体嵌套

结构体嵌套:一个结构体可能包含一个字段,而这个字段反过来就是一个结构体,这种结构被称为嵌套结构。

类似Java中的对象的包含关系 has a


1.实例

定义图书, 学生结构体。其中,学生结构体嵌套了图书结构体

// 定义 Book 结构体
type Book struct {
bookName string
price float64
}
// 定义 Student 结构体,其中一个字段是 Book 类型
type Student struct {
name string
age int
book Book // 嵌套 Book 结构体
}

初始化结构体:

// 声明初始化 book
book1 := Book{
bookName: "三国演义",
price: 56.5,
}
// 声明初始化 sutdent
student1 := Student{
name: "Tom",
age: 20,
book: book1,
}
fmt.Println("student1 结构体内容:", student1)
fmt.Printf("访问 book1 中的字段,书名:%s,价格:%.2f\n", student1.book.bookName, student1.book.price)

输出:

student1 结构体内容: {Tom 20 {三国演义 56.5}}
访问 book1 中的字段,书名:三国演义,价格:56.50

外部结构体对象(student1)访问内部结构体对象(book1)中的字段时,不能直接student1.bookName,这是不允许的, 因为两个结构体之间的关系是包含关系,二者的字段是相互独立的。

那如果就是想 student1.bookName 来获取图书名称呢?这就涉及的结构体的继承性了。


三.结构体模拟继承性

在学习了前两小节后,可以顺利的学习Golang中的继承,因为前两小节是学习继承的知识铺垫。

其实Golang并不是纯粹的面向对象的编程语言,但也可以实现继承关系,类似:


  • Java中的 class_sub extend class_father


    • Python中的 class_father(class_sub)

是一种 is a的关系。


1.实例

Golang中通过嵌套匿名结构体来实现继承,具体是什么样的呢?我们实例操作一下:

//1.定义父类
type Person struct {
name string
age int
}
//2.定义子类
type Student struct {
Person //模拟继承结构
school string //子类的新增属性
}

以上代码就实现了继承, 其中 Student结构体中嵌套了Person结构体,且Person必须作为匿名字段。

实例操作如下:

//1.创建父类的对象
p1 := Person{name: "张三", age: 30}
fmt.Println("父类对象:", p1)
//2.创建子类的对象
s1 := Student{Person{"李四", 17}, "清华大学"}
fmt.Println("子类对象 s1:", s1)

输出:

父类对象 p1: {张三 30}
子类对象 s1: {{李四 17} 清华大学}

刚刚在 (二)小节中,想通过student1.bookName来直接访问书名是不允许,但是在本节学习了继承关系后,我们可以实现此操作了。

// 子类对象间接访问父类属性
s3.Person.name = "王五"
s3.Person.age = 19
s3.school = "清华大学"
fmt.Println("子类对象 s3:", s3)
// 子类对象直接访问父类属性
s3.name = "Ruby"
s3.age = 20
fmt.Println("子类对象 s3:", s3)

输出:

子类对象 s3: {{王五 19} 清华大学}
子类对象 s3: {{Ruby 20} 清华大学}

一般地,在实现了继承后,开发习惯通常都是直接子类对象.字段名来获取属性值。

但是如果有多重继承的情况,那就得指定访问哪个父类的属性。否则父类之间字段名重复的话,会引起访问歧义,编译会报错。

我们新增一个Teenager结构体,其中age字段和Personage字段完成相同,然后Student也继承它:

// 新增一个青少年结构体,只有年龄属性
type Teenager struct {
age int
}
// 学生结构体中多了一个 Teenager 匿名字段,模拟多重继承
type Student struct {
Person
Teenager // 新增了一个匿名字段,是Teenager结构体
school string
}

TeenagerPerson结构体有个相同的字段 age,访问时需要显示指定是访问哪个父类下的age。否则会编译报错。

我们还是使用之前的直接访问属性的方式:

// 子类对象直接访问父类属性
s3.name = "Ruby"
s3.age = 16 // 重名的字段会报错
fmt.Println("子类对象 s3:", s3)

我们试着输出下报错信息:

# command-line-arguments
.\demo09_struct_extend.go:51:4: ambiguous selector s3.age

ambiguous selector s3.age 表明s3.age有歧义,因为我们PersonTeenager有完全相同的字段。


2.结构体嵌套is ahas a区别

总结一下:
Golang结构体嵌套,会衍生出两种关系:
1.模拟继承性 - > is a,如下:

type A struct{
field
}
type B struct{
A // 匿名字段
}

2.模拟聚合性 - > has a,如下:

type C struct{
field
}
type D struct{
c C // 聚合关系
}

语法上的区别就是:嵌套的结构体是否匿名

结构体的记录暂时记录到这里,如果后续有新的知识,会持续更新。




Golang学习


推荐阅读
  • 本文介绍了lua语言中闭包的特性及其在模式匹配、日期处理、编译和模块化等方面的应用。lua中的闭包是严格遵循词法定界的第一类值,函数可以作为变量自由传递,也可以作为参数传递给其他函数。这些特性使得lua语言具有极大的灵活性,为程序开发带来了便利。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • Java String与StringBuffer的区别及其应用场景
    本文主要介绍了Java中String和StringBuffer的区别,String是不可变的,而StringBuffer是可变的。StringBuffer在进行字符串处理时不生成新的对象,内存使用上要优于String类。因此,在需要频繁对字符串进行修改的情况下,使用StringBuffer更加适合。同时,文章还介绍了String和StringBuffer的应用场景。 ... [详细]
  • 本文介绍了RPC框架Thrift的安装环境变量配置与第一个实例,讲解了RPC的概念以及如何解决跨语言、c++客户端、web服务端、远程调用等需求。Thrift开发方便上手快,性能和稳定性也不错,适合初学者学习和使用。 ... [详细]
  • Android源码深入理解JNI技术的概述和应用
    本文介绍了Android源码中的JNI技术,包括概述和应用。JNI是Java Native Interface的缩写,是一种技术,可以实现Java程序调用Native语言写的函数,以及Native程序调用Java层的函数。在Android平台上,JNI充当了连接Java世界和Native世界的桥梁。本文通过分析Android源码中的相关文件和位置,深入探讨了JNI技术在Android开发中的重要性和应用场景。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • 本文介绍了一种轻巧方便的工具——集算器,通过使用集算器可以将文本日志变成结构化数据,然后可以使用SQL式查询。集算器利用集算语言的优点,将日志内容结构化为数据表结构,SPL支持直接对结构化的文件进行SQL查询,不再需要安装配置第三方数据库软件。本文还详细介绍了具体的实施过程。 ... [详细]
  • Ihaveaworkfolderdirectory.我有一个工作文件夹目录。holderDir.glob(*)>holder[ProjectOne, ... [详细]
  • 本文介绍了在实现了System.Collections.Generic.IDictionary接口的泛型字典类中如何使用foreach循环来枚举字典中的键值对。同时还讨论了非泛型字典类和泛型字典类在foreach循环中使用的不同类型,以及使用KeyValuePair类型在foreach循环中枚举泛型字典类的优势。阅读本文可以帮助您更好地理解泛型字典类的使用和性能优化。 ... [详细]
  • Mono为何能跨平台
    概念JIT编译(JITcompilation),运行时需要代码时,将Microsoft中间语言(MSIL)转换为机器码的编译。CLR(CommonLa ... [详细]
  • 开发笔记:Python之路第一篇:初识Python
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Python之路第一篇:初识Python相关的知识,希望对你有一定的参考价值。Python简介& ... [详细]
  • 只使用’if-else’语句的’else’部分是否可以接受?有时,我觉得检查所有条件是否都是真的更容易,但是只处理“其他”情况。我想 ... [详细]
author-avatar
连向明
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有