您好,匿名用户
随意问技术百科期待您的加入

Go语言中slice成员地址的问题

0 投票

自己写了下《GO语言编程》第三章音乐库的例子,发现一个问题,MusicManager的Remove方法是删除某首歌,并且返回删除的那首歌,但是在删除前后removedMusic指针指向的元素确发生了改变,感觉removedMusic是&m.musics[index]的一个别名,slice的改变会影响到它,google了很多资料,但是好像也没有完全说清楚,希望大牛解释一下缘由

package main

import "fmt"

type MusicEntry struct {
Id string
Name string
}

type MusicManager struct {
musics []MusicEntry
}

func (m *MusicManager) Add(music MusicEntry) {
m.musics = append(m.musics, music)
}

func (m *MusicManager) Len() int {
return len(m.musics)
}

func (m *MusicManager) Remove(index int) *MusicEntry {
if index < 0 || index >= m.Len() {
return nil
}

removedMusic := &m.musics[index]
fmt.Println("removedMusic.Id:", removedMusic.Id)

if index == 0 {
m.musics = m.musics[1:]
} else if index == m.Len()-1 {
m.musics = m.musics[0 : index-1]
} else {
m.musics = append(m.musics[0:index], m.musics[index+1:]...)
}

''fmt.Println("removedMusic.Id:", removedMusic.Id)''

return removedMusic
}

func main() {
fmt.Println("Hello, player")

mm := &MusicManager{make([]MusicEntry, 0, 100)}
m0 := MusicEntry{"1", "My Heart will go on"}
m1 := MusicEntry{"2", "In your arms"}
m2 := MusicEntry{"3", "Someone like you"}

mm.Add(m0)
mm.Add(m1)
mm.Add(m2)

fmt.Println("The lib has", mm.Len(), "songs")

m := mm.Remove(1)

if m.Id != m1.Id {
fmt.Println("Mismatched")
}
}

执行结果:

Hello, player
The lib has 3 songs
removedMusic.Id: 2
removedMusic.Id: 3
Mismatched
用户头像 提问 2012年 12月1日 @ Varus 上等兵 (281 威望)
分享到:

1个回答

0 投票
 
最佳答案

谢谢邀请!

你提到的这个问题是Remove函数包含的一个缺陷导致的。主要原因是这一个赋值语句:removedMusic := &m.musics[index] 只取得了该元素的地址,而在之后的数组重整操作中该元素地址会被后跟的一个元素前移覆盖,从而导致打印的是后一个元素的Id。

修正方法很简单,就是将上面提到的语句修改为removedMusic := m.musics[index]。当然,相应的最后一个返回语句需要做一个取地址操作。

完整代码如下:

func (m *MusicManager) Remove(index int) *MusicEntry {
	if index < 0 || index >= m.Len() {
		return nil
	}

	removedMusic := m.musics[index]
	fmt.Println("removedMusic.Id:", removedMusic.Id)

	if index == 0 {
		m.musics = m.musics[1:]
	} else if index == m.Len()-1 {
		m.musics = m.musics[0 : index-1]
	} else {
		m.musics = append(m.musics[0:index], m.musics[index+1:]...)
	}

	fmt.Println("removedMusic.Id:", removedMusic.Id)

	return &removedMusic
}
用户头像 回复 2012年 12月1日 @ 阿尔托莉雅 下士 (587 威望)
选中 2012年 12月1日 @Varus
提一个问题:

相关问题

0 投票
1 回复 29 阅读
0 投票
1 回复 38 阅读
用户头像 提问 2012年 12月1日 @ Sion 上等兵 (319 威望)
0 投票
1 回复 31 阅读
用户头像 提问 2012年 12月1日 @ Sejuani 上等兵 (427 威望)
0 投票
1 回复 66 阅读
用户头像 提问 2012年 12月1日 @ Talon 上等兵 (294 威望)
0 投票
1 回复 191 阅读
用户头像 提问 2012年 12月1日 @ Athena 上等兵 (346 威望)

欢迎来到随意问技术百科, 这是一个面向专业开发者的IT问答网站,提供途径助开发者查找IT技术方案,解决程序bug和网站运维难题等。
温馨提示:本网站禁止用户发布与IT技术无关的、粗浅的、毫无意义的或者违法国家法规的等不合理内容,谢谢支持。

欢迎访问随意问技术百科,为了给您提供更好的服务,请及时反馈您的意见。
...