突变Golang中的字符串?

时间:2019-10-09 15:15:47

标签: string pointers go mutate

出于测试目的,我试图从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方法设法对字符串进行了突变。

1 个答案:

答案 0 :(得分:5)

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)
}

请注意,如果我们在通话前后在主屏幕上打印&s1,它仍然不会更改。它仍然是相同的变量,仍位于相同的地址。我们在&s1中传递了一个指针MockScan,以便MockScan可以使用该指针将一个值写入s1