2 Вопрос: Как гарантировать наличие структурного поля, как это делают интерфейсы для методов?

вопрос создан в Wed, May 8, 2019 12:00 AM

У меня есть несколько структур транзакций:

SpendTx
NameTransferTx
NameUpdateTx
...

Я хотел бы оценить размер этих структур, исключая поле «Плата». Все они имеют поле структуры Fee. В настоящее время для каждой структуры у меня есть этот метод:

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(), и сделать из этого интерфейс, но это не лучше. Или так делают другие люди?

    
0
  1. А как насчет написания структуры с общими полями, такой как pricedTx, с последующим внедрением ее в другие структуры?
    2019-05-08 15: 58: 17Z
  2. Это может быть интересно - хотя потребуется несколько часов, чтобы попробовать этот подход.
    2019-05-08 21: 17: 32Z
2 ответа                              2                         

Ты не. Если вас не интересует конкретный тип (т. Е. Вы можете использовать интерфейс), то вам не важны данные, а только их поведение (поэтому интерфейсы указывают только методы). Если вы заботитесь о данных, то вы уже по колено во внутренностях типа, и вам следует использовать конкретный конкретный тип (или использовать переключатель утверждения типа /типа, чтобы добраться до него). Это не специфично для Go; большинство языков не позволяют указывать поля в интерфейсах.

Сборщик не был бы худшей вещью. Вы также можете инкапсулировать поля, к которым вам нужен прямой доступ, в их собственный тип структуры, и иметь для этого геттер (если есть несколько связанных полей, с которыми вы хотите работать вместе). Наконец, вы можете переделать общий дизайн, чтобы устранить или перенести необходимость. Здесь недостаточно контекста, чтобы сделать жесткое предложение, но, чтобы сделать общее предположение, кажется, что у вас, вероятно, есть что-то, что записывает эти транзакции куда-то, и вас интересует размер того, что должно быть написано. Поскольку также кажется, что вы выполняете всю связанную обработку для создания сообщения в методе, в котором вы пытаетесь получить его окончательную длину, вы не могли бы просто создать сообщение как []byte, взять его длину и затем использовать тот же вывод, когда вы делаете ... что бы вы ни делали с этими?

    
0
2019-05-08 16: 40: 49Z
  1. Я не уверен, что вы подразумеваете под "Поскольку также кажется, что вы выполняете всю связанную с этим обработку для создания сообщения в методе, в котором вы пытаетесь чтобы получить его окончательную длину, не могли бы вы просто создать сообщение в виде байта [], взять его длину, а затем использовать тот же вывод, когда вы делаете ... что бы вы ни делали с ними? " Это только один шаг в более крупной операции - есть сложное уравнение, которое зависит от размера транзакции после этого.
    2019-05-08 20: 52: 18Z
  2. ОК. Опять же, трудно угадать, какие у вас могут быть варианты, потому что нет предоставленного контекста.
    2019-05-09 13: 20: 22Z

Для оценки размера 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)
}
...
    
0
2019-05-09 00: 15: 02Z
источник размещен Вот
Другие вопросы