prefácio
No artigo anterior, introduzimos principalmente os genéricos na linguagem Move, e aprendemos sobre a definição e uso de genéricos.No Move, os genéricos podem ser usados para estruturas e funções. A estrutura de tipos de dados pode nos ajudar a criar nossos próprios tipos e armazenar estruturas de dados complexas, mas às vezes precisamos de estruturas de dados mais flexíveis, escaláveis e gerenciáveis.Para atender a essa demanda, o Move fornece o Vector.
o que é vetor
Vector é um tipo de dados integrado do Move para armazenar grandes quantidades de dados. Esta é uma solução para coleções de qualquer tipo de dados. Seus recursos são fornecidos pela máquina virtual, portanto, a única maneira de usá-lo é a biblioteca padrão. Os exemplos são os seguintes:
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);
}
}
A capacidade máxima que o vetor pode armazenar dados é 18446744073709551615, e também podemos empacotá-lo para facilitar o uso:
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)
}
}
Matrizes e strings hexadecimais definidas por vetor embutido
Vetores também podem representar strings. A VM oferece suporte à passagem de vetores como argumentos para funções no script principal. Os vetores também podem ser definidos em scripts ou módulos usando literais hexadecimais
script {
use 0x1::Vector;
// 这时main函数接受参数的方式
fun main(name: vector<u8>) {
let _ = name;
// 这是 "hello world" 字符串!
let str = x"68656c6c6f20776f726c64";
}
}
Uma maneira mais fácil é usar uma string literal:
script {
fun main() {
let _ = b"hello world";
}
}
Eles são tratados como strings ASCII e também interpretados como vetores.
folha de dicas do vetor
Aqui está uma pequena lista de métodos Vector na biblioteca padrão:
Cria um vetor vazio do tipo
Vector::empty<E>(): vector<E>;
obter o comprimento do vetor
Vector::length<E>(v: &vector<E>): u64;
adicione o elemento e ao final do vetor
Vector::push_back<E>(v: &mut vector<E>, e: E);
Obtenha uma referência mutável para os elementos do vetor. Referências imutáveis podem usar Vector::borrow()
Vector::borrow_mut<E>(v: &mut vector<E>, i: u64): &E;
pegue um elemento do final do vetor
Vector::pop_back<E>(v: &mut vector<E>): E;
Recurso
A seguir aprenderemos um conceito muito importante Resource in Move, que torna o Move único, seguro e poderoso.
Primeiro, vamos dar uma olhada nos principais pontos sobre Resource no site do desenvolvedor Diem (a página original foi excluída após a renomeação de Libra para Diem):
A principal função do Move é fornecer um tipo de Recurso personalizado. Os tipos de recursos codificam ativos digitais seguros e fornecem uma programação avançada. Um Recurso é um valor comum na linguagem Move. Eles podem ser armazenados como estruturas de dados, passados como argumentos para funções e retornados de funções.
Resource é uma estrutura especial que pode ser definida e criada no código Move, ou um Resource existente pode ser usado. Portanto, podemos gerenciar ativos digitais como qualquer outro dado, como vetores ou estruturas.
O sistema de tipo de movimento fornece garantias especiais de segurança para o Recurso. O recurso nunca pode ser copiado, reutilizado ou descartado. Um tipo de recurso só pode ser criado ou destruído pelo módulo que o define. Essas verificações são impostas pela máquina virtual Move por meio da verificação de bytecode. O Move VM se recusará a executar qualquer código que não tenha passado pela verificação de bytecode.
signatário
Antes de começarmos a trabalhar com Recursos, precisamos entender o tipo de signatário e por que ele existe.
O signatário é um tipo não copiável semelhante ao recurso nativo que contém o endereço do remetente da transação.
O tipo Signatário representa a autoridade do remetente. Em outras palavras, usar um signatário significa ter acesso ao endereço e recurso do remetente. Não está diretamente relacionado à assinatura, no que diz respeito ao Move VM, significa apenas o remetente.
Signatário tem apenas uma habilidade: Soltar.
assinante do script
Signer é um tipo nativo e deve ser criado antes do uso. Ao contrário de tipos primitivos como vetor, signatário não pode ser criado diretamente no código, mas pode ser passado como um parâmetro de script:
script {
fun main(account: signer) {
let _ = account;
}
}
Parâmetro do signatário Não há necessidade de passá-lo manualmente para o script, o cliente (CLI) o colocará automaticamente em seu script. Além disso, o signatário é apenas uma referência e, embora o valor real do signatário esteja acessível na biblioteca padrão, a função que usa esse valor é privada e não pode usar ou passar o valor do signatário em nenhum outro lugar.
Atualmente, o nome da variável habitual do tipo de signatário é account
O módulo Signer na biblioteca padrão
Os tipos nativos são inseparáveis dos métodos nativos e os métodos nativos do signatário estão incluídos no módulo 0x1::Signer. Este módulo é relativamente simples. Para detalhes, consulte a implementação do módulo Signer na biblioteca padrão Diem:
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)
}
}
O módulo contém dois métodos, um é um método nativo e o outro é um método Move. Este último é mais conveniente de usar porque usa o operador de acesso para copiar o endereço.
assinante no módulo
module M {
use 0x1::Signer;
// let's proxy Signer::address_of
public fun get_address(account: signer): address {
Signer::address_of(&account)
}
}
Usar &signer como um argumento para uma função indica que a função está usando o endereço do remetente.
Uma das razões para introduzir o tipo de signatário é deixar claro quais funções requerem permissões de remetente e quais não. Portanto, uma função não pode induzir um usuário a obter acesso não autorizado a seu recurso.
afinal
Este artigo apresenta principalmente alguns conceitos básicos relacionados a vetores e recursos na linguagem Move.Para mais artigos, você pode prestar atenção à conta oficial QStack.