Skip to content

Commit

Permalink
Merge pull request #6 from Web3-Club/yanboishere-patch-4
Browse files Browse the repository at this point in the history
Update ch02-01-variables-and-mutability.md
  • Loading branch information
yanboishere committed Jun 15, 2023
2 parents cb8dc59 + 060a7ed commit bbe1dcb
Showing 1 changed file with 45 additions and 43 deletions.
88 changes: 45 additions & 43 deletions src/ch02-01-variables-and-mutability.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,28 @@ Cairo使用不可变的内存模型,这意味着一旦写入内存单元,就
当变量是不可变的时,一旦将一个值绑定到一个名称,就无法更改该值。为了说明这一点,在cairo_projects目录中生成一个名为variables的新项目,使用命令scarb new variables。

然后,在您的新variables目录中,打开src/lib.cairo文件并将其代码替换为以下代码,该代码目前无法编译:
use debug::PrintTrait;
fn main() {
let x = 5;
x.print();
x = 6;
x.print();
}

use debug::PrintTrait;
fn main() {
let x = 5;
x.print();
x = 6;
x.print();
}

保存并使用cairo-run src/lib.cairo运行程序。您应该会收到有关不可变性错误的错误消息,如以下输出所示:

error: Cannot assign to an immutable variable.
--> lib.cairo:5:5
x = 6;
^***^
error: Cannot assign to an immutable variable.
--> lib.cairo:5:5
x = 6;
^***^

Error: failed to compile: src/lib.cairo
Error: failed to compile: src/lib.cairo


该示例演示了编译器如何帮助您查找程序中的错误。编译器错误可能让人沮丧,但它们只意味着您的程序尚未安全地执行所需的操作;它们不意味着您不是一个好的程序员!经验丰富的Caironautes仍然会出现编译器错误。

您收到了错误消息Cannot assign to an immutable variable.,因为您尝试为不可变x变量分配第二个值。
您收到了错误消息 Cannot assign to an immutable variable. ,因为您尝试为不可变x变量分配第二个值。

当我们试图更改被指定为不可变的值时,获得编译时错误非常重要,因为这种情况可能导致错误。如果我们的代码的一部分在假设一个值永远不会改变,而我们的代码的另一部分更改了该值,那么这种错误的原因可能在事后很难追踪,特别是当第二段代码只有有时更改该值时。 Cairo编译器保证了当您声明一个值不会改变时,它确实不会改变,因此您不必自己跟踪它。因此,您的代码更容易推理。

Expand All @@ -34,20 +35,21 @@ Error: failed to compile: src/lib.cairo
然而,此时您可能会想知道当一个变量被声明为mut时到底发生了什么,因为我们之前提到Cairo的内存是不可变的。答案是,Cairo的内存是不可变的,但是变量指向的内存地址可以更改。在检查低级Cairo汇编代码时,变量突变被实现为语法糖,它将变异操作转换为等效于变量遮蔽的一系列步骤。唯一的区别是在Cairo级别,变量没有被重新声明,因此它的类型不能改变。

例如,让我们将src/lib.cairo更改为以下内容:
use debug::PrintTrait;
fn main() {
let mut x = 5;
x.print();
x = 6;
x.print();
}

现在运行该程序,我们会得到以下输出:
[DEBUG] (raw: 5)

[DEBUG] (raw: 6)
use debug::PrintTrait;
fn main() {
let mut x = 5;
x.print();
x = 6;
x.print();
}

Run completed successfully, returning []
现在运行该程序,我们会得到以下输出:
[DEBUG] (raw: 5)

[DEBUG] (raw: 6)

Run completed successfully, returning []

当使用mut时,我们被允许将x绑定的值从5更改为6。最终,决定是否使用可变性取决于您,这取决于您认为在特定情况下最清晰的内容。

Expand Down Expand Up @@ -98,31 +100,31 @@ Cairo对常量的命名惯例是使用所有大写字母,并在单词之间使
变量屏蔽与将变量标记为mut不同,因为如果意外尝试重新分配给此变量而不使用let关键字,我们将获得编译时错误。使用let,我们可以对值执行一些转换,但在完成这些转换后,变量必须是不可变的。
mut和遮蔽之间的另一个区别是,当我们再次使用let关键字时,我们实际上正在创建一个新变量,这允许我们改变值的类型,同时重用相同的名称。如前所述,变量屏蔽和可变变量在较低级别上是等效的。唯一的区别是通过变量屏蔽,如果您更改其类型,编译器不会抱怨变量。例如,假设我们的程序在u64和felt252类型之间执行类型转换。

let x = 2;
x.print();
let x: felt252 = x.into(); // converts x to a felt, type annotation is required.
x.print()
let x = 2;
x.print();
let x: felt252 = x.into(); // converts x to a felt, type annotation is required.
x.print()


第一个 x 变量具有 u64 类型,而第二个变量 x 具有 felt252 类型。因此,使用变量屏蔽可以避免我们必须想出不同的名称,例如 x_u64 和 x_felt252;相反,我们可以重用更简单的 x 名称。然而,如果我们尝试在此处使用 mut,则会在编译时出现错误:

use debug::PrintTrait;
use traits::Into;
fn main() {
let mut x = 2;
x.print();
x = x.into();
x.print()
}

use debug::PrintTrait;
use traits::Into;
fn main() {
let mut x = 2;
x.print();
x = x.into();
x.print()
}

错误信息表明我们期望取得一个 u64(原始类型),但我们获得了一个不同的类型:

error: Unexpected argument type. Expected: "core::integer::u64", found: "core::felt252".
--> lib.cairo:6:9
x = x.into();
^******^
Error: failed to compile: src/lib.cairo
error: Unexpected argument type. Expected: "core::integer::u64", found: "core::felt252".
--> lib.cairo:6:9
x = x.into();
^******^
Error: failed to compile: src/lib.cairo


现在,我们已经探讨了变量的工作方式,让我们来看一下它们可以具有的更多数据类型。

0 comments on commit bbe1dcb

Please sign in to comment.