List
Por defecto, no hay ningún tipo de lista soportado en Cairo, pero puedes usar Alexandria. Puede consultar la documentación de Alexandria para más detalles.
What is List
?
Una secuencia ordenada de valores que puede utilizarse en el storage de Starknet:
#[storage]
stuct Storage {
amounts: List<u128>
}
Interface
trait ListTrait<T> {
fn len(self: @List<T>) -> u32;
fn is_empty(self: @List<T>) -> bool;
fn append(ref self: List<T>, value: T) -> u32;
fn get(self: @List<T>, index: u32) -> Option<T>;
fn set(ref self: List<T>, index: u32, value: T);
fn pop_front(ref self: List<T>) -> Option<T>;
fn array(self: @List<T>) -> Array<T>;
}
List
también implementa IndexView
para que puedas utilizar la notación familiar de corchetes para acceder a sus miembros:
let second = self.amounts.read()[1];
Tenga en cuenta que, a diferencia de get
, el uso de esta notación de corchetes entra en pánico cuando se accede a un índice fuera de los límites.
Support for custom types
List
soporta la mayoría de los tipos de corelib. Si quieres almacenar un tipo personalizado en una List
, tiene que implementar el trait Store
. Puedes hacer que el compilador lo derive por ti usando el atributo #[derive(starknet::Store)]
.
Caveats
Hay dos particularidades que debe tener en cuenta al utilizar List
- The
append
operation costs 2 storage writes - one for the value itself and another one for updating the List's length - Due to a compiler limitation, it is not possible to use mutating operations with a single inline statement. For example,
self.amounts.read().append(42);
will not work. You have to do it in 2 steps:
let mut amounts = self.amounts.read();
amounts.append(42);
Dependencies
Actualice las dependencias de su proyecto en el archivo Scarb.toml
:
[dependencies]
(...)
alexandria_storage = { git = "https://github.com/keep-starknet-strange/alexandria.git" }
Por ejemplo, utilicemos List
para crear un contrato que realice el seguimiento de una lista de importes y tareas:
#[starknet::interface]
trait IListExample<TContractState> {
fn add_in_amount(ref self: TContractState, number: u128);
fn add_in_task(ref self: TContractState, description: felt252, status: felt252);
fn is_empty_list(self: @TContractState) -> bool;
fn list_length(self: @TContractState) -> u32;
fn get_from_index(self: @TContractState, index: u32) -> u128;
fn set_from_index(ref self: TContractState, index: u32, number: u128);
fn pop_front_list(ref self: TContractState);
fn array_conversion(self: @TContractState) -> Array<u128>;
}
#[starknet::contract]
mod ListExample {
use alexandria_storage::list::{List, ListTrait};
#[storage]
struct Storage {
amount: List<u128>,
tasks: List<Task>
}
#[derive(Copy, Drop, Serde, starknet::Store)]
struct Task {
description: felt252,
status: felt252
}
#[abi(embed_v0)]
impl ListExample of super::IListExample<ContractState> {
fn add_in_amount(ref self: ContractState, number: u128) {
let mut current_amount_list = self.amount.read();
current_amount_list.append(number);
}
fn add_in_task(ref self: ContractState, description: felt252, status: felt252) {
let new_task = Task { description: description, status: status };
let mut current_tasks_list = self.tasks.read();
current_tasks_list.append(new_task);
}
fn is_empty_list(self: @ContractState) -> bool {
let mut current_amount_list = self.amount.read();
current_amount_list.is_empty()
}
fn list_length(self: @ContractState) -> u32 {
let mut current_amount_list = self.amount.read();
current_amount_list.len()
}
fn get_from_index(self: @ContractState, index: u32) -> u128 {
self.amount.read()[index]
}
fn set_from_index(ref self: ContractState, index: u32, number: u128) {
let mut current_amount_list = self.amount.read();
current_amount_list.set(index, number);
}
fn pop_front_list(ref self: ContractState) {
let mut current_amount_list = self.amount.read();
current_amount_list.pop_front();
}
fn array_conversion(self: @ContractState) -> Array<u128> {
let mut current_amount_list = self.amount.read();
current_amount_list.array()
}
}
}