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

时间:2019-05-08 15:53:32

标签: go

我有几种交易结构:

SpendTx
NameTransferTx
NameUpdateTx
...

我想估计这些结构的大小,但不包括“费用”字段。它们都有一个Fee struct字段。目前,对于每种结构,我都有此方法:

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
}

这是很多重复的代码,都是因为我不能写这样的东西:

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
}

当然,我可以编写一个getFee()之类的getter函数,并从中创建一个接口,但这并没有什么好。还是别人怎么做?

2 个答案:

答案 0 :(得分:0)

你不知道。如果您不关心特定的类型(即可以使用接口),那么您就不必关心数据,仅关心行为(这就是为什么接口仅指定方法的原因)。如果您关心数据,那么您就已经深陷该类型的内部,并且应该使用特定的具体类型(或者使用类型断言/类型开关来获取它)。这不是Go特定的;大多数语言不允许在接口中指定字段。

吸气剂不是最坏的事情。您还可以将需要直接访问的字段封装为它们自己的struct类型,并为此使用一个getter方法(如果要与多个相关字段一起使用)。最后,您可以重新设计整体设计以消除或转移需求。这里没有足够的上下文来提出很难的建议,但总的来说,似乎您可能有一些东西可以将这些事务写到某个地方,而这正是您所关心的事情的大小。由于似乎您还在尝试获取消息的最终长度的方法中正在执行所有相关的处理以生成消息,因此您是否不能仅将消息生成为[]byte并取其长度,然后在执行操作时使用相同的输出...无论您在做什么这些操作?

答案 1 :(得分:0)

估算Tx的大小需要Tx.RLP()(由Tx接口保证)和Tx.Fee字段(一直存在,但无法被编译器证明)。

所有交易类型的大小估计均相同。因此,我找到了一个令人满意的解决方案,使尺寸估算本身成为一个函数,我只是将交易的Fee用作该函数的参数:

// 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)
}
...