前语

上一篇文章咱们主要介绍了Move言语中的泛型,了解了泛型的界说与运用,在Move中泛型能够用于结构体和函数。结构体这个数据类型能够协助咱们创立自己的类型和存储复杂的数据结构,可是有时候咱们需求更灵活,扩展性更好和管理性更好的数据结构,为了满意这个需求,Move供给了Vector。

什么是Vector

Vector是Move内置的数据类型用于存储很多的数据,这是用于恣意类型数据的调集的解决办法,它的能力是虚拟机供给的,所以运用它的唯一办法便是规范库,例子如下:

script {
    use 0x1::Vector;
    fun main() {
        // 运用泛型创立一个空的vector
        let a = Vector::empty<u8>();
        let i = 0;
        // 填充数据
        while (i < 10) {
            Vector::push_back(&mut a, i);
            i = i + 1;
        };
        // 打印vector的长度
        let a_len = Vector::length(&a);
        0x1::Debug::print<u64>(&a_len);
        // 从vector中移除数据
        Vector::pop_back(&mut a);
        Vector::pop_back(&mut a);
        // 重新打印长度
        let a_len = Vector::length(&a);
        0x1::Debug::print<u64>(&a_len);
    }
}

vector能够存储数据的最大容量为18446744073709551615,咱们还能够对其进行包装,方便运用:

module Shelf {
    use 0x1::Vector;
    struct Box<T> {
        value: T
    }
    struct Shelf<T> {
        boxes: vector<Box<T>>
    }
    public fun create_box<T>(value: T): Box<T> {
        Box { value }
    }
    public fun value<T: copy>(box: &Box<T>): T {
        *&box.value
    }
    public fun create<T>(): Shelf<T> {
        Shelf {
            boxes: Vector::empty<Box<T>>()
        }
    }
    public fun put<T>(shelf: &mut Shelf<T>, box: Box<T>) {
        Vector::push_back<Box<T>>(&mut shelf.boxes, box);
    }
    public fun remove<T>(shelf: &mut Shelf<T>): Box<T> {
        Vector::pop_back<Box<T>>(&mut shelf.boxes)
    }
    public fun size<T>(shelf: &Shelf<T>): u64 {
        Vector::length<Box<T>>(&shelf.boxes)
    }
}

内联 Vector 界说的十六进制数组和字符串

Vector 也能够表明字符串。VM支持将vector作为参数传递给main脚本中的函数。也能够运用十六进制字面值(literal)在脚本或模块中界说vector

script {
    use 0x1::Vector;
    // 这时main函数承受参数的办法
    fun main(name: vector<u8>) {
        let _ = name;
        // 这是 "hello world" 字符串!
        let str = x"68656c6c6f20776f726c64";
    }
}

更简略的办法是运用字符串字面值(literal):

script {
    fun main() {
        let _ = b"hello world";
    }
}

它们被视为 ASCII 字符串,也被解释为 vector。

vector速查表

这是规范库中 Vector 办法的简短列表:

创立一个类型为的空向量

Vector::empty<E>(): vector<E>;

获取向量的长度

Vector::length<E>(v: &vector<E>): u64;

将元素 e 添加到向量末尾

Vector::push_back<E>(v: &mut vector<E>, e: E);

获取对向量元素的可变引证。不行变引证可运用Vector::borrow()

Vector::borrow_mut<E>(v: &mut vector<E>, i: u64): &E;

从向量的末尾取出一个元素

Vector::pop_back<E>(v: &mut vector<E>): E;

Resource

接下来咱们就要学习Move中非常重要的一个概念Resource,它使 Move 变得绝无仅有,安全且强壮。
首要,让咱们看一下 Diem 开发者网站上的关于 Resource 的要点(将 Libra 改名为 Diem 后,原页面已删去):

Move 的主要功能是供给了自界说 Resource 类型。Resource 类型为安全的数字财物编码且供给了丰厚的可编程性。 Resource 在Move言语中便是普通的值。它们能够作为数据结构被存储,作为参数被传递给函数,也能够从函数中返回。

Resource 是一种特别的结构体,能够在 Move 代码中界说和创立,也能够运用现有的 Resource。因而,咱们能够像运用任何其它数据(比如向量或结构体)那样来管理数字财物。

Move 类型系统为 Resource 供给了特别的安全保证。Resource 永久不能被仿制,重用或丢弃。Resource 类型只能由界说该类型的模块创立或毁掉。这些检查由 Move 虚拟机经过字节码校验强制执行。Move 虚拟机将回绝运转任何没有经过字节码校验的代码。

signer

在开始运用 Resource 之前,咱们需求了解 signer 类型以及这种类型存在的原因。

Signer 是一种原生的相似 Resource 的不行仿制的类型,它包含了买卖发送者的地址。
Signer 类型代表了发送者权限。换句话说,运用 signer 意味着能够拜访发送者的地址和 Resource。它与signature没有直接关系,就Move VM 而言,它仅表明发送者。
Signer 只要一种 ability: Drop。

脚本的signer

Signer 是原生类型,运用前必须先创立。与 vector 这样的原生类型不同,signer 不能直接在代码中创立,可是能够作为脚本参数传递:

script {
    fun main(account: signer) {
        let _ = account;
    }
}

Signer 参数无需手动将其传递到脚本中,客户端(CLI)会主动将它放入你的脚本中。而且,signer 自始至终都只是引证,尽管规范库中能够拜访签名者的实践值,但运用此值的函数是私有的,无法在其他任何地方运用或传递 signer 值。

当时,约定俗成的 signer 类型的变量名是 account

规范库中的Signer模块

原生类型离不开原生办法, signer 的原生办法包含在0x1::Signer模块中。这个模块相对比较简略,详细能够参阅 Diem 规范库 Signer 模块的完成:

module Signer {
    // Borrows the address of the signer
    // Conceptually, you can think of the `signer`
    // as being a resource struct wrapper arround an address
    // ```
    // resource struct Signer { addr: address }
    // ```
    // `borrow_address` borrows this inner field
    native public fun borrow_address(s: &signer): &address;
    // Copies the address of the signer
    public fun address_of(s: &signer): address {
        *borrow_address(s)
    }
}

模块中包含两个办法,一个是原生办法,另一个是 Move 办法。后者运用更方便,由于它运用了取值运算符来仿制地址。

模块中的signer

module M {
    use 0x1::Signer;
    // let's proxy Signer::address_of
    public fun get_address(account: signer): address {
        Signer::address_of(&account)
    }
}

运用&signer作为函数的参数说明该函数正在运用发送者的地址。
引入signer类型的原因之一是要清晰显示哪些函数需求发送者权限,哪些不需求。因而,函数不能欺骗用户未经授权拜访其 Resource。

最终

这篇文章主要介绍了Move言语中的vector和Resource的一些相关基本概念,更多文章能够重视大众号QStack。