Bringing Paths into Scope with the use
Keyword
Tener que escribir las rutas para llamar a las funciones puede resultar incómodo y repetitivo. Afortunadamente, hay una manera de simplificar este proceso: podemos crear un acceso directo a una ruta con la palabra clave use
una vez, y luego utilizar el nombre más corto en todas partes en el ámbito.
In Listing 7-5, we bring the restaurant::front_of_house::hosting
module into the
scope of the eat_at_restaurant
function so we only have to specify
hosting::add_to_waitlist
to call the add_to_waitlist
function in
eat_at_restaurant
.
Filename: src/lib.cairo
#![allow(unused)] fn main() { // Assuming "front_of_house" module is contained in a crate called "restaurant", as mentioned in the section "Defining Modules to Control Scope" // If the path is created in the same crate, "restaurant" is optional in the use statement mod front_of_house { mod hosting { fn add_to_waitlist() {} } } use restaurant::front_of_house::hosting; fn eat_at_restaurant() { hosting::add_to_waitlist(); // ✅ Shorter path } }
Añadir use y una ruta en un ámbito es similar a crear un enlace simbólico en el sistema de ficheros. Al añadir use restaurant::front_of_house::hosting
en la raíz de crate, hosting es ahora un nombre válido en ese ámbito, como si el módulo hosting
se hubiera definido en la raíz de un crate.
Note that use
only creates the shortcut for the particular scope in which the use
occurs. Listing 7-6 moves the eat_at_restaurant
function into a new
child module named customer
, which is then a different scope than the use
statement, so the function body won’t compile:
Filename: src/lib.cairo
#![allow(unused)] fn main() { mod front_of_house { mod hosting { fn add_to_waitlist() {} } } use restaurant::front_of_house::hosting; mod customer { fn eat_at_restaurant() { hosting::add_to_waitlist(); } } }
The compiler error shows that the shortcut no longer applies within the
customer
module:
❯ scarb build
error: Identifier not found.
--> lib.cairo:11:9
hosting::add_to_waitlist();
^*****^
Creating Idiomatic use
Paths
In Listing 7-5, you might have wondered why we specified use restaurant::front_of_house::hosting
and then called hosting::add_to_waitlist
in
eat_at_restaurant
rather than specifying the use
path all the way out to
the add_to_waitlist
function to achieve the same result, as in Listing 7-7.
Filename: src/lib.cairo
#![allow(unused)] fn main() { mod front_of_house { mod hosting { fn add_to_waitlist() {} } } use restaurant::front_of_house::hosting::add_to_waitlist; fn eat_at_restaurant() { add_to_waitlist(); } }
Although both Listing 7-5 and 6-7 accomplish the same task, Listing 7-5 is
the idiomatic way to bring a function into scope with use
. Bringing the
function’s parent module into scope with use
means we have to specify the
parent module when calling the function. Specifying the parent module when
calling the function makes it clear that the function isn’t locally defined
while still minimizing repetition of the full path. The code in Listing 7-7 is
unclear as to where add_to_waitlist
is defined.
On the other hand, when bringing in structs, enums, traits, and other items with use
,
it’s idiomatic to specify the full path. Listing 7-8 shows the idiomatic way
to bring the core library’s ArrayTrait
trait into the scope.
fn main() { let mut arr = ArrayTrait::new(); arr.append(1); }
There’s no strong reason behind this idiom: it’s just the convention that has emerged in the Rust community, and folks have gotten used to reading and writing Rust code this way. As Cairo shares many idioms with Rust, we follow this convention as well.
The exception to this idiom is if we’re bringing two items with the same name
into scope with use
statements, because Cairo doesn’t allow that.
Providing New Names with the as
Keyword
There’s another solution to the problem of bringing two types of the same name
into the same scope with use
: after the path, we can specify as
and a new
local name, or alias, for the type. Listing 7-9 shows how you can rename an import with as
:
Filename: src/lib.cairo
use array::ArrayTrait as Arr; fn main() { let mut arr = Arr::new(); // ArrayTrait was renamed to Arr arr.append(1); }
En este caso, hemos introducido ArrayTrait
en el ámbito con el alias Arr
. Ahora podemos acceder a los métodos del rasgo con el identificador Arr
.
Importing multiple items from the same module
When you want to import multiple items (like functions, structs or enums)
from the same module in Cairo, you can use curly braces {}
to list all of
the items that you want to import. This helps to keep your code clean and easy
to read by avoiding a long list of individual use statements.
La sintaxis general para importar varios elementos del mismo módulo es:
#![allow(unused)] fn main() { use module::{item1, item2, item3}; }
He aquí un ejemplo en el que importamos tres estructuras del mismo módulo:
// Assuming we have a module called `shapes` with the structures `Square`, `Circle`, and `Triangle`. mod shapes { #[derive(Drop)] struct Square { side: u32 } #[derive(Drop)] struct Circle { radius: u32 } #[derive(Drop)] struct Triangle { base: u32, height: u32, } } // We can import the structures `Square`, `Circle`, and `Triangle` from the `shapes` module like this: use shapes::{Square, Circle, Triangle}; // Now we can directly use `Square`, `Circle`, and `Triangle` in our code. fn main() { let sq = Square { side: 5 }; let cr = Circle { radius: 3 }; let tr = Triangle { base: 5, height: 2 }; // ... }
Re-exporting Names in Module Files
When we bring a name into scope with the use
keyword, the name available in
the new scope can be imported as if it had been defined in that code’s scope.
This technique is called re-exporting because we’re bringing an item into scope,
but also making that item available for others to bring into their scope.
Por ejemplo, reexportemos la función add_to_waitlist
del ejemplo del restaurante:
Filename: src/lib.cairo
#![allow(unused)] fn main() { mod front_of_house { mod hosting { fn add_to_waitlist() {} } } use restaurant::front_of_house::hosting; fn eat_at_restaurant() { hosting::add_to_waitlist(); } }
Before this change, external code would have to call the add_to_waitlist
function by using the path
restaurant::front_of_house::hosting::add_to_waitlist()
. Now that this use
has re-exported the hosting
module from the root module, external code
can now use the path restaurant::hosting::add_to_waitlist()
instead.
Re-exporting is useful when the internal structure of your code is different
from how programmers calling your code would think about the domain. For
example, in this restaurant metaphor, the people running the restaurant think
about “front of house” and “back of house.” But customers visiting a restaurant
probably won’t think about the parts of the restaurant in those terms. With
use
, we can write our code with one structure but expose a different
structure. Doing so makes our library well organized for programmers working on
the library and programmers calling the library.
Using External Packages in Cairo with Scarb
Puede que necesite utilizar paquetes externos para aprovechar la funcionalidad proporcionada por la comunidad. Para utilizar un paquete externo en su proyecto con Scarb, siga estos pasos:
The dependencies system is still a work in progress. You can check the official documentation.