You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang中如何模拟database/sql的Rows.Scan实现字符串赋值?

为什么你的MockScan无法修改外部字符串变量?

这是一个典型的Go语言值传递特性导致的误解问题,咱们一步步拆解清楚:

首先看你的代码核心问题:当你调用MockScan(&s1)时,args[0]是&s1的副本——Go里所有参数都是值传递,哪怕是指针也不例外。你在函数里做args[0] = &s2,只是把这个指针副本改成了指向s2,但完全没碰原来的&s1指向的内存区域,所以外部的s1自然不会有任何变化。

而database/sql的Rows.Scan之所以能修改外部变量,核心逻辑是它不会修改指针参数本身,而是通过指针间接修改其指向的内存。举个例子,对于传入的字符串指针,它会把数据库查询到的字符串值,写入到这个指针指向的地址里(也就是外部变量的内存位置),而不是替换掉指针。

修正后的MockScan实现

我们来写一个能正确模拟Scan行为的版本:

package main

import (
	"fmt"
	"log"
)

func MockScan(args ...interface{}) error {
	// 模拟从数据库获取的测试值
	mockStr := "模拟的数据库字符串"
	for idx, dest := range args {
		// 类型断言判断传入的是不是字符串指针
		strPtr, ok := dest.(*string)
		if !ok {
			return fmt.Errorf("索引%d处的参数不是*string类型", idx)
		}
		// 解引用指针,修改它指向的内存区域(也就是外部的s1变量)
		*strPtr = mockStr
	}
	return nil
}

func main() {
	var s1 string
	fmt.Println("Scan前的s1值:", s1)
	if err := MockScan(&s1); err != nil {
		log.Fatal(err)
	}
	fmt.Println("Scan后的s1值:", s1)
}

运行这个代码,你会看到s1成功被修改成了模拟的字符串值。

再深入理解值传递

回到你原来的运行结果:

0xc000012950  // main里的&s1地址
0xc000012950  // MockScan里args[0]的初始值(&s1的副本,地址相同)
0xc000012960  // args[0]被赋值为&s2后的地址(指向s2的内存)
0xc000012950  // main里的&s1还是原来的地址,完全没被修改

这里的关键是:args[0]是指针的副本,修改它本身不会影响外部的&s1。只有当你解引用这个副本(*args[0]),修改它指向的内容,才能让外部变量s1发生变化——因为这个副本和原来的&s1指向的是同一块内存(也就是s1的存储位置)。

总结核心要点

  • Go语言中所有参数都是值传递,包括指针类型,传递的是指针的副本
  • Rows.Scan的核心是通过指针的副本,间接修改外部变量的内存,而不是修改指针本身
  • 你的MockScan错误地修改了指针副本的指向,而不是通过指针修改目标变量的内容

内容的提问来源于stack exchange,提问作者natsuki_2002

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:46:24