避免在包API中公开反射

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):
", 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?

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.