如何在Golang中装饰具有不同签名的功能?

I tried to apply decorators from this famous Golang decorators talk but it only works for him because all the functions he's decorating are attached to a struct, and he's just decorating one Do() function. Every other tutorial I've seen also does it this way, which is quite annoying.

I want to decorate these functions with a base58/64 encoder function

func SpendTx(senderID, recipientID string, amount, fee utils.BigInt, payload string, ttl, nonce uint64) (rlpRawMsg []byte, err error)
func NamePreclaimTx(accountID, commitmentID string, fee uint64, ttl, nonce uint64) (rlpRawMsg []byte, err error)
func NameClaimTx(accountID, name string, nameSalt, fee uint64, ttl, nonce uint64) (rlpRawMsg []byte, err error)
...

As you can see, the arguments are all different, and they are also pure functions, not attached to a struct. But they all return []byte and an error, so this should be possible.

Disclaimer the only decoration I've done is through embedding structs, but one way could be to define a type for the function you'd like to decorate (not strictly necessary but will make signatures simpler):

type SpendTXFn = func SpendTx(senderID, recipientID string, amount, fee utils.BigInt, payload string, ttl, nonce uint64) (rlpRawMsg []byte, err error)

Now functions can talk in terms of this type, a decorator function would contain the same call signature as this type

func EncodedSpendTX(s SpendTX) SpendTX {
     return func(senderID, recipientID string, amount, fee utils.BigInt, payload string, ttl, nonce uint64) (rlpRawMsg []byte, err error) {
        // compute decorated result 
        res, err := s(senderID, recipientID, amount, fee, payload, ttl, nonce)
        if err != nil {
          return res, err
        } 
        // encode the res
        // return encoded res
     }
}

Now you can decorate your SpendTX function:

decorated := EncodedSpendTX(originalSpendTx)

decorated(...) -> []byte, err

Downsides of this is there is a decorator per function type. Upsides are many with my favorite being that the encoding is easy to test and separate from the original logic, so it doesn't require any mutation to your original function.


Actually I think this is the approach that go's http middleware takes through http.Handler

https://www.alexedwards.net/blog/making-and-using-middleware