你如何在 Substrate 特定类型和 Rust 原始类型之间进行转换?

Posted

技术标签:

【中文标题】你如何在 Substrate 特定类型和 Rust 原始类型之间进行转换?【英文标题】:How do you convert between Substrate specific types and Rust primitive types? 【发布时间】:2019-09-28 13:41:45 【问题描述】:

使用 Substrate 区块链框架,我如何在 Substrate 特定类型和 Rust 原始类型之间进行转换,反之亦然?

例如:

将时间 (T::Moment) 转换为 u64 将 u64 转换为 T::Balance

等等……

【问题讨论】:

你做到了吗? 【参考方案1】:

最新的 Substrate master

基板有removed As 支持From/Into假设所有类型至少为u32

通过特征SimpleArithmatic,实现了以下内容:

From: u8, u16, u32 TryFromu64u128usize TryInto: u8, u16, u32, u64, u128, usize

还提供了另一个特性以提供符合人体工程学的 当您不在乎值是否饱和时,绝对可靠的转换。

UniqueSaturatedInto: u8, u16, u32, u64, u128 UniqueSaturatedFrom: u64, u128

Gav 对SaturatedConversion 的说明

不应使用SaturatedConversionsaturated_intosaturated_from),除非您知道自己在做什么,您已经考虑并考虑了所有选项,并且您的用例暗示饱和度基本上是正确的。我唯一想到的情况是在运行时算术中很深,你在逻辑上确定它不会溢出,但不能提供证明,因为它取决于一致的预先存在的状态。

这意味着从 u32 到 Substrate 特定类型的工作应该很容易:

pub fn u32_to_balance(input: u32) -> T::Balance 
    input.into()

对于较大的类型,您需要处理运行时的 Balance 类型小于可用类型的情况:

pub fn u64_to_balance_option(input: u64) -> Option<T::Balance> 
    input.try_into().ok()


// Note the warning above about saturated conversions
pub fn u64_to_balance_saturated(input: u64) -> T::Balance 
    input.saturated_into()

当从T::Balance 转换为 rust 原语时,还需要处理不兼容类型之间的转换:

pub fn balance_to_u64(input: T::Balance) -> Option<u64> 
    TryInto::<u64>::try_into(input).ok()


// Note the warning above about saturated conversions
pub fn balance_to_u64_saturated(input: T::Balance) -> u64 
    input.saturated_into::<u64>()


对于 Substrate v1.0

基板提供pub trait As&lt;T&gt; in the sr-primitives crate:

/// Simple trait similar to `Into`, except that it can be used to convert numerics between each
/// other.
pub trait As<T> 
    /// Convert forward (ala `Into::into`).
    fn as_(self) -> T;
    /// Convert backward (ala `From::from`).
    fn sa(_: T) -> Self;

以下是一些如何使用它的工作示例:

impl<T: Trait> Module<T> 
    // `as_` will turn T::Balance into a u64
    pub fn balance_to_u64(input: T::Balance) -> u64 
        input.as_()
    

    // Being explicit, you can convert a `u64` to a T::Balance
    // using the `As` trait, with `T: u64`, and then calling `sa`
    pub fn u64_to_balance(input: u64) -> T::Balance 
        <T::Balance as As<u64>>::sa(input)
    

    // You can also let Rust figure out what `T` is
    pub fn u64_to_balance_implied(input: u64) -> T::Balance 
        <T::Balance as As<_>>::sa(input)
    

    // You can also let Rust figure out where `sa` is implemented
    pub fn u64_to_balance_implied_more(input: u64) -> T::Balance 
        T::Balance::sa(input)
    

【讨论】:

Better to avoid As and use From/Into. 这很快就会被这个 PR github.com/paritytech/substrate/pull/4517稍微改变一下 有没有人能够将基板块号转换为 u8? 你可以用saturated_into()来做,但是一旦你的块号超过255,返回的值就会卡在255,可能不是很有用。

以上是关于你如何在 Substrate 特定类型和 Rust 原始类型之间进行转换?的主要内容,如果未能解决你的问题,请参考以下文章

你如何在 Rust 中定义自定义的 `Error` 类型?

Rust 语言如何帮助你防止 bug

波卡与 Wasm 合约双剑合璧

5 个非常有用的 Rust 小技巧

5 个非常有用的 Rust 小技巧

你如何在结构之前的一个文档块中记录一个 Rust 结构/枚举?