Go入门(11)——结构体

Go入门(11)——结构体,第1张

概述Go入门(11)——结构体定义Go通过类型别名(AliasTypes)和结构体的形式支持用户自定义类型。结构体是复合类型(CompositeTypes)。组成结构体类型的数据称为字段(Fields)。每个字段都有一个类型和名称;单个结构体中名称必须是唯一的。typeidentifierstruct{field1type1fie Go入门(11)——结构体定义

Go通过类型别名(Alias Types)和结构体的形式支持用户自定义类型。结构体是复合类型(Composite Types)。组成结构体类型的数据称为字段(FIElds)。每个字段都有一个类型和名称;单个结构体中名称必须是唯一的。

type IDentifIEr struct {    fIEld1 type1     fIEld2 type2    // ...}

另外,定义简单的结构体可以使用:

type T struct {a, b int}

结构体中的字段都有名称,但是如果某字段不会被使用,可以命名为_

结构体的字段可以是任何类型,甚至是结构体本身,也可以是函数或者接口。

分配

使用new为结构体分配内存,这将返回已分配内存的指针。

var t *T = new(T)

这条语句惯用写成:

t := new(T)

t是指向T的指针。new完成后,结构体内字段的值是其所属类型的零值。

如果声明采用:

var t T

这样也会给t分配内存,并零值化,但此时t的类型是T

以上两种声明方式中,t通常被称为类型T的一个实例(Instance)或对象(Object)。

示例:

package main import "fmt"type struct1 struct {    i1 int     f1 float32     str string}func main() {    ms := new(struct1)    ms.i1 = 10    ms.f1 = 15.5     ms.str = "4thrun"        fmt.Printf("The int is: %d\n", ms.i1)    fmt.Printf("The float is: %f\n", ms.f1)    fmt.Printf("The string is: %s\n", ms.str)    fmt.Println(ms)}

运行结果:

The int is: 10The float is: 15.500000The string is: 4thrun&{10 15.5 4thrun}
结构体递归

结构体类型可以通过引用自身来定义。在定义二叉链表、二叉树等结构时,通常会用到这种定义方式(用结构体表示结点)。在结点信息中,需要包含临近结点的链接(地址)。如下所示:

// 链表结构体type Node struct {    data float64    su *Node // 存放下一地址}
// 双向链表type Node struct {    pr *Node    data float64     su *Node }
// 二叉树type Tree struct {    le *Tree    data float64     ri *Tree}
结构体转换

当为结构体定义了Alias类型时,此结构体和它的Alias类型具有相同的底层类型。它们可以使用如下代码进行相互转化,非法赋值或转换会引起编译错误:

package main import "fmt"type number struct {    f float32}type nr number // Alias type func main() {    a := number{5.0}    b := nr{5.0}    // var i float32 = b   // compile-error: cannot use b (type nr) as type float32 in assignment    // var i = float32(b)  // compile-error: cannot convert b (type nr) to type float32    // var c number = b    // compile-error: cannot use b (type nr) as type number in assignment    // needs a conversion:    var c = number(b)    fmt.Println(a, b, c)}
匿名字段与struct嵌套
package mainimport (    "fmt")type inner struct {    in1 int    in2 int}type outer struct {    ou1 int    ou2 int    int    inner}func main() {    o := new(outer)    o.ou1 = 1    o.ou2 = 2    o.int = 3    o.in1 = 4    o.in2 = 5    fmt.Println(o.ou1)      fmt.Println(o.ou2)      fmt.Println(o.int)      fmt.Println(o.in1)     fmt.Println(o.in2) }

输出为:

12345
工厂模式

Go不支持传统面向对象语言的构造子方法,但是可以实现构造子工厂。通常会为一个类型定义工厂模式,工厂名称以new或者New开头,便于识别。如以下file结构体类型:

type file struct {    fd int // 文件描述符    name string // 文件名}

对这个结构体定义工厂方法,返回指向结构体实例的指针:

func Newfile(fd int, name string) *file {    if fd < 0 {        return nil     }    return &file{fd, name}}

如果file是结构体类型,那么new(file)&file{}两个表达式是等价的。

强制使用工厂方法

通过禁止使用new函数,强制使用工厂方法,可以让类型变成私有,达到面向对象语言中的相同效果。

type matrix struct {    // ... }func NewMatrix(params) *matrix {    m := new(matrix) // 初始化m    return m}

在其它包使用工厂方法:

package main import "matrix"// ...wrong := new(matrix.matrix) // 编译失败,matrix是私有的right := matrix.NewMatrix(...) // 实例化matrix的唯一方法
结构体传值/传指

Go函数给参数传递值时是以复制的方式进行的。复制传值时,如果函数的参数是一个结构体对象,将复制整个数据结构的副本传递给函数,这会导致两个问题:

函数内部无法修改传递给函数的原始数据结构,只能修改副本;如果原始数据结构很大,传值代价是不能接受的。

原则上都应该传递指针,而不是传递副本。

结构体方法

结构体中可以包含属性,同样结构体可以有方法。

方法实际上就是函数,结构体方法即是具有特殊接收器类型的函数。接收器用于在函数内部进行访问。

func (t Type) methodname (parameter List) {    // ...}

许多编程面向对象的编程语言,都会有this或者self隐式地指向当前实例,但是Go中没有这个概念,定义方法时都会给定变量名。

对于方法而言,使用引用和使用值区别不大,编译时也会自行优化。

总结

以上是内存溢出为你收集整理的Go入门(11)——结构体全部内容,希望文章能够帮你解决Go入门(11)——结构体所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1232187.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-06
下一篇 2022-06-06

发表评论

登录后才能评论

评论列表(0条)

保存