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

  1. The append operation costs 2 storage writes - one for the value itself and another one for updating the List's length
  2. 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()
        }
    }
}
Last change: 2023-11-27, commit: e112ed3