GO 给临时结构体变量字段赋值的编译错误

33 阅读1分钟

在go语言中,如果给结构体的临时变量的字段赋值,会出现编译错误。

type Employee struct {
	ID            int
	Name, Address string
}

func EmployeeById(id int) *Employee {
	return &Employee{ID: id, Name: "hello", Address: "beijing"}
}

func EmployeeById2(id int) Employee {
	return Employee{ID: id, Name: "hello", Address: "beijing"}
}

func main() {
	EmployeeById(0).ID = 11
        // 编译错误
	EmployeeById2(0).ID = 10
        // 与上一句的编译错误属于同一个类型。声明了hello之后没有访问。
        hello := 0
        // 下面这段没有问题
        employee := EmployeeById2(0)
	employee.ID = 2
	fmt.Println(employee) //打印出的ID是2
}

为什么会出现编译错误?

对于EmployeeById返回的指针临时变量的字段赋值不会有编译错误,是因为这个赋值是有意义的。因为这个赋值语句更新了EmployeeById返回的指针所指向的对象。

但是EmployeeById2返回的是一个结构体的副本。更新副本的字段,只会更新该副本对象;而这是一个临时变量,之后再也无法访问,因此GO编译器认为是没有意义的操作,报编译错误。与后面一句hello := 0(hello被声明了,但是没有被访问)的编译错误一样。

上面的解释可能不太对。

看下编译器的提示:

image.png

EmployeeById2(0).ID = 10这句的主要问题是,赋值语句的左侧是不可寻址(addressable)的,或者映射索引表达式(map index expression)。所谓可寻址的,包括变量、结构体字段、数组元素。在这里,虽然EmployeeById2(0).ID是一个结构体字段,但是该结构体不是可寻址的,因为EmployeeById2(0)是一个临时变量,无法再访问到EmployeeById2(0);所谓映射索引表达式,就是go中的map类型。