惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

C
CXSECURITY Database RSS Feed - CXSecurity.com
aimingoo的专栏
aimingoo的专栏
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
D
Docker
博客园 - 叶小钗
Recent Announcements
Recent Announcements
人人都是产品经理
人人都是产品经理
云风的 BLOG
云风的 BLOG
Vercel News
Vercel News
Hugging Face - Blog
Hugging Face - Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
美团技术团队
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
F
Fortinet All Blogs
博客园 - 三生石上(FineUI控件)
Microsoft Security Blog
Microsoft Security Blog
H
Heimdal Security Blog
有赞技术团队
有赞技术团队
The Cloudflare Blog
S
Secure Thoughts
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
T
The Blog of Author Tim Ferriss
M
MIT News - Artificial intelligence
Google DeepMind News
Google DeepMind News
Schneier on Security
Schneier on Security
N
News and Events Feed by Topic
小众软件
小众软件
C
Cybersecurity and Infrastructure Security Agency CISA
Application and Cybersecurity Blog
Application and Cybersecurity Blog
博客园 - Franky
T
Tenable Blog
The Last Watchdog
The Last Watchdog
腾讯CDC
量子位
Google DeepMind News
Google DeepMind News
Help Net Security
Help Net Security
雷峰网
雷峰网
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Cyberwarzone
Cyberwarzone
S
Securelist
Martin Fowler
Martin Fowler
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
罗磊的独立博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
P
Proofpoint News Feed
D
Darknet – Hacking Tools, Hacker News & Cyber Security
I
InfoQ
Spread Privacy
Spread Privacy
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
H
Hackread – Cybersecurity News, Data Breaches, AI and More

吴润写字的地方

从零构建 A 股 ETF 动量轮动系统:一个量化新手的完整指南 2025 年 8 月 Digest 2025 年 7 月 Digest 2025 年 6 月 Digest 2025 年 5 月 Digest 2025 年 4 月 Digest 清明桐庐行 2025 年 3 月 Digest 2024 年终总结 换车 崇明岛一日游 夜游徐汇滨江绿地 2023 年终总结 踏春之浦康休闲公园 香港澳门行 读「投资第一课」有感 皮皮玩球 Chrome 插件推荐 Go 并发之道:并发介绍 The Night Agent 我是如何使用 ChatGPT 的 2022 年终总结 在 Ubuntu 上搭建 MinIO 2021 年终总结 Golang 的 defer 关键字使用注意事项 恭王府 强制删除 k8s terminating 状态命名空间 PromQL 计算 CPU 使用率 PromQL 如何计算变化(率) Trickster 使用 奥森的向日葵 Go Modules - checksum mismatch 错误解决 CDN 使用初探 k8s 介绍 再探 798 解决 gin 路由冲突问题 wu.run 域名正式使用 GoLand 使用指南 macOS 软件推荐 2020 这一年 Python 循环列表删除元素的注意事项 Mac 下的定时任务工具:Launchctl Linux 服务器搭建 VNC 可视化桌面 Jenkins 个别 job 页面打开超时的解决方法 遇见 Aamir Khan Hexo 从 GitHub 到阿里云 『从未说出口的秘密』词云分析 768 的秋天 北戴河 Outing 飞盘记 三里屯夜景 爬虫图解:轮子哥关注了哪些人 2017-06-30 GitHub+Hexo 搭建个人网站详细教程 特朗普税改 如果有一天,苹果和微信只能选一个,你会选哪一个? About | 吴润写字的地方 Links | 吴润写字的地方 Memos | 吴润写字的地方
Golang 不可寻址的理解
2021-11-12 · via 吴润写字的地方
Table of Contents

如果没有听过 Golang 的不可寻址(not addressable)相关概念,没有关系,从字面上看,就是无法获取值的地址。先举个简单的例子:

package main

import "fmt"

func main() {
    m := map[int]string{0: "hello"}
    fmt.Printf("%p", &m[0])
}

mmap[int]string 类型,只包含一个键值对,打印这个键值对的值的地址,直接编译错误:cannot take the address of m[0],无法获取 map 中值的地址。这是个比较常见的不可寻址的例子。原因也比较简单,map 类型是通过哈希表实现的,随着 map 元素的增多,可能触发扩容,那么 map 的值的位置发生改变,即其地址会发生变化,所以无法对 map 的值寻址。另一方面,如果元素不存在于map 中,返回零值,而零值是不可变对象,是不能寻址的(golang 中不可变对象是不可寻址的,如常量)。

再看个稍微复杂的例子,在Golang wiki 的 MethodSets 有这样一句话:

The concrete value stored in an interface is not addressable, in the same way that a map element is not addressable.

意思具体值赋值给 interface 类型后与 map 中的元素一样是不可寻址的。先不去理解这句话,先看个例子:

package main

const NewName = "run.wu"

type Male struct {
	Name string
}

func (m Male) getName() string {
	return m.Name
}

func (m *Male) setName(name string) {
	m.Name = name
}

func main() {
	m1 := Male{}
	m1.getName()
	m1.setName(NewName)

	m2 := &Male{}
	m2.getName()
	m2.setName(NewName)
}

定义了一个 Male 类型,有两个方法,一个是值接收者的 getName() 方法,一个是指针接收者 setName() 方法。在 main() 中,m1Male 类型的值对象,m2Male 类型的指针对象,在这两个对象上都调用了 getName()setName() 方法,可以正常调用执行。那么问题来了:

  • m1 是值类型对象(调用者),为什么可以调用指针接收者方法 setName()
  • m2 是指针类型对象(调用者),什么可以调用值接收者方法 getName()?

对于第一个问题,值调用者调用指针接收者方法时, 编译器默认会使用调用者的引用(取地址)来调用方法,即编译器隐示转换 成 (&m1).setName() 对于第二个问题,指针调用者调用值接收者方法时,编译器默认会将指针调用者解引用(取值)为值类型,即编译器隐示转换成 (*m2).getName()

上面的例子还是比较好理解的,很多书和文章都有解释这个问题。

那再看另一个例子:

package main

const NewName = "run.wu"

type Person interface {
	getName() string
	setName(name string)
}

type Male struct {
	Name string
}

func (m Male) getName() string {
	return m.Name
}

func (m *Male) setName(name string) {
	m.Name = name
}

func main() {
	var p1 Person = Male{} // error
	p1.getName()
	p1.setName(NewName)

	var p2 Person = &Male{}
	p2.getName()
	p2.setName(NewName)
}

这个例子和刚刚的例子很类似,不同点的是,增加了一个 Person 类型的接口,定义了 Male 类型,实现了值接收者的 getName() 方法,实现了指针接收者的 setName() 方法。

初始化 Male 的值对象赋值给 Person 接口,记作 p1,直接报错:

cannot use Male literal (type Male) as type Person in assignment:
	Male does not implement Person (setName method has pointer receiver)

错误内容是,Male 类型的变量不能赋值给 Person,因为 Male 类型没有实现 Person 接口(setName 是指针接收者方法)。

那为什么之前的例子中,编译器可以自动将值类型(非接口类型)取地址做隐示转换,而这里就不可以了?原因就是开头那就话:

The concrete value stored in an interface is not addressable.

值类型赋值给接口,是不可寻址的,既然不可寻址,编译器也就没办法自动取其地址传给指针接收的方法了。