向结构添加“静态”功能

encoding/base64 and encoding/hex both support nearly the same set of functions, but base64 uses a class-based encoder, whereas hex exports the methods at the top level. Is there a simple way to create a wrapper around hex so that you can work with an abstracted encoding interface? More generally, is there a way to do the equivalent of binding a method to a struct? (e.g., SomeStruct.Encode = hex.Encode)

So far, I had to define functions on a hexEncoder struct with the same signature as the hex functions. I created an interface like this:

type Encoding interface {
    Decode(dst, src []byte) (n int, err error)
    DecodedLen(n int) int
    Encode(dst, src []byte) // base64 returns nothing, hex returns int
    EncodedLen(n int) int
}

which works perfectly with base64.StdEncoding, but I wasn't clear on how to wrap the hex methods. I created an empty struct for hex:

// wrap hex encoding/decoding so that it can be used interchangeably with base64 encoding
type hexEncoder struct {}

func (h hexEncoder) Decode(dst, src []byte) (n int, err error) {
    return hex.Decode(dst, src)
}
func (h hexEncoder) DecodedLen(n int) int {
    return hex.DecodedLen(n)
}
func (h hexEncoder) Encode(dst, src []byte) {
    hex.Encode(dst, src) // don't return the int to match Encoding
}
func (h hexEncoder) EncodedLen(n int) int {
    return hex.EncodedLen(n)
}

This works, but it's a bunch of extra boiler plate (where all that really needs to be wrapped is hex.Encode). Is there a better way to do this? Ultimately, the goal is to be able to use hex and base64 interchangeably with encoding/decoding, like in something like this:

func convert(src []byte, decoder Encoding, encoder Encoding) ([]byte, error) {
    temp := make([]byte, decoder.DecodedLen(len(src)))
    n, err := decoder.Decode(temp, src)
    if err != nil {
        return temp, err
    }
    dst := make([]byte, encoder.EncodedLen(len(src)))
    encoder.Encode(dst, temp[:n])
    return dst, nil
}

No, there is no better way to implement an interface that dispatches to functions in another package, and to be honest I cannot really imagine how a better way would look like.

What you're saying in that wrapper is:

type myType struct{}

func (myType) WhenCalledLikeThis() { DoThat() }

Which seems optimal. It doesn't need any backing memory, allows slight changes in naming and return values (as you've done for Encode), and dispatches with a single call.