#[liquid(storage)]
pub struct HelloWorld {
pub name: storage::Value<String>,
pub
可见性代表外界可以直接访问该状态变量,Liquid 会自动为此类状态变量生成一个公开的访问器。关于访问器的更多细节可参考合约方法一节。但是除了pub
可见性以外,其他种类的可见性声明均不能使用。
Liquid 中的容器包括单值容器(Value
)、向量容器(Vec
)、映射容器(Mapping
)及可迭代映射容器(IterableMapping
)。
Liquid中所有容器均没有实现拷贝语义,因此无法拷贝容器。同时,Liquid限制了您不能移动容器的所有权,因此在合约中只能通过引用的方式使用容器。
单值容器
单值容器的类型定义为Value<T>
。当状态变量类型定义为单值容器时,可以像使用普通变量一般使用该状态变量。使用单值容器时需要通过模板参数传入状态变量的实际类型,如Value<bool>
、Value<String>
等。基本容器提供下列方法:
pub fn initialize(&mut self, input: T)
用于在合约构造函数中使用提供的初始值初始化单值容器。此方法应当只在构造函数中使用,且只使用一次。若状态变量初始化后再次调用initialize
方法将不会产生任何效果。
pub fn set(&mut self, new_val: T)
用一个新的值更新状态变量的值。
pub fn mutate_with<F>(&mut self, f: F) -> &T
where
F: FnOnce(&mut T),
允许传入一个用于修改状态变量的函数,在修改完状态变量后,返回状态变量的引用。当状态变量未初始化时,调用mutate_with
会引发运行时异常并导致交易回滚。
pub fn get(&self) -> &T
返回状态变量的只读引用。
pub fn get_mut(&mut self) -> &mut T
返回状态变量的可变引用,可以通过该可变引用直接修改状态变量的值。
除了上述基本接口外,单值容器还通过实现core::ops
中的运算符 trait,对大量的运算符进行了重载,从而能够直接使用容器进行运算。单值容器重载的运算符包括:
Deref
通过容器的只读引用返回 &T
,借助 Rust 语言的 解引用强制多态 ,可以像操作普通变量那样操单值容器。例如:若状态变量 name
的类型为 Value<String>
,如需获取 name
的长度,则可以直接使用 name.len()
DerefMut
通过容器的可变引用返回 &mut T
需要 T
自身支持双目 +
运算,例如:若状态变量 len
的类型为 Value<u8>
,则可以直接使用 len + 1
AddAssign
需要 T
自身支持 +=
运算
需要 T
自身支持双目 -
运算
SubAssign
需要 T
自身支持 -=
运算
需要 T
自身支持 *
运算
MulAssign
需要 T
自身支持 *=
运算
需要 T
自身支持 /
运算
DivAssign
需要 T
自身支持 /=
运算
需要 T
自身支持 %
运算
RemAssign
求模并赋值
需要 T
自身支持 %=
运算
BitAnd
需要 T
自身支持 &
运算
BitAndAssign
按位与并赋值
需要 T
自身支持 &=
运算
BitOr
需要 T
自身支持 |
运算
BitOrAssign
按位或并赋值
需要 T
自身支持 |=
运算
BitXor
需要 T
自身支持 ^
运算
BitXorAssign
按位异或并赋值
需要 T
自身支持 ^=
运算
需要 T
自身支持 <<
运算
ShlAssign
左移并赋值
需要 T
自身支持 <<=
运算
需要 T
自身支持 >>
运算
ShrAssign
右移并赋值
需要 T
自身支持 >>=
运算
需要 T
自身支持单目 -
运算
需要 T
自身支持 !
运算
Index
需要 T
自身支持按下标进行索引
IndexMut
同上,但是用于可变引用上下文中
==、!=、>、>=、<、<=
PartialEq、PartialOrd、Ord
需要 T
自身支持相应的比较运算
向量容器
向量容器的类型定义为Vec<T>
。当状态变量类型为向量容器时,可以像使用动态数组一般的方式使用该状态变量。在向量容器中,所有元素按照严格的线性顺序排序,可以通过元素在序列中的位置访问对应的元素。使用向量容器时需要通过模板参数传入元素的实际类型,如Vec<bool>
、Vec<String>
等。向量容器提供下列方法:
pub fn initialize(&mut self)
用于在构造函数中初始化向量容器。若向量容器初始化后再调用initialize
接口,则不会产生任何效果。
pub fn len(&self) -> u32
返回向量容器中元素的个数。
pub fn is_empty(&self) -> bool
检查向量容器是否为空。
pub fn get(&self, n: u32) -> Option<&T>
返回向量容器中第n
个元素的只读引用。若n
越界,则返回None
。
pub fn get_mut(&mut self, n: u32) -> Option<&mut T>
返回向量容器中第n
个元素的可变引用。若n
越界,则返回None
。
pub fn mutate_with<F>(&mut self, n: u32, f: F) -> Option<&T>
where
F: FnOnce(&mut T),
允许传入一个用于修改向量容器中第n
个元素的值的函数,在修改完毕后,返回该元素的只读引用。若n
越界,则返回None
。
pub fn push(&mut self, val: T)
向向量容器的尾部插入一个新元素。当插入前向量容器的长度等于 232 - 1 时,引发 panic。
pub fn pop(&mut self) -> Option<T>
移除向量容器的最后一个元素并将其返回。若向量容器为空,则返回None
。
pub fn swap(&mut self, a: u32, b: u32)
交换向量容器中第a
个及第b
个元素。若a
或b
越界,则引发 panic。
pub fn swap_remove(&mut self, n: u32) -> Option<T>
从向量容器中移除第n
个元素,并将最后一个元素移动至第n
个元素所在的位置,随后返回被移除元素的引用。若n
越界,则返回None
;若第n
个元素就是向量容器中的最后一个元素,则效果等同于pop
接口。
同时,向量容器实现了以下 trait:
impl<T> Extend<T> for Vec<T>
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = T>;
按顺序遍历迭代器,并将迭代器所访问的元素依次插入到向量容器的尾部。
impl<'a, T> Extend<&'a T> for Vec<T>
where
T: Copy + 'a,
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = &'a T>;
按顺序遍历迭代器,并将迭代器所访问的元素依次插入到向量容器的尾部。
impl<T> core::ops::Index<u32> for Vec<T>
type Output = T;
fn index(&self, index: u32) -> &Self::Output;
使用下标对序列中的任意元素进行快速直接访问,下标的类型为u32
,返回元素的只读引用。若下标越界,则会引发运行时异常并导致交易回滚。
impl<T> core::ops::IndexMut<u32> for Vec<T>
fn index_mut(&mut self, index: u32) -> &mut Self::Output;
使用下标对序列中的任意元素进行快速直接访问,下标的类型为u32
,返回元素的可变引用。若下标越界,则会引发运行时异常并导致交易回滚。
向量容器支持迭代。在迭代时,需要先调用向量容器的iter
方法生成迭代器,并配合for ... in ...
等语法完成对向量容器的迭代,如下列代码所示:
14
#[liquid(storage)]
struct Sum {
value: storage::Vec<u32>,
pub fn sum(&self) -> u32 {
let mut ret = 0u32;
for elem in self.value.iter() {
ret += elem;
向量容器的长度并不能无限增长,其上限为2 32 - 1(4294967295,约为42亿)。
映射容器
映射容器的类型定义为Mapping<K, V>
。映射容器是键值对集合,当状态变量类型为映射容器时,能够通过键来获取一个值。使用映射容器时需要通过模板参数传入键和值的实际类型,如Mapping<u8, bool>
、Mapping<String, u32>
等。映射容器提供下列方法:
pub fn initialize(&mut self)
用于在构造函数中初始化映射容器。若映射容器初始化后再调用initialize
接口,则不会产生任何效果。
pub fn len(&self) -> u32
返回映射容器中元素的个数。
pub fn is_empty(&self) -> bool
检查映射容器是否为空。
pub fn insert<Q>(&mut self, key: &Q, val: V) -> Option<V>
向映射容器中插入一个由key
、val
组成的键值对,注意key
的类型为一个引用。当key
在之前的映射容器中不存在时,返回None
;否则返回之前的key
所对应的值。
pub fn mutate_with<Q, F>(&mut self, key: &Q, f: F) -> Option<&V>
where
K: Borrow<Q>,
F: FnOnce(&mut V),
允许传入一个用于修改映射容器中key
所对应的值的函数,在修改完毕后,返回值的只读引用。若key
在映射容器中不存在,则返回None
。
pub fn remove<Q>(&mut self, key: &Q) -> Option<V>
where
K: Borrow<Q>,
从映射容器中移除key
及对应的值,并返回被移除的值。若key
在映射容器中不存在,则返回None
。
pub fn get<Q>(&self, key: &Q) -> Option<&V>
返回映射容器中key
所对应的值的只读引用。若key
在映射容器中不存在,则返回None
。
pub fn get_mut<Q>(&mut self, key: &Q) -> Option<&mut V>
返回映射容器中key
所对应的值的可变引用。若key
在映射容器中不存在,则返回None
。
pub fn contains_key<Q>(&self, key: &Q) -> bool
检查key
在映射容器中是否存在。
同时,映射容器实现了以下 trait:
impl<K, V> Extend<(K, V)> for Mapping<K, V>
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = (K, V)>;
按顺序遍历迭代器,并将迭代器所访问的键值对依次插入到映射容器中。
impl<'a, K, V> Extend<(&'a K, &'a V)> for Mapping<K, V>
where
K: Copy,
V: Copy,
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = (&'a K, &'a V)>;
按顺序遍历迭代器,并将迭代器所访问的键值对依次插入到映射容器中。
impl<'a, K, Q, V> core::ops::Index<&'a Q> for Mapping<K, V>
where
K: Borrow<Q>,
type Output = V;
fn index(&self, index: &'a Q) -> &Self::Output;
以键为索引访问映射容器中对应的值,索引类型为&Q
,返回值的只读引用。若索引不存在,则会引发运行时异常并导致交易回滚。
impl<'a, K, Q, V> core::ops::IndexMut<&'a Q> for Mapping<K, V>
where
K: Borrow<Q>,
fn index_mut(&mut self, index: &'a Q) -> &mut Self::Output;
以键为索引访问映射容器中对应的值,索引类型为&Q
,返回值的可变引用。若索引不存在,则会引发运行时异常并导致交易回滚。
映射容器的容量大小并不能无限增长,其上限为2 32 - 1(4294967295,约为42亿)。
映射容器不支持迭代,如果需要迭代映射容器,请使用可迭代映射容器。
可迭代映射容器
可迭代映射容器的类型定义为IterableMapping<K, V>
,其功能与映射容器基本类似,但是提供了迭代功能。使用可迭代映射容器时需要通过模板参数传入键和值的实际类型,如IterableMapping<u8, bool>
、IterableMapping<String, u32>
等。
可迭代映射容器支持迭代。在迭代时,需要先调用可迭代映射容器的iter
方法生成迭代器,迭代器在迭代时会不断返回由键的引用及对应的值的引用组成的元组,可配合for ... in ...
等语法完成对可迭代映射容器的迭代,如下列代码所示:
14
#[liquid(storage)]
struct Sum {
values: storage::IterableMapping<String, u32>,
pub fn sum(&self) -> u32 {
let mut ret = 0u32;
for (_, v) in self.values.iter() {
ret += v;
此外,可迭代映射容器的insert
方法与映射容器略有不同,其描述如下:
pub fn insert(&mut self, key: K, val: V) -> Option<V>
其功能与映射容器的insert
方法相同,但是其参数并不K
类型的引用。
可迭代映射容器的容量大小并不能无限增长,其上限为2 32 - 1(4294967295,约为42亿)。
为实现迭代功能,可迭代映射容器在内部存储了所有的键,且受限于区块链特性,这些键不会被删除。因此,可迭代容器的性能及存储开销较大,请根据应用需求谨慎选择使用。