英文:
If the type of a parameter is interface{} how do you know whether you pass by pointer or by value?
问题
对于接受 interface{}
类型参数的任何函数,如何知道是否需要带上 &
来传递参数,而不需要查看函数的源代码呢?
例如,如果我有一个给出以下类型签名的函数:
func foo(x interface{}, y int) int
有没有办法确定 x 是按值传递还是按指针传递的呢?
英文:
Given any function that takes a parameter of type interface{}
how would I know whether or not to pass that parameter with or without &
without navigating the source code of the function.
For example if I had a function with this type signature given to me:
func foo(x interface{}, y int) int
Would there be any way to figure out if x was supposed to be passed by value or by pointer?
答案1
得分: 3
以下是源代码片段的翻译:
// DecodeElement的功能类似于Unmarshal,但它接受一个指向开始XML元素的指针来解码为v。
// 当客户端自己读取一些原始的XML标记,但也想将某些元素推迟到Unmarshal时,它非常有用。
func (d *Decoder) DecodeElement(v interface{}, start *StartElement) error {
val := reflect.ValueOf(v)
if val.Kind() != reflect.Ptr {
return errors.New("传递给Unmarshal的非指针")
}
return d.unmarshal(val.Elem(), start)
}
它检查了val.Kind() != reflect.Ptr
,这意味着你必须传递指针,即&v
。
这完全取决于编写该方法或函数的人,所以interface{}
可以是*ptr
或其他任何类型,但你必须在函数内部使用reflect.ValueOf(v).Kind()
检查该值是否为指针,并相应地进行处理。
指定零个方法的接口类型被称为空接口:
interface{}
空接口可以保存任何类型的值。(每种类型至少实现了零个方法。)
空接口被用于处理未知类型的值的代码。例如,fmt.Print接受任意数量的类型为interface{}
的参数。
另一个有用的讨论:文档
英文:
Here is the snippet from the source:
// DecodeElement works like Unmarshal except that it takes
// a pointer to the start XML element to decode into v.
// It is useful when a client reads some raw XML tokens itself
// but also wants to defer to Unmarshal for some elements.
func (d *Decoder) DecodeElement(v interface{}, start *StartElement) error {
val := reflect.ValueOf(v)
if val.Kind() != reflect.Ptr {
return errors.New("non-pointer passed to Unmarshal")
}
return d.unmarshal(val.Elem(), start)
}
It is checking val.Kind() != reflect.Ptr
Which means you have to pass the pointer i.e &v.
Its entirely depend on the person who wrote the method or function, so interface{}
could be either *ptr or anything but u ve to check that inside your function using reflect.ValueOf(v).Kind()
whether the value is a pointer or not and proceeds accordingly.
And little bit about empty interface:
The interface type that specifies zero methods is known as the empty interface:
interface{}
An empty interface may hold values of any type. (Every type implements at least zero methods.)
Empty interfaces are used by code that handles values of unknown type. For example, fmt.Print takes any number of arguments of type interface{}
.
Another useful discussion: docs
答案2
得分: 1
DecodeElement()
和相关函数有一个正式的v interface{}
参数,其类型在Unmarshal()
函数的文档中有详细说明:
> Unmarshal函数解析XML编码的数据,并将结果存储在指向v的值中,v必须是任意的结构体、切片或字符串。
所以,直接回答你的问题,如果你要传递的值是一个结构体本身,你需要间接传递,否则你不需要。
例如:
type Result struct {
XMLName xml.Name `xml:"Person"`
Name string `xml:"FullName"`
Phone string
Email []Email
Groups []string `xml:"Group>Value"`
Address
}
var (
a Result
b *Result
c string
)
xmlDecoder.DecodeElement(&a, startElement)
xmlDecoder.DecodeElement(&c, startElement)
但是
xmlDecoder.DecodeElement(b, startElement)
英文:
DecodeElement()
and friends have a formal v interface{}
whose type is documented in the Unmarshal()
function documentation:
> Unmarshal parses the XML-encoded data and stores the result in the
> value pointed to by v, which must be an arbitrary struct, slice, or
> string.
So to literally answer your question, no, you cannot know without reading the source - if the value you want to pass is a struct proper, you need to indirect. If it is already a pointer to that struct, you do not.
For example:
type Result struct {
XMLName xml.Name `xml:"Person"`
Name string `xml:"FullName"`
Phone string
Email []Email
Groups []string `xml:"Group>Value"`
Address
}
var (
a Result
b *Result
c string
)
xmlDecoder.DecodeElement(&a, startElement)
xmlDecoder.DecodeElement(&c, startElement)
but
xmlDecoder.DecodeElement(b, startElement)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论