【问题标题】:How to guarantee the presence of a struct field like interfaces do for methods?如何保证结构字段的存在,如接口为方法所做的?
【发布时间】:2019-05-09 08:15:02
【问题描述】:

我有几个事务结构:

SpendTx
NameTransferTx
NameUpdateTx
...

我想估计这些结构的大小,不包括费用字段。他们都有一个费用结构字段。目前,对于每个结构,我都有这个方法:

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 函数并用它制作一个接口,但这并没有更好。还是其他人是这样的?

【问题讨论】:

  • 如何编写一个带有公共字段的结构体,例如 priceTx,然后将其嵌入到其他结构体中?
  • 这可能很有趣 - 不过尝试这种方法需要几个小时。

标签: go


【解决方案1】:

你没有。如果您不关心特定类型(即,您可以使用接口),那么您不关心数据,只关心行为(这就是接口只指定方法的原因)。如果您关心数据,那么您已经深入了解类型的内部结构,您应该使用特定的具体类型(或使用类型断言/类型开关来获取它)。这不是 Go 特定的;大多数语言不允许在接口中指定字段。

吸气剂不会是最糟糕的事情。您还可以将需要直接访问的字段封装到它们自己的结构类型中,并为此设置一个 getter(如果您想一起使用多个相关字段)。最后,您可以重新设计整体设计以消除或迁移需求。这里没有足够的上下文来提出一个硬性建议,但总而言之,似乎您可能有一些东西将这些事务写入某个地方,并且它是您所关心的要写入的内容的大小。由于您似乎还在尝试获取其最终长度的方法中生成消息的所有相关处理,所以您不能将消息生成为[]byte,取其长度,然后然后在你做的时候使用相同的输出......不管你用这些做什么?

【讨论】:

  • 我不确定您所说的“因为看起来您正在执行所有相关的处理以在您试图获取其最终长度的方法中生成消息,所以我不确定您的意思是'您不只是将消息生成为 [] 字节,获取它的长度,然后在执行时使用相同的输出......无论您正在使用这些做什么?”这只是更大操作中的一个步骤 - 有一个复杂的等式取决于之后的交易规模。
  • 好的。同样,很难猜测您的选择可能是什么,因为没有提供上下文。
【解决方案2】:

估计 Tx 的大小需要 Tx.RLP()(由 Tx 接口保证)和 Tx.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)
}
...

【讨论】:

    猜你喜欢
    • 2015-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-20
    • 2019-02-06
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    相关资源
    最近更新 更多