pointers - 如何在不指定类型的情况下修改函数输入参数?

标签 pointers go reflection interface

我正在尝试制作一个接受2个参数的函数,并将第二个参数的值设置为第一个参数,它可能看起来像(我不确定):

func set(a interface{}, b interface{}) {
  // do something to make a = b
}
它是这样的:
a := 0
b := 10
set(&a, b)
// here a should be 10

s1 := ""
s2 := "what"
set(&s1, s2)
// here s1 should be "what"
它应该适用于所有基本类型,例如int,float,string,bool等。
我该如何实现?

最佳答案

使用反射可以做到这一点:

func set(a interface{}, b interface{}) {
    reflect.ValueOf(a).Elem().Set(reflect.ValueOf(b))
}
注意,此代码不检查a是否为指针,并且其元素类型与b中的值的类型匹配。另请注意,使用反射速度较慢,并且会失去编译时类型的安全性。上面的代码比将单个int值分配给int变量或将string值分配给string变量要慢得多。
测试它:
a := 0
b := 10
set(&a, b)
fmt.Println(a)

s1 := ""
s2 := "what"
set(&s1, s2)
fmt.Println(s1)
输出(在Go Playground上尝试):
10
what
这是一个添加检查以避免运行时出现紧急情况的版本:
func set(a interface{}, b interface{}) error {
    v1 := reflect.ValueOf(a)
    if v1.Kind() != reflect.Ptr {
        return errors.New("a must be pointer")
    }
    if v1.IsZero() {
        return errors.New("a must not be a nil pointer")
    }

    v1 = v1.Elem()
    v2 := reflect.ValueOf(b)
    if v1.Type() != v2.Type() {
        return errors.New("a's element type must match b's type")
    }

    if !v1.CanSet() {
        return errors.New("unsettable value in a")
    }

    v1.Set(v2)
    return nil
}
测试它:
a := 0
b := 10
err := set(a, b)
fmt.Printf("set(a, b): a=%v, err: %v\n", a, err)
err = set(&a, b)
fmt.Printf("set(&a, b): a=%v, err: %v\n", a, err)
err = set((*int)(nil), b)
fmt.Printf("set((*int)(nil), b): a=%v, err: %v\n", a, err)

s1 := ""
s2 := "what"
err = set(&s1, s2)
fmt.Printf("set(&s1, s2): s1=%v, err: %v\n", s1, err)
err = set(&s1, b)
fmt.Printf("set(&s1, s2): s1=%v, err: %v\n", s1, err)
输出(在Go Playground上尝试):
set(a, b): a=0, err: a must be pointer
set(&a, b): a=10, err: <nil>
set((*int)(nil), b): a=10, err: a must not be a nil pointer
set(&s1, s2): s1=what, err: <nil>
set(&s1, s2): s1=what, err: a's element type must match b's type

关于pointers - 如何在不指定类型的情况下修改函数输入参数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62909981/

相关文章:

c - *p[5] 和 (*p)[5] 有什么区别?

c++ - 使用此关键字在结构中引用类时出现问题

go - 指针接收器困惑

golang,我可以使用 rsa key 创建 X509KeyPair 吗?

c# - 如何使用 lambda 获取作为参数发送的属性名称

c - 返回一个动态分配的数组? (C)

c - 在 C 中初始化指针最干净的方法是什么?

session - 如何使用 String 扩展 session.Value

java - 使用 NativeMethodAccessor 而不是 GeneratedMethodAccessor 时缺少 Lambda 堆栈跟踪

java - 验证是否调用了所有 getter 方法