Go每日一题(104) 的题目如下

4193 次点击 · 6 赞 ·大约8小时之前 开始浏览   · 来源「Golang来啦」

下面这段代码输出结果正确吗?

type Foo struct {
	bar string
}
func main() {
	s1 := []Foo{
		{"A"},
		{"B"},
		{"C"},
	}
	s2 := make([]*Foo, len(s1))
	for i, value := range s1 {
		s2[i] = &value
	}
	fmt.Println(s1[0], s1[1], s1[2])
	fmt.Println(s2[0], s2[1], s2[2])
}
输出:
{A} {B} {C}
&{A} &{B} &{C}
4193 阅读
43 回复
henry1
henry1 · #1 · 3年之前

1

neil_liu
neil_liu · #2 · 3年之前

mark

Inforleo
Inforleo · #3 · 3年之前

m

Dessert
Dessert · #4 · 3年之前

重用就是同个变量重新使用,重新声明就是声明不同的变量吧

Skysolderone
Skysolderone · #5 · 3年之前

加深理解了

minQie
minQie · #6 · 3年之前

di

dingweihua
dingweihua · #7 · 3年之前

mark

cy422396350
cy422396350 · #8 · 3年之前

加深理解了+1

yayaleslie
yayaleslie · #9 · 3年之前

mark

Natsuwau
Natsuwau · #10 · 3年之前

mark

hypersus
hypersus · #11 · 3年之前

踩坑,打卡

NovaChaos
NovaChaos · #12 · 3年之前

mk

Zuos
Zuos · #13 · 3年之前

mark

cuiqiang988
cuiqiang988 · #14 · 3年之前

重新声明会开辟新的内存空间,重用的话还是同一块地址,所以已经存到s2的前两个元素会变成最新的v值

feiyang
feiyang · #15 · 3年之前

mark

mingtop
mingtop · #16 · 3年之前

for range 用法

zyicy
zyicy · #17 · 3年之前

马克

bsdx866
bsdx866 · #18 · 2年之前

image.png

feiyang
feiyang · #19 · 2年之前

for range 使用短变量声明(:=)的形式迭代变量时,变量 i、value 在每次循环体中都会被重用,而不是重新声明。

jfxyl
jfxyl · #20 · 2年之前

在哪可以看到历史的每日一题呢

cainiaoyige01
cainiaoyige01 · #21 · 2年之前

value再每次range都会被重用,不是重新开辟一块空间的!故以后最后一次赋值的为基准!

528548004
528548004 · #22 · 2年之前

mark

YuPeng
YuPeng · #23 · 2年之前

mark

hasbug
hasbug · #24 · 2年之前

mark

brothersam
brothersam · #25 · 2年之前

{A} {B} {C} &{C} &{C} &{C} for range 遍历出来的 临时变量 如果是指针,就会出现这种情况。

huangyf168
huangyf168 · #26 · 2年之前

mark

1174en
1174en · #27 · 2年之前

m

cllgeek
cllgeek · #28 · 2年之前

是的

euibieur894
euibieur894 · #29 · 2年之前

打卡

1174en
1174en · #30 · 大约1年之前

m

528548004
528548004 · #31 · 大约1年之前

mark

gyj123
gyj123 · #32 · 大约1年之前

还有一种解决办法,就是有点多余了

for i, value := range s1 {
    value := value
    s2[i] = &value
}
sone
sone · #33 · 大约1年之前

range的如果本身就是一个指针切片,如举例的s1变为[]*Foo,会直接用原来的内存地址,会直接把原来的三个地址全部对应赋值过去,相当于进行一次copy操作。这时候对s2[0].bar的值再进行改动就会影响到原值了。

zhangwei_go
zhangwei_go · #34 · 大约1年之前

value是一个变量, 使用value的指针,所以s2都会是c

YuPeng
YuPeng · #35 · 大约1年之前

go 1.22 发布之后 答案需要更新一下了, 因为go1.22 for循环语义发生了变化 具体的 1.22之前 输出

{A} {B} {C}
&{C} &{C} &{C}

1.22 输出

{A} {B} {C}
&{A} &{B} &{C}

见 : https://go.dev/play/p/1EtkTIWWOfC

BigBigGopher
BigBigGopher · #36 · 大约1年之前

mark

Qmfuser
Qmfuser · #37 · 大约1年之前

mark

1174en
1174en · #38 · 大约1年之前

m

rabbit-rm
rabbit-rm · #39 · 大约1年之前

go 1.22 之前 for range 使用短变量声明(:=)的形式迭代变量时,变量 i、value 在每次循环体中都会被重用,而不是重新声明。对value进行取址操作,拿到的都是同一个变量地址 go 1.22 语义发生变化,value都是重新声明的 详见:https://go.dev/play/p/u_hGBXO5KDm

amocea
amocea · #40 · 大约1年之前

注意在 go1.22 for range 循环已经不是地址复用了,而是重新创建。

BigBigGopher
BigBigGopher · #41 · 9月之前

mark

zhangwei_go
zhangwei_go · #42 · 5月之前

参考答案及解析:s2 的输出结果错误。

s2 的输出是 &{C} &{C} &{C},在前面题目我们提到过,for range 使用短变量声明(:=)的形式迭代变量时,变量 i、value 在每次循环体中都会被重用,而不是重新声明。所以 s2 每次填充的都是临时变量 value 的地址,而在最后一次循环中,value 被赋值为{c}。因此,s2 输出的时候显示出了三个 &{c}。

Dessert
Dessert · #43 · 大约1个月之前

高版本如1.22已修复该问题

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传