<<Go 语言核心 36 讲>> 郝林 总结的
不可寻址的值:
- 常量的值。
- 基本类型值的字面量。
- 算术操作的结果值。
- 对各种字面量的索引表达式和切片表达式的结果值。不过有一个例外,对切片字面量的索引结果值却是可寻址的。
- 对字符串变量的索引表达式和切片表达式的结果值。
- 对字典变量的索引表达式的结果值。
- 函数字面量和方法字面量,以及对它们的调用表达式的结果值。
- 结构体字面量的字段值,也就是对结构体字面量的选择表达式的结果值。
- 类型转换表达式的结果值。
- 类型断言表达式的结果值。
- 接收表达式的结果值。
规律:
- 不可变的 - 寻址没有意义, 不能改
- 临时结果 - 例外, 切片字面量的索引结果值.
- 不安全的 - "不安全的"操作很可能会破坏程序的一致性,引发不可预知的错误,从而严重影响程序的功能和稳定性。
上代码, 自己品
package main
type Pet interface {
Name() string
Category() string
}
type Dog struct {
name string
}
func (self Dog) SetName(name string) {
self.name = name
}
func (self Dog) Name() string {
return self.name
}
func (self Dog) Category() string {
return "Dog"
}
func New(name string) Dog {
return Dog{name}
}
func main() {
// 不会报错. 不需要指针类型调用 SetName
New("Max").SetName("Bear")
}
package main
type Pet interface {
Name() string
Category() string
}
type Dog struct {
name string
}
func (self *Dog) SetName(name string) {
self.name = name
}
func (self *Dog) Name() string {
return self.name
}
func (self *Dog) Category() string {
return "Dog"
}
func New(name string) Dog {
return Dog{name}
}
func main() {
dog := New("Max")
dog.SetName("Bear") // 编译器会自动转换成 (&dog).SetName("Bear")
// 会报错, 因为 New("Max") 是临时结果, 不可以寻址, 无法获取指针
New("Max").SetName("Bear")
// cannot call pointer method on New("Max")
// cannot take the address of New("Max")
}
package main
import (
"fmt"
)
func main() {
map[string]int{"the": 0, "word": 0, "counter": 0}["word"]++
map1 := map[string]int{"the": 0, "word": 0, "counter": 0}
map1["word"]++
fmt.Println(map1["word"]) // 1
}
package main
import (
"fmt"
"unsafe"
)
type Dog struct {
name string
}
func (self *Dog) SetName(name string) {
self.name = name
}
func (self *Dog) Name() string {
return self.name
}
func (self *Dog) Category() string {
return "Dog"
}
func main() {
dog := Dog{}
dog.SetName("Max")
dogP := &dog
dogPtr := uintptr(unsafe.Pointer(dogP))
namePtr := dogPtr + unsafe.Offsetof(dogP.name)
nameP := (*string)(unsafe.Pointer(namePtr))
fmt.Println(*nameP) // Max
namePtr = dogPtr + 64
unknownP := (*[]byte)(unsafe.Pointer(namePtr))
fmt.Println(*unknownP) // 内存泄漏, 获取到了某个地址指向的数据. 如果改了, 可能会导致不可知的问题
}