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

16

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

例如:

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

等等...


你成功实现了吗? - Ryan Falzon
2个回答

18

关于Substrate master最新版本更新

Substrate已经移除了As,改为使用From/Into假设所有类型至少为u32

从trait SimpleArithmatic中,实现了以下内容:

  • Fromu8u16u32
  • TryFromu64u128usize
  • TryIntou8u16u32u64u128usize

另外提供了一个trait以实现舒适的不可失败转换,当您不在意值是否饱和时可以使用。

  • UniqueSaturatedIntou8u16u32u64u128
  • UniqueSaturatedFromu64u128
Gav关于SaturatedConversion的说明: 除非您知道自己在做什么,已经考虑了所有选项并且您的用例意味着饱和是基本正确的,否则不应使用SaturatedConversion(saturated_into和saturated_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

Substrate 提供了 sr-primitives 包中的 pub trait As<T>

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

4
最好避免使用As,而改用From/Into - Bryan Chen
这将很快通过此PR https://github.com/paritytech/substrate/pull/4517 稍作更改。 - kianenigma
有没有人能够将 Substrate 的 blocknumber 转换成 u8 类型? - Ryan Falzon
你可以使用saturated_into()来实现,但是一旦你的块编号超过255,返回的值将会被固定在255,并且可能没有什么用处。 - Shawn Tabrizi

2
以下是一些示例,可帮助将数字转换为余额类型:
//declare following import
use frame_support::sp_runtime::traits::Zero;
use frame_support::sp_runtime::SaturatedConversion;

//then saturated_into can be used to convert number into Balance type as follows
let cost_in_u64: u64 = 250; //or expression like 200 + 50;
let cost: BalanceOf<T> = cost_in_u64.saturated_into::<BalanceOf<T>>();

//convert 1010 of type u32 into Balance
let cost2: BalanceOf<T> = 1010u32.into();
//set zero balance
let cost3 = BalanceOf::<T>::zero();

在cfg中,BalanceOf的定义如下:

#[cfg(feature = "std")]
type BalanceOf<T> =
        <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接