Appendix C: Derivable Traits

En varias partes del libro, hemos discutido el atributo derive, que puedes aplicar a una definición struct o enum. El atributo derive genera código para implementar un trait por defecto en el tipo que has anotado con la sintaxis derive.

En este apéndice, proporcionamos una referencia completa que detalla todos los traits de la biblioteca estándar compatibles con el atributo derive.

Estos traits listados aquí son los únicos definidos por la librería principal que pueden ser implementados en tus tipos usando derive. Otros traits definidos en la biblioteca estándar no tienen un comportamiento sensible por defecto, por lo que depende de ti implementarlos de la manera que tenga sentido para lo que estás tratando de lograr.

La lista de traits derivables proporcionada en este apéndice no abarca todas las posibilidades: las bibliotecas externas pueden implementar derive para sus propios rasgos, ampliando la lista de rasgos compatibles con derive.

PartialEq for equality comparison

El trait PartialEq permite la comparación entre instancias de un tipo por igualdad, habilitando así los operadores == y !=.

Cuando PartialEq se deriva en structs, dos instancias son iguales sólo si todos los campos son iguales, y las instancias no son iguales si algún campo no lo es. Cuando se deriva en enums, cada variante es igual a sí misma y no a las demás variantes.

Ejemplo:

#[derive(PartialEq, Drop)]
struct A {
    item: felt252
}

fn main() {
    let first_struct = A {
        item: 2
    };
    let second_struct = A {
        item: 2
    };
    assert(first_struct == second_struct, 'Structs are different');
}

Clone and Copy for Duplicating Values

El trait Clone proporciona la funcionalidad de crear explícitamente una copia profunda de un valor.

Derivar Clone implementa el método clone, que, a su vez, llama a clone en cada uno de los componentes del tipo. Esto significa que todos los campos o valores del tipo también deben implementar Clone para derivar Clone.

Ejemplo:

use clone::Clone;

#[derive(Clone, Drop)]
struct A {
    item: felt252
}

fn main() {
    let first_struct = A {
        item: 2
    };
    let second_struct = first_struct.clone();
    assert(second_struct.item == 2, 'Not equal');
}

El trait Copy permite la duplicación de valores. Puedes derivar Copy de cualquier tipo cuyas partes implementen Copy.

Ejemplo:

#[derive(Copy, Drop)]
struct A {
    item: felt252
}

fn main() {
    let first_struct = A {
        item: 2
    };
    let second_struct = first_struct;
    assert(second_struct.item == 2, 'Not equal');
    assert(first_struct.item == 2, 'Not Equal'); // Copy Trait prevents firs_struct from moving into second_struct
}

Serializing with Serde

Serde proporciona implementaciones trait para las funciones serialize y deserialize para estructuras de datos definidas en tu crate. Te permite transformar tu estructura en un array (o lo contrario).

Ejemplo:

use serde::Serde;
use array::ArrayTrait;

#[derive(Serde, Drop)]
struct A {
    item_one: felt252,
    item_two: felt252,
}

fn main() {
    let first_struct = A {
        item_one: 2,
        item_two: 99,
    };
    let mut output_array = ArrayTrait::new();
    let serialized = first_struct.serialize(ref output_array);
    panic(output_array);
}

Output:

Run panicked with [2 (''), 99 ('c'), ].

Podemos ver aquí que nuestra estructura A ha sido serializada en el array de salida.

Además, podemos utilizar la función deserialize para convertir el array serializado de nuevo en nuestra estructura A.

Ejemplo:

use serde::Serde;
use array::ArrayTrait;
use option::OptionTrait;

#[derive(Serde, Drop)]
struct A {
    item_one: felt252,
    item_two: felt252,
}

fn main() {
    let first_struct = A {
        item_one: 2,
        item_two: 99,
    };
    let mut output_array = ArrayTrait::new();
    let mut serialized = first_struct.serialize(ref output_array);
    let mut span_array = output_array.span();
    let deserialized_struct: A = Serde::<A>::deserialize(ref span_array).unwrap();
}

Aquí estamos convirtiendo un array span serializado de nuevo a la estructura A. deserialize devuelve una Option por lo que necesitamos desenvolverla. Cuando usamos deserialize también necesitamos especificar el tipo al que queremos deserializar.

Drop and Destruct

When moving out of scope, variables need to be moved first. This is where the Drop trait intervenes. You can find more details about its usage here.

Moreover Dictionary need to be squashed before going out of scope. Calling manually the squash method on each of them can be quickly redundant. Destruct trait allows Dictionaries to be automatically squashed when they get out of scope. You can also find more information about Destruct here.

Store

Storing a user-defined struct in a storage variable within a Starknet contract requires the Store trait to be implemented for this type. You can automatically derive the store trait for all structs that do not contain complex types like Dictionaries or Arrays.

Ejemplo:

#[starknet::contract]
mod contract {
    #[derive(Drop, starknet::Store)]
    struct A {
        item_one: felt252,
        item_two: felt252,
    }

    #[storage]
    struct Storage {
        my_storage: A,
    }
}

Here we demonstrate the implementation of a struct A that derives the Store trait. This struct A is subsequently used as a storage variable in the contract.

PartialOrd and Ord for Ordering Comparisons

In addition to the PartialEq trait, the standard library also provides the PartialOrd and Ord traits to compare values for ordering.

The PartialOrd trait allows for comparison between instances of a type for ordering, thereby enabling the <, <=, >, and >= operators.

When PartialOrd is derived on structs, two instances are ordered by comparing each field in turn.

Last change: 2023-09-20, commit: cbb0049