确保参数必须是指针(或接口,内部是指针)

huangapple go评论86阅读模式
英文:

Ensuring a parameter must be pointer (or interface, which internally a pointer)

问题

有时我们会创建一个类似于C#中的out参数的函数,就像json.Unmarshal或任何其他类型的解组函数一样。

在Go中,我们如何在编译时(而不是运行时)确保传递的变量是指针或接口?

在运行时,我可以这样做:

func mustStructPtr(f interface{}) {
	v := reflect.ValueOf(f)
	if v.Kind() != reflect.Ptr {
		panic(fmt.Errorf("not a pointer: %T", f))
	}
	v = v.Elem() // 解引用指针
	if v.Kind() != reflect.Struct { // TODO: 非空映射或切片也可以
		panic(fmt.Errorf("not struct; is %T", f))
	}
}

如何在Golang中在编译时强制执行此操作?所以像这样的代码是允许的:

var myStruct MyStruct
myFunc(&myStruct) // 可以,因为是指针
myFunc(myStruct) // <-- 不可以,因为不能接收非指针
var x interface{} = &mystruct
myFunc(x) // 可以,因为接口转为指针
x = myStruct
myFunc(x) // <-- 不可以,因为接口转为非指针

var y map[string]interface{}
myFunc(y) // 可以,因为映射内部是指针

var z = []myStruct{}
myFunc(&z) // 可以,因为是指针
英文:

Sometimes we make a function that like C#'s out in the parameter, just like json.Unmarshal or any kind of unmarshal function.

How in Go compile time (instead of runtime) we can make sure that the variable that being passed is a pointer or an interface?

In runtime I can do something like this:

func mustStructPtr(f interface{}) {
	v := reflect.ValueOf(f)
	if v.Kind() != reflect.Ptr {
		panic(fmt.Errorf(&quot;not a pointer: %T&quot;, f))
	}
	v = v.Elem() // dereference the pointer
	if v.Kind() != reflect.Struct { // TODO: non null map or slice also ok
		panic(fmt.Errorf(&quot;not struct; is %T&quot;, f))
	}
}

How to enfoce this on compile time in Golang? so something like this are allowed

var myStruct MyStruct
myFunc(&amp;myStruct) // ok, because pointer
myFunc(myStruct) // &lt;-- not ok, because this cannot receive
var x interface{} = &amp;mystruct
myFunc(x) // ok, because interface to pointer 
x = myStruct
myFunc(x) // &lt;-- not ok, because interface to non pointer

var y map[string]interface{}
myFunc(y) // ok, because map internally a pointer

var z = []myStruct{}
myFunc(&amp;z) // ok, because a pointer

答案1

得分: 1

你无法真正确保这一点。如果你真的想要一个指针,我猜你可以使你的函数通用,并接受*T,但是你仍然不知道T是一个结构体,而且它不能与接口一起使用。

你可以使用代码检查工具(至少对于json.Unmarshal)和单元测试来捕捉这个问题。

英文:

You can't really ensure that. If you really want a pointer I guess you could make your function generic and have it accept *T, but then you still don't know that T is a struct and it won't work with an interface.

You can catch this with linters (at least for json.Unmarshal) and otherwise, unit testing.

答案2

得分: 0

在你的情况下,增加类型安全性的一种方法是声明一个新类型并在创建时强制进行检查。

type PointerOrInterface struct {
    val interface{}
}

func NewPointerOrInterface(val interface{}) PointerOrInterface {
    // 检查
    return PointerOrInterface{
        val: val,
    }
}

这段代码中,我们声明了一个名为PointerOrInterface的新类型,并在创建时进行了检查。通过这种方式,我们可以增加类型安全性,确保只有符合特定要求的值才能被赋给PointerOrInterface类型的变量。

英文:

One of the approaches to increase type safety in your case would be to declare a new type and enforce the check on creation.

type PointerOrInterface struct {
	val interface{}
}

func NewPointerOrInterface(val interface{}) PointerOrInterface {
	// check
	return PointerOrInterface{
		val: val,
	}
}

huangapple
  • 本文由 发表于 2022年7月8日 14:40:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/72907571.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定