避免在包的API中暴露反射功能。

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

avoid exposing reflection in the package API

问题

在Alan Donovan和Brian Kernighan的《Go编程语言》书的第333页(第12.3节“显示,递归值打印器”)中提到:

在可能的情况下,应避免在包的API中暴露反射。我们将定义一个未导出的函数display来执行递归的实际工作,并导出Display,它是对其的简单包装,接受一个interface{}参数。

func Display(name string, x interface{}) {
    fmt.Printf("Display %s (%T):\n", name, x)
    display(name, reflection.ValueOf(x))
}

display函数根据输入反射值的Kind打印不同的内容。

我有两个问题:

  1. 为什么最好不在包的API中暴露反射?
  2. 为什么使用未导出的display函数被认为不会在API中暴露反射?难道我们不是在Display中调用reflection.ValueOf()吗?

我猜我不知道“在包的API中暴露反射”的定义。它只指函数参数还是同时指参数和内容?如果是前者,那似乎没有必要定义display,因为Display的签名是x interface{}。如果是后者,为什么这样做更好?

英文:

In Alan Donovan and Brian Kernighan's "The Go programming language" book p333 (section 12.3 Display, a recursive value printer), it is mentioned that

> Where possible, you should avoid exposing reflection in the API of a package. We'll define an unexported function display to do the real work of the recursion, and export Display, a simple wrapper around it that accepts an interface{} parameter.

func Display(name string, x interface{}) {
    fmt.Printf("Display %s (%T):\n", name, x)
    display(name, reflection.ValueOf(x))

And the display function prints different contents depending on the Kind of the input reflection value.

I have two questions

  1. Why is it better to not expose the reflection in the package API?
  2. Why is using an unexposed display function considered as not exposing reflection in the API? Don't we still call reflection.ValueOf() in Display?

I guess I don't know the definition of "exposing reflection in the package API". Does it just refer to the function arguments or both arguments and content? If it's the former case, then there seems no need to define display since the signature of Display is x interface{}. If it's the latter case, why is it better?

答案1

得分: 0

在书中的例子中

在书中的例子中,使用反射是一个实现细节。你应该总是尽量隐藏实现细节,这样你可以在任何时候更改实现,而不会破坏包的“公共”API。如果你将某些东西导出/添加到包的API中,那么你就必须一直携带它(假设你不想进行不兼容的API更改,这通常是很糟糕的)。

一般情况下

interface{}什么都不说” - Rob Pike。鉴于此,reflect.Value说的更少。除非你有一个很好的理由(除了reflect包本身之外,我想不出其他的理由),你不应该创建期望reflect.Value作为参数的公共函数。

即使你有一个“通用”函数必须接受任何类型的值,interface{}也是首选,因为这样至少客户端可以直接传递它们所拥有的值,而不需要将它们包装在reflect.Value中。

英文:

In the book's example

In the book's example, it is because the usage of reflection is an implementation detail. You should always try to hide the implementation details, so you may change the implementation at any time without breaking the "public" API of the package. If you export / add something to the API of your package, you have to carry that for the rest of your life (given you don't want to make backward-incompatible API changes, which is really bad in general).

In general

"interface{} says nothing" – Rob Pike. Given that, reflect.Value says even less. Unless you have a good reason (can't think of any outside of the reflect package itself), you shouldn't create public functions that expect reflect.Value as their arguments.

Even if you have a "general" function that must take a value of any type, interface{} is preferred as then at least the clients can pass what they have as-is, without having to wrap them in reflect.Value.

huangapple
  • 本文由 发表于 2016年12月5日 10:33:28
  • 转载请务必保留本文链接:https://go.coder-hub.com/40966289.html
匿名

发表评论

匿名网友

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

确定