{"content":{"title":"开始使用 Cairo 1.0","body":"> * 原文链接： https://www.argent.xyz/blog/getting-started-with-cairo-1.0/\r\n> * 译文出自：[登链翻译计划](https://github.com/lbc-team/Pioneer)\r\n> * 译者：[翻译小组](https://learnblockchain.cn/people/412)  校对：[Tiny 熊](https://learnblockchain.cn/people/15)\r\n> * 本文永久链接：[learnblockchain.cn/article…](https://learnblockchain.cn/article/5427)\r\n\r\n\r\n\r\n![Getting Started With Cairo 1.0](https://img.learnblockchain.cn/2023/02/21/12962.jpeg)\r\n\r\n\r\n\r\n去年9月，StarkWare 发布了两个重要的公告，这将大大改善网络上的开发者体验。\r\n\r\n它们是：\r\n\r\n1. **Cairo 1.0：** 对Starknet的原生编程语言Cairo进行了巨大的升级，承诺为Starknet开发者提供更安全、更简单和更好的编程体验。\r\n2.  **Sierra:** 一个中间表示层，将为Cairo程序提供更大的长期稳定性。\r\n\r\n许多开发人员在使用旧版本的Cairo编写代码时面临的繁琐体验将成为过去，因为Cairo 1.0使编写代码明显变得更容易、更整洁，因为该语言变得与Rust相似。\r\n\r\n随着Cairo的这一变化，它还有一个额外的好处，就是让熟悉Rust的新开发者进入Starknet生态系统。\r\n\r\n这就是为什么Cairo 1.0，随着Sierra的引入，让Starknet开发者社区兴奋，而且是有理由的。\r\n\r\n在这篇文章中，我们将教你如何编写和编译你的第一个Cairo 1.0合约，并探索所有随着改进而来的新功能。现在，让我们一起开始吧。\r\n\r\n## 设置开发环境\r\n\r\n在我们开始写代码之前，我们需要建立开发环境。不幸的是，你*可能*熟悉的Starknet工具，如Protostar、Nile或官方Starknet CLI开发，目前不支持Cairo 1.0。这意味着我们需要使用一个替代的解决方案...\r\n\r\n我们已经解决了这个问题，通过克隆和修改官方 repo，创建了一个[Cairo 1.0的自定义开发环境](https://github.com/Darlington02/cairo1.0)。你将需要克隆这个 repo 来编写和编译你的 Cairo 1.0 合约。\r\n\r\n![设置你的Cairo 0.1开发者环境](https://img.learnblockchain.cn/2023/02/21/83203.jpeg)\r\n\r\n我们所有的合约都将被放入src文件夹。我们已经创建了一个模板合约，我们将在本文的下一节将其编译为**sierra**和**casm**。\r\n\r\n一旦我们克隆了 repo，我们就可以继续激活 Cairo 1.0 VS代码扩展来实现语法高亮。\r\n\r\n要做到这一点：\r\n\r\n1. 安装Node.js 18 LTS\r\n\r\n2. 导航到vscode-cairo文件夹中\r\n\r\n在终端中运行以下命令：\r\n\r\n```bash\r\nsudo npm install --global @vscode/vsce\r\n\r\nnpm install\r\n\r\nvsce package\r\n\r\ncode --install-extension cairo1*.vsix\r\n```\r\n\r\n3. 构建语言服务器：\r\n\r\n```bash\r\ncargo build --bin cairo-language-server --release\r\n```\r\n\r\n4. 在你的当前目录中打开Vscode\r\n\r\n运行这些命令：\r\n\r\n```bash\r\nnpm install\r\n\r\nnpm run compile\r\n```\r\n\r\n5. 最后，重新加载VScode并按F5键\r\n\r\nPS: 你应该在VScode中的**settings.json**文件中添加这个额外的代码片段，以确保事情正确运行。\r\n\r\n```\r\n\"cairo1.languageServerPath\": \"/Some/Path/target/release/cairo-language-server\",\r\n```\r\n\r\n![成功地设置你的Cairo 0.1开发环境](https://img.learnblockchain.cn/2023/02/21/44430.jpeg)\r\n\r\n如果你的安装成功了，前往**src/hello.cairo**，你应该激活了语法高亮，如上图所示。\r\n\r\n## 编译你的第一个Cairo 1.0合约\r\n\r\n在建立了开发环境之后，现在可以开始编译我们的Cairo 1.0合约。\r\n\r\n我们将使用位于**src/hello.cairo**的一个简单的合约：\r\n\r\n```cairo\r\n#[contract]\r\n\r\nmod HelloStarknet {\r\n\r\n   struct Storage {\r\n\r\n       balance: felt,\r\n\r\n   }\r\n\r\n   #[external]\r\n\r\n   fn increase_balance(amount: felt) {\r\n\r\n       balance::write(balance::read() + amount);\r\n\r\n   }\r\n\r\n   #[view]\r\n\r\n   fn get_balance() -> felt {\r\n\r\n       balance::read()\r\n\r\n   }\r\n\r\n}\r\n```\r\n\r\n这个合约实现了简单的函数来增加和获得余额变量。#[contract]标志着我们正在编写一个Starknet合约，而不是一个Cairo程序。\r\n\r\n与版本0.x合约不同的是，0.x 直接编译成Cairo汇编（casm），在Cairo 1.0中，编译我们的合约将分两个阶段进行。\r\n\r\n1. Cairo > Sierra\r\n2. Sierra > Casm\r\n\r\n**Sierra**代表安全中间表示法，旨在构成Cairo程序和其字节码之间的表示层。Sierra开启证明每个Cairo运行的可能性，从而允许强大的拒绝服务攻击（DoS）保护。\r\n\r\n要编译到Sierra，请运行下面的命令：\r\n\r\n```\r\ncargo run --bin starknet-compile -- src/hello.cairo src/hello.sierra --replace-ids\r\n```\r\n\r\n如果编译成功，你应该在你的[ src/hello.sierra](https://github.com/argentlabs/starknet-build/blob/main/cairo1.0/src/hello.sierra)中看到Sierra的输出。\r\n\r\n要进一步从Sierra编译到Casm，请运行下面的命令：\r\n\r\n```\r\ncargo run --bin starknet-sierra-compile -- src/hello.sierra src/hello.casm\r\n```\r\n\r\n如果编译成功，你应该在你的[ src/hello.casm](https://github.com/argentlabs/starknet-build/blob/main/cairo1.0/src/hello.casm)中看到casm的输出。\r\n\r\nStarknet Alpha v0.11.0还没有发布，所以我们不能把我们编译的合约部署到testnet或mainnet上。然而，这个网络升级预计将在2023年2月底发生。\r\n\r\n## 你需要了解的Cairo 1.0关键功能\r\n\r\n要想了解Cairo 1.0的所有新功能，一篇文章是不够的，但我们将在本节中探讨一些关键功能：\r\n\r\n### 一个新的语法\r\n\r\n如前所述，Cairo 1.0带有一个更干净、更好的语法，其灵感来自Rust。这包括采用类似Rust的特性，如traits和它们的实现，模式匹配，panic等。\r\n\r\n\r\n\r\n### 语言指令和导入\r\n\r\n通过Cairo 1.0，要开始编写Starknet合约，你必须指定宏：\r\n\r\n```\r\n#[contract]\r\n```\r\n\r\n虽然每个Cairo程序都必须实现一个主函数，但导入一个函数也变得更加容易。\r\n\r\n你可以像这样做：\r\n\r\n```\r\nuse starknet::get_caller_address;\r\n```\r\n\r\n另外，你也可以导入整个 \"包\"：\r\n\r\n```\r\nuse starknet;\r\n```\r\n\r\n并像这样使用它：\r\n\r\n```\r\nstarknet::get_caller_address() \r\n```\r\n\r\n### 数据类型\r\n\r\nStarknet生态系统的标志是felt数据类型，当然，它们也不会很快消失!\r\n\r\n除了felt数据类型外，还支持其他Integer类型，如u256、u128、u64、u32和u8。\r\n\r\n虽然这些Integer类型是在幕后使用felts实现的，但它们被认为使用起来更安全，现在可以支持算术运算，而不需要自定义库。例如，你现在可以执行如下操作。\r\n\r\n```\r\nlet sum = 1_u128 + 2_u128;\r\n\r\nlet product = 5_u256 * 10_u256;\r\n```\r\n\r\n这些运算符的使用是有溢出保护的，如果检测到溢出，会引起panic。\r\n\r\n还支持类似于Solidity地址的contractAddress数据类型，该类型最近才在Cairo 0.1中实现。\r\n\r\n### Type 常量\r\n\r\n数字常量，如1,2,3，默认为felt。然而，你可以通过附加数据类型为它们指定一个不同的数据类型，就像这样：\r\n\r\n```\r\nlet num_u256 = 1_u256\r\n```\r\n\r\n### 统一使用 Let 关键字\r\n\r\n在Cairo 1.0中，我们最终消除了多种变量声明模式（tempvar、local等），而只接受使用let关键字。\r\n\r\n这非常有帮助，因为我们终于告别了*撤销引用（revoked references）* 的编译器错误。\r\n\r\n现在你也可以使用**mut**关键字来创建可变的变量。\r\n\r\n### 结构和存储变量\r\n\r\nCairo 1.0没有使用@storage_var修饰器，而是将一个合约分为三个主要部分：一个存储结构、合约接口（traits）和其实现。\r\n\r\n所有的存储变量都被打包到一个名为**Storage**的结构中，尽管这可能会被改变。\r\n\r\n在写这篇文章的时候，它看起来是这样的：\r\n\r\n```\r\nstruct Storage {\r\n\r\n   name: felt,\r\n\r\n   symbol: felt,\r\n\r\n   decimals: u8,\r\n\r\n   total_supply: u256,\r\n\r\n   balances: LegacyMap::<felt, u256>,\r\n\r\n   allowances: LegacyMap::<(felt, felt), u256>,\r\n\r\n}\r\n```\r\n\r\n并可以用这种方式读或写：\r\n\r\n```\r\nlet name = name::read()\r\n\r\nlet name = name::write(_name)\r\n```\r\n\r\n可以使用LegacyMap关键字创建映射，其中映射变量的数据类型被插入到**<**和**>**之间。你也可以映射元组（tuples）。\r\n\r\n### 事件\r\n\r\n事件允许合约在其执行过程中发出信息，这些信息可以在Starknet之外使用。\r\n\r\n一个事件可以像这样创建：\r\n\r\n```\r\n#[event]\r\n\r\nfn Transfer(from_: felt, to: felt, value: u256) {}\r\n```\r\n\r\n并随后以这种方式发出:\r\n\r\n```\r\nTransfer(sender, recipient, amount);\r\n```\r\n\r\n### 函数\r\n\r\nCairo 1.0中的函数与0.x版本相似，只是省略了隐含参数，并按照Rust的惯例将func关键字改为fn。下面是一个Cairo 1.0中基本函数签名的例子:\r\n\r\n```\r\nfn balance_of(account: felt) -> u256 {\r\n\r\n   ...\r\n\r\n}\r\n```\r\n\r\n你还会注意到，返回变量不再包含变量名，而只是其数据类型。\r\n\r\n### 返回语句\r\n\r\n就像Rust一样，Cairo 1.0中的函数既可以通过省略结尾的分号来隐含地返回值，就像这样:\r\n\r\n```\r\n#[view]\r\n\r\nfn get_name() -> felt {\r\n\r\n   name::read()\r\n\r\n}\r\n```\r\n\r\n在此案例中，函数的最终表达式会自动返回，或者通过使用return关键字显式返回，像这样:\r\n\r\n```\r\n#[view]\r\n\r\nfn get_name() -> felt {\r\n\r\n   return name::read();\r\n\r\n}\r\n```\r\n\r\n### 修饰器\r\n\r\n修饰器在Cairo 1.0中仍然存在，但有一个类似于Rust的宏的新语法。\r\n\r\n你可以像这样声明一个修饰器:\r\n\r\n```\r\n#[external]\r\n\r\n#[view]\r\n```\r\n\r\n### 枚举和模式匹配\r\n\r\n枚举（Enum）是一种特殊的数据类型，由你定义的一组固定的常数组成。\r\n\r\n你可以在Cairo 1.0中创建一个Enum，像这样：\r\n\r\n```\r\nenum Animals { Goat: felt, Dog: felt, Cat: felt }\r\n```\r\n\r\nCairo 1.0 也使我们能够使用 match 关键字创建类似于 Rust 的模式匹配。当与Enum结合时，模式匹配可以让我们根据遇到的数据变量来调整函数的行为：\r\n\r\n```\r\nenum Colors { Red: felt, Green: felt, Blue: felt }\r\n\r\nfunc get_favorite_color() -> Colors {\r\n\r\n   Colors::Green(0)\r\n\r\n}\r\n\r\nfunc main() -> felt {\r\n\r\n   let my_color = get_favorite_color();\r\n\r\n   let result = match my_color {\r\n\r\n       Colors::Red(_) => {\r\n\r\n           1\r\n\r\n       },\r\n\r\n       Colors::Green(_) => {\r\n\r\n           2\r\n\r\n       },\r\n\r\n       Colors::Blue(_) => {\r\n\r\n           3\r\n\r\n       },\r\n\r\n   };\r\n\r\n   result // returns 2\r\n\r\n}\r\n```\r\n\r\n### 数组\r\n\r\nCairo 1.0使数组操作变得更加容易，因为核心库除了导出一个数组类型外，还有一些相关的函数，如**append**, **array_at**, 和**array_len**。一些基本的数组操作包括向现有的数组添加新元素，获得元素索引，获得数组长度等。这些都可以通过[ArrayTrait](https://github.com/starkware-libs/cairo/blob/main/corelib/array.cairo#L11)访问。\r\n\r\n```\r\nfn fib(n: usize) -> (Array::<felt>, felt, usize) {\r\n\r\n   let mut arr = ArrayTrait::new();\r\n\r\n   arr.append(1);\r\n\r\n   arr.append(1);\r\n\r\n   let mut arr = fib_inner(:n, :arr);\r\n\r\n   let len = arr.len();\r\n\r\n   let last = arr.at(len - 1_usize);\r\n\r\n   return (arr, last, len);\r\n\r\n}\r\n```\r\n\r\n### 错误信息和访问控制\r\n\r\n你可以在Cairo中创建自定义错误，在执行失败时输出给用户。这对于实现检查和适当的访问控制机制非常有用。\r\n\r\n在Cairo 1.0中，你可以很容易地使用assert语句来做到这一点，其模式与Solidity中的require语句相似。\r\n\r\n```\r\nassert(sender != 0, 'ERC20: transfer from 0');\r\n```\r\n\r\n其中错误信息必须小于31个字符。\r\n\r\n### Traits 及其实现\r\n\r\nCairo 1.0引入了traits和实现。把traits看作是一种特殊的合约接口，因为它们定义了一个特定类型的功能，并且可以与其他类型共享。它们是用**trait**关键字定义的：\r\n\r\n```\r\ntrait IContract{\r\n\r\n   fn set_something(num: felt, pair: felt);\r\n\r\n   fn get_something(num: felt) -> felt;\r\n\r\n}\r\n```\r\n\r\n\r\n\r\n另一方面，一个实现了特定的trait行为的实现中，需要包含 trait中的所有定义函数。\r\n\r\n它们是用**impl**关键字定义的，像这样：\r\n\r\n```\r\nimpl Contract of IContract {\r\n\r\n   fn set_something(num: felt, pair: felt) {\r\n\r\n       number_pair::write(num, pair)\r\n\r\n   }\r\n\r\n   fn get_something(num: felt) -> felt {\r\n\r\n       number_pair::read(num)\r\n\r\n   }\r\n\r\n}\r\n```\r\n\r\n### 泛型\r\n\r\nCairo 1.0与Rust类似，也支持泛型，这使你能够编写灵活的代码，可以与多种类型一起工作，而不是被束缚在一个特定的类型上。\r\n\r\n一个类型参数通过使用角括号<>来指定为泛型，像这样：\r\n\r\n```\r\nfn foo<T>(arg: T) -> T {\r\n    …\r\n }\r\n```\r\n\r\n### Replace_class sysall\r\n\r\n在Cairo 1.0和Starknet v0.11中，将增加一个新的syscall，使你能够在不改变合约的入口点的情况下交换底层的合约实现（class hash）。想想看，一个默认的代理!\r\n\r\n最重要的是，你只需用一行代码就可以做到这一点：\r\n\r\n```\r\n#[contract]\r\n\r\nmod upgradeable {\r\n\tuse starknet::replace_class;\r\n\t\r\n.\t….\r\n\r\n\t#[external]\r\n\tfn upgradeable(cls_hash: felt) {\r\n\t\treplace_class(cls_hash);\r\n\t}\r\n}\r\n```\r\n\r\n## 结论\r\n\r\n恭喜你，你刚刚编写并编译了你的第一个Cairo 1.0合约，并了解了Cairo 1.0的关键特性\r\n\r\n再次强调，Cairo 1.0仍然是一项正在进行中的工作，而且发展很快。新的功能每天都在增加，所以要经常查看[官方版本](https://github.com/starkware-libs/cairo)和[Discord讨论频道](https://discord.com/channels/793094838509764618/1065544063245365288)，以保持最新的信息!\r\n\r\n这里有一些额外的资源，我们认为会对你的Cairo 0.10之旅有所帮助。\r\n\r\n1. [Cairo1.0初探： 一个更安全、更强大、更简单的可验证编程语言](https://medium.com/nethermind-eth/a-first-look-at-cairo-1-0-a-safer-stronger-simpler-provable-programming-language-892ce4c07b38)\r\n2. [Cairo 1.0--变化、特性、发布日期](https://extropy-io.medium.com/cairo-1-0-changes-features-release-date-15a266d7b919)\r\n3. https://github.com/starkware-libs/cairo/blob/main/docs/reference/src/SUMMARY.adoc\r\n\r\n4. https://github.com/argentlabs/starknet-build/tree/main/cairo1.0/examples\r\n5. [Cairo 1.0 by StarkWare](https://medium.com/starkware/cairo-1-0-aa96eefb19a0#:~:text=Introducing Sierra%3A ensuring every Cairo run can be proven)\r\n\r\n如果你对此有任何问题，请联系我[@0xdarlington](https://twitter.com/0xdarlington)，我很乐意帮助你用Argent X建立Starknet。"},"author":{"user":"https://learnblockchain.cn/people/412","address":null},"history":"QmVorjzvHswTD475GivKtrRQ3erqfZLQHDaLccMJnT1gHK","timestamp":1676952083,"version":1}