使用 use
关键字将路径引入作用域
不得不编写路径来调用函数显得不便且重复。幸运的是,有一种方法可以简化这个过程:我们可以用use
关键字创建一个路径的快捷方式,然后在作用域内的其他地方使用这个较短的名字。
在示例7-5中,我们把restaurant::front_of_house::hosting
模块带入到作用域内,所以我们只需要指定 hosting::add_to_waitlist
来调用eat_at_restaurant
中的add_to_waitlist
函数。
文件名: 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 } }
在作用域中添加 use 和路径类似于在文件系统中创建一个软连接(符号连接,symbolic link)。通过在 crate 根中添加 use restaurant::front_of_house::hosting
,hosting 现在是该作用域中的一个有效名称,就像在 crate 根中定义了hosting
模块一样。
注意 use
只能创建 use
所在的特定作用域内的短路径。示例 7-6 将 eat_at_restaurant
函数移到一个新的子模块中,这又是一个不同于 use
语句的作用域,所以函数体不能编译:
文件名: 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(); } } }
编译器错误显示短路径不在适用于 customer
模块中:
❯ scarb build
error: Identifier not found.
--> lib.cairo:11:9
hosting::add_to_waitlist();
^*****^
创建惯用的 use
路径
在示例6-5中,你可能想知道为什么我们指定restaurant::front_of_house::hosting
,然后调用eat_at_restaurant
中的hosting::add_to_waitlist
,而不是通过指定一直到
add_to_waitlist
函数的 use
路径来得到相同的结果,如示例7-7。
文件名: 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(); } }
尽管示例7-5和7-7都完成了相同的任务,但示例 7-5 是使用 use 将函数引入作用域的习惯用法。要想使用 use
将函数的父模块引入作用域,我们必须在调用函数时指定父模块,这样可以清晰地表明函数不是在本地定义的,同时使完整路径的重复度最小化。示例 7-7 中的代码不清楚 add_to_waitlist
是在哪里被定义的。
另一方面,使用 use
引入结构体、枚举和其他项时,习惯是指定它们的完整路径。示例 7-8 展示了将核心库的 ArrayTrait
trait带入作用域。
fn main() { let mut arr = ArrayTrait::new(); arr.append(1); }
这种习惯用法背后没有什么硬性要求:它只是一种惯例,人们已经习惯了以这种方式阅读和编写 Rust 代码。它只是在Rust社区中出现的惯例。 由于Cairo与Rust共享许多惯例,我们也遵循这一惯例。
这个习惯用法有一个例外,那就是我们想使用 use
语句将两个具有相同名称的项带入作用域,因为Cairo不允许这样做。
使用 as 关键字提供新的名称
使用 use
将两个同名类型引入同一作用域这个问题还有另一个解决办法:在这个类型的路径后面,我们使用 as
指定一个新的本地名称或者别名( alias )。示例7-9显示了如何用as
重命名一个导入:
文件名: src/lib.cairo
use array::ArrayTrait as Arr; fn main() { let mut arr = Arr::new(); // ArrayTrait was renamed to Arr arr.append(1); }
在这里,我们用别名Arr
将ArrayTrait
带入作用域。现在我们可以用Arr
标识符来访问该trait的方法。
从同一模块中导入多个项
当你想从同一个模块中导入多个项(如函数、结构体或枚举)时,
你可以使用大括号{}
来列出所有你想导入的项目。
避免了一长串单独的use
有助于保持你的代码整洁和便于阅读。
从同一模块导入多个项的常见语法是:
#![allow(unused)] fn main() { use module::{item1, item2, item3}; }
下面是一个从同一个模块导入三个结构体的例子:
// 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 }; // ... }
在模块文件中重导出名称
当我们用use
关键字将一个名字带入作用域时,在新的作用域中也能够正常使用这个名称,就好像它本来就在当前作用域一样。
这种技术被称为 重导出( re-exporting ),因为我们将一个项目带入作用域、但同时也使这个项目可以被其他人带入他们的作用域。
下面这个例子,让我们重新导出餐厅例子中的add_to_waitlist
函数:
文件名: 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(); } }
在这个修改之前,外部代码需要使用路径 restaurant::front_of_house::hosting::add_to_waitlist()
来调用 add_to_waitlist
函数。
现在这个 use
从根模块重导出了 hosting
模块,外部代码现在可以使用路径 restaurant::hosting::add_to_waitlist()
。
当你代码的内部结构与调用你代码的程序员所想象的结构不同时,重导出会很有用。
例如,在这个餐馆的比喻中,经营餐馆的人会想到“前台”和“后台”。但顾客在光顾一家餐馆时,可能不会以这些术语来考虑餐馆的各个部分。
使用 use
,我们可以使用一种结构编写代码,却将不同的结构形式暴露出来。这样做使我们的库井井有条,也使开发这个库的程序员和调用这个库的程序员都更加方便。
在Cairo使用外部包与Scarb
你可能需要使用外部包来利用社区提供的功能。要在你的项目中使用Scarb的外部包,请遵循以下步骤:
依赖关系系统仍然是一项正在进行的工作。你可以查看官方的文档。