如何保证像接口那样的结构字段存在于方法中?

I have several transaction structs:

SpendTx
NameTransferTx
NameUpdateTx
...

I'd like to estimate the size of these structs, excluding the Fee field. They all have a Fee struct field. Currently, for each struct I have this method:

func (tx *NameTransferTx) sizeEstimate() (int, error) {
    feeRlp, err := rlp.EncodeToBytes(tx.Fee)
    if err != nil {
        return 0, err
    }
    feeRlpLen := len(feeRlp)

    rlpRawMsg, err := tx.RLP()
    if err != nil {
        return 0, err
    }

    return len(rlpRawMsg) - feeRlpLen + 8, nil
}

That's a lot of duplicated code, all because I cannot write something like this:

type Tx interface {
    RLP() ([]byte, error)
    Fee utils.BigInt // Golang won't allow this
}
func estimateSizeOfTx(tx Tx) (int, error) {
    feeRlp, err := rlp.EncodeToBytes(tx.Fee)
    if err != nil {
        return 0, err
    }
    feeRlpLen := len(feeRlp)

    rlpRawMsg, err := tx.RLP()
    if err != nil {
        return 0, err
    }

    return len(rlpRawMsg) - feeRlpLen + 8, nil
}

Of course I could write a getter function like getFee() and make an interface out of that, but that's not any better. Or is that how other people do it?

You don't. If you don't care about the specific type (i.e., you can use an interface), then you don't care about the data, only the behavior (which is why interfaces only specify methods). If you care about the data, then you're already knee-deep in the type's internals, and you should be using the specific concrete type (or using a type assertion/type switch to get at it). This is not Go-specific; most languages do not permit specifying fields in interfaces.

A getter wouldn't be the worst thing. You could also encapsulate the fields you need direct access to into their own struct type, and have a getter for that (if there are multiple related fields you want to work with together). Lastly, you could rework the overall design to eliminate or migrate the need. There's not enough context to make a hard suggestion here, but to take a total guess, it seems like you likely have something that writes these transactions to somewhere, and it's the size of what's to be written you're concerned with. Since it also appears that you're doing all the associated processing for producing the message in the method where you're trying to get its final length, couldn't you just produce the message as a []byte, take its length, and then use that same output when you do... whatever it is you're doing with these?

Estimating the size of the Tx requires the Tx.RLP() (guaranteed by the Tx interface) and the Tx.Fee field (which is there all the time but can't be proven to the compiler).

Size estimation is the same for all transaction types. So I found a satisfactory solution making the size estimation a function on its own, and I just provide the transaction's Fee as an argument to the function:

// sizeEstimate returns the size of the transaction when RLP serialized, assuming the Fee has a length of 8 bytes.
func calcSizeEstimate(tx Tx, fee *utils.BigInt) (int, error) {
    feeRlp, err := rlp.EncodeToBytes(fee)
    if err != nil {
        return 0, err
    }
    feeRlpLen := len(feeRlp)

    rlpRawMsg, err := tx.RLP()
    if err != nil {
        return 0, err
    }

    return len(rlpRawMsg) - feeRlpLen + 8, nil
}

...
func (tx *SpendTx) sizeEstimate() (int, error) {
    return calcSizeEstimate(tx, &tx.Fee)
}
...
func (tx *NamePreclaimTx) sizeEstimate() (int, error) {
    return calcSizeEstimate(tx, &tx.Fee)
}
...
func (tx *NameClaimTx) sizeEstimate() (int, error) {
    return calcSizeEstimate(tx, &tx.Fee)
}
...