首页 > 编程笔记 > Go语言笔记

Go语言结构体字面量

结构体类型的值可以通过结构体字面量来设置,即通过设置结构体的成员变量来设置。

type Point struct{ X, Y int }
p := Point{1, 2}

有两种格式的结构体字面量。第一种格式如上所示,它要求按照正确的顺序,为每个成员变量指定一个值。这会给开发和阅读代码的人增加负担,因为他们必须记住每个成员变量的顺序,另外这也使得未来结构体成员变量扩充或者重新排列的时候代码维护性差。

所以,这种格式一般用在定义结构体类型的包中或者一些有明显的成员变量顺序约定的小结构体中,比如image.Point{x, y}或者color.RGBA{red, green, blue, alpha}

我们用得更多的是第二种格式,通过指定部分或者全部成员变量的名称和值来初始化结构体变量:

anim := gif.GIF{LoopCount: nframes}

如果在这种初始化方式中某个成员变量没有指定,那么它的值就是该成员变量类型的零值。因为指定了成员变量的名字,所以它们的顺序是无所谓的。

这两种初始化方式不可以混合使用,另外也无法使用第一种初始化方式来绕过不可导岀变量无法在其他包中使用的规则。

package p
type T struct{ a,b int }   // a 和 b 都是不可导出的

package q
import "p"
var _ = p.T{a: 1, b: 2}      //编译错误,无法引用 a、b
var _ = p.T{l, 2}               //编译错误,无法引用 a、b

虽然上面的最后一行代码没有显式地提到不可导出变量,但是它们被隐式地引用了,所以这也是不允许的。

结构体类型的值可以作为参数传递给函数或者作为函数的返回值。例如,下面的函数将 Point 缩放了一个比率:

func Scale(p Point, factor int) Point {
    return Point{p.X * factor, p.Y * factor}
}

fmt.Println(Scale(Point{1, 2}» 5)) // "{5 10}"

出于效率的考虑,大型的结构体通常都使用结构体指针的方式直接传递给函数或者从函数中返回。

func Bonus(e *Employee, percent int) int {
    return e.Salary * percent / 100
}

这种方式在函数需要修改结构体内容的时候也是必需的,在Go语言这种按值调用的编程语言中,调用的函数接收到的是实参的一个副本,并不是实参的引用。

func AwardAnnualRaise(e *Employee) {
    e.Salary = e.Salary * 105 / 100
}

由于通常结构体都通过指针的方式使用,因此可以使用一种简单的方式来创建、初始化一个 struct 类型的变量并获取它的地址:

pp := &Point{1, 2}

这个等价于:

pp := new(Point)
*pp = Point{1, 2}

但是 &Point{1, 2} 这种方式可以直接使用在一个表达式中,例如函数调用。

结构体比较

如果结构体的所有成员变量都可以比较,那么这个结构体就是可比较的。两个结构体的比较可以使用 == 或者 !=。其中 == 操作符按照顺序比较两个结构体变量的成员变量,所以下面的两个输出语句是等价的:

type Point struct{ X, Y int }

p := Point{1, 2}
q := Point{2, 1}
fmt.Println(p.X == q.X && p.Y == q.Y) // "false"
fmt.Println(p == q)                                // "false"

和其他可比较的类型一样,可比较的结构体类型都可以作为 map 的键类型。

type address struct {
    hostname string
    port int
}
hits := make(map[address]int)
hits[address{"golang.org", 443}]++

所有教程

优秀文章