【问题标题】:Mutate a string in Golang?在Golang中改变一个字符串?
【发布时间】:2020-02-06 23:27:28
【问题描述】:

出于测试目的,我试图模拟来自database/sql 库的Rows.Scan 方法。签名如下所示:

func (r *Rows) Scan(dest ...interface{}) error

许多关于如何使用它的示例表明,您将一个指向字符串的指针(例如)传递给 Scan 方法,它将通过指针分配值。

var name string
rows.Scan(&name)

我一直在尝试重新创建类似的东西以供我自己理解并最终用于模拟,但它不起作用。

func MockScan(args ...interface{}) {
    var s2 string
    fmt.Println(args[0])
    args[0] = &s2
    fmt.Println(args[0])
}

func main() {
    var s1 string
    fmt.Println(&s1)
    MockScan(&s1)
    fmt.Println(&s1)
}

结果:

0xc000012950
0xc000012950
0xc000012960
0xc000012950

我的初始字符串永远不会采用它的新值。我知道字符串是不可变的(尽管我对这个概念的真正理解有点不稳定)但不知何故,实际的 Rows.Scan 方法设法改变了字符串。

【问题讨论】:

标签: string pointers go


【解决方案1】:

args[0] = &s2

这在MockScan 之外没有任何作用。你正在改变args[0] 指向的东西,你并没有改变args[0] 指向的东西

你想做类似的事情

func MockScan(args ...interface{}) {
    // In real life, there would be some logic here to figure out what
    // kind of pointer we're dealing with, or some error handling to
    // handle the case where the user didn't pass a *string
    dst := args[0].(*string)
    *dst = "A new value"
}

func main() {
    var s1 string = "An old value"
    fmt.Println(s1)
    MockScan(&s1)
    fmt.Println(s1)
}

请注意,如果我们在调用之前和之后在 main 中打印 &s1,它仍然不会改变。它仍然是同一个变量,它仍然在同一个地址。我们已将指针&s1 传递给MockScan,以便MockScan 可以使用该指针将值写入s1

【讨论】:

  • 这里值得一提的是,Type Assertion 用于确保我们以字符串指针的形式访问 args[0]。
  • Natski,请参阅 this 了解更多背景信息——这是掌握的关键。
  • 感谢您的回复和回答。我正在关注这篇博客文章,它做同样的事情但使用结构(它似乎工作):goinbigdata.com/golang-pass-by-pointer-vs-pass-by-value。我是否正确假设结构和字符串在我的示例和博客文章之间的行为不同?
  • @natsuki_2002 关于链接的帖子,如果你这样做 p = &Person{firstName: "Bob"} 你会得到与字符串指针相同的结果,所以在这方面结构和字符串之间没有区别。但是 selector 表达式 s.f 有所不同,这里 s 可以是指向结构的指针,并且该语言仍然允许您访问字段 f 而无需先取消引用指针,例如你不必做(*s).f,这是自动完成的。 more here
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-05-28
  • 1970-01-01
  • 2016-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多