diff --git a/.all-contributorsrc b/.all-contributorsrc index a872eb5e2..54daa6dcc 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -123,6 +123,42 @@ "contributions": [ "code" ] + }, + { + "login": "tiagofneto", + "name": "Tiago Neto", + "avatar_url": "https://avatars.githubusercontent.com/u/46165861?v=4", + "profile": "https://github.com/tiagofneto", + "contributions": [ + "review" + ] + }, + { + "login": "omahs", + "name": "omahs", + "avatar_url": "https://avatars.githubusercontent.com/u/73983677?v=4", + "profile": "https://github.com/omahs", + "contributions": [ + "code" + ] + }, + { + "login": "shramee", + "name": "Shramee Srivastav", + "avatar_url": "https://avatars.githubusercontent.com/u/11048263?v=4", + "profile": "http://shramee.me", + "contributions": [ + "code" + ] + }, + { + "login": "dbejarano820", + "name": "Daniel Bejarano", + "avatar_url": "https://avatars.githubusercontent.com/u/58019353?v=4", + "profile": "https://github.com/dbejarano820", + "contributions": [ + "code" + ] } ], "contributorsPerLine": 7, diff --git a/.github/workflows/cairo-verify/action.yml b/.github/workflows/cairo-verify/action.yml new file mode 100644 index 000000000..5bbe4ea77 --- /dev/null +++ b/.github/workflows/cairo-verify/action.yml @@ -0,0 +1,19 @@ +name: Cairo Verify + +description: Run the cairo-verify tools on all cairo programs in the book. + +runs: + using: composite + steps: + - uses: actions/checkout@v3 + - uses: software-mansion/setup-scarb@v1 + with: + scarb-version: "0.7.0" + + - name: Install cairo-verify + run: cargo install --path cairo-verify --locked + shell: bash + + - name: Run cairo-verify and generate summary + run: cairo-verify >> $GITHUB_STEP_SUMMARY + shell: bash diff --git a/.github/workflows/install-mdbook/action.yml b/.github/workflows/install-mdbook/action.yml index bb582001b..438b2116c 100644 --- a/.github/workflows/install-mdbook/action.yml +++ b/.github/workflows/install-mdbook/action.yml @@ -7,13 +7,13 @@ runs: steps: # The --locked flag is important for reproducible builds. - name: Install mdbook - run: cargo install mdbook --locked --version 0.4.28 + run: cargo install mdbook --locked --version 0.4.31 shell: bash - name: Install mdbook-i18n-helpers run: cargo install mdbook-i18n-helpers --locked --version 0.1.0 shell: bash - - name: Install cairo programs verifier + - name: Install mdbook-cairo preprocessor run: cargo install --path mdbook-cairo --locked shell: bash diff --git a/.github/workflows/mdbook.yml b/.github/workflows/mdbook.yml index f02c9a503..99d85c812 100644 --- a/.github/workflows/mdbook.yml +++ b/.github/workflows/mdbook.yml @@ -36,6 +36,9 @@ jobs: - name: Setup Rust cache uses: ./.github/workflows/setup-rust-cache + - name: Cairo Verify + uses: ./.github/workflows/cairo-verify + - name: Install mdbook uses: ./.github/workflows/install-mdbook @@ -43,26 +46,27 @@ jobs: run: | mdbook build -d book + - name: Copy WASM-Cairo pkg + run: | + cp -r theme/pkg book + cp -r theme/js book + - name: Build all translations run: | for po_lang in $(cat ./LANGUAGES); do echo "::group::Building $po_lang translation" MDBOOK_BOOK__LANGUAGE=$po_lang \ mdbook build -d book/$po_lang - mv book/$po_lang/html book/html/$po_lang echo "::endgroup::" done - # - name: Verify Cairo programs - # uses: ./.github/workflows/verify-cairo-programs - - name: Setup Pages uses: actions/configure-pages@v3 - name: Upload artifact uses: actions/upload-pages-artifact@v1 with: - path: ./book/html + path: ./book - name: Deploy to GitHub Pages id: deployment diff --git a/.github/workflows/verify-cairo-programs/action.yml b/.github/workflows/verify-cairo-programs/action.yml deleted file mode 100644 index 1e727bf2a..000000000 --- a/.github/workflows/verify-cairo-programs/action.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: Verify Cairo programs compilation - -description: Verify if all Cairo programs extracted from markdown can be compiled. - -runs: - using: composite - steps: - - name: Copy Cairo program verifier script - shell: bash - run: | - cp mdbook-cairo/scripts/cairo_programs_verifier.sh book/cairo/cairo-programs/ - - - name: Verify Cairo programs - uses: addnab/docker-run-action@v3 - with: - image: starknet/cairo:1.1.0 - options: -v ${{ github.workspace }}/book/cairo/cairo-programs:/cairo - run: | - sh /cairo/cairo_programs_verifier.sh false > /cairo/summary.md - - - name: Generate job summary - shell: bash - run: cat book/cairo/cairo-programs/summary.md >> $GITHUB_STEP_SUMMARY - if: always() diff --git a/.github/workflows/verify_programs.yml b/.github/workflows/verify_programs.yml new file mode 100644 index 000000000..7ed1432c1 --- /dev/null +++ b/.github/workflows/verify_programs.yml @@ -0,0 +1,30 @@ +name: Verify Cairo programs compilation + +on: + pull_request: + branches: + - main + +jobs: + compile_and_verify: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + + - name: Setup Scarb + uses: software-mansion/setup-scarb@v1 + with: + scarb-version: "0.7.0" + + - name: Setup Rust cache + uses: ./.github/workflows/setup-rust-cache + + - name: Install cairo-verify + run: cargo install --path cairo-verify --locked + shell: bash + + - name: Run cairo-verify and generate summary + run: cairo-verify >> $GITHUB_STEP_SUMMARY + shell: bash diff --git a/.github/workflows/verify_programs.yml.old b/.github/workflows/verify_programs.yml.old deleted file mode 100644 index 0303d9925..000000000 --- a/.github/workflows/verify_programs.yml.old +++ /dev/null @@ -1,42 +0,0 @@ -name: Verify Cairo programs compilation - -on: - pull_request: - branches: - - main - -jobs: - compile_and_verify: - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v3 - - - name: Setup Rust cache - uses: ./.github/workflows/setup-rust-cache - - - name: Install mdbook - uses: ./.github/workflows/install-mdbook - - - name: Build in English - run: | - mdbook build -d book - - - name: Copy Cairo program verifier script - run: | - cp mdbook-cairo/scripts/cairo_programs_verifier.sh book/cairo/cairo-programs/ - shell: bash - - - name: Verify Cairo programs - uses: addnab/docker-run-action@v3 - with: - image: starknet/cairo:1.1.0 - options: -v ${{ github.workspace }}/book/cairo/cairo-programs:/cairo - run: | - sh /cairo/cairo_programs_verifier.sh false > /cairo/summary.md - - - name: Generate job summary - run: cat book/cairo/cairo-programs/summary.md >> $GITHUB_STEP_SUMMARY - shell: bash - if: always() diff --git a/.gitignore b/.gitignore index f1797da84..e9cb13199 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ output # Editors tmp files. *~ +.idea/ diff --git a/.tool-versions b/.tool-versions new file mode 100644 index 000000000..2175a337d --- /dev/null +++ b/.tool-versions @@ -0,0 +1 @@ +scarb 0.7.0 diff --git a/Cargo.lock b/Cargo.lock index e4fdc74be..5a9f8d79d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -13,9 +13,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" dependencies = [ "memchr", ] @@ -33,6 +33,12 @@ dependencies = [ "url", ] +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + [[package]] name = "android_system_properties" version = "0.1.5" @@ -59,15 +65,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ed9a86bf92ae6580e0a31281f65a1b1d867c0cc68d5346e2ae128dddfa6a7d" +checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" [[package]] name = "anstyle-parse" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e765fd216e48e067936442276d1d57399e37bce53c264d6fefbe298080cb57ee" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" dependencies = [ "utf8parse", ] @@ -97,6 +103,17 @@ version = "1.0.71" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + [[package]] name = "autocfg" version = "1.1.0" @@ -111,9 +128,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.0" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" [[package]] name = "bitflags" @@ -132,9 +149,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09" +checksum = "a246e68bb43f6cd9db24bea052a53e40405417c5fb372e3d1a8a7f770a564ef5" dependencies = [ "memchr", "once_cell", @@ -144,9 +161,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.12.2" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "byteorder" @@ -160,6 +177,21 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +[[package]] +name = "cairo-verify" +version = "0.1.0" +dependencies = [ + "clap", + "colored", + "env_logger", + "indicatif", + "lazy_static", + "log", + "regex", + "serde", + "walkdir", +] + [[package]] name = "cc" version = "1.0.79" @@ -174,30 +206,32 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.24" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" dependencies = [ + "android-tzdata", "iana-time-zone", - "num-integer", "num-traits", "winapi", ] [[package]] name = "clap" -version = "4.2.7" +version = "4.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34d21f9bf1b425d2968943631ec91202fe5e837264063503708b83013f8fc938" +checksum = "2686c4115cb0810d9a984776e197823d08ec94f176549a89a9efded477c456dc" dependencies = [ "clap_builder", + "clap_derive", + "once_cell", ] [[package]] name = "clap_builder" -version = "4.2.7" +version = "4.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "914c8c79fb560f238ef6429439a30023c862f7a28e688c58f7203f12b29970bd" +checksum = "2e53afce1efce6ed1f633cf0e57612fe51db54a1ee4fd8f8503d078fe02d69ae" dependencies = [ "anstream", "anstyle", @@ -210,18 +244,30 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.2.3" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1594fe2312ec4abf402076e407628f5c313e54c32ade058521df4ee34ecac8a8" +checksum = "7f6b5c519bab3ea61843a7923d074b04245624bb84a64a8c150f5deb014e388b" dependencies = [ "clap", ] +[[package]] +name = "clap_derive" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.18", +] + [[package]] name = "clap_lex" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" [[package]] name = "colorchoice" @@ -229,6 +275,30 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + +[[package]] +name = "console" +version = "0.15.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys 0.45.0", +] + [[package]] name = "core-foundation-sys" version = "0.8.4" @@ -237,9 +307,9 @@ checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "cpufeatures" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" dependencies = [ "libc", ] @@ -256,9 +326,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", ] @@ -275,9 +345,9 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "crypto-common", @@ -295,6 +365,12 @@ dependencies = [ "serde_json", ] +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + [[package]] name = "env_logger" version = "0.10.0" @@ -358,9 +434,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] @@ -408,7 +484,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.18", ] [[package]] @@ -450,9 +526,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", @@ -536,6 +612,21 @@ dependencies = [ "http", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "hermit-abi" version = "0.2.6" @@ -631,9 +722,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -654,9 +745,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -689,6 +780,19 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "indicatif" +version = "0.17.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ff8cc23a7393a397ed1d7f56e6365cba772aba9f9912ab968b03043c395d057" +dependencies = [ + "console", + "instant", + "number_prefix", + "portable-atomic", + "unicode-width", +] + [[package]] name = "inotify" version = "0.9.6" @@ -720,9 +824,9 @@ dependencies = [ [[package]] name = "io-lifetimes" -version = "1.0.10" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi 0.3.1", "libc", @@ -749,9 +853,9 @@ checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "js-sys" -version = "0.3.62" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68c16e1bfd491478ab155fd8b4896b86f9ede344949b641e61501e07c2b8b4d5" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -784,21 +888,21 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.144" +version = "0.2.146" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" [[package]] name = "linux-raw-sys" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -806,12 +910,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "mac" @@ -841,9 +942,9 @@ dependencies = [ [[package]] name = "mdbook" -version = "0.4.29" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d317294c6e3d7f9d2e60dfd20932bec627f86c76ec101a5da0110fc0fbe06266" +checksum = "7b67ee4a744f36e6280792016c17e69921b51df357181d1eb17d620fcc3609f3" dependencies = [ "ammonia", "anyhow", @@ -875,14 +976,14 @@ dependencies = [ [[package]] name = "mdbook-cairo" -version = "0.1.0" +version = "0.2.0" dependencies = [ + "clap", "lazy_static", "mdbook", - "pulldown-cmark", "regex", - "serde", - "serde_derive", + "semver", + "serde_json", ] [[package]] @@ -909,14 +1010,14 @@ dependencies = [ [[package]] name = "mio" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", "log", "wasi", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -927,9 +1028,9 @@ checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" [[package]] name = "notify" -version = "5.1.0" +version = "5.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58ea850aa68a06e48fdb069c0ec44d0d64c8dbffa49bf3b6f7f0a901fdea1ba9" +checksum = "729f63e1ca555a43fe3efa4f3efdf4801c479da85b432242a7b726f353c88486" dependencies = [ "bitflags", "crossbeam-channel", @@ -940,7 +1041,7 @@ dependencies = [ "libc", "mio", "walkdir", - "windows-sys 0.42.0", + "windows-sys 0.45.0", ] [[package]] @@ -953,16 +1054,6 @@ dependencies = [ "notify", ] -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - [[package]] name = "num-traits" version = "0.2.15" @@ -982,11 +1073,17 @@ dependencies = [ "libc", ] +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "opener" @@ -1010,28 +1107,28 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.2.16", + "redox_syscall 0.3.5", "smallvec", - "windows-sys 0.45.0", + "windows-targets 0.48.0", ] [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e68e84bfb01f0507134eac1e9b410a12ba379d064eab48c50ba4ce329a527b70" +checksum = "f73935e4d55e2abf7f130186537b19e7a4abc886a0252380b59248af473a3fc9" dependencies = [ "thiserror", "ucd-trie", @@ -1039,9 +1136,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b79d4c71c865a25a4322296122e3924d30bc8ee0834c8bfc8b95f7f054afbfb" +checksum = "aef623c9bbfa0eedf5a0efba11a5ee83209c326653ca31ff019bec3a95bfff2b" dependencies = [ "pest", "pest_generator", @@ -1049,22 +1146,22 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c435bf1076437b851ebc8edc3a18442796b30f1728ffea6262d59bbe28b077e" +checksum = "b3e8cba4ec22bada7fc55ffe51e2deb6a0e0db2d0b7ab0b103acc80d2510c190" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.18", ] [[package]] name = "pest_meta" -version = "2.6.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "745a452f8eb71e39ffd8ee32b3c5f51d03845f99786fa9b68db6ff509c505411" +checksum = "a01f71cb40bd8bb94232df14b946909e14660e33fc05db3e50ae2a82d7ea0ca0" dependencies = [ "once_cell", "pest", @@ -1126,7 +1223,7 @@ checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.18", ] [[package]] @@ -1141,6 +1238,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "portable-atomic" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "767eb9f07d4a5ebcb39bbf2d452058a93c011373abf6832e24194a1c3f004794" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -1155,18 +1258,18 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "proc-macro2" -version = "1.0.56" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" +checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" dependencies = [ "unicode-ident", ] [[package]] name = "pulldown-cmark" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63" +checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998" dependencies = [ "bitflags", "memchr", @@ -1175,9 +1278,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.27" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" dependencies = [ "proc-macro2", ] @@ -1232,11 +1335,11 @@ dependencies = [ [[package]] name = "regex" -version = "1.8.1" +version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ - "aho-corasick 1.0.1", + "aho-corasick 1.0.2", "memchr", "regex-syntax", ] @@ -1249,15 +1352,15 @@ checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" [[package]] name = "regex-syntax" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "rustix" -version = "0.37.19" +version = "0.37.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" dependencies = [ "bitflags", "errno", @@ -1273,7 +1376,7 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" dependencies = [ - "base64 0.21.0", + "base64 0.21.2", ] [[package]] @@ -1303,31 +1406,37 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + [[package]] name = "serde" -version = "1.0.163" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.163" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.18", ] [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "bdf3bf93142acad5821c99197022e170842cdbc1c30482b98750c688c640842a" dependencies = [ "itoa", "ryu", @@ -1359,9 +1468,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if", "cpufeatures", @@ -1450,9 +1559,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.15" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" dependencies = [ "proc-macro2", "quote", @@ -1461,15 +1570,16 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.5.0" +version = "3.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6" dependencies = [ + "autocfg", "cfg-if", "fastrand", "redox_syscall 0.3.5", "rustix", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -1519,7 +1629,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.18", ] [[package]] @@ -1549,9 +1659,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.28.1" +version = "1.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105" +checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" dependencies = [ "autocfg", "bytes", @@ -1572,7 +1682,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.18", ] [[package]] @@ -1708,9 +1818,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" [[package]] name = "unicode-normalization" @@ -1721,11 +1831,17 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + [[package]] name = "url" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" dependencies = [ "form_urlencoded", "idna", @@ -1762,11 +1878,10 @@ dependencies = [ [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -1808,9 +1923,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.85" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b6cb788c4e39112fbe1822277ef6fb3c55cd86b95cb3d3c4c1c9597e4ac74b4" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1818,24 +1933,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.85" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e522ed4105a9d626d885b35d62501b30d9666283a5c8be12c14a8bdafe7822" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.18", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.85" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "358a79a0cb89d21db8120cbfb91392335913e4890665b1a7981d9e956903b434" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1843,22 +1958,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.85" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4783ce29f09b9d93134d41297aded3a712b7b979e9c6f28c32cb88c973a94869" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.18", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.85" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a901d592cafaa4d711bc324edfaff879ac700b19c3dfd60058d2b445be2691eb" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "winapi" @@ -1900,21 +2015,6 @@ dependencies = [ "windows-targets 0.48.0", ] -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - [[package]] name = "windows-sys" version = "0.45.0" diff --git a/Cargo.toml b/Cargo.toml index 68d56b2a4..0c7ff2e0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,4 +1,5 @@ [workspace] members = [ "mdbook-cairo", -] + "cairo-verify" +] \ No newline at end of file diff --git a/README.md b/README.md index cb94bc086..da8b3fe21 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,9 @@ -[![All Contributors](https://img.shields.io/badge/all_contributors-12-orange.svg?style=flat-square)](#contributors) + +[![All Contributors](https://img.shields.io/badge/all_contributors-16-orange.svg?style=flat-square)](#contributors) +

The Cairo Programming Language Book

@@ -34,6 +36,7 @@ This repository contains the source of "The Cairo Programming Language" book, a `sudo apt install gettext`. 3. Clone this repository. + 4. Install mdbook-cairo [for Cairo code blocks](#work-locally-cairo-programs-verification) ``` cargo install --path mdbook-cairo @@ -69,47 +72,89 @@ To work with translations, those are the steps to update the translated content: The translation work is inspired from [Comprehensive Rust repository](https://github.com/google/comprehensive-rust/blob/main/TRANSLATIONS.md). #### Initiate a new translation for your language + If you wish to initiate a new translation for your language without running a local server, consider the following tips: + - Execute the command `./translations.sh new xx` (replace `xx` with your language code). This method can generate the `xx.po` file of your language for you. - To update your `xx.po` file, execute the command `./translations.sh xx` (replace `xx` with your language code), as mentioned in the previous chapter. - If the `xx.po` file already exists (which means you are not initiating a new translation), you should not run this command. ### Work locally (Cairo programs verification) -The current book has a mdbook backend to extract Cairo programs from the markdown sources. Currently, for each program it test two things: if it compiles and if it adheres to the `cairo-format` coding style. You can run this locally and test if a Cairo program you have written in the book passes these tests. +The `cairo-verify` tool is designed to wrap all cairo and starknet plugins for quickly verifying cairo programs. -The mdbook-cairo backend is working as following: +#### Setup -1. It takes every code blocks in the markdown source and parse all of them. -2. Code blocks with a main function `fn main()` are extracted into Cairo programs. -3. The extracted programs are named based on the chapter they belong to, and a consecutive - number of the `fn main()` found in the chapter. -4. If you have a code block with a `fn main()` function that you know does not compile, - you can indicate it by adding the `does_not_compile` attribute to the code block, like this: +Firstly, you need to have `scarb` resolved in your path: - ```` - ```rust,does_not_compile - fn main() { - } - ``` - ```` +They should be available after installing cairo, see [here](https://cairo-book.github.io/ch01-01-installation.html) for more details. - This main function will still count in the consecutive number of `fn main()` in the chapter file, - but will not be extracted into a Cairo program. +To run the `cairo-verify` helper tool, ensure that you are at the root of the repository (same directory of this `README.md` file), and run: -5. Alternatively, if you want to disable the format check using `cairo-format`, - you can add the `ignore_format` attribute to the code block, like this: +```sh +cargo run --bin cairo-verify +``` - ```` - ```rust,ignore_format - fn main() { - } - ``` - ```` +Alternatively, you can also install the tool with: + +```sh +cargo install --path cairo-verify +``` + +#### Usage + +The tool scans for all `*.cairo` files in the specified directory and performs the following actions: + +For a Starknet contract: + +- `scarb build` +- If it has tests: `scarb test` -To run the CI locally, ensure that you are at the root of the repository (same directory of this `README.md` file), and run: +Cairo program: -`bash mdbook-cairo/scripts/cairo_local_verify.sh` +- If it has a `main` function: `scarb cairo-run` +- Else, `scarb build` +- If it has tests: `scarb test` +- `scarb fmt -c` + +To specify which tests to run, you can add a comment at the top of your file with the following format: + +```rust +// TAG: +// TAGS: , +``` + +Here is a list of available tags: + +- `does_not_compile`: don't run `scarb build` +- `does_not_run`: don't run `scarb cairo-run` +- `ignore_fmt`: don't run `scarb fmt` +- `tests_fail`: don't run `scarb test` + +You can skip and ignore a specific test by adding the corresponding flag: + +```sh +$ cairo-verify --help + +Usage: cairo-verify [OPTIONS] + +Options: + -p, --path The path to explore for *.cairo files [default: ./listings] + -v, --verbose Print more information + -q, --quiet Only print final results + -f, --formats-skip Skip cairo-format checks + -s, --starknet-skip Skip starknet-compile checks + -c, --compile-skip Skip cairo-compile checks + -r, --run-skip Skip cairo-run checks + -t, --test-skip Skip cairo-test checks + --file Specify file to check + -h, --help Print help + -V, --version Print version +``` + +In CI, it's preferable to reduce output, so run `cairo-verify` with the `--quiet` flag. + +The mdbook-cairo is a mdbook preprocessor that only removes the `// TAG` lines in code blocks. ## Contributors @@ -133,6 +178,12 @@ To run the CI locally, ensure that you are at the root of the repository (same d julio4
julio4

💻 🔧 Haresh Gedia
Haresh Gedia

📖 Darlington Nnam
Darlington Nnam

💻 + Tiago Neto
Tiago Neto

👀 + omahs
omahs

💻 + + + Shramee Srivastav
Shramee Srivastav

💻 + Daniel Bejarano
Daniel Bejarano

💻 diff --git a/Scarb.toml b/Scarb.toml index dde7cb8f1..46b75662b 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -1,5 +1,5 @@ [package] -name = "cairo-book" +name = "cairo_book" version = "0.1.0" # Only required to have LS enabled in this directory. diff --git a/book.toml b/book.toml index dc64bb550..9e8fef44a 100644 --- a/book.toml +++ b/book.toml @@ -8,13 +8,13 @@ title = "The Cairo Programming Language" [build] extra-watch-dirs = ["po"] -[preprocessor.gettext] +[preprocessor.cairo] after = ["links"] +[preprocessor.gettext] +after = ["cairo"] + [output.html] git-repository-url = "https://github.com/cairo-book/cairo-book.github.io/" edit-url-template = "https://github.com/cairo-book/cairo-book.github.io/edit/main/{path}" -playground.runnable = false - -[output.cairo] -output-dir = "cairo-programs" +playground.runnable = true diff --git a/cairo-verify/Cargo.toml b/cairo-verify/Cargo.toml new file mode 100644 index 000000000..68db90c33 --- /dev/null +++ b/cairo-verify/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "cairo-verify" +version = "0.1.0" +edition = "2021" +license = "MIT" +authors = ["Cairo-book community"] +description = "A tool for running adequate cairo tests tools on cairo files." +repository = "https://github.com/cairo-book/cairo-book.github.io" + +[dependencies] +clap = { version = "4.3.4", features = ["derive"] } +colored = "2.0.0" +env_logger = "0.10.0" +indicatif = "0.17.5" +lazy_static = "1.4.0" +log = "0.4.19" +regex = "1.8.4" +serde = "1.0.164" +walkdir = "2.3.3" diff --git a/cairo-verify/README.md b/cairo-verify/README.md new file mode 100644 index 000000000..9a6c6ab82 --- /dev/null +++ b/cairo-verify/README.md @@ -0,0 +1,7 @@ +# Cli tool to verify cairo programs + +This tool is designed to wrap all cairo and starknet plugins for quickly verifying cairo programs. + +# Useful links: + +- https://github.com/cairo-book/cairo-book.github.io/pull/209 \ No newline at end of file diff --git a/cairo-verify/src/cmd.rs b/cairo-verify/src/cmd.rs new file mode 100644 index 000000000..46e9ee99d --- /dev/null +++ b/cairo-verify/src/cmd.rs @@ -0,0 +1,57 @@ +use std::process::Command; + +pub enum Cmd { + ScarbFormat(), + ScarbBuild(), + ScarbCairoRun(), + ScarbTest(), +} + +impl Cmd { + pub fn as_str(&self) -> String { + let command = match self { + Cmd::ScarbFormat() => "fmt", + Cmd::ScarbBuild() => "build", + Cmd::ScarbCairoRun() => "cairo-run", + Cmd::ScarbTest() => "test", + }; + command.into() + } + + fn manifest_option(&self, manifest_path: &str) -> Vec { + vec!["--manifest-path".to_string(), manifest_path.to_string()] + } + + fn args(&self) -> Vec<&str> { + match self { + Cmd::ScarbFormat() => vec!["-c"], + Cmd::ScarbBuild() => vec![], + Cmd::ScarbCairoRun() => vec!["--available-gas=20000000"], + Cmd::ScarbTest() => vec![], + } + } + + pub fn test(&self, manifest_path: &str) -> Result<(), String> { + // Temporary workaround that compiles before trying to run + // Until Scarb does it by default. + if let Cmd::ScarbCairoRun() = self { + let mut command = Command::new("scarb"); + command.args(self.manifest_option(manifest_path)); + command.arg("build"); + + let _output = command.output().expect("Failed to execute scarb"); + } + let mut command = Command::new("scarb"); + command.args(self.manifest_option(manifest_path)); + command.arg(self.as_str()); + command.args(self.args()); + + let output = command.output().expect("Failed to execute scarb"); + + if !output.status.success() { + return Err(String::from_utf8_lossy(&output.stderr).to_string()); + } + + Ok(()) + } +} diff --git a/cairo-verify/src/config.rs b/cairo-verify/src/config.rs new file mode 100644 index 000000000..bd44b5654 --- /dev/null +++ b/cairo-verify/src/config.rs @@ -0,0 +1,56 @@ +use clap::Parser; +use regex::Regex; + +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +pub struct Config { + /// The path to explore for *.cairo files. + #[arg(short, long, default_value = "./listings")] + pub path: String, + + /// Print more information. + #[arg(short, long)] + pub verbose: bool, + + /// Only print final results. + #[arg(short, long)] + pub quiet: bool, + + /// Skip cairo-format checks + #[arg(short, long)] + pub formats_skip: bool, + + /// Skip starknet-compile checks + #[arg(short, long)] + pub starknet_skip: bool, + + /// Skip cairo-compile checks + #[arg(short, long)] + pub compile_skip: bool, + + /// Skip cairo-run checks + #[arg(short, long)] + pub run_skip: bool, + + /// Skip cairo-test checks + #[arg(short, long)] + pub test_skip: bool, + + /// Specify file to check + #[arg(long)] + pub file: Option, +} + +/// Expected statement in a cairo program for it to be runnable. +pub const STATEMENT_IS_RUNNABLE: &str = "fn main()"; +/// Expected statement in a starknet contract for it to compile. +pub const STATEMENT_IS_CONTRACT: &str = "#[starknet::contract]"; +/// Expected statement in a cairo program containing tests. +pub const STATEMENT_IS_TESTABLE: &str = "#[test]"; +/// Expected regex for tags +const TAG_REGEX_PATTERN: &str = r"^//\s*TAG(S)?\s*(:)?\s*"; + +lazy_static! { + pub static ref TAG_REGEX: Regex = + Regex::new(TAG_REGEX_PATTERN).expect("Failed to create TAG_REGEX"); +} diff --git a/cairo-verify/src/error_sets.rs b/cairo-verify/src/error_sets.rs new file mode 100644 index 000000000..3a688d197 --- /dev/null +++ b/cairo-verify/src/error_sets.rs @@ -0,0 +1,31 @@ +use crate::cmd::Cmd; +use std::collections::HashSet; + +pub struct ErrorSets { + pub compile_errors: HashSet, + pub run_errors: HashSet, + pub test_errors: HashSet, + pub format_errors: HashSet, + pub starknet_errors: HashSet, +} + +impl ErrorSets { + pub fn new() -> Self { + Self { + compile_errors: HashSet::new(), + run_errors: HashSet::new(), + test_errors: HashSet::new(), + format_errors: HashSet::new(), + starknet_errors: HashSet::new(), + } + } + + pub fn get_mut_error_set(&mut self, cmd: &Cmd) -> &mut HashSet { + match cmd { + Cmd::ScarbFormat() => &mut self.format_errors, + Cmd::ScarbBuild() => &mut self.compile_errors, + Cmd::ScarbCairoRun() => &mut self.run_errors, + Cmd::ScarbTest() => &mut self.test_errors, + } + } +} diff --git a/cairo-verify/src/logger.rs b/cairo-verify/src/logger.rs new file mode 100644 index 000000000..1bf9d798a --- /dev/null +++ b/cairo-verify/src/logger.rs @@ -0,0 +1,43 @@ +use env_logger::Env; +use indicatif::ProgressBar; +use log::{Log, Metadata, Record}; + +use crate::Config; + +struct ProgressBarLogger { + pb: ProgressBar, +} + +impl Log for ProgressBarLogger { + fn enabled(&self, metadata: &Metadata) -> bool { + metadata.level() <= log::Level::Info + } + + fn log(&self, record: &Record) { + if self.enabled(record.metadata()) { + self.pb.suspend(|| println!("{}", record.args())) + } + } + + fn flush(&self) {} +} + +pub fn setup(cfg: &Config, pb: ProgressBar) { + let env = Env::default() + .filter_or("APP_LOG", "info") // Default log level is "info" + .write_style_or("APP_LOG_STYLE", "always"); + + if cfg.verbose { + let logger = ProgressBarLogger { pb }; + log::set_boxed_logger(Box::new(logger)).unwrap(); + log::set_max_level(log::LevelFilter::max()); + } else if cfg.quiet { + env_logger::Builder::from_env(env) + .filter(None, log::LevelFilter::Off) + .init(); + } else { + let logger = ProgressBarLogger { pb }; + log::set_boxed_logger(Box::new(logger)).unwrap(); + log::set_max_level(log::LevelFilter::Error); + } +} diff --git a/cairo-verify/src/main.rs b/cairo-verify/src/main.rs new file mode 100644 index 000000000..80470ea40 --- /dev/null +++ b/cairo-verify/src/main.rs @@ -0,0 +1,188 @@ +use clap::Parser; +use colored::Colorize; +use indicatif::ProgressBar; +use log::error; +use std::collections::HashSet; +use std::fs::File; +use std::io::{BufRead, BufReader}; +use std::sync::Mutex; + +#[macro_use] +extern crate lazy_static; + +mod cmd; +mod config; +mod error_sets; +mod logger; +mod tags; +mod utils; + +use crate::cmd::Cmd; +use crate::config::Config; +use crate::error_sets::ErrorSets; +use crate::tags::Tags; +use crate::utils::{clickable, find_scarb_manifests, print_error_table}; + +lazy_static! { + static ref CFG: Config = Config::parse(); +} + +lazy_static! { + static ref ERRORS: Mutex = Mutex::new(ErrorSets::new()); +} + +fn main() { + let cfg = &*CFG; + let scarb_packages = find_scarb_manifests(cfg); + + let pb = ProgressBar::new(scarb_packages.len() as u64); + logger::setup(cfg, pb.clone()); + + for file in scarb_packages { + process_file(&file); + if !cfg.quiet { + pb.inc(1); + } + } + + pb.finish_and_clear(); + + let errors = ERRORS.lock().unwrap(); + let total_errors = errors.compile_errors.len() + + errors.run_errors.len() + + errors.test_errors.len() + + errors.format_errors.len(); + + if total_errors > 0 { + println!("{}\n", " ==== RESULT === ".red().bold()); + + print_error_table(&errors.compile_errors, "Compile Errors"); + print_error_table(&errors.run_errors, "Run Errors"); + print_error_table(&errors.test_errors, "Test Errors"); + print_error_table(&errors.format_errors, "Format Errors"); + + println!( + "{}", + format!("Total errors: {}", total_errors.to_string().red()).bold() + ); + + println!("\n{}", "Please review the errors above. Do not hesitate to ask for help by commenting on the issue on Github.".red().italic()); + std::process::exit(1); + } else { + println!("\n{}\n", "ALL TESTS PASSED!".green().bold()); + } +} + +fn process_file(manifest_path: &str) { + let cfg = &*CFG; + let manifest_path_as_path = std::path::Path::new(manifest_path); + let file_path = manifest_path_as_path + .parent() + .unwrap() + .join("src/lib.cairo"); + let file_path = file_path.to_str().unwrap(); + + let file = + File::open(file_path).unwrap_or_else(|_| panic!("Failed to open file {}", file_path)); + let reader = BufReader::new(file); + + // Parsed tags (if any) + let mut tags: HashSet = HashSet::new(); + let mut in_tag_block = true; + + // Program info + let mut should_be_runnable = false; + let mut should_be_testable = false; + let mut is_contract = false; + + reader.lines().for_each(|line| { + if let Ok(line_contents) = line { + // Parse tags + if in_tag_block && config::TAG_REGEX.is_match(&line_contents) { + let line_contents = config::TAG_REGEX.replace(&line_contents, ""); + let tags_in_line: Vec<&str> = line_contents + .trim() + .split(',') + .map(|tag| tag.trim()) + .collect(); + + tags_in_line.iter().for_each(|tag| { + if let Some(tag_enum) = tags::Tags::from_str(tag) { + tags.insert(tag_enum); + } + }); + } else { + // Stop parsing tags when we reach the first non-comment line + in_tag_block = false; + } + + // Check for statements + is_contract |= line_contents.contains(config::STATEMENT_IS_CONTRACT); + should_be_runnable |= line_contents.contains(config::STATEMENT_IS_RUNNABLE); + should_be_testable |= line_contents.contains(config::STATEMENT_IS_TESTABLE); + } + }); + + // COMPILE / RUN CHECKS + if is_contract { + // This is a contract, it must pass starknet-compile + if !tags.contains(&Tags::DoesNotCompile) && !cfg.starknet_skip { + match Cmd::ScarbBuild().test(manifest_path) { + Ok(_) => {} + Err(e) => handle_error(e, file_path, Cmd::ScarbBuild()), + } + } + } else if should_be_runnable { + // This is a cairo program, it must pass cairo-run + if !tags.contains(&Tags::DoesNotRun) + && !tags.contains(&Tags::DoesNotCompile) + && !cfg.run_skip + { + match Cmd::ScarbCairoRun().test(manifest_path) { + Ok(_) => {} + Err(e) => handle_error(e, file_path, Cmd::ScarbCairoRun()), + } + } + } else { + // This is a cairo program, it must pass cairo-compile + if !tags.contains(&Tags::DoesNotCompile) && !cfg.compile_skip { + match Cmd::ScarbBuild().test(manifest_path) { + Ok(_) => {} + Err(e) => handle_error(e, file_path, Cmd::ScarbBuild()), + } + } + } + + // TEST CHECKS + if should_be_testable && !cfg.test_skip && !tags.contains(&Tags::FailingTests) { + // This program has tests, it must pass cairo-test + match Cmd::ScarbTest().test(manifest_path) { + Ok(_) => {} + Err(e) => handle_error(e, file_path, Cmd::ScarbTest()), + } + } + + // FORMAT CHECKS + if !tags.contains(&Tags::IgnoreFormat) && !cfg.formats_skip { + // This program must pass cairo-format + match Cmd::ScarbFormat().test(manifest_path) { + Ok(_) => {} + Err(e) => handle_error(e, file_path, Cmd::ScarbFormat()), + } + } +} + +fn handle_error(e: String, file_path: &str, cmd: Cmd) { + let clickable_file = clickable(file_path); + let msg = match cmd { + Cmd::ScarbTest() | Cmd::ScarbCairoRun() => { + format!("{} -> {}: {}", clickable_file, cmd.as_str(), e.as_str()) + } + _ => format!("{} -> {}", cmd.as_str(), clickable_file), + }; + + error!("{}", msg); + + let mut errors = ERRORS.lock().unwrap(); + errors.get_mut_error_set(&cmd).insert(clickable_file); +} diff --git a/cairo-verify/src/tags.rs b/cairo-verify/src/tags.rs new file mode 100644 index 000000000..d6face6fd --- /dev/null +++ b/cairo-verify/src/tags.rs @@ -0,0 +1,19 @@ +#[derive(Debug, PartialEq, Eq, Hash)] +pub enum Tags { + DoesNotCompile, + DoesNotRun, + IgnoreFormat, + FailingTests, +} + +impl Tags { + pub fn from_str(tag: &str) -> Option { + match tag { + "does_not_compile" => Some(Tags::DoesNotCompile), + "does_not_run" => Some(Tags::DoesNotRun), + "ignore_fmt" => Some(Tags::IgnoreFormat), + "tests_fail" => Some(Tags::FailingTests), + _ => None, + } + } +} diff --git a/cairo-verify/src/utils.rs b/cairo-verify/src/utils.rs new file mode 100644 index 000000000..5b802964e --- /dev/null +++ b/cairo-verify/src/utils.rs @@ -0,0 +1,74 @@ +use colored::Colorize; +use regex::Regex; +use std::collections::HashSet; +use walkdir::WalkDir; + +use crate::config::Config; + +pub fn find_scarb_manifests(cfg: &Config) -> Vec { + let path = cfg.path.as_str(); + + let mut scarb_manifests: Vec = Vec::new(); + + for entry in WalkDir::new(path).into_iter().filter_map(|e| e.ok()) { + if let Some(file_name) = entry.file_name().to_str() { + if file_name.eq("Scarb.toml") { + if cfg.file.is_some() && !file_name.ends_with(cfg.file.as_ref().unwrap()) { + continue; + } + + scarb_manifests.push(entry.path().display().to_string()); + } + } + } + + scarb_manifests +} + +/// Will replace the file path contained in the input string with a clickable format for better output +pub fn clickable(relative_path: &str) -> String { + let full_path = std::env::current_dir() + .unwrap() + .join(relative_path) + .display() + .to_string(); + let mut path_parts: Vec<&str> = full_path.split(|c: char| c == '\\' || c == '/').collect(); + + let file_listing_path: Vec<&str> = full_path.split("listings").collect(); + let mut filename: String = file_listing_path.last().unwrap_or(&"")[1..].to_string(); + let re = Regex::new(r"([^:]+(:\d+:\d+)?)(:\s|$)").unwrap(); + if let Some(captures) = re.captures(filename.as_str()) { + filename = captures.get(1).map_or("", |m| m.as_str()).to_string(); + } + + if let Some(parts) = path_parts.last_mut() { + *parts = &filename; + } + + let clickable_format = format!( + "\u{1b}]8;;file://{}\u{1b}\\{}\u{1b}]8;;\u{1b}\\", + full_path, filename + ) + .bold() + .red() + .to_string(); + + full_path.replacen(&full_path, &clickable_format, 1) +} + +pub fn print_error_table(errors: &HashSet, section_name: &str) { + if errors.is_empty() { + return; + } + + println!( + "{}", + format!("{}: {}", section_name, errors.len()) + .bold() + .on_red() + ); + + for error in errors { + println!(" - {}", error); + } +} diff --git a/listings/ch02-99-common-collections/no_listing_00_array_new_append/.gitignore b/listings/ch02-99-common-collections/no_listing_00_array_new_append/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_00_array_new_append/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-99-common-collections/no_listing_00_array_new_append/Scarb.toml b/listings/ch02-99-common-collections/no_listing_00_array_new_append/Scarb.toml new file mode 100644 index 000000000..6eb1290f8 --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_00_array_new_append/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_00_array_new_append" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_30_array_new_append.cairo b/listings/ch02-99-common-collections/no_listing_00_array_new_append/src/lib.cairo similarity index 80% rename from listings/ch02-common-programming-concepts/no_listing_30_array_new_append.cairo rename to listings/ch02-99-common-collections/no_listing_00_array_new_append/src/lib.cairo index 146cceb61..5fe852c85 100644 --- a/listings/ch02-common-programming-concepts/no_listing_30_array_new_append.cairo +++ b/listings/ch02-99-common-collections/no_listing_00_array_new_append/src/lib.cairo @@ -1,5 +1,3 @@ -use array::ArrayTrait; - fn main() { let mut a = ArrayTrait::new(); a.append(0); diff --git a/listings/ch02-99-common-collections/no_listing_01_array_pop_front/.gitignore b/listings/ch02-99-common-collections/no_listing_01_array_pop_front/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_01_array_pop_front/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-99-common-collections/no_listing_01_array_pop_front/Scarb.toml b/listings/ch02-99-common-collections/no_listing_01_array_pop_front/Scarb.toml new file mode 100644 index 000000000..a62bffb27 --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_01_array_pop_front/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_01_array_pop_front" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_31_array_pop_front.cairo b/listings/ch02-99-common-collections/no_listing_01_array_pop_front/src/lib.cairo similarity index 81% rename from listings/ch02-common-programming-concepts/no_listing_31_array_pop_front.cairo rename to listings/ch02-99-common-collections/no_listing_01_array_pop_front/src/lib.cairo index 13f8edfce..1e6886af1 100644 --- a/listings/ch02-common-programming-concepts/no_listing_31_array_pop_front.cairo +++ b/listings/ch02-99-common-collections/no_listing_01_array_pop_front/src/lib.cairo @@ -1,5 +1,3 @@ -use option::OptionTrait; -use array::ArrayTrait; use debug::PrintTrait; fn main() { diff --git a/listings/ch02-99-common-collections/no_listing_02_array_at/.gitignore b/listings/ch02-99-common-collections/no_listing_02_array_at/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_02_array_at/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-99-common-collections/no_listing_02_array_at/Scarb.toml b/listings/ch02-99-common-collections/no_listing_02_array_at/Scarb.toml new file mode 100644 index 000000000..3a4692b91 --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_02_array_at/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_02_array_at" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_32_array_at.cairo b/listings/ch02-99-common-collections/no_listing_02_array_at/src/lib.cairo similarity index 85% rename from listings/ch02-common-programming-concepts/no_listing_32_array_at.cairo rename to listings/ch02-99-common-collections/no_listing_02_array_at/src/lib.cairo index a9c782fa7..ecfac6c03 100644 --- a/listings/ch02-common-programming-concepts/no_listing_32_array_at.cairo +++ b/listings/ch02-99-common-collections/no_listing_02_array_at/src/lib.cairo @@ -1,4 +1,3 @@ -use array::ArrayTrait; fn main() { let mut a = ArrayTrait::new(); a.append(0); diff --git a/listings/ch02-99-common-collections/no_listing_03_array_get/.gitignore b/listings/ch02-99-common-collections/no_listing_03_array_get/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_03_array_get/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-99-common-collections/no_listing_03_array_get/Scarb.toml b/listings/ch02-99-common-collections/no_listing_03_array_get/Scarb.toml new file mode 100644 index 000000000..780952999 --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_03_array_get/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_03_array_get" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_33_array_get.cairo b/listings/ch02-99-common-collections/no_listing_03_array_get/src/lib.cairo similarity index 89% rename from listings/ch02-common-programming-concepts/no_listing_33_array_get.cairo rename to listings/ch02-99-common-collections/no_listing_03_array_get/src/lib.cairo index 8cff80e03..445877e69 100644 --- a/listings/ch02-common-programming-concepts/no_listing_33_array_get.cairo +++ b/listings/ch02-99-common-collections/no_listing_03_array_get/src/lib.cairo @@ -1,5 +1,3 @@ -use array::ArrayTrait; -use box::BoxTrait; fn main() -> u128 { let mut arr = ArrayTrait::::new(); arr.append(100); @@ -8,7 +6,7 @@ fn main() -> u128 { match arr.get(index_to_access) { Option::Some(x) => { *x.unbox() - // Don't worry about * for now, if you are curious see Chapter 3.2 #desnap operator + // Don't worry about * for now, if you are curious see Chapter 4.2 #desnap operator // It basically means "transform what get(idx) returned into a real value" }, Option::None(_) => { diff --git a/listings/ch02-99-common-collections/no_listing_04_array_with_enums/.gitignore b/listings/ch02-99-common-collections/no_listing_04_array_with_enums/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_04_array_with_enums/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-99-common-collections/no_listing_04_array_with_enums/Scarb.toml b/listings/ch02-99-common-collections/no_listing_04_array_with_enums/Scarb.toml new file mode 100644 index 000000000..e9dcf1664 --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_04_array_with_enums/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_04_array_with_enums" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_34_array_with_enums.cairo b/listings/ch02-99-common-collections/no_listing_04_array_with_enums/src/lib.cairo similarity index 87% rename from listings/ch02-common-programming-concepts/no_listing_34_array_with_enums.cairo rename to listings/ch02-99-common-collections/no_listing_04_array_with_enums/src/lib.cairo index 7353af425..1d2997c71 100644 --- a/listings/ch02-common-programming-concepts/no_listing_34_array_with_enums.cairo +++ b/listings/ch02-99-common-collections/no_listing_04_array_with_enums/src/lib.cairo @@ -1,6 +1,3 @@ -use array::ArrayTrait; -use traits::Into; - #[derive(Copy, Drop)] enum Data { Integer: u128, diff --git a/listings/ch02-99-common-collections/no_listing_05_array_span/.gitignore b/listings/ch02-99-common-collections/no_listing_05_array_span/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_05_array_span/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-99-common-collections/no_listing_05_array_span/Scarb.toml b/listings/ch02-99-common-collections/no_listing_05_array_span/Scarb.toml new file mode 100644 index 000000000..9c5aa5e14 --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_05_array_span/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_05_array_span" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-99-common-collections/no_listing_05_array_span/src/lib.cairo b/listings/ch02-99-common-collections/no_listing_05_array_span/src/lib.cairo new file mode 100644 index 000000000..73aa069a2 --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_05_array_span/src/lib.cairo @@ -0,0 +1,4 @@ +fn main() { + let mut array: Array = ArrayTrait::new(); + array.span(); +} diff --git a/listings/ch02-99-common-collections/no_listing_07_intro/.gitignore b/listings/ch02-99-common-collections/no_listing_07_intro/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_07_intro/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-99-common-collections/no_listing_07_intro/Scarb.toml b/listings/ch02-99-common-collections/no_listing_07_intro/Scarb.toml new file mode 100644 index 000000000..45feec3eb --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_07_intro/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_07_intro" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-99-common-collections/no_listing_07_intro/src/lib.cairo b/listings/ch02-99-common-collections/no_listing_07_intro/src/lib.cairo new file mode 100644 index 000000000..05a53be87 --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_07_intro/src/lib.cairo @@ -0,0 +1,12 @@ +fn main() { + let mut balances: Felt252Dict = Default::default(); + + balances.insert('Alex', 100); + balances.insert('Maria', 200); + + let alex_balance = balances.get('Alex'); + assert(alex_balance == 100, 'Balance is not 100'); + + let maria_balance = balances.get('Maria'); + assert(maria_balance == 200, 'Balance is not 200'); +} diff --git a/listings/ch02-99-common-collections/no_listing_08_intro_rewrite/.gitignore b/listings/ch02-99-common-collections/no_listing_08_intro_rewrite/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_08_intro_rewrite/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-99-common-collections/no_listing_08_intro_rewrite/Scarb.toml b/listings/ch02-99-common-collections/no_listing_08_intro_rewrite/Scarb.toml new file mode 100644 index 000000000..bf4bc43ed --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_08_intro_rewrite/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_08_intro_rewrite" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-99-common-collections/no_listing_08_intro_rewrite/src/lib.cairo b/listings/ch02-99-common-collections/no_listing_08_intro_rewrite/src/lib.cairo new file mode 100644 index 000000000..ac56f269b --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_08_intro_rewrite/src/lib.cairo @@ -0,0 +1,15 @@ +fn main() { + let mut balances: Felt252Dict = Default::default(); + + // Insert Alex with 100 balance + balances.insert('Alex', 100); + // Check that Alex has indeed 100 asociated with him + let alex_balance = balances.get('Alex'); + assert(alex_balance == 100, 'Alex balance is not 100'); + + // Insert Alex again, this time with 200 balance + balances.insert('Alex', 200); + // Check the new balance is correct + let alex_balance_2 = balances.get('Alex'); + assert(alex_balance_2 == 200, 'Alex balance is not 200'); +} diff --git a/listings/ch02-99-common-collections/no_listing_09_entries/.gitignore b/listings/ch02-99-common-collections/no_listing_09_entries/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_09_entries/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-99-common-collections/no_listing_09_entries/Scarb.toml b/listings/ch02-99-common-collections/no_listing_09_entries/Scarb.toml new file mode 100644 index 000000000..9da08421e --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_09_entries/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_09_entries" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-99-common-collections/no_listing_09_entries/src/lib.cairo b/listings/ch02-99-common-collections/no_listing_09_entries/src/lib.cairo new file mode 100644 index 000000000..9a6d83056 --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_09_entries/src/lib.cairo @@ -0,0 +1,17 @@ +// ANCHOR: struct +struct Entry { + key: felt252, + previous_value: T, + new_value: T, +} +// ANCHOR_END: struct + +fn main() { + let mut balances: Felt252Dict = Default::default(); + // ANCHOR: inserts + balances.insert('Alex', 100_u64); + balances.insert('Maria', 50_u64); + balances.insert('Alex', 200_u64); + balances.get('Maria'); +// ANCHOR_END: inserts +} diff --git a/listings/ch02-99-common-collections/no_listing_10_custom_methods/.gitignore b/listings/ch02-99-common-collections/no_listing_10_custom_methods/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_10_custom_methods/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-99-common-collections/no_listing_10_custom_methods/Scarb.toml b/listings/ch02-99-common-collections/no_listing_10_custom_methods/Scarb.toml new file mode 100644 index 000000000..22f49ce69 --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_10_custom_methods/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_10_custom_methods" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-99-common-collections/no_listing_10_custom_methods/src/lib.cairo b/listings/ch02-99-common-collections/no_listing_10_custom_methods/src/lib.cairo new file mode 100644 index 000000000..5ec47b819 --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_10_custom_methods/src/lib.cairo @@ -0,0 +1,58 @@ +// ANCHOR: imports +use dict::Felt252DictEntryTrait; +// ANCHOR_END: imports + +use debug::PrintTrait; + +// ANCHOR: custom_get +fn custom_get, impl TDrop: Drop, impl TCopy: Copy>( + ref dict: Felt252Dict, key: felt252 +) -> T { + // Get the new entry and the previous value held at `key` + let (entry, prev_value) = dict.entry(key); + + // Store the value to return + let return_value = prev_value; + + // Update the entry with `prev_value` and get back ownership of the dictionary + dict = entry.finalize(prev_value); + + // Return the read value + return_value +} +// ANCHOR_END: custom_get + +// ANCHOR: custom_insert +fn custom_insert< + T, + impl TDefault: Felt252DictValue, + impl TDestruct: Destruct, + impl TPrint: PrintTrait, + impl TDrop: Drop +>( + ref dict: Felt252Dict, key: felt252, value: T +) { + // Get the last entry associated with `key` + // Notice that if `key` does not exists, _prev_value will + // be the default value of T. + let (entry, _prev_value) = dict.entry(key); + + // Insert `entry` back in the dictionary with the updated value, + // and recieve ownership of the dictionary + dict = entry.finalize(value); +} +// ANCHOR_END: custom_insert + +// ANCHOR: main +fn main() { + let mut dict: Felt252Dict = Default::default(); + + custom_insert(ref dict, '0', 100); + + let val = custom_get(ref dict, '0'); + + assert(val == 100, 'Expecting 100'); +} +// ANCHOR_END: main + + diff --git a/listings/ch02-99-common-collections/no_listing_11_dict_of_complex/.gitignore b/listings/ch02-99-common-collections/no_listing_11_dict_of_complex/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_11_dict_of_complex/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-99-common-collections/no_listing_11_dict_of_complex/Scarb.toml b/listings/ch02-99-common-collections/no_listing_11_dict_of_complex/Scarb.toml new file mode 100644 index 000000000..3aba306d8 --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_11_dict_of_complex/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_11_dict_of_complex" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-99-common-collections/no_listing_11_dict_of_complex/src/lib.cairo b/listings/ch02-99-common-collections/no_listing_11_dict_of_complex/src/lib.cairo new file mode 100644 index 000000000..4b9495049 --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_11_dict_of_complex/src/lib.cairo @@ -0,0 +1,42 @@ +// ANCHOR: all + +// ANCHOR: imports +use dict::Felt252DictTrait; +use nullable::{nullable_from_box, match_nullable, FromNullableResult}; +// ANCHOR_END: imports + +// ANCHOR: header +fn main() { + // Create the dictionary + let mut d: Felt252Dict>> = Default::default(); + + // Crate the array to insert + let mut a = ArrayTrait::new(); + a.append(8); + a.append(9); + a.append(10); + + // Insert it as a `Span` + d.insert(0, nullable_from_box(BoxTrait::new(a.span()))); + // ANCHOR_END: header + + // ANCHOR: footer + // Get value back + let val = d.get(0); + + // Search the value and assert it is not null + let span = match match_nullable(val) { + FromNullableResult::Null(()) => panic_with_felt252('No value found'), + FromNullableResult::NotNull(val) => val.unbox(), + }; + + // Verify we are having the right values + assert(*span.at(0) == 8, 'Expecting 8'); + assert(*span.at(1) == 9, 'Expecting 9'); + assert(*span.at(2) == 10, 'Expecting 10'); +} +// ANCHOR_END: footer + +// ANCHOR_END: all + + diff --git a/listings/ch02-99-common-collections/no_listing_12_dict_struct_member/.gitignore b/listings/ch02-99-common-collections/no_listing_12_dict_struct_member/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_12_dict_struct_member/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-99-common-collections/no_listing_12_dict_struct_member/Scarb.toml b/listings/ch02-99-common-collections/no_listing_12_dict_struct_member/Scarb.toml new file mode 100644 index 000000000..22aafaa64 --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_12_dict_struct_member/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_12_dict_struct_member" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-99-common-collections/no_listing_12_dict_struct_member/src/lib.cairo b/listings/ch02-99-common-collections/no_listing_12_dict_struct_member/src/lib.cairo new file mode 100644 index 000000000..71394111c --- /dev/null +++ b/listings/ch02-99-common-collections/no_listing_12_dict_struct_member/src/lib.cairo @@ -0,0 +1,64 @@ +// ANCHOR: struct +struct UserDatabase { + users_amount: u64, + balances: Felt252Dict, +} +// ANCHOR_END: struct + +// ANCHOR: trait +trait UserDatabaseTrait { + fn new() -> UserDatabase; + fn add_user>(ref self: UserDatabase, name: felt252, balance: T); + fn get_user>(ref self: UserDatabase, name: felt252) -> T; +} +// ANCHOR_END: trait + +// ANCHOR: impl +impl UserDatabaseImpl> of UserDatabaseTrait { + // Creates a database + fn new() -> UserDatabase { + UserDatabase { users_amount: 0, balances: Default::default() } + } + + // Get the user + fn get_user>(ref self: UserDatabase, name: felt252) -> T { + self.balances.get(name) + } + + // Add a user + fn add_user>(ref self: UserDatabase, name: felt252, balance: T) { + self.balances.insert(name, balance); + self.users_amount += 1; + } +} +// ANCHOR_END: impl + +// ANCHOR: destruct +impl UserDatabaseDestruct< + T, impl TDrop: Drop, impl TDefault: Felt252DictValue +> of Destruct> { + fn destruct(self: UserDatabase) nopanic { + self.balances.squash(); + } +} +// ANCHOR_END: destruct + +// ANCHOR: main +fn main() { + let mut db = UserDatabaseTrait::new(); + + db.add_user('Alex', 100); + db.add_user('Maria', 80); + + db.add_user('Alex', 40); + db.add_user('Maria', 0); + + let alex_latest_balance = db.get_user('Alex'); + let maria_latest_balance = db.get_user('Maria'); + + assert(alex_latest_balance == 40, 'Expected 40'); + assert(maria_latest_balance == 0, 'Expected 0'); +} +// ANCHOR_END: main + + diff --git a/listings/ch02-common-programming-concepts/listing_01_statement/.gitignore b/listings/ch02-common-programming-concepts/listing_01_statement/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/listing_01_statement/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/listing_01_statement/Scarb.toml b/listings/ch02-common-programming-concepts/listing_01_statement/Scarb.toml new file mode 100644 index 000000000..08fa7d33d --- /dev/null +++ b/listings/ch02-common-programming-concepts/listing_01_statement/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_01_statement" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/listing_01_statement.cairo b/listings/ch02-common-programming-concepts/listing_01_statement/src/lib.cairo similarity index 100% rename from listings/ch02-common-programming-concepts/listing_01_statement.cairo rename to listings/ch02-common-programming-concepts/listing_01_statement/src/lib.cairo diff --git a/listings/ch02-common-programming-concepts/no_listing_01_variables_are_immutable/.gitignore b/listings/ch02-common-programming-concepts/no_listing_01_variables_are_immutable/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_01_variables_are_immutable/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_01_variables_are_immutable/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_01_variables_are_immutable/Scarb.toml new file mode 100644 index 000000000..2a39b2100 --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_01_variables_are_immutable/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_01_variables_are_immutable" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_01_variables_are_immutable.cairo b/listings/ch02-common-programming-concepts/no_listing_01_variables_are_immutable/src/lib.cairo similarity index 79% rename from listings/ch02-common-programming-concepts/no_listing_01_variables_are_immutable.cairo rename to listings/ch02-common-programming-concepts/no_listing_01_variables_are_immutable/src/lib.cairo index 3ad722319..d9dc53bbe 100644 --- a/listings/ch02-common-programming-concepts/no_listing_01_variables_are_immutable.cairo +++ b/listings/ch02-common-programming-concepts/no_listing_01_variables_are_immutable/src/lib.cairo @@ -1,3 +1,4 @@ +//TAG: does_not_compile use debug::PrintTrait; fn main() { let x = 5; diff --git a/listings/ch02-common-programming-concepts/no_listing_02_adding_mut/.gitignore b/listings/ch02-common-programming-concepts/no_listing_02_adding_mut/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_02_adding_mut/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_02_adding_mut/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_02_adding_mut/Scarb.toml new file mode 100644 index 000000000..076f17cdd --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_02_adding_mut/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_02_adding_mut" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_02_adding_mut.cairo b/listings/ch02-common-programming-concepts/no_listing_02_adding_mut/src/lib.cairo similarity index 100% rename from listings/ch02-common-programming-concepts/no_listing_02_adding_mut.cairo rename to listings/ch02-common-programming-concepts/no_listing_02_adding_mut/src/lib.cairo diff --git a/listings/ch02-common-programming-concepts/no_listing_03_shadowing/.gitignore b/listings/ch02-common-programming-concepts/no_listing_03_shadowing/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_03_shadowing/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_03_shadowing/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_03_shadowing/Scarb.toml new file mode 100644 index 000000000..7e468182b --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_03_shadowing/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_03_shadowing" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_03_shadowing.cairo b/listings/ch02-common-programming-concepts/no_listing_03_shadowing/src/lib.cairo similarity index 100% rename from listings/ch02-common-programming-concepts/no_listing_03_shadowing.cairo rename to listings/ch02-common-programming-concepts/no_listing_03_shadowing/src/lib.cairo diff --git a/listings/ch02-common-programming-concepts/no_listing_04_shadowing_different_type/.gitignore b/listings/ch02-common-programming-concepts/no_listing_04_shadowing_different_type/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_04_shadowing_different_type/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_04_shadowing_different_type/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_04_shadowing_different_type/Scarb.toml new file mode 100644 index 000000000..ac40c52fd --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_04_shadowing_different_type/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_04_shadowing_different_type" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_04_shadowing_different_type.cairo b/listings/ch02-common-programming-concepts/no_listing_04_shadowing_different_type/src/lib.cairo similarity index 82% rename from listings/ch02-common-programming-concepts/no_listing_04_shadowing_different_type.cairo rename to listings/ch02-common-programming-concepts/no_listing_04_shadowing_different_type/src/lib.cairo index 57e466646..eff26cfc6 100644 --- a/listings/ch02-common-programming-concepts/no_listing_04_shadowing_different_type.cairo +++ b/listings/ch02-common-programming-concepts/no_listing_04_shadowing_different_type/src/lib.cairo @@ -1,7 +1,7 @@ use debug::PrintTrait; -use traits::Into; + fn main() { - let x = 2; + let x: u64 = 2; x.print(); let x: felt252 = x.into(); // converts x to a felt, type annotation is required. x.print() diff --git a/listings/ch02-common-programming-concepts/no_listing_05_mut_cant_change_type.cairo b/listings/ch02-common-programming-concepts/no_listing_05_mut_cant_change_type.cairo deleted file mode 100644 index e79c4a84c..000000000 --- a/listings/ch02-common-programming-concepts/no_listing_05_mut_cant_change_type.cairo +++ /dev/null @@ -1,8 +0,0 @@ -use debug::PrintTrait; -use traits::Into; -fn main() { - let mut x = 2; - x.print(); - x = x.into(); - x.print() -} diff --git a/listings/ch02-common-programming-concepts/no_listing_05_mut_cant_change_type/.gitignore b/listings/ch02-common-programming-concepts/no_listing_05_mut_cant_change_type/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_05_mut_cant_change_type/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_05_mut_cant_change_type/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_05_mut_cant_change_type/Scarb.toml new file mode 100644 index 000000000..b82f404e4 --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_05_mut_cant_change_type/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_05_mut_cant_change_type" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_05_mut_cant_change_type/src/lib.cairo b/listings/ch02-common-programming-concepts/no_listing_05_mut_cant_change_type/src/lib.cairo new file mode 100644 index 000000000..b9a0d9643 --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_05_mut_cant_change_type/src/lib.cairo @@ -0,0 +1,9 @@ +//TAG: does_not_compile +use debug::PrintTrait; + +fn main() { + let mut x: u64 = 2; + x.print(); + x = 100_felt252; + x.print() +} diff --git a/listings/ch02-common-programming-concepts/no_listing_06_data_types/.gitignore b/listings/ch02-common-programming-concepts/no_listing_06_data_types/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_06_data_types/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_06_data_types/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_06_data_types/Scarb.toml new file mode 100644 index 000000000..c1cad1a62 --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_06_data_types/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_06_data_types" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_06_data_types.cairo b/listings/ch02-common-programming-concepts/no_listing_06_data_types/src/lib.cairo similarity index 62% rename from listings/ch02-common-programming-concepts/no_listing_06_data_types.cairo rename to listings/ch02-common-programming-concepts/no_listing_06_data_types/src/lib.cairo index 3fc8b5f7d..236d87335 100644 --- a/listings/ch02-common-programming-concepts/no_listing_06_data_types.cairo +++ b/listings/ch02-common-programming-concepts/no_listing_06_data_types/src/lib.cairo @@ -1,5 +1,3 @@ -use traits::TryInto; -use option::OptionTrait; fn main() { let x: felt252 = 3; let y: u32 = x.try_into().unwrap(); diff --git a/listings/ch02-common-programming-concepts/no_listing_07_integer_types/.gitignore b/listings/ch02-common-programming-concepts/no_listing_07_integer_types/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_07_integer_types/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_07_integer_types/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_07_integer_types/Scarb.toml new file mode 100644 index 000000000..72cc8f8e6 --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_07_integer_types/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_07_integer_types" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_07_integer_types.cairo b/listings/ch02-common-programming-concepts/no_listing_07_integer_types/src/lib.cairo similarity index 100% rename from listings/ch02-common-programming-concepts/no_listing_07_integer_types.cairo rename to listings/ch02-common-programming-concepts/no_listing_07_integer_types/src/lib.cairo diff --git a/listings/ch02-common-programming-concepts/no_listing_08_numeric_operations/.gitignore b/listings/ch02-common-programming-concepts/no_listing_08_numeric_operations/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_08_numeric_operations/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_08_numeric_operations/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_08_numeric_operations/Scarb.toml new file mode 100644 index 000000000..52285eeb0 --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_08_numeric_operations/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_08_numeric_operations" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_08_numeric_operations.cairo b/listings/ch02-common-programming-concepts/no_listing_08_numeric_operations/src/lib.cairo similarity index 100% rename from listings/ch02-common-programming-concepts/no_listing_08_numeric_operations.cairo rename to listings/ch02-common-programming-concepts/no_listing_08_numeric_operations/src/lib.cairo diff --git a/listings/ch02-common-programming-concepts/no_listing_09_boolean_type/.gitignore b/listings/ch02-common-programming-concepts/no_listing_09_boolean_type/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_09_boolean_type/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_09_boolean_type/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_09_boolean_type/Scarb.toml new file mode 100644 index 000000000..97c5b87f6 --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_09_boolean_type/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_09_boolean_type" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_09_boolean_type.cairo b/listings/ch02-common-programming-concepts/no_listing_09_boolean_type/src/lib.cairo similarity index 100% rename from listings/ch02-common-programming-concepts/no_listing_09_boolean_type.cairo rename to listings/ch02-common-programming-concepts/no_listing_09_boolean_type/src/lib.cairo diff --git a/listings/ch02-common-programming-concepts/no_listing_10_short_string_type/.gitignore b/listings/ch02-common-programming-concepts/no_listing_10_short_string_type/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_10_short_string_type/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_10_short_string_type/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_10_short_string_type/Scarb.toml new file mode 100644 index 000000000..395768c5c --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_10_short_string_type/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_10_short_string_type" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_10_short_string_type.cairo b/listings/ch02-common-programming-concepts/no_listing_10_short_string_type/src/lib.cairo similarity index 97% rename from listings/ch02-common-programming-concepts/no_listing_10_short_string_type.cairo rename to listings/ch02-common-programming-concepts/no_listing_10_short_string_type/src/lib.cairo index a1a9073e7..a31b2a5fb 100644 --- a/listings/ch02-common-programming-concepts/no_listing_10_short_string_type.cairo +++ b/listings/ch02-common-programming-concepts/no_listing_10_short_string_type/src/lib.cairo @@ -1,4 +1,4 @@ fn main() { let my_first_char = 'C'; let my_first_string = 'Hello world'; -} \ No newline at end of file +} diff --git a/listings/ch02-common-programming-concepts/no_listing_11_type_casting/.gitignore b/listings/ch02-common-programming-concepts/no_listing_11_type_casting/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_11_type_casting/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_11_type_casting/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_11_type_casting/Scarb.toml new file mode 100644 index 000000000..ae67ed157 --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_11_type_casting/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_11_type_casting" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_11_type_casting.cairo b/listings/ch02-common-programming-concepts/no_listing_11_type_casting/src/lib.cairo similarity index 90% rename from listings/ch02-common-programming-concepts/no_listing_11_type_casting.cairo rename to listings/ch02-common-programming-concepts/no_listing_11_type_casting/src/lib.cairo index 34e4a041f..39b9bb41e 100644 --- a/listings/ch02-common-programming-concepts/no_listing_11_type_casting.cairo +++ b/listings/ch02-common-programming-concepts/no_listing_11_type_casting/src/lib.cairo @@ -1,7 +1,3 @@ -use traits::TryInto; -use traits::Into; -use option::OptionTrait; - fn main() { let my_felt252 = 10; // Since a felt252 might not fit in a u8, we need to unwrap the Option type diff --git a/listings/ch02-common-programming-concepts/no_listing_12_tuple_type/.gitignore b/listings/ch02-common-programming-concepts/no_listing_12_tuple_type/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_12_tuple_type/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_12_tuple_type/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_12_tuple_type/Scarb.toml new file mode 100644 index 000000000..4180edff3 --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_12_tuple_type/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_12_tuple_type" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_12_tuple_type.cairo b/listings/ch02-common-programming-concepts/no_listing_12_tuple_type/src/lib.cairo similarity index 100% rename from listings/ch02-common-programming-concepts/no_listing_12_tuple_type.cairo rename to listings/ch02-common-programming-concepts/no_listing_12_tuple_type/src/lib.cairo diff --git a/listings/ch02-common-programming-concepts/no_listing_13_tuple_destructuration/.gitignore b/listings/ch02-common-programming-concepts/no_listing_13_tuple_destructuration/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_13_tuple_destructuration/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_13_tuple_destructuration/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_13_tuple_destructuration/Scarb.toml new file mode 100644 index 000000000..11ddb9e53 --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_13_tuple_destructuration/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_13_tuple_destructuration" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_13_tuple_destructuration.cairo b/listings/ch02-common-programming-concepts/no_listing_13_tuple_destructuration/src/lib.cairo similarity index 98% rename from listings/ch02-common-programming-concepts/no_listing_13_tuple_destructuration.cairo rename to listings/ch02-common-programming-concepts/no_listing_13_tuple_destructuration/src/lib.cairo index e94460f84..2deab26e9 100644 --- a/listings/ch02-common-programming-concepts/no_listing_13_tuple_destructuration.cairo +++ b/listings/ch02-common-programming-concepts/no_listing_13_tuple_destructuration/src/lib.cairo @@ -7,4 +7,4 @@ fn main() { if y == 6 { 'y is six!'.print(); } -} \ No newline at end of file +} diff --git a/listings/ch02-common-programming-concepts/no_listing_14_tuple_types/.gitignore b/listings/ch02-common-programming-concepts/no_listing_14_tuple_types/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_14_tuple_types/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_14_tuple_types/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_14_tuple_types/Scarb.toml new file mode 100644 index 000000000..206e53efa --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_14_tuple_types/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_14_tuple_types" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_14_tuple_types.cairo b/listings/ch02-common-programming-concepts/no_listing_14_tuple_types/src/lib.cairo similarity index 96% rename from listings/ch02-common-programming-concepts/no_listing_14_tuple_types.cairo rename to listings/ch02-common-programming-concepts/no_listing_14_tuple_types/src/lib.cairo index ba894ef01..569232773 100644 --- a/listings/ch02-common-programming-concepts/no_listing_14_tuple_types.cairo +++ b/listings/ch02-common-programming-concepts/no_listing_14_tuple_types/src/lib.cairo @@ -1,3 +1,3 @@ fn main() { let (x, y): (felt252, felt252) = (2, 3); -} \ No newline at end of file +} diff --git a/listings/ch02-common-programming-concepts/no_listing_15_functions/.gitignore b/listings/ch02-common-programming-concepts/no_listing_15_functions/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_15_functions/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_15_functions/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_15_functions/Scarb.toml new file mode 100644 index 000000000..c5992cd89 --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_15_functions/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_15_functions" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_15_functions.cairo b/listings/ch02-common-programming-concepts/no_listing_15_functions/src/lib.cairo similarity index 100% rename from listings/ch02-common-programming-concepts/no_listing_15_functions.cairo rename to listings/ch02-common-programming-concepts/no_listing_15_functions/src/lib.cairo diff --git a/listings/ch02-common-programming-concepts/no_listing_16_single_param/.gitignore b/listings/ch02-common-programming-concepts/no_listing_16_single_param/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_16_single_param/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_16_single_param/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_16_single_param/Scarb.toml new file mode 100644 index 000000000..d42a00350 --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_16_single_param/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_16_single_param" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_16_single_param.cairo b/listings/ch02-common-programming-concepts/no_listing_16_single_param/src/lib.cairo similarity index 100% rename from listings/ch02-common-programming-concepts/no_listing_16_single_param.cairo rename to listings/ch02-common-programming-concepts/no_listing_16_single_param/src/lib.cairo diff --git a/listings/ch02-common-programming-concepts/no_listing_17_multiple_params/.gitignore b/listings/ch02-common-programming-concepts/no_listing_17_multiple_params/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_17_multiple_params/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_17_multiple_params/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_17_multiple_params/Scarb.toml new file mode 100644 index 000000000..b40e1ea31 --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_17_multiple_params/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_17_multiple_params" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_17_multiple_params.cairo b/listings/ch02-common-programming-concepts/no_listing_17_multiple_params/src/lib.cairo similarity index 100% rename from listings/ch02-common-programming-concepts/no_listing_17_multiple_params.cairo rename to listings/ch02-common-programming-concepts/no_listing_17_multiple_params/src/lib.cairo diff --git a/listings/ch02-common-programming-concepts/no_listing_18_statements_dont_return_values/.gitignore b/listings/ch02-common-programming-concepts/no_listing_18_statements_dont_return_values/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_18_statements_dont_return_values/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_18_statements_dont_return_values/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_18_statements_dont_return_values/Scarb.toml new file mode 100644 index 000000000..7056e4c4e --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_18_statements_dont_return_values/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_18_statements_dont_return_values" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_18_statements_dont_return_values.cairo b/listings/ch02-common-programming-concepts/no_listing_18_statements_dont_return_values/src/lib.cairo similarity index 51% rename from listings/ch02-common-programming-concepts/no_listing_18_statements_dont_return_values.cairo rename to listings/ch02-common-programming-concepts/no_listing_18_statements_dont_return_values/src/lib.cairo index 213ab59a9..3b306fe8b 100644 --- a/listings/ch02-common-programming-concepts/no_listing_18_statements_dont_return_values.cairo +++ b/listings/ch02-common-programming-concepts/no_listing_18_statements_dont_return_values/src/lib.cairo @@ -1,3 +1,4 @@ +//TAG: does_not_compile, ignore_fmt fn main() { let x = (let y = 6); } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_19_blocks_are_expressions/.gitignore b/listings/ch02-common-programming-concepts/no_listing_19_blocks_are_expressions/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_19_blocks_are_expressions/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_19_blocks_are_expressions/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_19_blocks_are_expressions/Scarb.toml new file mode 100644 index 000000000..9b299348e --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_19_blocks_are_expressions/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_19_blocks_are_expressions" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_19_blocks_are_expressions.cairo b/listings/ch02-common-programming-concepts/no_listing_19_blocks_are_expressions/src/lib.cairo similarity index 100% rename from listings/ch02-common-programming-concepts/no_listing_19_blocks_are_expressions.cairo rename to listings/ch02-common-programming-concepts/no_listing_19_blocks_are_expressions/src/lib.cairo diff --git a/listings/ch02-common-programming-concepts/no_listing_20_function_return_values/.gitignore b/listings/ch02-common-programming-concepts/no_listing_20_function_return_values/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_20_function_return_values/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_20_function_return_values/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_20_function_return_values/Scarb.toml new file mode 100644 index 000000000..d0b02e96f --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_20_function_return_values/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_20_function_return_values" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_20_function_return_values.cairo b/listings/ch02-common-programming-concepts/no_listing_20_function_return_values/src/lib.cairo similarity index 100% rename from listings/ch02-common-programming-concepts/no_listing_20_function_return_values.cairo rename to listings/ch02-common-programming-concepts/no_listing_20_function_return_values/src/lib.cairo diff --git a/listings/ch02-common-programming-concepts/no_listing_21_function_return_values_2/.gitignore b/listings/ch02-common-programming-concepts/no_listing_21_function_return_values_2/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_21_function_return_values_2/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_21_function_return_values_2/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_21_function_return_values_2/Scarb.toml new file mode 100644 index 000000000..d0613adb1 --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_21_function_return_values_2/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_21_function_return_values_2" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_21_function_return_values_2.cairo b/listings/ch02-common-programming-concepts/no_listing_21_function_return_values_2/src/lib.cairo similarity index 100% rename from listings/ch02-common-programming-concepts/no_listing_21_function_return_values_2.cairo rename to listings/ch02-common-programming-concepts/no_listing_21_function_return_values_2/src/lib.cairo diff --git a/listings/ch02-common-programming-concepts/no_listing_22_function_return_invalid/.gitignore b/listings/ch02-common-programming-concepts/no_listing_22_function_return_invalid/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_22_function_return_invalid/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_22_function_return_invalid/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_22_function_return_invalid/Scarb.toml new file mode 100644 index 000000000..ac72696d9 --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_22_function_return_invalid/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_22_function_return_invalid" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_22_function_return_invalid.cairo b/listings/ch02-common-programming-concepts/no_listing_22_function_return_invalid/src/lib.cairo similarity index 83% rename from listings/ch02-common-programming-concepts/no_listing_22_function_return_invalid.cairo rename to listings/ch02-common-programming-concepts/no_listing_22_function_return_invalid/src/lib.cairo index bf9ededae..e406df9ed 100644 --- a/listings/ch02-common-programming-concepts/no_listing_22_function_return_invalid.cairo +++ b/listings/ch02-common-programming-concepts/no_listing_22_function_return_invalid/src/lib.cairo @@ -1,3 +1,4 @@ +//TAG: does_not_compile use debug::PrintTrait; fn main() { diff --git a/listings/ch02-common-programming-concepts/no_listing_23_comments/.gitignore b/listings/ch02-common-programming-concepts/no_listing_23_comments/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_23_comments/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_23_comments/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_23_comments/Scarb.toml new file mode 100644 index 000000000..0b73db64c --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_23_comments/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_23_comments" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_23_comments.cairo b/listings/ch02-common-programming-concepts/no_listing_23_comments/src/lib.cairo similarity index 100% rename from listings/ch02-common-programming-concepts/no_listing_23_comments.cairo rename to listings/ch02-common-programming-concepts/no_listing_23_comments/src/lib.cairo diff --git a/listings/ch02-common-programming-concepts/no_listing_24_if/.gitignore b/listings/ch02-common-programming-concepts/no_listing_24_if/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_24_if/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_24_if/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_24_if/Scarb.toml new file mode 100644 index 000000000..4b600c4c4 --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_24_if/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_24_if" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_24_if.cairo b/listings/ch02-common-programming-concepts/no_listing_24_if/src/lib.cairo similarity index 98% rename from listings/ch02-common-programming-concepts/no_listing_24_if.cairo rename to listings/ch02-common-programming-concepts/no_listing_24_if/src/lib.cairo index c72071969..4e21f894c 100644 --- a/listings/ch02-common-programming-concepts/no_listing_24_if.cairo +++ b/listings/ch02-common-programming-concepts/no_listing_24_if/src/lib.cairo @@ -8,4 +8,4 @@ fn main() { } else { 'condition was false'.print(); } -} \ No newline at end of file +} diff --git a/listings/ch02-common-programming-concepts/no_listing_25_else_if/.gitignore b/listings/ch02-common-programming-concepts/no_listing_25_else_if/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_25_else_if/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_25_else_if/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_25_else_if/Scarb.toml new file mode 100644 index 000000000..e4023b0ed --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_25_else_if/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_25_else_if" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_25_else_if.cairo b/listings/ch02-common-programming-concepts/no_listing_25_else_if/src/lib.cairo similarity index 100% rename from listings/ch02-common-programming-concepts/no_listing_25_else_if.cairo rename to listings/ch02-common-programming-concepts/no_listing_25_else_if/src/lib.cairo diff --git a/listings/ch02-common-programming-concepts/no_listing_26_if_let/.gitignore b/listings/ch02-common-programming-concepts/no_listing_26_if_let/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_26_if_let/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_26_if_let/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_26_if_let/Scarb.toml new file mode 100644 index 000000000..9a02e9000 --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_26_if_let/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_26_if_let" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_26_if_let.cairo b/listings/ch02-common-programming-concepts/no_listing_26_if_let/src/lib.cairo similarity index 100% rename from listings/ch02-common-programming-concepts/no_listing_26_if_let.cairo rename to listings/ch02-common-programming-concepts/no_listing_26_if_let/src/lib.cairo diff --git a/listings/ch02-common-programming-concepts/no_listing_27_loop/.gitignore b/listings/ch02-common-programming-concepts/no_listing_27_loop/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_27_loop/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_27_loop/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_27_loop/Scarb.toml new file mode 100644 index 000000000..38a5d514c --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_27_loop/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_27_loop" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_27_loop.cairo b/listings/ch02-common-programming-concepts/no_listing_27_loop/src/lib.cairo similarity index 86% rename from listings/ch02-common-programming-concepts/no_listing_27_loop.cairo rename to listings/ch02-common-programming-concepts/no_listing_27_loop/src/lib.cairo index d92f63c42..b110300e3 100644 --- a/listings/ch02-common-programming-concepts/no_listing_27_loop.cairo +++ b/listings/ch02-common-programming-concepts/no_listing_27_loop/src/lib.cairo @@ -3,7 +3,7 @@ fn main() { let mut i: usize = 0; loop { if i > 10 { - break (); + break; } 'again!'.print(); } diff --git a/listings/ch02-common-programming-concepts/no_listing_28_loop_break/.gitignore b/listings/ch02-common-programming-concepts/no_listing_28_loop_break/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_28_loop_break/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_28_loop_break/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_28_loop_break/Scarb.toml new file mode 100644 index 000000000..3665382fc --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_28_loop_break/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_28_loop_break" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_28_loop_break.cairo b/listings/ch02-common-programming-concepts/no_listing_28_loop_break/src/lib.cairo similarity index 87% rename from listings/ch02-common-programming-concepts/no_listing_28_loop_break.cairo rename to listings/ch02-common-programming-concepts/no_listing_28_loop_break/src/lib.cairo index 02f30ad22..c3a9478a3 100644 --- a/listings/ch02-common-programming-concepts/no_listing_28_loop_break.cairo +++ b/listings/ch02-common-programming-concepts/no_listing_28_loop_break/src/lib.cairo @@ -3,7 +3,7 @@ fn main() { let mut i: usize = 0; loop { if i > 10 { - break (); + break; } 'again'.print(); i += 1; diff --git a/listings/ch02-common-programming-concepts/no_listing_29_loop_return_values/.gitignore b/listings/ch02-common-programming-concepts/no_listing_29_loop_return_values/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_29_loop_return_values/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_29_loop_return_values/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_29_loop_return_values/Scarb.toml new file mode 100644 index 000000000..1c99b1497 --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_29_loop_return_values/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_29_loop_return_values" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_29_loop_return_values.cairo b/listings/ch02-common-programming-concepts/no_listing_29_loop_return_values/src/lib.cairo similarity index 100% rename from listings/ch02-common-programming-concepts/no_listing_29_loop_return_values.cairo rename to listings/ch02-common-programming-concepts/no_listing_29_loop_return_values/src/lib.cairo diff --git a/listings/ch02-common-programming-concepts/no_listing_30_named_parameters/.gitignore b/listings/ch02-common-programming-concepts/no_listing_30_named_parameters/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_30_named_parameters/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch02-common-programming-concepts/no_listing_30_named_parameters/Scarb.toml b/listings/ch02-common-programming-concepts/no_listing_30_named_parameters/Scarb.toml new file mode 100644 index 000000000..fa6d94038 --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_30_named_parameters/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_30_named_parameters" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch02-common-programming-concepts/no_listing_30_named_parameters/src/lib.cairo b/listings/ch02-common-programming-concepts/no_listing_30_named_parameters/src/lib.cairo new file mode 100644 index 000000000..0bfec9cc5 --- /dev/null +++ b/listings/ch02-common-programming-concepts/no_listing_30_named_parameters/src/lib.cairo @@ -0,0 +1,10 @@ +fn foo(x: u8, y: u8) {} + +fn main() { + let first_arg = 3; + let second_arg = 4; + foo(x: first_arg, y: second_arg); + let x = 1; + let y = 2; + foo(:x, :y) +} diff --git a/listings/ch02-common-programming-concepts/no_listing_35_array_span.cairo b/listings/ch02-common-programming-concepts/no_listing_35_array_span.cairo deleted file mode 100644 index f84dc5fac..000000000 --- a/listings/ch02-common-programming-concepts/no_listing_35_array_span.cairo +++ /dev/null @@ -1,6 +0,0 @@ -use array::ArrayTrait; - -fn main() { - let mut array = ArrayTrait::new(); - array.span() -} diff --git a/listings/ch03-understanding-ownership/listing_03_01/.gitignore b/listings/ch03-understanding-ownership/listing_03_01/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch03-understanding-ownership/listing_03_01/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch03-understanding-ownership/listing_03_01/Scarb.toml b/listings/ch03-understanding-ownership/listing_03_01/Scarb.toml new file mode 100644 index 000000000..670d74ed4 --- /dev/null +++ b/listings/ch03-understanding-ownership/listing_03_01/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_03_01" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch03-understanding-ownership/listing_03_01.cairo b/listings/ch03-understanding-ownership/listing_03_01/src/lib.cairo similarity index 94% rename from listings/ch03-understanding-ownership/listing_03_01.cairo rename to listings/ch03-understanding-ownership/listing_03_01/src/lib.cairo index b4e93b7af..99d7dfbf2 100644 --- a/listings/ch03-understanding-ownership/listing_03_01.cairo +++ b/listings/ch03-understanding-ownership/listing_03_01/src/lib.cairo @@ -1,3 +1,4 @@ +//TAG: ignore_fmt fn main() { // ANCHOR: here { // s is not valid here, it’s not yet declared diff --git a/listings/ch03-understanding-ownership/listing_03_03/.gitignore b/listings/ch03-understanding-ownership/listing_03_03/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch03-understanding-ownership/listing_03_03/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch03-understanding-ownership/listing_03_03/Scarb.toml b/listings/ch03-understanding-ownership/listing_03_03/Scarb.toml new file mode 100644 index 000000000..3a62cfc6b --- /dev/null +++ b/listings/ch03-understanding-ownership/listing_03_03/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_03_03" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch03-understanding-ownership/listing_03_03.cairo b/listings/ch03-understanding-ownership/listing_03_03/src/lib.cairo similarity index 98% rename from listings/ch03-understanding-ownership/listing_03_03.cairo rename to listings/ch03-understanding-ownership/listing_03_03/src/lib.cairo index e2d343f60..91f46a8e0 100644 --- a/listings/ch03-understanding-ownership/listing_03_03.cairo +++ b/listings/ch03-understanding-ownership/listing_03_03/src/lib.cairo @@ -1,3 +1,4 @@ +//TAG: ignore_fmt #[derive(Drop)] struct MyStruct{} diff --git a/listings/ch03-understanding-ownership/listing_03_04/.gitignore b/listings/ch03-understanding-ownership/listing_03_04/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch03-understanding-ownership/listing_03_04/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch03-understanding-ownership/listing_03_04/Scarb.toml b/listings/ch03-understanding-ownership/listing_03_04/Scarb.toml new file mode 100644 index 000000000..eccab7776 --- /dev/null +++ b/listings/ch03-understanding-ownership/listing_03_04/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_03_04" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch03-understanding-ownership/listing_03_04.cairo b/listings/ch03-understanding-ownership/listing_03_04/src/lib.cairo similarity index 98% rename from listings/ch03-understanding-ownership/listing_03_04.cairo rename to listings/ch03-understanding-ownership/listing_03_04/src/lib.cairo index 2c63d6067..3c40c90d6 100644 --- a/listings/ch03-understanding-ownership/listing_03_04.cairo +++ b/listings/ch03-understanding-ownership/listing_03_04/src/lib.cairo @@ -1,3 +1,4 @@ +//TAG: ignore_fmt #[derive(Drop)] struct A {} diff --git a/listings/ch03-understanding-ownership/listing_03_05/.gitignore b/listings/ch03-understanding-ownership/listing_03_05/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch03-understanding-ownership/listing_03_05/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch03-understanding-ownership/listing_03_05/Scarb.toml b/listings/ch03-understanding-ownership/listing_03_05/Scarb.toml new file mode 100644 index 000000000..7ff49e77b --- /dev/null +++ b/listings/ch03-understanding-ownership/listing_03_05/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_03_05" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch03-understanding-ownership/listing_03_05.cairo b/listings/ch03-understanding-ownership/listing_03_05/src/lib.cairo similarity index 91% rename from listings/ch03-understanding-ownership/listing_03_05.cairo rename to listings/ch03-understanding-ownership/listing_03_05/src/lib.cairo index be94a9a4a..f89511aba 100644 --- a/listings/ch03-understanding-ownership/listing_03_05.cairo +++ b/listings/ch03-understanding-ownership/listing_03_05/src/lib.cairo @@ -1,4 +1,3 @@ -use array::ArrayTrait; fn main() { let arr1 = ArrayTrait::::new(); diff --git a/listings/ch03-understanding-ownership/listing_03_06/.gitignore b/listings/ch03-understanding-ownership/listing_03_06/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch03-understanding-ownership/listing_03_06/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch03-understanding-ownership/listing_03_06/Scarb.toml b/listings/ch03-understanding-ownership/listing_03_06/Scarb.toml new file mode 100644 index 000000000..e660b2686 --- /dev/null +++ b/listings/ch03-understanding-ownership/listing_03_06/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_03_06" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch03-understanding-ownership/listing_03_06.cairo b/listings/ch03-understanding-ownership/listing_03_06/src/lib.cairo similarity index 91% rename from listings/ch03-understanding-ownership/listing_03_06.cairo rename to listings/ch03-understanding-ownership/listing_03_06/src/lib.cairo index 7533c9562..06e51604d 100644 --- a/listings/ch03-understanding-ownership/listing_03_06.cairo +++ b/listings/ch03-understanding-ownership/listing_03_06/src/lib.cairo @@ -1,4 +1,4 @@ -// does_not_compile +//TAG: does_not_compile #[derive(Copy, Drop)] struct Rectangle { height: u64, diff --git a/listings/ch03-understanding-ownership/listing_03_07/.gitignore b/listings/ch03-understanding-ownership/listing_03_07/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch03-understanding-ownership/listing_03_07/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch03-understanding-ownership/listing_03_07/Scarb.toml b/listings/ch03-understanding-ownership/listing_03_07/Scarb.toml new file mode 100644 index 000000000..807947a4e --- /dev/null +++ b/listings/ch03-understanding-ownership/listing_03_07/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_03_07" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch03-understanding-ownership/listing_03_07.cairo b/listings/ch03-understanding-ownership/listing_03_07/src/lib.cairo similarity index 100% rename from listings/ch03-understanding-ownership/listing_03_07.cairo rename to listings/ch03-understanding-ownership/listing_03_07/src/lib.cairo diff --git a/listings/ch03-understanding-ownership/no_listing_01_array/.gitignore b/listings/ch03-understanding-ownership/no_listing_01_array/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch03-understanding-ownership/no_listing_01_array/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch03-understanding-ownership/no_listing_01_array/Scarb.toml b/listings/ch03-understanding-ownership/no_listing_01_array/Scarb.toml new file mode 100644 index 000000000..a26b3b9c0 --- /dev/null +++ b/listings/ch03-understanding-ownership/no_listing_01_array/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_01_array" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch03-understanding-ownership/no_listing_01_array.cairo b/listings/ch03-understanding-ownership/no_listing_01_array/src/lib.cairo similarity index 80% rename from listings/ch03-understanding-ownership/no_listing_01_array.cairo rename to listings/ch03-understanding-ownership/no_listing_01_array/src/lib.cairo index 37f250cda..9e8244360 100644 --- a/listings/ch03-understanding-ownership/no_listing_01_array.cairo +++ b/listings/ch03-understanding-ownership/no_listing_01_array/src/lib.cairo @@ -1,4 +1,3 @@ -use array::ArrayTrait; fn main() { let mut arr = ArrayTrait::::new(); arr.append(1); diff --git a/listings/ch03-understanding-ownership/no_listing_02_pass_array_by_value/.gitignore b/listings/ch03-understanding-ownership/no_listing_02_pass_array_by_value/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch03-understanding-ownership/no_listing_02_pass_array_by_value/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch03-understanding-ownership/no_listing_02_pass_array_by_value/Scarb.toml b/listings/ch03-understanding-ownership/no_listing_02_pass_array_by_value/Scarb.toml new file mode 100644 index 000000000..982685dd2 --- /dev/null +++ b/listings/ch03-understanding-ownership/no_listing_02_pass_array_by_value/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_02_pass_array_by_value" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch03-understanding-ownership/no_listing_02_pass_array_by_value.cairo b/listings/ch03-understanding-ownership/no_listing_02_pass_array_by_value/src/lib.cairo similarity index 86% rename from listings/ch03-understanding-ownership/no_listing_02_pass_array_by_value.cairo rename to listings/ch03-understanding-ownership/no_listing_02_pass_array_by_value/src/lib.cairo index 7e9b892ce..6d61ded8c 100644 --- a/listings/ch03-understanding-ownership/no_listing_02_pass_array_by_value.cairo +++ b/listings/ch03-understanding-ownership/no_listing_02_pass_array_by_value/src/lib.cairo @@ -1,4 +1,5 @@ -use array::ArrayTrait; +//TAG: does_not_run + fn foo(arr: Array) {} fn bar(arr: Array) {} diff --git a/listings/ch03-understanding-ownership/no_listing_03_copy_trait/.gitignore b/listings/ch03-understanding-ownership/no_listing_03_copy_trait/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch03-understanding-ownership/no_listing_03_copy_trait/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch03-understanding-ownership/no_listing_03_copy_trait/Scarb.toml b/listings/ch03-understanding-ownership/no_listing_03_copy_trait/Scarb.toml new file mode 100644 index 000000000..b6b3f4081 --- /dev/null +++ b/listings/ch03-understanding-ownership/no_listing_03_copy_trait/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_03_copy_trait" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch03-understanding-ownership/no_listing_03_copy_trait.cairo b/listings/ch03-understanding-ownership/no_listing_03_copy_trait/src/lib.cairo similarity index 75% rename from listings/ch03-understanding-ownership/no_listing_03_copy_trait.cairo rename to listings/ch03-understanding-ownership/no_listing_03_copy_trait/src/lib.cairo index f78ca8193..d51f15bcb 100644 --- a/listings/ch03-understanding-ownership/no_listing_03_copy_trait.cairo +++ b/listings/ch03-understanding-ownership/no_listing_03_copy_trait/src/lib.cairo @@ -10,6 +10,5 @@ fn main() { foo(p1); } -fn foo(p: Point) { - // do something with p -} \ No newline at end of file +fn foo(p: Point) { // do something with p +} diff --git a/listings/ch03-understanding-ownership/no_listing_04_no_drop_derive_fails/.gitignore b/listings/ch03-understanding-ownership/no_listing_04_no_drop_derive_fails/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch03-understanding-ownership/no_listing_04_no_drop_derive_fails/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch03-understanding-ownership/no_listing_04_no_drop_derive_fails/Scarb.toml b/listings/ch03-understanding-ownership/no_listing_04_no_drop_derive_fails/Scarb.toml new file mode 100644 index 000000000..7e178d5f7 --- /dev/null +++ b/listings/ch03-understanding-ownership/no_listing_04_no_drop_derive_fails/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_04_no_drop_derive_fails" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch03-understanding-ownership/no_listing_04_no_drop_derive_fails.cairo b/listings/ch03-understanding-ownership/no_listing_04_no_drop_derive_fails/src/lib.cairo similarity index 71% rename from listings/ch03-understanding-ownership/no_listing_04_no_drop_derive_fails.cairo rename to listings/ch03-understanding-ownership/no_listing_04_no_drop_derive_fails/src/lib.cairo index 474131619..0cb538029 100644 --- a/listings/ch03-understanding-ownership/no_listing_04_no_drop_derive_fails.cairo +++ b/listings/ch03-understanding-ownership/no_listing_04_no_drop_derive_fails/src/lib.cairo @@ -1,5 +1,6 @@ +//TAG: does_not_compile struct A {} fn main() { A {}; // error: Value not dropped. -} \ No newline at end of file +} diff --git a/listings/ch03-understanding-ownership/no_listing_05_drop_derive_compiles/.gitignore b/listings/ch03-understanding-ownership/no_listing_05_drop_derive_compiles/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch03-understanding-ownership/no_listing_05_drop_derive_compiles/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch03-understanding-ownership/no_listing_05_drop_derive_compiles/Scarb.toml b/listings/ch03-understanding-ownership/no_listing_05_drop_derive_compiles/Scarb.toml new file mode 100644 index 000000000..623e85a05 --- /dev/null +++ b/listings/ch03-understanding-ownership/no_listing_05_drop_derive_compiles/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_05_drop_derive_compiles" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch03-understanding-ownership/no_listing_05_drop_derive_compiles.cairo b/listings/ch03-understanding-ownership/no_listing_05_drop_derive_compiles/src/lib.cairo similarity index 100% rename from listings/ch03-understanding-ownership/no_listing_05_drop_derive_compiles.cairo rename to listings/ch03-understanding-ownership/no_listing_05_drop_derive_compiles/src/lib.cairo diff --git a/listings/ch03-understanding-ownership/no_listing_06_no_destruct_compile_fails.cairo b/listings/ch03-understanding-ownership/no_listing_06_no_destruct_compile_fails.cairo deleted file mode 100644 index 64664994d..000000000 --- a/listings/ch03-understanding-ownership/no_listing_06_no_destruct_compile_fails.cairo +++ /dev/null @@ -1,9 +0,0 @@ -use dict::Felt252DictTrait; - -struct A { - dict: Felt252Dict -} - -fn main() { - A { dict: Felt252DictTrait::new() }; -} diff --git a/listings/ch03-understanding-ownership/no_listing_06_no_destruct_compile_fails/.gitignore b/listings/ch03-understanding-ownership/no_listing_06_no_destruct_compile_fails/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch03-understanding-ownership/no_listing_06_no_destruct_compile_fails/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch03-understanding-ownership/no_listing_06_no_destruct_compile_fails/Scarb.toml b/listings/ch03-understanding-ownership/no_listing_06_no_destruct_compile_fails/Scarb.toml new file mode 100644 index 000000000..326ab5944 --- /dev/null +++ b/listings/ch03-understanding-ownership/no_listing_06_no_destruct_compile_fails/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_06_no_destruct_compile_fails" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch03-understanding-ownership/no_listing_06_no_destruct_compile_fails/src/lib.cairo b/listings/ch03-understanding-ownership/no_listing_06_no_destruct_compile_fails/src/lib.cairo new file mode 100644 index 000000000..1939b7215 --- /dev/null +++ b/listings/ch03-understanding-ownership/no_listing_06_no_destruct_compile_fails/src/lib.cairo @@ -0,0 +1,9 @@ +//TAG: does_not_compile + +struct A { + dict: Felt252Dict +} + +fn main() { + A { dict: Default::default() }; +} diff --git a/listings/ch03-understanding-ownership/no_listing_07_destruct_compiles.cairo b/listings/ch03-understanding-ownership/no_listing_07_destruct_compiles.cairo deleted file mode 100644 index ac1c5e91d..000000000 --- a/listings/ch03-understanding-ownership/no_listing_07_destruct_compiles.cairo +++ /dev/null @@ -1,10 +0,0 @@ -use dict::Felt252DictTrait; - -#[derive(Destruct)] -struct A { - dict: Felt252Dict -} - -fn main() { - A { dict: Felt252DictTrait::new() }; // No error here -} diff --git a/listings/ch03-understanding-ownership/no_listing_07_destruct_compiles/.gitignore b/listings/ch03-understanding-ownership/no_listing_07_destruct_compiles/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch03-understanding-ownership/no_listing_07_destruct_compiles/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch03-understanding-ownership/no_listing_07_destruct_compiles/Scarb.toml b/listings/ch03-understanding-ownership/no_listing_07_destruct_compiles/Scarb.toml new file mode 100644 index 000000000..ef1cb40a1 --- /dev/null +++ b/listings/ch03-understanding-ownership/no_listing_07_destruct_compiles/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_07_destruct_compiles" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch03-understanding-ownership/no_listing_07_destruct_compiles/src/lib.cairo b/listings/ch03-understanding-ownership/no_listing_07_destruct_compiles/src/lib.cairo new file mode 100644 index 000000000..3e6c530e9 --- /dev/null +++ b/listings/ch03-understanding-ownership/no_listing_07_destruct_compiles/src/lib.cairo @@ -0,0 +1,8 @@ +#[derive(Destruct)] +struct A { + dict: Felt252Dict +} + +fn main() { + A { dict: Default::default() }; // No error here +} diff --git a/listings/ch03-understanding-ownership/no_listing_08_array_clone/.gitignore b/listings/ch03-understanding-ownership/no_listing_08_array_clone/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch03-understanding-ownership/no_listing_08_array_clone/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch03-understanding-ownership/no_listing_08_array_clone/Scarb.toml b/listings/ch03-understanding-ownership/no_listing_08_array_clone/Scarb.toml new file mode 100644 index 000000000..3d7582afa --- /dev/null +++ b/listings/ch03-understanding-ownership/no_listing_08_array_clone/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_08_array_clone" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch03-understanding-ownership/no_listing_08_array_clone.cairo b/listings/ch03-understanding-ownership/no_listing_08_array_clone/src/lib.cairo similarity index 85% rename from listings/ch03-understanding-ownership/no_listing_08_array_clone.cairo rename to listings/ch03-understanding-ownership/no_listing_08_array_clone/src/lib.cairo index 053bc95cb..c2bccc07f 100644 --- a/listings/ch03-understanding-ownership/no_listing_08_array_clone.cairo +++ b/listings/ch03-understanding-ownership/no_listing_08_array_clone/src/lib.cairo @@ -1,4 +1,3 @@ -use array::ArrayTrait; use clone::Clone; use array::ArrayTCloneImpl; fn main() { diff --git a/listings/ch03-understanding-ownership/no_listing_09_snapshots/.gitignore b/listings/ch03-understanding-ownership/no_listing_09_snapshots/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch03-understanding-ownership/no_listing_09_snapshots/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch03-understanding-ownership/no_listing_09_snapshots/Scarb.toml b/listings/ch03-understanding-ownership/no_listing_09_snapshots/Scarb.toml new file mode 100644 index 000000000..c4a83c3aa --- /dev/null +++ b/listings/ch03-understanding-ownership/no_listing_09_snapshots/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_09_snapshots" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch03-understanding-ownership/no_listing_09_snapshots.cairo b/listings/ch03-understanding-ownership/no_listing_09_snapshots/src/lib.cairo similarity index 96% rename from listings/ch03-understanding-ownership/no_listing_09_snapshots.cairo rename to listings/ch03-understanding-ownership/no_listing_09_snapshots/src/lib.cairo index 0433cc19c..1fb3e452d 100644 --- a/listings/ch03-understanding-ownership/no_listing_09_snapshots.cairo +++ b/listings/ch03-understanding-ownership/no_listing_09_snapshots/src/lib.cairo @@ -1,4 +1,3 @@ -use array::ArrayTrait; use debug::PrintTrait; fn main() { diff --git a/listings/ch03-understanding-ownership/no_listing_10_desnap/.gitignore b/listings/ch03-understanding-ownership/no_listing_10_desnap/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch03-understanding-ownership/no_listing_10_desnap/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch03-understanding-ownership/no_listing_10_desnap/Scarb.toml b/listings/ch03-understanding-ownership/no_listing_10_desnap/Scarb.toml new file mode 100644 index 000000000..e408dccee --- /dev/null +++ b/listings/ch03-understanding-ownership/no_listing_10_desnap/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_10_desnap" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch03-understanding-ownership/no_listing_10_desnap.cairo b/listings/ch03-understanding-ownership/no_listing_10_desnap/src/lib.cairo similarity index 100% rename from listings/ch03-understanding-ownership/no_listing_10_desnap.cairo rename to listings/ch03-understanding-ownership/no_listing_10_desnap/src/lib.cairo diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_01_user_struct/.gitignore b/listings/ch04-using-structs-to-structure-related-data/listing_04_01_user_struct/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_01_user_struct/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_01_user_struct/Scarb.toml b/listings/ch04-using-structs-to-structure-related-data/listing_04_01_user_struct/Scarb.toml new file mode 100644 index 000000000..9bed1b252 --- /dev/null +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_01_user_struct/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_04_01_user_struct" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_01_user_struct.cairo b/listings/ch04-using-structs-to-structure-related-data/listing_04_01_user_struct/src/lib.cairo similarity index 100% rename from listings/ch04-using-structs-to-structure-related-data/listing_04_01_user_struct.cairo rename to listings/ch04-using-structs-to-structure-related-data/listing_04_01_user_struct/src/lib.cairo diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_03_mut_struct/.gitignore b/listings/ch04-using-structs-to-structure-related-data/listing_04_03_mut_struct/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_03_mut_struct/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_03_mut_struct/Scarb.toml b/listings/ch04-using-structs-to-structure-related-data/listing_04_03_mut_struct/Scarb.toml new file mode 100644 index 000000000..23951d82b --- /dev/null +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_03_mut_struct/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_04_03_mut_struct" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_03_mut_struct.cairo b/listings/ch04-using-structs-to-structure-related-data/listing_04_03_mut_struct/src/lib.cairo similarity index 89% rename from listings/ch04-using-structs-to-structure-related-data/listing_04_03_mut_struct.cairo rename to listings/ch04-using-structs-to-structure-related-data/listing_04_03_mut_struct/src/lib.cairo index 221ff91b3..7e9f30f64 100644 --- a/listings/ch04-using-structs-to-structure-related-data/listing_04_03_mut_struct.cairo +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_03_mut_struct/src/lib.cairo @@ -17,14 +17,15 @@ fn main() { // ANCHOR: build_user fn build_user(email: felt252, username: felt252) -> User { - User { active: true, username: username, email: email, sign_in_count: 1, } + User { active: true, username: username, email: email, sign_in_count: 1, } } // ANCHOR_END: build_user // ANCHOR: build_user2 fn build_user_short(email: felt252, username: felt252) -> User { - User { active: true, username, email, sign_in_count: 1, } + User { active: true, username, email, sign_in_count: 1, } } // ANCHOR_END: build_user2 // ANCHOR_END: all + diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_06_no_struct/.gitignore b/listings/ch04-using-structs-to-structure-related-data/listing_04_06_no_struct/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_06_no_struct/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_06_no_struct/Scarb.toml b/listings/ch04-using-structs-to-structure-related-data/listing_04_06_no_struct/Scarb.toml new file mode 100644 index 000000000..914681f3f --- /dev/null +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_06_no_struct/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_04_06_no_struct" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_06_no_struct.cairo b/listings/ch04-using-structs-to-structure-related-data/listing_04_06_no_struct/src/lib.cairo similarity index 99% rename from listings/ch04-using-structs-to-structure-related-data/listing_04_06_no_struct.cairo rename to listings/ch04-using-structs-to-structure-related-data/listing_04_06_no_struct/src/lib.cairo index 50d52ac29..fae125347 100644 --- a/listings/ch04-using-structs-to-structure-related-data/listing_04_06_no_struct.cairo +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_06_no_struct/src/lib.cairo @@ -8,4 +8,4 @@ fn main() { fn area(width: u64, height: u64) -> u64 { width * height -} \ No newline at end of file +} diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_07_w_tuples/.gitignore b/listings/ch04-using-structs-to-structure-related-data/listing_04_07_w_tuples/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_07_w_tuples/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_07_w_tuples/Scarb.toml b/listings/ch04-using-structs-to-structure-related-data/listing_04_07_w_tuples/Scarb.toml new file mode 100644 index 000000000..16bdd6007 --- /dev/null +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_07_w_tuples/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_04_07_w_tuples" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_07_w_tuples.cairo b/listings/ch04-using-structs-to-structure-related-data/listing_04_07_w_tuples/src/lib.cairo similarity index 100% rename from listings/ch04-using-structs-to-structure-related-data/listing_04_07_w_tuples.cairo rename to listings/ch04-using-structs-to-structure-related-data/listing_04_07_w_tuples/src/lib.cairo diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_08_w_structs/.gitignore b/listings/ch04-using-structs-to-structure-related-data/listing_04_08_w_structs/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_08_w_structs/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_08_w_structs/Scarb.toml b/listings/ch04-using-structs-to-structure-related-data/listing_04_08_w_structs/Scarb.toml new file mode 100644 index 000000000..ad8c9fd6d --- /dev/null +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_08_w_structs/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_04_08_w_structs" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_08_w_structs.cairo b/listings/ch04-using-structs-to-structure-related-data/listing_04_08_w_structs/src/lib.cairo similarity index 80% rename from listings/ch04-using-structs-to-structure-related-data/listing_04_08_w_structs.cairo rename to listings/ch04-using-structs-to-structure-related-data/listing_04_08_w_structs/src/lib.cairo index 6202fd7a3..7db5eeac1 100644 --- a/listings/ch04-using-structs-to-structure-related-data/listing_04_08_w_structs.cairo +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_08_w_structs/src/lib.cairo @@ -6,7 +6,7 @@ struct Rectangle { } fn main() { - let rectangle = Rectangle { width: 30, height: 10, }; + let rectangle = Rectangle { width: 30, height: 10, }; let area = area(rectangle); area.print(); // print out the area } diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_10_print_rectangle/.gitignore b/listings/ch04-using-structs-to-structure-related-data/listing_04_10_print_rectangle/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_10_print_rectangle/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_10_print_rectangle/Scarb.toml b/listings/ch04-using-structs-to-structure-related-data/listing_04_10_print_rectangle/Scarb.toml new file mode 100644 index 000000000..243072d65 --- /dev/null +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_10_print_rectangle/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_04_10_print_rectangle" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_10_print_rectangle.cairo b/listings/ch04-using-structs-to-structure-related-data/listing_04_10_print_rectangle/src/lib.cairo similarity index 81% rename from listings/ch04-using-structs-to-structure-related-data/listing_04_10_print_rectangle.cairo rename to listings/ch04-using-structs-to-structure-related-data/listing_04_10_print_rectangle/src/lib.cairo index 4f54ffec8..412db5030 100644 --- a/listings/ch04-using-structs-to-structure-related-data/listing_04_10_print_rectangle.cairo +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_10_print_rectangle/src/lib.cairo @@ -6,7 +6,7 @@ struct Rectangle { } fn main() { - let rectangle = Rectangle { width: 30, height: 10, }; + let rectangle = Rectangle { width: 30, height: 10, }; rectangle.print(); } diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_13_area_method/.gitignore b/listings/ch04-using-structs-to-structure-related-data/listing_04_13_area_method/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_13_area_method/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_13_area_method/Scarb.toml b/listings/ch04-using-structs-to-structure-related-data/listing_04_13_area_method/Scarb.toml new file mode 100644 index 000000000..0299a3d72 --- /dev/null +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_13_area_method/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_04_13_area_method" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_13_area_method.cairo b/listings/ch04-using-structs-to-structure-related-data/listing_04_13_area_method/src/lib.cairo similarity index 85% rename from listings/ch04-using-structs-to-structure-related-data/listing_04_13_area_method.cairo rename to listings/ch04-using-structs-to-structure-related-data/listing_04_13_area_method/src/lib.cairo index eb158b7d5..02d7964ac 100644 --- a/listings/ch04-using-structs-to-structure-related-data/listing_04_13_area_method.cairo +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_13_area_method/src/lib.cairo @@ -16,7 +16,7 @@ impl RectangleImpl of RectangleTrait { } fn main() { - let rect1 = Rectangle { width: 30, height: 50, }; + let rect1 = Rectangle { width: 30, height: 50, }; rect1.area().print(); } diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_14_width_method/.gitignore b/listings/ch04-using-structs-to-structure-related-data/listing_04_14_width_method/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_14_width_method/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_14_width_method/Scarb.toml b/listings/ch04-using-structs-to-structure-related-data/listing_04_14_width_method/Scarb.toml new file mode 100644 index 000000000..4013efeab --- /dev/null +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_14_width_method/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_04_14_width_method" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_14_width_method.cairo b/listings/ch04-using-structs-to-structure-related-data/listing_04_14_width_method/src/lib.cairo similarity index 85% rename from listings/ch04-using-structs-to-structure-related-data/listing_04_14_width_method.cairo rename to listings/ch04-using-structs-to-structure-related-data/listing_04_14_width_method/src/lib.cairo index 080fab4ca..0d846fc4f 100644 --- a/listings/ch04-using-structs-to-structure-related-data/listing_04_14_width_method.cairo +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_14_width_method/src/lib.cairo @@ -16,6 +16,6 @@ impl RectangleImpl of RectangleTrait { } fn main() { - let rect1 = Rectangle { width: 30, height: 50, }; + let rect1 = Rectangle { width: 30, height: 50, }; rect1.width().print(); } diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_15_can_hold/.gitignore b/listings/ch04-using-structs-to-structure-related-data/listing_04_15_can_hold/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_15_can_hold/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_15_can_hold/Scarb.toml b/listings/ch04-using-structs-to-structure-related-data/listing_04_15_can_hold/Scarb.toml new file mode 100644 index 000000000..18910b023 --- /dev/null +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_15_can_hold/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_04_15_can_hold" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch04-using-structs-to-structure-related-data/listing_04_15_can_hold.cairo b/listings/ch04-using-structs-to-structure-related-data/listing_04_15_can_hold/src/lib.cairo similarity index 80% rename from listings/ch04-using-structs-to-structure-related-data/listing_04_15_can_hold.cairo rename to listings/ch04-using-structs-to-structure-related-data/listing_04_15_can_hold/src/lib.cairo index 815a75689..66dedf44d 100644 --- a/listings/ch04-using-structs-to-structure-related-data/listing_04_15_can_hold.cairo +++ b/listings/ch04-using-structs-to-structure-related-data/listing_04_15_can_hold/src/lib.cairo @@ -1,4 +1,4 @@ -// does_not_compile +//TAG: does_not_compile // ANCHOR: all // ANCHOR: no_method use debug::PrintTrait; @@ -9,9 +9,9 @@ struct Rectangle { } fn main() { - let rect1 = Rectangle { width: 30, height: 50, }; - let rect2 = Rectangle { width: 10, height: 40, }; - let rect3 = Rectangle { width: 60, height: 45, }; + let rect1 = Rectangle { width: 30, height: 50, }; + let rect2 = Rectangle { width: 10, height: 40, }; + let rect3 = Rectangle { width: 60, height: 45, }; 'Can rect1 hold rect2?'.print(); rect1.can_hold(@rect2).print(); diff --git a/listings/ch04-using-structs-to-structure-related-data/no_listing_01_implementation_functions/.gitignore b/listings/ch04-using-structs-to-structure-related-data/no_listing_01_implementation_functions/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch04-using-structs-to-structure-related-data/no_listing_01_implementation_functions/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch04-using-structs-to-structure-related-data/no_listing_01_implementation_functions/Scarb.toml b/listings/ch04-using-structs-to-structure-related-data/no_listing_01_implementation_functions/Scarb.toml new file mode 100644 index 000000000..4ed15de20 --- /dev/null +++ b/listings/ch04-using-structs-to-structure-related-data/no_listing_01_implementation_functions/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_01_implementation_functions" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch04-using-structs-to-structure-related-data/no_listing_01_implementation_functions.cairo b/listings/ch04-using-structs-to-structure-related-data/no_listing_01_implementation_functions/src/lib.cairo similarity index 99% rename from listings/ch04-using-structs-to-structure-related-data/no_listing_01_implementation_functions.cairo rename to listings/ch04-using-structs-to-structure-related-data/no_listing_01_implementation_functions/src/lib.cairo index a8ccc0101..ae36b7418 100644 --- a/listings/ch04-using-structs-to-structure-related-data/no_listing_01_implementation_functions.cairo +++ b/listings/ch04-using-structs-to-structure-related-data/no_listing_01_implementation_functions/src/lib.cairo @@ -16,3 +16,4 @@ impl RectangleImpl of RectangleTrait { } // ANCHOR_END: here + diff --git a/listings/ch04-using-structs-to-structure-related-data/no_listing_02_multiple_impls/.gitignore b/listings/ch04-using-structs-to-structure-related-data/no_listing_02_multiple_impls/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch04-using-structs-to-structure-related-data/no_listing_02_multiple_impls/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch04-using-structs-to-structure-related-data/no_listing_02_multiple_impls/Scarb.toml b/listings/ch04-using-structs-to-structure-related-data/no_listing_02_multiple_impls/Scarb.toml new file mode 100644 index 000000000..8431301bb --- /dev/null +++ b/listings/ch04-using-structs-to-structure-related-data/no_listing_02_multiple_impls/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_02_multiple_impls" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch04-using-structs-to-structure-related-data/no_listing_02_multiple_impls.cairo b/listings/ch04-using-structs-to-structure-related-data/no_listing_02_multiple_impls/src/lib.cairo similarity index 88% rename from listings/ch04-using-structs-to-structure-related-data/no_listing_02_multiple_impls.cairo rename to listings/ch04-using-structs-to-structure-related-data/no_listing_02_multiple_impls/src/lib.cairo index 41dbfc025..d6daf6ce9 100644 --- a/listings/ch04-using-structs-to-structure-related-data/no_listing_02_multiple_impls.cairo +++ b/listings/ch04-using-structs-to-structure-related-data/no_listing_02_multiple_impls/src/lib.cairo @@ -20,7 +20,7 @@ trait RectangleCmp { impl RectangleCmpImpl of RectangleCmp { fn can_hold(self: @Rectangle, other: @Rectangle) -> bool { - *self.width > *other.width & *self.height > *other.height + *self.width > *other.width && *self.height > *other.height } } // ANCHOR_END: here diff --git a/listings/ch05-enums-and-pattern-matching/listing_05_03/.gitignore b/listings/ch05-enums-and-pattern-matching/listing_05_03/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch05-enums-and-pattern-matching/listing_05_03/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch05-enums-and-pattern-matching/listing_05_03/Scarb.toml b/listings/ch05-enums-and-pattern-matching/listing_05_03/Scarb.toml new file mode 100644 index 000000000..13b80bb40 --- /dev/null +++ b/listings/ch05-enums-and-pattern-matching/listing_05_03/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_05_03" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch05-enums-and-pattern-matching/listing_05_03.cairo b/listings/ch05-enums-and-pattern-matching/listing_05_03/src/lib.cairo similarity index 99% rename from listings/ch05-enums-and-pattern-matching/listing_05_03.cairo rename to listings/ch05-enums-and-pattern-matching/listing_05_03/src/lib.cairo index 4eebf80d4..919705178 100644 --- a/listings/ch05-enums-and-pattern-matching/listing_05_03.cairo +++ b/listings/ch05-enums-and-pattern-matching/listing_05_03/src/lib.cairo @@ -18,3 +18,4 @@ fn value_in_cents(coin: Coin) -> felt252 { // ANCHOR_END: function // ANCHOR_END: all + diff --git a/listings/ch05-enums-and-pattern-matching/listing_05_04/.gitignore b/listings/ch05-enums-and-pattern-matching/listing_05_04/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch05-enums-and-pattern-matching/listing_05_04/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch05-enums-and-pattern-matching/listing_05_04/Scarb.toml b/listings/ch05-enums-and-pattern-matching/listing_05_04/Scarb.toml new file mode 100644 index 000000000..2c7182df3 --- /dev/null +++ b/listings/ch05-enums-and-pattern-matching/listing_05_04/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_05_04" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch05-enums-and-pattern-matching/listing_05_04.cairo b/listings/ch05-enums-and-pattern-matching/listing_05_04/src/lib.cairo similarity index 84% rename from listings/ch05-enums-and-pattern-matching/listing_05_04.cairo rename to listings/ch05-enums-and-pattern-matching/listing_05_04/src/lib.cairo index 9b4dbed82..c842e785a 100644 --- a/listings/ch05-enums-and-pattern-matching/listing_05_04.cairo +++ b/listings/ch05-enums-and-pattern-matching/listing_05_04/src/lib.cairo @@ -9,5 +9,5 @@ enum Coin { Penny: (), Nickel: (), Dime: (), - Quarter: (UsState, ), + Quarter: (UsState,), } diff --git a/listings/ch05-enums-and-pattern-matching/listing_05_05/.gitignore b/listings/ch05-enums-and-pattern-matching/listing_05_05/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch05-enums-and-pattern-matching/listing_05_05/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch05-enums-and-pattern-matching/listing_05_05/Scarb.toml b/listings/ch05-enums-and-pattern-matching/listing_05_05/Scarb.toml new file mode 100644 index 000000000..2a26cd413 --- /dev/null +++ b/listings/ch05-enums-and-pattern-matching/listing_05_05/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_05_05" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch05-enums-and-pattern-matching/listing_05_05.cairo b/listings/ch05-enums-and-pattern-matching/listing_05_05/src/lib.cairo similarity index 72% rename from listings/ch05-enums-and-pattern-matching/listing_05_05.cairo rename to listings/ch05-enums-and-pattern-matching/listing_05_05/src/lib.cairo index cbb7e19d3..f24658ee0 100644 --- a/listings/ch05-enums-and-pattern-matching/listing_05_05.cairo +++ b/listings/ch05-enums-and-pattern-matching/listing_05_05/src/lib.cairo @@ -1,10 +1,9 @@ -use option::OptionTrait; use debug::PrintTrait; fn plus_one(x: Option) -> Option { match x { Option::Some(val) => Option::Some(val + 1), - Option::None(_) => Option::None(()), + Option::None(_) => Option::None, } } @@ -12,6 +11,6 @@ fn main() { let five: Option = Option::Some(5); let six: Option = plus_one(five); six.unwrap().print(); - let none = plus_one(Option::None(())); + let none = plus_one(Option::None); none.unwrap().print(); } diff --git a/listings/ch05-enums-and-pattern-matching/no_listing_01_enum_example/.gitignore b/listings/ch05-enums-and-pattern-matching/no_listing_01_enum_example/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch05-enums-and-pattern-matching/no_listing_01_enum_example/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch05-enums-and-pattern-matching/no_listing_01_enum_example/Scarb.toml b/listings/ch05-enums-and-pattern-matching/no_listing_01_enum_example/Scarb.toml new file mode 100644 index 000000000..407c6ecef --- /dev/null +++ b/listings/ch05-enums-and-pattern-matching/no_listing_01_enum_example/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_01_enum_example" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch05-enums-and-pattern-matching/no_listing_01_enum_example.cairo b/listings/ch05-enums-and-pattern-matching/no_listing_01_enum_example/src/lib.cairo similarity index 56% rename from listings/ch05-enums-and-pattern-matching/no_listing_01_enum_example.cairo rename to listings/ch05-enums-and-pattern-matching/no_listing_01_enum_example/src/lib.cairo index 9db1d7da4..2d9ae761f 100644 --- a/listings/ch05-enums-and-pattern-matching/no_listing_01_enum_example.cairo +++ b/listings/ch05-enums-and-pattern-matching/no_listing_01_enum_example/src/lib.cairo @@ -2,17 +2,17 @@ // ANCHOR: enum_example #[derive(Drop)] enum Direction { - North: (), - East: (), - South: (), - West: (), + North, + East, + South, + West, } // ANCHOR_END: enum_example fn main() { // ANCHOR: here - let direction = Direction::North(()); - // ANCHOR_END: here + let direction = Direction::North; +// ANCHOR_END: here } // ANCHOR_END: all diff --git a/listings/ch05-enums-and-pattern-matching/no_listing_02_enum_message/.gitignore b/listings/ch05-enums-and-pattern-matching/no_listing_02_enum_message/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch05-enums-and-pattern-matching/no_listing_02_enum_message/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch05-enums-and-pattern-matching/no_listing_02_enum_message/Scarb.toml b/listings/ch05-enums-and-pattern-matching/no_listing_02_enum_message/Scarb.toml new file mode 100644 index 000000000..cd1fd236c --- /dev/null +++ b/listings/ch05-enums-and-pattern-matching/no_listing_02_enum_message/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_02_enum_message" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch05-enums-and-pattern-matching/no_listing_02_enum_message.cairo b/listings/ch05-enums-and-pattern-matching/no_listing_02_enum_message/src/lib.cairo similarity index 88% rename from listings/ch05-enums-and-pattern-matching/no_listing_02_enum_message.cairo rename to listings/ch05-enums-and-pattern-matching/no_listing_02_enum_message/src/lib.cairo index b140de116..0e7bdb663 100644 --- a/listings/ch05-enums-and-pattern-matching/no_listing_02_enum_message.cairo +++ b/listings/ch05-enums-and-pattern-matching/no_listing_02_enum_message/src/lib.cairo @@ -3,7 +3,7 @@ use debug::PrintTrait; // ANCHOR: message #[derive(Drop)] enum Message { - Quit: (), + Quit, Echo: felt252, Move: (u128, u128), } @@ -17,7 +17,7 @@ trait Processing { impl ProcessingImpl of Processing { fn process(self: Message) { match self { - Message::Quit(()) => { + Message::Quit => { 'quitting'.print(); }, Message::Echo(value) => { @@ -32,7 +32,7 @@ impl ProcessingImpl of Processing { // ANCHOR_END: trait_impl fn main() { // ANCHOR: main - let msg: Message = Message::Quit(()); + let msg: Message = Message::Quit; msg.process(); // ANCHOR_END: main } diff --git a/listings/ch05-enums-and-pattern-matching/no_listing_03_enum_option/.gitignore b/listings/ch05-enums-and-pattern-matching/no_listing_03_enum_option/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch05-enums-and-pattern-matching/no_listing_03_enum_option/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch05-enums-and-pattern-matching/no_listing_03_enum_option/Scarb.toml b/listings/ch05-enums-and-pattern-matching/no_listing_03_enum_option/Scarb.toml new file mode 100644 index 000000000..45bf5b470 --- /dev/null +++ b/listings/ch05-enums-and-pattern-matching/no_listing_03_enum_option/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_03_enum_option" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch05-enums-and-pattern-matching/no_listing_03_enum_option.cairo b/listings/ch05-enums-and-pattern-matching/no_listing_03_enum_option/src/lib.cairo similarity index 85% rename from listings/ch05-enums-and-pattern-matching/no_listing_03_enum_option.cairo rename to listings/ch05-enums-and-pattern-matching/no_listing_03_enum_option/src/lib.cairo index ef95ce74d..1d3d9d39d 100644 --- a/listings/ch05-enums-and-pattern-matching/no_listing_03_enum_option.cairo +++ b/listings/ch05-enums-and-pattern-matching/no_listing_03_enum_option/src/lib.cairo @@ -1,9 +1,8 @@ -use array::ArrayTrait; use debug::PrintTrait; -use option::OptionTrait; + fn find_value_recursive(arr: @Array, value: felt252, index: usize) -> Option { if index >= arr.len() { - return Option::None(()); + return Option::None; } if *arr.at(index) == value { @@ -16,15 +15,15 @@ fn find_value_recursive(arr: @Array, value: felt252, index: usize) -> O fn find_value_iterative(arr: @Array, value: felt252) -> Option { let length = arr.len(); let mut index = 0; - let mut found: Option = Option::None(()); + let mut found: Option = Option::None; loop { if index < length { if *arr.at(index) == value { found = Option::Some(index); - break (); + break; } } else { - break (); + break; } index += 1; }; @@ -50,7 +49,7 @@ fn test_increase_amount() { 'it worked'.print(); } }, - Option::None(()) => { + Option::None => { 'not found'.print(); }, } @@ -60,7 +59,7 @@ fn test_increase_amount() { 'it worked'.print(); } }, - Option::None(()) => { + Option::None => { 'not found'.print(); }, } diff --git a/listings/ch05-enums-and-pattern-matching/no_listing_04_match_arms/.gitignore b/listings/ch05-enums-and-pattern-matching/no_listing_04_match_arms/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch05-enums-and-pattern-matching/no_listing_04_match_arms/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch05-enums-and-pattern-matching/no_listing_04_match_arms/Scarb.toml b/listings/ch05-enums-and-pattern-matching/no_listing_04_match_arms/Scarb.toml new file mode 100644 index 000000000..a9f754ed7 --- /dev/null +++ b/listings/ch05-enums-and-pattern-matching/no_listing_04_match_arms/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_04_match_arms" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch05-enums-and-pattern-matching/no_listing_04_match_arms.cairo b/listings/ch05-enums-and-pattern-matching/no_listing_04_match_arms/src/lib.cairo similarity index 90% rename from listings/ch05-enums-and-pattern-matching/no_listing_04_match_arms.cairo rename to listings/ch05-enums-and-pattern-matching/no_listing_04_match_arms/src/lib.cairo index cb0c06473..682bb7f95 100644 --- a/listings/ch05-enums-and-pattern-matching/no_listing_04_match_arms.cairo +++ b/listings/ch05-enums-and-pattern-matching/no_listing_04_match_arms/src/lib.cairo @@ -6,7 +6,7 @@ enum Coin { Quarter: (), } -// ANCHOR: main +// ANCHOR: here fn value_in_cents(coin: Coin) -> felt252 { match coin { Coin::Penny(_) => { @@ -18,3 +18,6 @@ fn value_in_cents(coin: Coin) -> felt252 { Coin::Quarter(_) => 25, } } +// ANCHOR_END: here + + diff --git a/listings/ch05-enums-and-pattern-matching/no_listing_05_print_enum/.gitignore b/listings/ch05-enums-and-pattern-matching/no_listing_05_print_enum/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch05-enums-and-pattern-matching/no_listing_05_print_enum/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch05-enums-and-pattern-matching/no_listing_05_print_enum/Scarb.toml b/listings/ch05-enums-and-pattern-matching/no_listing_05_print_enum/Scarb.toml new file mode 100644 index 000000000..ad28eebe4 --- /dev/null +++ b/listings/ch05-enums-and-pattern-matching/no_listing_05_print_enum/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_05_print_enum" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch05-enums-and-pattern-matching/no_listing_05_print_enum.cairo b/listings/ch05-enums-and-pattern-matching/no_listing_05_print_enum/src/lib.cairo similarity index 96% rename from listings/ch05-enums-and-pattern-matching/no_listing_05_print_enum.cairo rename to listings/ch05-enums-and-pattern-matching/no_listing_05_print_enum/src/lib.cairo index cac6b628e..4165e2835 100644 --- a/listings/ch05-enums-and-pattern-matching/no_listing_05_print_enum.cairo +++ b/listings/ch05-enums-and-pattern-matching/no_listing_05_print_enum/src/lib.cairo @@ -12,7 +12,7 @@ enum Coin { Penny: (), Nickel: (), Dime: (), - Quarter: (UsState, ), + Quarter: UsState, } // ANCHOR_END: enum_def @@ -41,3 +41,4 @@ impl UsStatePrintImpl of PrintTrait { } // ANCHOR_END: print_impl + diff --git a/listings/ch05-enums-and-pattern-matching/no_listing_06_match_zero/.gitignore b/listings/ch05-enums-and-pattern-matching/no_listing_06_match_zero/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch05-enums-and-pattern-matching/no_listing_06_match_zero/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch05-enums-and-pattern-matching/no_listing_06_match_zero/Scarb.toml b/listings/ch05-enums-and-pattern-matching/no_listing_06_match_zero/Scarb.toml new file mode 100644 index 000000000..8d96b6fdd --- /dev/null +++ b/listings/ch05-enums-and-pattern-matching/no_listing_06_match_zero/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_06_match_zero" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch05-enums-and-pattern-matching/no_listing_06_match_zero.cairo b/listings/ch05-enums-and-pattern-matching/no_listing_06_match_zero/src/lib.cairo similarity index 99% rename from listings/ch05-enums-and-pattern-matching/no_listing_06_match_zero.cairo rename to listings/ch05-enums-and-pattern-matching/no_listing_06_match_zero/src/lib.cairo index 35b6acd25..96f817bb0 100644 --- a/listings/ch05-enums-and-pattern-matching/no_listing_06_match_zero.cairo +++ b/listings/ch05-enums-and-pattern-matching/no_listing_06_match_zero/src/lib.cairo @@ -9,3 +9,4 @@ fn did_i_win(nb: felt252) { } // ANCHOR_END: here + diff --git a/listings/ch05-enums-and-pattern-matching/no_listing_07_missing_match_arm/.gitignore b/listings/ch05-enums-and-pattern-matching/no_listing_07_missing_match_arm/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch05-enums-and-pattern-matching/no_listing_07_missing_match_arm/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch05-enums-and-pattern-matching/no_listing_07_missing_match_arm/Scarb.toml b/listings/ch05-enums-and-pattern-matching/no_listing_07_missing_match_arm/Scarb.toml new file mode 100644 index 000000000..2d464a91a --- /dev/null +++ b/listings/ch05-enums-and-pattern-matching/no_listing_07_missing_match_arm/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_07_missing_match_arm" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch05-enums-and-pattern-matching/no_listing_07_missing_match_arm/src/lib.cairo b/listings/ch05-enums-and-pattern-matching/no_listing_07_missing_match_arm/src/lib.cairo new file mode 100644 index 000000000..0411e8b8f --- /dev/null +++ b/listings/ch05-enums-and-pattern-matching/no_listing_07_missing_match_arm/src/lib.cairo @@ -0,0 +1,19 @@ +//TAG: does_not_compile + +use debug::PrintTrait; + +//ANCHOR: here +fn plus_one(x: Option) -> Option { + match x { + Option::Some(val) => Option::Some(val + 1), + } +} +//ANCHOR_END: here + +fn main() { + let five: Option = Option::Some(5); + let six: Option = plus_one(five); + six.unwrap().print(); + let none = plus_one(Option::None); + none.unwrap().print(); +} diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_01/.gitignore b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_01/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_01/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_01/Scarb.toml b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_01/Scarb.toml new file mode 100644 index 000000000..7b5dc5092 --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_01/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_06_01" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_01.cairo b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_01/src/lib.cairo similarity index 100% rename from listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_01.cairo rename to listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_01/src/lib.cairo diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_03/.gitignore b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_03/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_03/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_03/Scarb.toml b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_03/Scarb.toml new file mode 100644 index 000000000..b31c51bd9 --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_03/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_06_03" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_03.cairo b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_03/src/lib.cairo similarity index 94% rename from listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_03.cairo rename to listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_03/src/lib.cairo index b308ef956..daabd4c5f 100644 --- a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_03.cairo +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_03/src/lib.cairo @@ -1,3 +1,4 @@ +//TAG: does_not_compile mod front_of_house { mod hosting { fn add_to_waitlist() {} diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_04/.gitignore b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_04/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_04/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_04/Scarb.toml b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_04/Scarb.toml new file mode 100644 index 000000000..4e66bae77 --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_04/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_06_04" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_04.cairo b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_04/src/lib.cairo similarity index 100% rename from listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_04.cairo rename to listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_04/src/lib.cairo diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_05/.gitignore b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_05/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_05/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_05/Scarb.toml b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_05/Scarb.toml new file mode 100644 index 000000000..89da1587a --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_05/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_06_05" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_05.cairo b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_05/src/lib.cairo similarity index 89% rename from listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_05.cairo rename to listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_05/src/lib.cairo index 10ac3229f..a1f5d88ce 100644 --- a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_05.cairo +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_05/src/lib.cairo @@ -1,4 +1,4 @@ -// does_not_compile +//TAG: does_not_compile mod front_of_house { mod hosting { fn add_to_waitlist() {} diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_06/.gitignore b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_06/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_06/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_06/Scarb.toml b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_06/Scarb.toml new file mode 100644 index 000000000..5600f9b9c --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_06/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_06_06" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_06.cairo b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_06/src/lib.cairo similarity index 89% rename from listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_06.cairo rename to listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_06/src/lib.cairo index 928726676..91adbd444 100644 --- a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_06.cairo +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_06/src/lib.cairo @@ -1,4 +1,4 @@ -// does_not_compile +//TAG: does_not_compile mod front_of_house { mod hosting { fn add_to_waitlist() {} diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_07/.gitignore b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_07/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_07/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_07/Scarb.toml b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_07/Scarb.toml new file mode 100644 index 000000000..46ba47977 --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_07/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_06_07" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_07.cairo b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_07/src/lib.cairo similarity index 88% rename from listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_07.cairo rename to listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_07/src/lib.cairo index 84f0a4337..3db58df7c 100644 --- a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_07.cairo +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_07/src/lib.cairo @@ -1,3 +1,4 @@ +//TAG: does_not_compile mod front_of_house { mod hosting { fn add_to_waitlist() {} diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_08/.gitignore b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_08/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_08/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_08/Scarb.toml b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_08/Scarb.toml new file mode 100644 index 000000000..0d468918d --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_08/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_06_08" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_08.cairo b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_08/src/lib.cairo similarity index 74% rename from listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_08.cairo rename to listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_08/src/lib.cairo index 68276118c..9890f8749 100644 --- a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_08.cairo +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_08/src/lib.cairo @@ -1,5 +1,3 @@ -use array::ArrayTrait; - fn main() { let mut arr = ArrayTrait::new(); arr.append(1); diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_09/.gitignore b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_09/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_09/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_09/Scarb.toml b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_09/Scarb.toml new file mode 100644 index 000000000..88557e02a --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_09/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_06_09" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_09.cairo b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_09/src/lib.cairo similarity index 100% rename from listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_09.cairo rename to listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_09/src/lib.cairo diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_10/.gitignore b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_10/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_10/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_10/Scarb.toml b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_10/Scarb.toml new file mode 100644 index 000000000..10d4d6558 --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_10/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_06_10" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_10.cairo b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_10/src/lib.cairo similarity index 100% rename from listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_10.cairo rename to listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_10/src/lib.cairo diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_11/.gitignore b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_11/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_11/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_11/Scarb.toml b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_11/Scarb.toml new file mode 100644 index 000000000..4276a23d1 --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_11/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_06_11" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_11.cairo b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_11/src/lib.cairo similarity index 88% rename from listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_11.cairo rename to listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_11/src/lib.cairo index fde2ffa9e..783f73a58 100644 --- a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_11.cairo +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_11/src/lib.cairo @@ -1,4 +1,4 @@ -// does_not_compile +//TAG: does_not_compile mod front_of_house { mod hosting { fn add_to_waitlist() {} diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_12/.gitignore b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_12/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_12/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_12/Scarb.toml b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_12/Scarb.toml new file mode 100644 index 000000000..e721af9d7 --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_12/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_06_12" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_12.cairo b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_12/src/lib.cairo similarity index 83% rename from listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_12.cairo rename to listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_12/src/lib.cairo index b04f162d6..19921e561 100644 --- a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_12.cairo +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_12/src/lib.cairo @@ -1,4 +1,4 @@ -// does_not_compile +//TAG: does_not_compile mod front_of_house; use restaurant::front_of_house::hosting; diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_13/.gitignore b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_13/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_13/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_13/Scarb.toml b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_13/Scarb.toml new file mode 100644 index 000000000..75c00ee65 --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_13/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_06_13" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_13.cairo b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_13/src/lib.cairo similarity index 100% rename from listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_13.cairo rename to listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_13/src/lib.cairo diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_01_lib/.gitignore b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_01_lib/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_01_lib/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_01_lib/Scarb.toml b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_01_lib/Scarb.toml new file mode 100644 index 000000000..90a4ede79 --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_01_lib/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_01_lib" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_01_lib.cairo b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_01_lib/src/lib.cairo similarity index 80% rename from listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_01_lib.cairo rename to listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_01_lib/src/lib.cairo index 621827d07..87041362a 100644 --- a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_01_lib.cairo +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_01_lib/src/lib.cairo @@ -1,4 +1,4 @@ -// does_not_compile +//TAG: does_not_compile use garden::vegetables::Asparagus; mod garden; diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_02_garden/.gitignore b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_02_garden/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_02_garden/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_02_garden/Scarb.toml b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_02_garden/Scarb.toml new file mode 100644 index 000000000..c5e9e67ea --- /dev/null +++ b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_02_garden/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_02_garden" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_02_garden.cairo b/listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_02_garden/src/lib.cairo similarity index 100% rename from listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_02_garden.cairo rename to listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_02_garden/src/lib.cairo diff --git a/listings/ch07-generic-types-and-traits/no_listing_01_missing_tdrop/.gitignore b/listings/ch07-generic-types-and-traits/no_listing_01_missing_tdrop/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_01_missing_tdrop/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch07-generic-types-and-traits/no_listing_01_missing_tdrop/Scarb.toml b/listings/ch07-generic-types-and-traits/no_listing_01_missing_tdrop/Scarb.toml new file mode 100644 index 000000000..930478f31 --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_01_missing_tdrop/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_01_missing_tdrop" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch07-generic-types-and-traits/no_listing_01_missing_tdrop.cairo b/listings/ch07-generic-types-and-traits/no_listing_01_missing_tdrop/src/lib.cairo similarity index 91% rename from listings/ch07-generic-types-and-traits/no_listing_01_missing_tdrop.cairo rename to listings/ch07-generic-types-and-traits/no_listing_01_missing_tdrop/src/lib.cairo index 9bc3e1d0a..7fef27cc2 100644 --- a/listings/ch07-generic-types-and-traits/no_listing_01_missing_tdrop.cairo +++ b/listings/ch07-generic-types-and-traits/no_listing_01_missing_tdrop/src/lib.cairo @@ -1,6 +1,4 @@ -// does_not_compile - -use array::ArrayTrait; +//TAG: does_not_compile // Specify generic type T between the angulars fn largest_list(l1: Array, l2: Array) -> Array { diff --git a/listings/ch07-generic-types-and-traits/no_listing_02_with_tdrop/.gitignore b/listings/ch07-generic-types-and-traits/no_listing_02_with_tdrop/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_02_with_tdrop/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch07-generic-types-and-traits/no_listing_02_with_tdrop/Scarb.toml b/listings/ch07-generic-types-and-traits/no_listing_02_with_tdrop/Scarb.toml new file mode 100644 index 000000000..578ca26a8 --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_02_with_tdrop/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_02_with_tdrop" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch07-generic-types-and-traits/no_listing_02_with_tdrop.cairo b/listings/ch07-generic-types-and-traits/no_listing_02_with_tdrop/src/lib.cairo similarity index 87% rename from listings/ch07-generic-types-and-traits/no_listing_02_with_tdrop.cairo rename to listings/ch07-generic-types-and-traits/no_listing_02_with_tdrop/src/lib.cairo index 348274c32..54e7d595a 100644 --- a/listings/ch07-generic-types-and-traits/no_listing_02_with_tdrop.cairo +++ b/listings/ch07-generic-types-and-traits/no_listing_02_with_tdrop/src/lib.cairo @@ -1,4 +1,3 @@ -use array::ArrayTrait; fn largest_list>(l1: Array, l2: Array) -> Array { if l1.len() > l2.len() { l1 diff --git a/listings/ch07-generic-types-and-traits/no_listing_03_missing_tcopy/.gitignore b/listings/ch07-generic-types-and-traits/no_listing_03_missing_tcopy/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_03_missing_tcopy/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch07-generic-types-and-traits/no_listing_03_missing_tcopy/Scarb.toml b/listings/ch07-generic-types-and-traits/no_listing_03_missing_tcopy/Scarb.toml new file mode 100644 index 000000000..9762cd009 --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_03_missing_tcopy/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_03_missing_tcopy" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch07-generic-types-and-traits/no_listing_03_missing_tcopy.cairo b/listings/ch07-generic-types-and-traits/no_listing_03_missing_tcopy/src/lib.cairo similarity index 95% rename from listings/ch07-generic-types-and-traits/no_listing_03_missing_tcopy.cairo rename to listings/ch07-generic-types-and-traits/no_listing_03_missing_tcopy/src/lib.cairo index 3fb19b0d0..224246c52 100644 --- a/listings/ch07-generic-types-and-traits/no_listing_03_missing_tcopy.cairo +++ b/listings/ch07-generic-types-and-traits/no_listing_03_missing_tcopy/src/lib.cairo @@ -1,5 +1,4 @@ -// does_not_compile -use array::ArrayTrait; +//TAG: does_not_compile // Given a list of T get the smallest one. // The PartialOrd trait implements comparison operations for T diff --git a/listings/ch07-generic-types-and-traits/no_listing_04_with_tcopy/.gitignore b/listings/ch07-generic-types-and-traits/no_listing_04_with_tcopy/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_04_with_tcopy/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch07-generic-types-and-traits/no_listing_04_with_tcopy/Scarb.toml b/listings/ch07-generic-types-and-traits/no_listing_04_with_tcopy/Scarb.toml new file mode 100644 index 000000000..735b68760 --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_04_with_tcopy/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_04_with_tcopy" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch07-generic-types-and-traits/no_listing_04_with_tcopy.cairo b/listings/ch07-generic-types-and-traits/no_listing_04_with_tcopy/src/lib.cairo similarity index 94% rename from listings/ch07-generic-types-and-traits/no_listing_04_with_tcopy.cairo rename to listings/ch07-generic-types-and-traits/no_listing_04_with_tcopy/src/lib.cairo index c8b740f51..7f3e9485d 100644 --- a/listings/ch07-generic-types-and-traits/no_listing_04_with_tcopy.cairo +++ b/listings/ch07-generic-types-and-traits/no_listing_04_with_tcopy/src/lib.cairo @@ -1,4 +1,3 @@ -use array::ArrayTrait; fn smallest_element, impl TCopy: Copy, impl TDrop: Drop>( list: @Array ) -> T { diff --git a/listings/ch07-generic-types-and-traits/no_listing_05_derive_generics/.gitignore b/listings/ch07-generic-types-and-traits/no_listing_05_derive_generics/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_05_derive_generics/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch07-generic-types-and-traits/no_listing_05_derive_generics/Scarb.toml b/listings/ch07-generic-types-and-traits/no_listing_05_derive_generics/Scarb.toml new file mode 100644 index 000000000..8fa7ee52c --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_05_derive_generics/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_05_derive_generics" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch07-generic-types-and-traits/no_listing_05_derive_generics.cairo b/listings/ch07-generic-types-and-traits/no_listing_05_derive_generics/src/lib.cairo similarity index 100% rename from listings/ch07-generic-types-and-traits/no_listing_05_derive_generics.cairo rename to listings/ch07-generic-types-and-traits/no_listing_05_derive_generics/src/lib.cairo diff --git a/listings/ch07-generic-types-and-traits/no_listing_06_drop_explicit/.gitignore b/listings/ch07-generic-types-and-traits/no_listing_06_drop_explicit/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_06_drop_explicit/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch07-generic-types-and-traits/no_listing_06_drop_explicit/Scarb.toml b/listings/ch07-generic-types-and-traits/no_listing_06_drop_explicit/Scarb.toml new file mode 100644 index 000000000..51eebf163 --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_06_drop_explicit/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_06_drop_explicit" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch07-generic-types-and-traits/no_listing_06_drop_explicit.cairo b/listings/ch07-generic-types-and-traits/no_listing_06_drop_explicit/src/lib.cairo similarity index 100% rename from listings/ch07-generic-types-and-traits/no_listing_06_drop_explicit.cairo rename to listings/ch07-generic-types-and-traits/no_listing_06_drop_explicit/src/lib.cairo diff --git a/listings/ch07-generic-types-and-traits/no_listing_07_two_generics/.gitignore b/listings/ch07-generic-types-and-traits/no_listing_07_two_generics/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_07_two_generics/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch07-generic-types-and-traits/no_listing_07_two_generics/Scarb.toml b/listings/ch07-generic-types-and-traits/no_listing_07_two_generics/Scarb.toml new file mode 100644 index 000000000..35c81abfb --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_07_two_generics/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_07_two_generics" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch07-generic-types-and-traits/no_listing_07_two_generics.cairo b/listings/ch07-generic-types-and-traits/no_listing_07_two_generics/src/lib.cairo similarity index 100% rename from listings/ch07-generic-types-and-traits/no_listing_07_two_generics.cairo rename to listings/ch07-generic-types-and-traits/no_listing_07_two_generics/src/lib.cairo diff --git a/listings/ch07-generic-types-and-traits/no_listing_08_option/.gitignore b/listings/ch07-generic-types-and-traits/no_listing_08_option/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_08_option/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch07-generic-types-and-traits/no_listing_08_option/Scarb.toml b/listings/ch07-generic-types-and-traits/no_listing_08_option/Scarb.toml new file mode 100644 index 000000000..78a1db578 --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_08_option/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_08_option" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch07-generic-types-and-traits/no_listing_08_option.cairo b/listings/ch07-generic-types-and-traits/no_listing_08_option/src/lib.cairo similarity index 69% rename from listings/ch07-generic-types-and-traits/no_listing_08_option.cairo rename to listings/ch07-generic-types-and-traits/no_listing_08_option/src/lib.cairo index efb36460a..3c933b8e0 100644 --- a/listings/ch07-generic-types-and-traits/no_listing_08_option.cairo +++ b/listings/ch07-generic-types-and-traits/no_listing_08_option/src/lib.cairo @@ -1,4 +1,4 @@ enum Option { Some: T, - None: (), + None, } diff --git a/listings/ch07-generic-types-and-traits/no_listing_09_result/.gitignore b/listings/ch07-generic-types-and-traits/no_listing_09_result/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_09_result/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch07-generic-types-and-traits/no_listing_09_result/Scarb.toml b/listings/ch07-generic-types-and-traits/no_listing_09_result/Scarb.toml new file mode 100644 index 000000000..7a054cbbc --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_09_result/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_09_result" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch07-generic-types-and-traits/no_listing_09_result.cairo b/listings/ch07-generic-types-and-traits/no_listing_09_result/src/lib.cairo similarity index 100% rename from listings/ch07-generic-types-and-traits/no_listing_09_result.cairo rename to listings/ch07-generic-types-and-traits/no_listing_09_result/src/lib.cairo diff --git a/listings/ch07-generic-types-and-traits/no_listing_10_generic_methods/.gitignore b/listings/ch07-generic-types-and-traits/no_listing_10_generic_methods/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_10_generic_methods/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch07-generic-types-and-traits/no_listing_10_generic_methods/Scarb.toml b/listings/ch07-generic-types-and-traits/no_listing_10_generic_methods/Scarb.toml new file mode 100644 index 000000000..451d4cb5b --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_10_generic_methods/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_10_generic_methods" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch07-generic-types-and-traits/no_listing_10_generic_methods.cairo b/listings/ch07-generic-types-and-traits/no_listing_10_generic_methods/src/lib.cairo similarity index 100% rename from listings/ch07-generic-types-and-traits/no_listing_10_generic_methods.cairo rename to listings/ch07-generic-types-and-traits/no_listing_10_generic_methods/src/lib.cairo diff --git a/listings/ch07-generic-types-and-traits/no_listing_11_constrained_generics/.gitignore b/listings/ch07-generic-types-and-traits/no_listing_11_constrained_generics/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_11_constrained_generics/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch07-generic-types-and-traits/no_listing_11_constrained_generics/Scarb.toml b/listings/ch07-generic-types-and-traits/no_listing_11_constrained_generics/Scarb.toml new file mode 100644 index 000000000..36d0db1df --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_11_constrained_generics/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_11_constrained_generics" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch07-generic-types-and-traits/no_listing_11_constrained_generics.cairo b/listings/ch07-generic-types-and-traits/no_listing_11_constrained_generics/src/lib.cairo similarity index 100% rename from listings/ch07-generic-types-and-traits/no_listing_11_constrained_generics.cairo rename to listings/ch07-generic-types-and-traits/no_listing_11_constrained_generics/src/lib.cairo diff --git a/listings/ch07-generic-types-and-traits/no_listing_12_not_compiling/.gitignore b/listings/ch07-generic-types-and-traits/no_listing_12_not_compiling/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_12_not_compiling/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch07-generic-types-and-traits/no_listing_12_not_compiling/Scarb.toml b/listings/ch07-generic-types-and-traits/no_listing_12_not_compiling/Scarb.toml new file mode 100644 index 000000000..71e548448 --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_12_not_compiling/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_12_not_compiling" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch07-generic-types-and-traits/no_listing_12_not_compiling.cairo b/listings/ch07-generic-types-and-traits/no_listing_12_not_compiling/src/lib.cairo similarity index 94% rename from listings/ch07-generic-types-and-traits/no_listing_12_not_compiling.cairo rename to listings/ch07-generic-types-and-traits/no_listing_12_not_compiling/src/lib.cairo index 719ca23f6..a53e1a572 100644 --- a/listings/ch07-generic-types-and-traits/no_listing_12_not_compiling.cairo +++ b/listings/ch07-generic-types-and-traits/no_listing_12_not_compiling/src/lib.cairo @@ -1,4 +1,4 @@ -// does_not_compile +//TAG: does_not_compile struct Wallet { balance: T, address: U, diff --git a/listings/ch07-generic-types-and-traits/no_listing_13_compiling/.gitignore b/listings/ch07-generic-types-and-traits/no_listing_13_compiling/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_13_compiling/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch07-generic-types-and-traits/no_listing_13_compiling/Scarb.toml b/listings/ch07-generic-types-and-traits/no_listing_13_compiling/Scarb.toml new file mode 100644 index 000000000..5d9a57dc6 --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_13_compiling/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_13_compiling" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch07-generic-types-and-traits/no_listing_13_compiling.cairo b/listings/ch07-generic-types-and-traits/no_listing_13_compiling/src/lib.cairo similarity index 100% rename from listings/ch07-generic-types-and-traits/no_listing_13_compiling.cairo rename to listings/ch07-generic-types-and-traits/no_listing_13_compiling/src/lib.cairo diff --git a/listings/ch07-generic-types-and-traits/no_listing_14_traits/.gitignore b/listings/ch07-generic-types-and-traits/no_listing_14_traits/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_14_traits/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch07-generic-types-and-traits/no_listing_14_traits/Scarb.toml b/listings/ch07-generic-types-and-traits/no_listing_14_traits/Scarb.toml new file mode 100644 index 000000000..ab527f47b --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_14_traits/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_14_traits" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch07-generic-types-and-traits/no_listing_14_traits/src/lib.cairo b/listings/ch07-generic-types-and-traits/no_listing_14_traits/src/lib.cairo new file mode 100644 index 000000000..93ea9d6d5 --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_14_traits/src/lib.cairo @@ -0,0 +1,45 @@ +use debug::PrintTrait; + +#[derive(Drop, Copy)] +struct Rectangle { + height: u64, + width: u64, +} + +//ANCHOR: trait +trait ShapeGeometry { + fn boundary(self: Rectangle) -> u64; + fn area(self: Rectangle) -> u64; +} +//ANCHOR_END: trait + +//ANCHOR: impl +impl RectangleGeometry of ShapeGeometry { + fn boundary(self: Rectangle) -> u64 { + 2 * (self.height + self.width) + } + fn area(self: Rectangle) -> u64 { + self.height * self.width + } +} +//ANCHOR_END: impl + +//ANCHOR: main +fn main() { + let rect = Rectangle { height: 5, width: 10 }; // Rectangle instantiation + + // First way, as a method on the struct instance + let area1 = rect.area(); + // Second way, from the implementation + let area2 = RectangleGeometry::area(rect); + // Third way, from the trait + let area3 = ShapeGeometry::area(rect); + + // `area1` has same value as `area2` and `area3` + area1.print(); + area2.print(); + area3.print(); +} +//ANCHOR_END: main + + diff --git a/listings/ch07-generic-types-and-traits/no_listing_15_generate_trait/.gitignore b/listings/ch07-generic-types-and-traits/no_listing_15_generate_trait/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_15_generate_trait/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch07-generic-types-and-traits/no_listing_15_generate_trait/Scarb.toml b/listings/ch07-generic-types-and-traits/no_listing_15_generate_trait/Scarb.toml new file mode 100644 index 000000000..794830652 --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_15_generate_trait/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_15_generate_trait" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch07-generic-types-and-traits/no_listing_15_generate_trait/src/lib.cairo b/listings/ch07-generic-types-and-traits/no_listing_15_generate_trait/src/lib.cairo new file mode 100644 index 000000000..506ac110c --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_15_generate_trait/src/lib.cairo @@ -0,0 +1,14 @@ +struct Rectangle { + height: u64, + width: u64, +} + +#[generate_trait] +impl RectangleGeometry of RectangleGeometryTrait { + fn boundary(self: Rectangle) -> u64 { + 2 * (self.height + self.width) + } + fn area(self: Rectangle) -> u64 { + self.height * self.width + } +} diff --git a/listings/ch07-generic-types-and-traits/no_listing_16_generic_traits/.gitignore b/listings/ch07-generic-types-and-traits/no_listing_16_generic_traits/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_16_generic_traits/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch07-generic-types-and-traits/no_listing_16_generic_traits/Scarb.toml b/listings/ch07-generic-types-and-traits/no_listing_16_generic_traits/Scarb.toml new file mode 100644 index 000000000..3f77c8bbf --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_16_generic_traits/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_16_generic_traits" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch07-generic-types-and-traits/no_listing_16_generic_traits/src/lib.cairo b/listings/ch07-generic-types-and-traits/no_listing_16_generic_traits/src/lib.cairo new file mode 100644 index 000000000..6b3a2f895 --- /dev/null +++ b/listings/ch07-generic-types-and-traits/no_listing_16_generic_traits/src/lib.cairo @@ -0,0 +1,50 @@ +use debug::PrintTrait; + +#[derive(Copy, Drop)] +struct Rectangle { + height: u64, + width: u64, +} + +#[derive(Copy, Drop)] +struct Circle { + radius: u64 +} + +// Here T is an alias type which will be provided during implementation +trait ShapeGeometry { + fn boundary(self: T) -> u64; + fn area(self: T) -> u64; +} + +// Implementation RectangleGeometry passes in +// to implement the trait for that type +impl RectangleGeometry of ShapeGeometry { + fn boundary(self: Rectangle) -> u64 { + 2 * (self.height + self.width) + } + fn area(self: Rectangle) -> u64 { + self.height * self.width + } +} + +// We might have another struct Circle +// which can use the same trait spec +impl CircleGeometry of ShapeGeometry { + fn boundary(self: Circle) -> u64 { + (2 * 314 * self.radius) / 100 + } + fn area(self: Circle) -> u64 { + (314 * self.radius * self.radius) / 100 + } +} + +fn main() { + let rect = Rectangle { height: 5, width: 7 }; + rect.area().print(); // 35 + rect.boundary().print(); // 24 + + let circ = Circle { radius: 5 }; + circ.area().print(); // 78 + circ.boundary().print(); // 31 +} diff --git a/listings/ch08-testing-cairo-programs/listing_08_01_02/.gitignore b/listings/ch08-testing-cairo-programs/listing_08_01_02/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch08-testing-cairo-programs/listing_08_01_02/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch08-testing-cairo-programs/listing_08_01_02/Scarb.toml b/listings/ch08-testing-cairo-programs/listing_08_01_02/Scarb.toml new file mode 100644 index 000000000..c9ccda601 --- /dev/null +++ b/listings/ch08-testing-cairo-programs/listing_08_01_02/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_08_01_02" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch08-testing-cairo-programs/listing_08_01_03.cairo b/listings/ch08-testing-cairo-programs/listing_08_01_02/src/lib.cairo similarity index 63% rename from listings/ch08-testing-cairo-programs/listing_08_01_03.cairo rename to listings/ch08-testing-cairo-programs/listing_08_01_02/src/lib.cairo index ce4bfb393..f49e01d3a 100644 --- a/listings/ch08-testing-cairo-programs/listing_08_01_03.cairo +++ b/listings/ch08-testing-cairo-programs/listing_08_01_02/src/lib.cairo @@ -14,13 +14,5 @@ mod tests { let result = 2 + 2; assert(result == 4, 'result is not 4'); } - // ANCHOR_END: exploration - - // ANCHOR: another - #[test] - fn another() { - let result = 2 + 2; - assert(result == 6, 'Make this test fail'); - } -// ANCHOR_END: another +// ANCHOR_END: exploration } diff --git a/listings/ch08-testing-cairo-programs/listing_08_03/.gitignore b/listings/ch08-testing-cairo-programs/listing_08_03/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch08-testing-cairo-programs/listing_08_03/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch08-testing-cairo-programs/listing_08_03/Scarb.toml b/listings/ch08-testing-cairo-programs/listing_08_03/Scarb.toml new file mode 100644 index 000000000..3383fae7e --- /dev/null +++ b/listings/ch08-testing-cairo-programs/listing_08_03/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_08_03" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch08-testing-cairo-programs/listing_08_03/src/lib.cairo b/listings/ch08-testing-cairo-programs/listing_08_03/src/lib.cairo new file mode 100644 index 000000000..a908dc053 --- /dev/null +++ b/listings/ch08-testing-cairo-programs/listing_08_03/src/lib.cairo @@ -0,0 +1,11 @@ +//TAG: tests_fail +#[cfg(test)] +mod tests { + // ANCHOR: another + #[test] + fn another() { + let result = 2 + 2; + assert(result == 6, 'Make this test fail'); + } +// ANCHOR_END: another +} diff --git a/listings/ch08-testing-cairo-programs/listing_08_06/.gitignore b/listings/ch08-testing-cairo-programs/listing_08_06/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch08-testing-cairo-programs/listing_08_06/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch08-testing-cairo-programs/listing_08_06/Scarb.toml b/listings/ch08-testing-cairo-programs/listing_08_06/Scarb.toml new file mode 100644 index 000000000..27f82c67f --- /dev/null +++ b/listings/ch08-testing-cairo-programs/listing_08_06/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_08_06" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch08-testing-cairo-programs/listing_08_06.cairo b/listings/ch08-testing-cairo-programs/listing_08_06/src/lib.cairo similarity index 75% rename from listings/ch08-testing-cairo-programs/listing_08_06.cairo rename to listings/ch08-testing-cairo-programs/listing_08_06/src/lib.cairo index 850025a12..5e41961e4 100644 --- a/listings/ch08-testing-cairo-programs/listing_08_06.cairo +++ b/listings/ch08-testing-cairo-programs/listing_08_06/src/lib.cairo @@ -17,7 +17,7 @@ impl RectangleImpl of RectangleTrait { } fn can_hold(self: @Rectangle, other: @Rectangle) -> bool { - *self.width > *other.width & *self.height > *other.height + *self.width > *other.width && *self.height > *other.height } } // ANCHOR_END: trait_impl @@ -32,8 +32,8 @@ mod tests { // ANCHOR: test1 #[test] fn larger_can_hold_smaller() { - let larger = Rectangle { height: 7, width: 8, }; - let smaller = Rectangle { height: 1, width: 5, }; + let larger = Rectangle { height: 7, width: 8, }; + let smaller = Rectangle { height: 1, width: 5, }; assert(larger.can_hold(@smaller), 'rectangle cannot hold'); } @@ -42,8 +42,8 @@ mod tests { // ANCHOR: test2 #[test] fn smaller_cannot_hold_larger() { - let larger = Rectangle { height: 7, width: 8, }; - let smaller = Rectangle { height: 1, width: 5, }; + let larger = Rectangle { height: 7, width: 8, }; + let smaller = Rectangle { height: 1, width: 5, }; assert(!smaller.can_hold(@larger), 'rectangle cannot hold'); } diff --git a/listings/ch08-testing-cairo-programs/listing_08_08/.gitignore b/listings/ch08-testing-cairo-programs/listing_08_08/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch08-testing-cairo-programs/listing_08_08/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch08-testing-cairo-programs/listing_08_08/Scarb.toml b/listings/ch08-testing-cairo-programs/listing_08_08/Scarb.toml new file mode 100644 index 000000000..75ece180d --- /dev/null +++ b/listings/ch08-testing-cairo-programs/listing_08_08/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_08_08" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch08-testing-cairo-programs/listing_08_08.cairo b/listings/ch08-testing-cairo-programs/listing_08_08/src/lib.cairo similarity index 86% rename from listings/ch08-testing-cairo-programs/listing_08_08.cairo rename to listings/ch08-testing-cairo-programs/listing_08_08/src/lib.cairo index f59ec8016..5c96fe9d8 100644 --- a/listings/ch08-testing-cairo-programs/listing_08_08.cairo +++ b/listings/ch08-testing-cairo-programs/listing_08_08/src/lib.cairo @@ -1,8 +1,6 @@ -use array::ArrayTrait; - #[derive(Copy, Drop)] struct Guess { - value: u64, + value: u64, } trait GuessTrait { @@ -11,7 +9,7 @@ trait GuessTrait { impl GuessImpl of GuessTrait { fn new(value: u64) -> Guess { - if value < 1 | value > 100 { + if value < 1 || value > 100 { let mut data = ArrayTrait::new(); data.append('Guess must be >= 1 and <= 100'); panic(data); diff --git a/listings/ch08-testing-cairo-programs/listing_08_09/.gitignore b/listings/ch08-testing-cairo-programs/listing_08_09/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch08-testing-cairo-programs/listing_08_09/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch08-testing-cairo-programs/listing_08_09/Scarb.toml b/listings/ch08-testing-cairo-programs/listing_08_09/Scarb.toml new file mode 100644 index 000000000..e7d8a6da2 --- /dev/null +++ b/listings/ch08-testing-cairo-programs/listing_08_09/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_08_09" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch08-testing-cairo-programs/listing_08_09.cairo b/listings/ch08-testing-cairo-programs/listing_08_09/src/lib.cairo similarity index 53% rename from listings/ch08-testing-cairo-programs/listing_08_09.cairo rename to listings/ch08-testing-cairo-programs/listing_08_09/src/lib.cairo index aecc2298a..f60dd8162 100644 --- a/listings/ch08-testing-cairo-programs/listing_08_09.cairo +++ b/listings/ch08-testing-cairo-programs/listing_08_09/src/lib.cairo @@ -1,8 +1,6 @@ -use array::ArrayTrait; - #[derive(Copy, Drop)] struct Guess { - value: u64, + value: u64, } trait GuessTrait { @@ -13,16 +11,12 @@ trait GuessTrait { impl GuessImpl of GuessTrait { fn new(value: u64) -> Guess { if value < 1 { - let mut data = ArrayTrait::new(); - data.append('Guess must be <= 100'); - panic(data); + panic_with_felt252('Guess must be >= 1'); } else if value > 100 { - let mut data = ArrayTrait::new(); - data.append('Guess must be >= 1'); - panic(data); + panic_with_felt252('Guess must be <= 100'); } - Guess { value, } + Guess { value, } } } @@ -33,11 +27,11 @@ mod tests { //ANCHOR: test_panic #[test] - #[should_panic(expected: ('Guess must be <= 100', ))] + #[should_panic(expected: ('Guess must be <= 100',))] fn greater_than_100() { GuessTrait::new(200); } - //ANCHOR_END: test_panic +//ANCHOR_END: test_panic } // ANCHOR_END:here diff --git a/listings/ch08-testing-cairo-programs/listing_08_10/.gitignore b/listings/ch08-testing-cairo-programs/listing_08_10/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch08-testing-cairo-programs/listing_08_10/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch08-testing-cairo-programs/listing_08_10/Scarb.toml b/listings/ch08-testing-cairo-programs/listing_08_10/Scarb.toml new file mode 100644 index 000000000..e3d394f1c --- /dev/null +++ b/listings/ch08-testing-cairo-programs/listing_08_10/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_08_10" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch08-testing-cairo-programs/listing_08_10.cairo b/listings/ch08-testing-cairo-programs/listing_08_10/src/lib.cairo similarity index 100% rename from listings/ch08-testing-cairo-programs/listing_08_10.cairo rename to listings/ch08-testing-cairo-programs/listing_08_10/src/lib.cairo diff --git a/listings/ch08-testing-cairo-programs/no_listing_01_meaningful_name/.gitignore b/listings/ch08-testing-cairo-programs/no_listing_01_meaningful_name/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch08-testing-cairo-programs/no_listing_01_meaningful_name/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch08-testing-cairo-programs/no_listing_01_meaningful_name/Scarb.toml b/listings/ch08-testing-cairo-programs/no_listing_01_meaningful_name/Scarb.toml new file mode 100644 index 000000000..62a84a54c --- /dev/null +++ b/listings/ch08-testing-cairo-programs/no_listing_01_meaningful_name/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_01_meaningful_name" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch08-testing-cairo-programs/no_listing_01_meaningful_name.cairo b/listings/ch08-testing-cairo-programs/no_listing_01_meaningful_name/src/lib.cairo similarity index 100% rename from listings/ch08-testing-cairo-programs/no_listing_01_meaningful_name.cairo rename to listings/ch08-testing-cairo-programs/no_listing_01_meaningful_name/src/lib.cairo diff --git a/listings/ch08-testing-cairo-programs/no_listing_02_wrong_can_hold_impl/.gitignore b/listings/ch08-testing-cairo-programs/no_listing_02_wrong_can_hold_impl/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch08-testing-cairo-programs/no_listing_02_wrong_can_hold_impl/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch08-testing-cairo-programs/no_listing_02_wrong_can_hold_impl/Scarb.toml b/listings/ch08-testing-cairo-programs/no_listing_02_wrong_can_hold_impl/Scarb.toml new file mode 100644 index 000000000..3f601dd4e --- /dev/null +++ b/listings/ch08-testing-cairo-programs/no_listing_02_wrong_can_hold_impl/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_02_wrong_can_hold_impl" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch08-testing-cairo-programs/no_listing_02_wrong_can_hold_impl.cairo b/listings/ch08-testing-cairo-programs/no_listing_02_wrong_can_hold_impl/src/lib.cairo similarity index 75% rename from listings/ch08-testing-cairo-programs/no_listing_02_wrong_can_hold_impl.cairo rename to listings/ch08-testing-cairo-programs/no_listing_02_wrong_can_hold_impl/src/lib.cairo index de9e7e031..a630039d9 100644 --- a/listings/ch08-testing-cairo-programs/no_listing_02_wrong_can_hold_impl.cairo +++ b/listings/ch08-testing-cairo-programs/no_listing_02_wrong_can_hold_impl/src/lib.cairo @@ -1,3 +1,4 @@ +//TAG: tests_fail use debug::PrintTrait; #[derive(Copy, Drop)] struct Rectangle { @@ -18,7 +19,7 @@ impl RectangleImpl of RectangleTrait { } fn can_hold(self: @Rectangle, other: @Rectangle) -> bool { - *self.width < *other.width & *self.height > *other.height + *self.width < *other.width && *self.height > *other.height } } //ANCHOR_END: wrong_impl @@ -34,8 +35,8 @@ mod tests { // ANCHOR: test1 #[test] fn larger_can_hold_smaller() { - let larger = Rectangle { height: 7, width: 8, }; - let smaller = Rectangle { height: 1, width: 5, }; + let larger = Rectangle { height: 7, width: 8, }; + let smaller = Rectangle { height: 1, width: 5, }; assert(larger.can_hold(@smaller), 'rectangle cannot hold'); } @@ -44,8 +45,8 @@ mod tests { // ANCHOR: test2 #[test] fn smaller_cannot_hold_larger() { - let larger = Rectangle { height: 7, width: 8, }; - let smaller = Rectangle { height: 1, width: 5, }; + let larger = Rectangle { height: 7, width: 8, }; + let smaller = Rectangle { height: 1, width: 5, }; assert(!smaller.can_hold(@larger), 'rectangle cannot hold'); } diff --git a/listings/ch08-testing-cairo-programs/no_listing_03_wrong_new_impl/.gitignore b/listings/ch08-testing-cairo-programs/no_listing_03_wrong_new_impl/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch08-testing-cairo-programs/no_listing_03_wrong_new_impl/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch08-testing-cairo-programs/no_listing_03_wrong_new_impl/Scarb.toml b/listings/ch08-testing-cairo-programs/no_listing_03_wrong_new_impl/Scarb.toml new file mode 100644 index 000000000..3f0ff7d02 --- /dev/null +++ b/listings/ch08-testing-cairo-programs/no_listing_03_wrong_new_impl/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_03_wrong_new_impl" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch08-testing-cairo-programs/no_listing_03_wrong_new_impl.cairo b/listings/ch08-testing-cairo-programs/no_listing_03_wrong_new_impl/src/lib.cairo similarity index 84% rename from listings/ch08-testing-cairo-programs/no_listing_03_wrong_new_impl.cairo rename to listings/ch08-testing-cairo-programs/no_listing_03_wrong_new_impl/src/lib.cairo index 00b6f47b8..dc22aa36e 100644 --- a/listings/ch08-testing-cairo-programs/no_listing_03_wrong_new_impl.cairo +++ b/listings/ch08-testing-cairo-programs/no_listing_03_wrong_new_impl/src/lib.cairo @@ -1,8 +1,6 @@ -use array::ArrayTrait; - #[derive(Copy, Drop)] struct Guess { - value: u64, + value: u64, } trait GuessTrait { @@ -18,8 +16,9 @@ impl GuessImpl of GuessTrait { panic(data); } - Guess { value, } + Guess { value, } } } // ANCHOR_END: here + diff --git a/listings/ch08-testing-cairo-programs/no_listing_04_new_bug/.gitignore b/listings/ch08-testing-cairo-programs/no_listing_04_new_bug/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch08-testing-cairo-programs/no_listing_04_new_bug/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch08-testing-cairo-programs/no_listing_04_new_bug/Scarb.toml b/listings/ch08-testing-cairo-programs/no_listing_04_new_bug/Scarb.toml new file mode 100644 index 000000000..020a2dce8 --- /dev/null +++ b/listings/ch08-testing-cairo-programs/no_listing_04_new_bug/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_04_new_bug" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch08-testing-cairo-programs/no_listing_04_new_bug.cairo b/listings/ch08-testing-cairo-programs/no_listing_04_new_bug/src/lib.cairo similarity index 84% rename from listings/ch08-testing-cairo-programs/no_listing_04_new_bug.cairo rename to listings/ch08-testing-cairo-programs/no_listing_04_new_bug/src/lib.cairo index 36924659e..d617ef42a 100644 --- a/listings/ch08-testing-cairo-programs/no_listing_04_new_bug.cairo +++ b/listings/ch08-testing-cairo-programs/no_listing_04_new_bug/src/lib.cairo @@ -1,8 +1,6 @@ -use array::ArrayTrait; - #[derive(Copy, Drop)] struct Guess { - value: u64, + value: u64, } trait GuessTrait { @@ -22,7 +20,7 @@ impl GuessImpl of GuessTrait { panic(data); } - Guess { value, } + Guess { value, } } } @@ -32,7 +30,7 @@ mod tests { use super::GuessTrait; #[test] - #[should_panic(expected: ('Guess must be <= 100', ))] + #[should_panic(expected: ('Guess must be <= 100',))] fn greater_than_100() { GuessTrait::new(200); } diff --git a/listings/ch08-testing-cairo-programs/no_listing_05_ignore_tests/.gitignore b/listings/ch08-testing-cairo-programs/no_listing_05_ignore_tests/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch08-testing-cairo-programs/no_listing_05_ignore_tests/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch08-testing-cairo-programs/no_listing_05_ignore_tests/Scarb.toml b/listings/ch08-testing-cairo-programs/no_listing_05_ignore_tests/Scarb.toml new file mode 100644 index 000000000..2f5b8b69c --- /dev/null +++ b/listings/ch08-testing-cairo-programs/no_listing_05_ignore_tests/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_05_ignore_tests" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch08-testing-cairo-programs/no_listing_05_ignore_tests.cairo b/listings/ch08-testing-cairo-programs/no_listing_05_ignore_tests/src/lib.cairo similarity index 74% rename from listings/ch08-testing-cairo-programs/no_listing_05_ignore_tests.cairo rename to listings/ch08-testing-cairo-programs/no_listing_05_ignore_tests/src/lib.cairo index cee0d8489..f85e42a38 100644 --- a/listings/ch08-testing-cairo-programs/no_listing_05_ignore_tests.cairo +++ b/listings/ch08-testing-cairo-programs/no_listing_05_ignore_tests/src/lib.cairo @@ -8,6 +8,6 @@ mod tests { #[test] #[ignore] - fn expensive_test() {// code that takes an hour to run + fn expensive_test() { // code that takes an hour to run } } diff --git a/listings/ch08-testing-cairo-programs/no_listing_06_cfg_attr/.gitignore b/listings/ch08-testing-cairo-programs/no_listing_06_cfg_attr/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch08-testing-cairo-programs/no_listing_06_cfg_attr/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch08-testing-cairo-programs/no_listing_06_cfg_attr/Scarb.toml b/listings/ch08-testing-cairo-programs/no_listing_06_cfg_attr/Scarb.toml new file mode 100644 index 000000000..f9fa90486 --- /dev/null +++ b/listings/ch08-testing-cairo-programs/no_listing_06_cfg_attr/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_06_cfg_attr" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch08-testing-cairo-programs/no_listing_06_cfg_attr.cairo b/listings/ch08-testing-cairo-programs/no_listing_06_cfg_attr/src/lib.cairo similarity index 100% rename from listings/ch08-testing-cairo-programs/no_listing_06_cfg_attr.cairo rename to listings/ch08-testing-cairo-programs/no_listing_06_cfg_attr/src/lib.cairo diff --git a/listings/ch08-testing-cairo-programs/no_listing_07_integration_test/.gitignore b/listings/ch08-testing-cairo-programs/no_listing_07_integration_test/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch08-testing-cairo-programs/no_listing_07_integration_test/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch08-testing-cairo-programs/no_listing_07_integration_test/Scarb.toml b/listings/ch08-testing-cairo-programs/no_listing_07_integration_test/Scarb.toml new file mode 100644 index 000000000..0456ded16 --- /dev/null +++ b/listings/ch08-testing-cairo-programs/no_listing_07_integration_test/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_07_integration_test" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch08-testing-cairo-programs/no_listing_07_integration_test.cairo b/listings/ch08-testing-cairo-programs/no_listing_07_integration_test/src/lib.cairo similarity index 99% rename from listings/ch08-testing-cairo-programs/no_listing_07_integration_test.cairo rename to listings/ch08-testing-cairo-programs/no_listing_07_integration_test/src/lib.cairo index 3d5f9cb89..73e23f5d6 100644 --- a/listings/ch08-testing-cairo-programs/no_listing_07_integration_test.cairo +++ b/listings/ch08-testing-cairo-programs/no_listing_07_integration_test/src/lib.cairo @@ -14,3 +14,4 @@ fn internal() { } // ANCHOR_END: here + diff --git a/listings/ch09-error-handling/listing_01/.gitignore b/listings/ch09-error-handling/listing_01/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch09-error-handling/listing_01/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch09-error-handling/listing_01/Scarb.toml b/listings/ch09-error-handling/listing_01/Scarb.toml new file mode 100644 index 000000000..845405747 --- /dev/null +++ b/listings/ch09-error-handling/listing_01/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_01" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch09-error-handling/listing_01.cairo b/listings/ch09-error-handling/listing_01/src/lib.cairo similarity index 92% rename from listings/ch09-error-handling/listing_01.cairo rename to listings/ch09-error-handling/listing_01/src/lib.cairo index ebda4ad67..90e77f36d 100644 --- a/listings/ch09-error-handling/listing_01.cairo +++ b/listings/ch09-error-handling/listing_01/src/lib.cairo @@ -1,5 +1,3 @@ -use traits::TryInto; - //ANCHOR: function fn parse_u8(s: felt252) -> Result { match s.try_into() { @@ -13,7 +11,6 @@ fn parse_u8(s: felt252) -> Result { #[cfg(test)] mod tests { use super::parse_u8; - use result::ResultTrait; #[test] fn test_felt252_to_u8() { let number: felt252 = 5_felt252; diff --git a/listings/ch09-error-handling/listing_02/.gitignore b/listings/ch09-error-handling/listing_02/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch09-error-handling/listing_02/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch09-error-handling/listing_02/Scarb.toml b/listings/ch09-error-handling/listing_02/Scarb.toml new file mode 100644 index 000000000..77e6b806d --- /dev/null +++ b/listings/ch09-error-handling/listing_02/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "listing_02" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch09-error-handling/listing_02.cairo b/listings/ch09-error-handling/listing_02/src/lib.cairo similarity index 97% rename from listings/ch09-error-handling/listing_02.cairo rename to listings/ch09-error-handling/listing_02/src/lib.cairo index 2e2ac78aa..9385380be 100644 --- a/listings/ch09-error-handling/listing_02.cairo +++ b/listings/ch09-error-handling/listing_02/src/lib.cairo @@ -1,5 +1,3 @@ -use traits::TryInto; - fn parse_u8(s: felt252) -> Result { match s.try_into() { Option::Some(value) => Result::Ok(value), diff --git a/listings/ch09-error-handling/no_listing_01_panic/.gitignore b/listings/ch09-error-handling/no_listing_01_panic/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch09-error-handling/no_listing_01_panic/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch09-error-handling/no_listing_01_panic/Scarb.toml b/listings/ch09-error-handling/no_listing_01_panic/Scarb.toml new file mode 100644 index 000000000..58a65840b --- /dev/null +++ b/listings/ch09-error-handling/no_listing_01_panic/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_01_panic" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch09-error-handling/no_listing_01_panic.cairo b/listings/ch09-error-handling/no_listing_01_panic/src/lib.cairo similarity index 88% rename from listings/ch09-error-handling/no_listing_01_panic.cairo rename to listings/ch09-error-handling/no_listing_01_panic/src/lib.cairo index 6ece0826d..4ff8319ba 100644 --- a/listings/ch09-error-handling/no_listing_01_panic.cairo +++ b/listings/ch09-error-handling/no_listing_01_panic/src/lib.cairo @@ -1,4 +1,3 @@ -use array::ArrayTrait; use debug::PrintTrait; fn main() { diff --git a/listings/ch09-error-handling/no_listing_02_with_felt252/.gitignore b/listings/ch09-error-handling/no_listing_02_with_felt252/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch09-error-handling/no_listing_02_with_felt252/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch09-error-handling/no_listing_02_with_felt252/Scarb.toml b/listings/ch09-error-handling/no_listing_02_with_felt252/Scarb.toml new file mode 100644 index 000000000..2c76d86b2 --- /dev/null +++ b/listings/ch09-error-handling/no_listing_02_with_felt252/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_02_with_felt252" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch09-error-handling/no_listing_02_with_felt252.cairo b/listings/ch09-error-handling/no_listing_02_with_felt252/src/lib.cairo similarity index 95% rename from listings/ch09-error-handling/no_listing_02_with_felt252.cairo rename to listings/ch09-error-handling/no_listing_02_with_felt252/src/lib.cairo index d5fdd9ce7..51c55b44f 100644 --- a/listings/ch09-error-handling/no_listing_02_with_felt252.cairo +++ b/listings/ch09-error-handling/no_listing_02_with_felt252/src/lib.cairo @@ -1,3 +1,3 @@ fn main() { panic_with_felt252(2); -} \ No newline at end of file +} diff --git a/listings/ch09-error-handling/no_listing_03_nopanic/.gitignore b/listings/ch09-error-handling/no_listing_03_nopanic/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch09-error-handling/no_listing_03_nopanic/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch09-error-handling/no_listing_03_nopanic/Scarb.toml b/listings/ch09-error-handling/no_listing_03_nopanic/Scarb.toml new file mode 100644 index 000000000..33d19f7ba --- /dev/null +++ b/listings/ch09-error-handling/no_listing_03_nopanic/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_03_nopanic" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch09-error-handling/no_listing_03_nopanic.cairo b/listings/ch09-error-handling/no_listing_03_nopanic/src/lib.cairo similarity index 100% rename from listings/ch09-error-handling/no_listing_03_nopanic.cairo rename to listings/ch09-error-handling/no_listing_03_nopanic/src/lib.cairo diff --git a/listings/ch09-error-handling/no_listing_04_nopanic_wrong/.gitignore b/listings/ch09-error-handling/no_listing_04_nopanic_wrong/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch09-error-handling/no_listing_04_nopanic_wrong/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch09-error-handling/no_listing_04_nopanic_wrong/Scarb.toml b/listings/ch09-error-handling/no_listing_04_nopanic_wrong/Scarb.toml new file mode 100644 index 000000000..1f60b7433 --- /dev/null +++ b/listings/ch09-error-handling/no_listing_04_nopanic_wrong/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_04_nopanic_wrong" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch09-error-handling/no_listing_04_nopanic_wrong.cairo b/listings/ch09-error-handling/no_listing_04_nopanic_wrong/src/lib.cairo similarity index 73% rename from listings/ch09-error-handling/no_listing_04_nopanic_wrong.cairo rename to listings/ch09-error-handling/no_listing_04_nopanic_wrong/src/lib.cairo index 9622d17ae..de0beb214 100644 --- a/listings/ch09-error-handling/no_listing_04_nopanic_wrong.cairo +++ b/listings/ch09-error-handling/no_listing_04_nopanic_wrong/src/lib.cairo @@ -1,4 +1,4 @@ -// does_not_compile +//TAG: does_not_compile fn function_never_panic() nopanic { assert(1 == 1, 'what'); } diff --git a/listings/ch09-error-handling/no_listing_05_panic_with/.gitignore b/listings/ch09-error-handling/no_listing_05_panic_with/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch09-error-handling/no_listing_05_panic_with/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch09-error-handling/no_listing_05_panic_with/Scarb.toml b/listings/ch09-error-handling/no_listing_05_panic_with/Scarb.toml new file mode 100644 index 000000000..3b8347b6b --- /dev/null +++ b/listings/ch09-error-handling/no_listing_05_panic_with/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_05_panic_with" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch09-error-handling/no_listing_05_panic_with.cairo b/listings/ch09-error-handling/no_listing_05_panic_with/src/lib.cairo similarity index 84% rename from listings/ch09-error-handling/no_listing_05_panic_with.cairo rename to listings/ch09-error-handling/no_listing_05_panic_with/src/lib.cairo index 53db00b1a..d83225073 100644 --- a/listings/ch09-error-handling/no_listing_05_panic_with.cairo +++ b/listings/ch09-error-handling/no_listing_05_panic_with/src/lib.cairo @@ -1,9 +1,7 @@ -use option::OptionTrait; - #[panic_with('value is 0', wrap_not_zero)] fn wrap_if_not_zero(value: u128) -> Option { if value == 0 { - Option::None(()) + Option::None } else { Option::Some(value) } diff --git a/listings/ch09-error-handling/no_listing_06_assert/.gitignore b/listings/ch09-error-handling/no_listing_06_assert/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch09-error-handling/no_listing_06_assert/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch09-error-handling/no_listing_06_assert/Scarb.toml b/listings/ch09-error-handling/no_listing_06_assert/Scarb.toml new file mode 100644 index 000000000..3cd373a59 --- /dev/null +++ b/listings/ch09-error-handling/no_listing_06_assert/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_06_assert" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch09-error-handling/no_listing_06_assert.cairo b/listings/ch09-error-handling/no_listing_06_assert/src/lib.cairo similarity index 100% rename from listings/ch09-error-handling/no_listing_06_assert.cairo rename to listings/ch09-error-handling/no_listing_06_assert/src/lib.cairo diff --git a/listings/ch09-error-handling/no_listing_07_result_enum/.gitignore b/listings/ch09-error-handling/no_listing_07_result_enum/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch09-error-handling/no_listing_07_result_enum/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch09-error-handling/no_listing_07_result_enum/Scarb.toml b/listings/ch09-error-handling/no_listing_07_result_enum/Scarb.toml new file mode 100644 index 000000000..70808e679 --- /dev/null +++ b/listings/ch09-error-handling/no_listing_07_result_enum/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_07_result_enum" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch09-error-handling/no_listing_07_result_enum.cairo b/listings/ch09-error-handling/no_listing_07_result_enum/src/lib.cairo similarity index 100% rename from listings/ch09-error-handling/no_listing_07_result_enum.cairo rename to listings/ch09-error-handling/no_listing_07_result_enum/src/lib.cairo diff --git a/listings/ch09-error-handling/no_listing_08_result_trait/.gitignore b/listings/ch09-error-handling/no_listing_08_result_trait/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch09-error-handling/no_listing_08_result_trait/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch09-error-handling/no_listing_08_result_trait/Scarb.toml b/listings/ch09-error-handling/no_listing_08_result_trait/Scarb.toml new file mode 100644 index 000000000..930164fb4 --- /dev/null +++ b/listings/ch09-error-handling/no_listing_08_result_trait/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_08_result_trait" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch09-error-handling/no_listing_08_result_trait.cairo b/listings/ch09-error-handling/no_listing_08_result_trait/src/lib.cairo similarity index 100% rename from listings/ch09-error-handling/no_listing_08_result_trait.cairo rename to listings/ch09-error-handling/no_listing_08_result_trait/src/lib.cairo diff --git a/listings/ch10-advanced-features/no_listing_01_potions/.gitignore b/listings/ch10-advanced-features/no_listing_01_potions/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch10-advanced-features/no_listing_01_potions/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch10-advanced-features/no_listing_01_potions/Scarb.toml b/listings/ch10-advanced-features/no_listing_01_potions/Scarb.toml new file mode 100644 index 000000000..86ad65031 --- /dev/null +++ b/listings/ch10-advanced-features/no_listing_01_potions/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_01_potions" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } \ No newline at end of file diff --git a/listings/ch10-advanced-features/no_listing_01_potions.cairo b/listings/ch10-advanced-features/no_listing_01_potions/src/lib.cairo similarity index 97% rename from listings/ch10-advanced-features/no_listing_01_potions.cairo rename to listings/ch10-advanced-features/no_listing_01_potions/src/lib.cairo index 255b04015..bf0de8bdd 100644 --- a/listings/ch10-advanced-features/no_listing_01_potions.cairo +++ b/listings/ch10-advanced-features/no_listing_01_potions/src/lib.cairo @@ -5,7 +5,7 @@ struct Potion { impl PotionAdd of Add { fn add(lhs: Potion, rhs: Potion) -> Potion { - Potion { health: lhs.health + rhs.health, mana: lhs.mana + rhs.mana, } + Potion { health: lhs.health + rhs.health, mana: lhs.mana + rhs.mana, } } } diff --git a/listings/ch10-advanced-features/no_listing_02_array_macro/.gitignore b/listings/ch10-advanced-features/no_listing_02_array_macro/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch10-advanced-features/no_listing_02_array_macro/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch10-advanced-features/no_listing_02_array_macro/Scarb.toml b/listings/ch10-advanced-features/no_listing_02_array_macro/Scarb.toml new file mode 100644 index 000000000..15ef8bab6 --- /dev/null +++ b/listings/ch10-advanced-features/no_listing_02_array_macro/Scarb.toml @@ -0,0 +1,8 @@ +[package] +name = "no_listing_02_array_macro" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } diff --git a/listings/ch10-advanced-features/no_listing_02_array_macro/src/lib.cairo b/listings/ch10-advanced-features/no_listing_02_array_macro/src/lib.cairo new file mode 100644 index 000000000..9ed342558 --- /dev/null +++ b/listings/ch10-advanced-features/no_listing_02_array_macro/src/lib.cairo @@ -0,0 +1,10 @@ +fn main() { + let mut arr = ArrayTrait::new(); + arr.append(1); + arr.append(2); + arr.append(3); + arr.append(4); + arr.append(5); + + let arr = array![1, 2, 3, 4, 5]; +} diff --git a/listings/ch99-starknet-smart-contracts/listing_99_01/.gitignore b/listings/ch99-starknet-smart-contracts/listing_99_01/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_01/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch99-starknet-smart-contracts/listing_99_01/Scarb.toml b/listings/ch99-starknet-smart-contracts/listing_99_01/Scarb.toml new file mode 100644 index 000000000..98e6405a2 --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_01/Scarb.toml @@ -0,0 +1,9 @@ +[package] +name = "listing_99_01" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } +starknet = ">=2.2.0" diff --git a/listings/ch99-starknet-smart-contracts/listing_99_01/src/lib.cairo b/listings/ch99-starknet-smart-contracts/listing_99_01/src/lib.cairo new file mode 100644 index 000000000..9f22016b4 --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_01/src/lib.cairo @@ -0,0 +1,36 @@ +// ANCHOR:all +// ANCHOR: interface +#[starknet::interface] +trait ISimpleStorage { + fn set(ref self: TContractState, x: u128); + fn get(self: @TContractState) -> u128; +} +//ANCHOR_END: interface + +#[starknet::contract] +mod SimpleStorage { + use starknet::get_caller_address; + use starknet::ContractAddress; + + #[storage] + struct Storage { + stored_data: u128 + } + + //ANCHOR: impl + #[external(v0)] + impl SimpleStorage of super::ISimpleStorage { + //ANCHOR: write_state + fn set(ref self: ContractState, x: u128) { + self.stored_data.write(x); + } + //ANCHOR_END: write_state + fn get(self: @ContractState) -> u128 { + self.stored_data.read() + } + } +//ANCHOR_END: impl +} +//ANCHOR_END: all + + diff --git a/listings/ch99-starknet-smart-contracts/listing_99_01_bis_wrong_impl/.gitignore b/listings/ch99-starknet-smart-contracts/listing_99_01_bis_wrong_impl/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_01_bis_wrong_impl/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch99-starknet-smart-contracts/listing_99_01_bis_wrong_impl/Scarb.toml b/listings/ch99-starknet-smart-contracts/listing_99_01_bis_wrong_impl/Scarb.toml new file mode 100644 index 000000000..423ca857a --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_01_bis_wrong_impl/Scarb.toml @@ -0,0 +1,9 @@ +[package] +name = "listing_99_01_bis_wrong_impl" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } +starknet = ">=2.2.0" diff --git a/listings/ch99-starknet-smart-contracts/listing_99_01_bis_wrong_impl/src/lib.cairo b/listings/ch99-starknet-smart-contracts/listing_99_01_bis_wrong_impl/src/lib.cairo new file mode 100644 index 000000000..96caf79cf --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_01_bis_wrong_impl/src/lib.cairo @@ -0,0 +1,33 @@ +//TAG: does_not_compile +// ANCHOR:all +// ANCHOR: interface +#[starknet::interface] +trait ISimpleStorage { + fn set(ref self: TContractState, x: u128); + fn get(self: @TContractState) -> u128; +} +//ANCHOR_END: interface + +#[starknet::contract] +mod SimpleStorage { + use starknet::get_caller_address; + use starknet::ContractAddress; + + #[storage] + struct Storage { + stored_data: u128 + } + + //ANCHOR: impl + #[external(v0)] + impl SimpleStorage of super::ISimpleStorage { + fn set(ref self: ContractState) {} + fn get(self: @ContractState) -> u128 { + self.stored_data.read() + } + } +//ANCHOR_END: impl +} +//ANCHOR_END: all + + diff --git a/listings/ch99-starknet-smart-contracts/listing_99_02/.gitignore b/listings/ch99-starknet-smart-contracts/listing_99_02/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_02/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch99-starknet-smart-contracts/listing_99_02/Scarb.toml b/listings/ch99-starknet-smart-contracts/listing_99_02/Scarb.toml new file mode 100644 index 000000000..530447678 --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_02/Scarb.toml @@ -0,0 +1,9 @@ +[package] +name = "listing_99_02" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } +starknet = ">=2.2.0" diff --git a/listings/ch99-starknet-smart-contracts/listing_99_02.cairo b/listings/ch99-starknet-smart-contracts/listing_99_02/src/lib.cairo similarity index 52% rename from listings/ch99-starknet-smart-contracts/listing_99_02.cairo rename to listings/ch99-starknet-smart-contracts/listing_99_02/src/lib.cairo index e5958935c..1f2c1d426 100644 --- a/listings/ch99-starknet-smart-contracts/listing_99_02.cairo +++ b/listings/ch99-starknet-smart-contracts/listing_99_02/src/lib.cairo @@ -1,9 +1,11 @@ -#[contract] -mod Contract { +#[starknet::contract] +mod contract { + use starknet::ContractAddress; //ANCHOR: here + #[storage] struct Storage { id: u8, names: LegacyMap::, } - //ANCHOR_END: here +//ANCHOR_END: here } diff --git a/listings/ch99-starknet-smart-contracts/listing_99_03_example_contract.cairo b/listings/ch99-starknet-smart-contracts/listing_99_03_example_contract.cairo deleted file mode 100644 index 9f4949b6d..000000000 --- a/listings/ch99-starknet-smart-contracts/listing_99_03_example_contract.cairo +++ /dev/null @@ -1,48 +0,0 @@ -//ANCHOR: all -#[contract] -mod Example { - use starknet::get_caller_address; - use starknet::ContractAddress; - - struct Storage { - names: LegacyMap::, - } - - //ANCHOR: event - #[event] - fn StoredName(caller: ContractAddress, name: felt252) {} - //ANCHOR_END: event - - //ANCHOR: constructor - #[constructor] - fn constructor(_name: felt252, _address: ContractAddress) { - names::write(_address, _name); - } - //ANCHOR_END: constructor - - //ANCHOR: external - #[external] - fn store_name(_name: felt252) { - let caller = get_caller_address(); - //ANCHOR: write - names::write(caller, _name); - //ANCHOR_END: write - //ANCHOR: emit_event - StoredName(caller, _name); - //ANCHOR_END: emit_event - } - //ANCHOR_END: external - - //ANCHOR: view - #[view] - fn get_name(_address: ContractAddress) -> felt252 { - //ANCHOR: read - let name = names::read(_address); - //ANCHOR_END: read - return name; - } -//ANCHOR_END: view -} -//ANCHOR_END: all - - diff --git a/listings/ch99-starknet-smart-contracts/listing_99_03_example_contract/.gitignore b/listings/ch99-starknet-smart-contracts/listing_99_03_example_contract/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_03_example_contract/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch99-starknet-smart-contracts/listing_99_03_example_contract/Scarb.toml b/listings/ch99-starknet-smart-contracts/listing_99_03_example_contract/Scarb.toml new file mode 100644 index 000000000..c6a4d6a75 --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_03_example_contract/Scarb.toml @@ -0,0 +1,9 @@ +[package] +name = "listing_99_03_example_contract" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } +starknet = ">=2.2.0" diff --git a/listings/ch99-starknet-smart-contracts/listing_99_03_example_contract/src/lib.cairo b/listings/ch99-starknet-smart-contracts/listing_99_03_example_contract/src/lib.cairo new file mode 100644 index 000000000..179c51156 --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_03_example_contract/src/lib.cairo @@ -0,0 +1,101 @@ +//ANCHOR: all + +use starknet::ContractAddress; + +#[starknet::interface] +trait INameRegistry { + fn store_name(ref self: TContractState, name: felt252); + fn get_name(self: @TContractState, address: ContractAddress) -> felt252; +} + + +#[starknet::contract] +mod NameRegistry { + use starknet::{ContractAddress, get_caller_address}; + + #[storage] + struct Storage { + names: LegacyMap::, + total_names: u128, + owner: Person + } + + //ANCHOR: event + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + StoredName: StoredName, + } + + #[derive(Drop, starknet::Event)] + struct StoredName { + #[key] + user: ContractAddress, + name: felt252 + } + //ANCHOR_END: event + + //ANCHOR: person + #[derive(Copy, Drop, Serde, starknet::Store)] + struct Person { + name: felt252, + address: ContractAddress + } + //ANCHOR_END: person + + //ANCHOR: constructor + #[constructor] + fn constructor(ref self: ContractState, owner: Person) { + self.names.write(owner.address, owner.name); + self.total_names.write(1); + self.owner.write(owner); + } + //ANCHOR_END: constructor + + //ANCHOR: impl_public + #[external(v0)] + impl NameRegistry of super::INameRegistry { + //ANCHOR: external + fn store_name(ref self: ContractState, name: felt252) { + let caller = get_caller_address(); + self._store_name(caller, name); + } + //ANCHOR_END: external + + //ANCHOR: view + fn get_name(self: @ContractState, address: ContractAddress) -> felt252 { + //ANCHOR: read + let name = self.names.read(address); + //ANCHOR_END: read + name + } + //ANCHOR_END: view + } + //ANCHOR_END: impl_public + + // ANCHOR: state_internal + #[generate_trait] + impl InternalFunctions of InternalFunctionsTrait { + fn _store_name(ref self: ContractState, user: ContractAddress, name: felt252) { + let mut total_names = self.total_names.read(); + //ANCHOR: write + self.names.write(user, name); + //ANCHOR_END: write + self.total_names.write(total_names + 1); + //ANCHOR: emit_event + self.emit(StoredName { user: user, name: name }); + //ANCHOR_END: emit_event + + } + } + // ANCHOR_END: state_internal + + // ANCHOR: stateless_internal + fn _get_contract_name() -> felt252 { + 'Name Registry' + } +// ANCHOR_END: stateless_internal +} +//ANCHOR_END: all + + diff --git a/listings/ch99-starknet-smart-contracts/listing_99_04_L1_L2_messaging/.gitignore b/listings/ch99-starknet-smart-contracts/listing_99_04_L1_L2_messaging/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_04_L1_L2_messaging/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch99-starknet-smart-contracts/listing_99_04_L1_L2_messaging/Scarb.toml b/listings/ch99-starknet-smart-contracts/listing_99_04_L1_L2_messaging/Scarb.toml new file mode 100644 index 000000000..ff1df9623 --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_04_L1_L2_messaging/Scarb.toml @@ -0,0 +1,9 @@ +[package] +name = "listing_99_04_L1_L2_messaging" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } +starknet = ">=2.2.0" diff --git a/listings/ch99-starknet-smart-contracts/listing_99_04_L1_L2_messaging/src/lib.cairo b/listings/ch99-starknet-smart-contracts/listing_99_04_L1_L2_messaging/src/lib.cairo new file mode 100644 index 000000000..ba9bf746b --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_04_L1_L2_messaging/src/lib.cairo @@ -0,0 +1,81 @@ +#[starknet::contract] +mod Evaluator { + use starknet::get_caller_address; + use starknet::get_contract_address; + use starknet::ContractAddress; + use starknet::syscalls::send_message_to_l1_syscall; + + + use zeroable::Zeroable; + + + use integer::u256; + use integer::u256_from_felt252; + + #[storage] + struct Storage { + l1_evaluator_address: felt252, + messages: LegacyMap, + messages_count: usize + } + + #[constructor] + fn constructor(ref self: ContractState) {} + + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + ReceivedSomething: ReceivedSomething, + } + + #[derive(Drop, starknet::Event)] + struct ReceivedSomething { + #[key] + from: usize, + name: usize + } + + + //ANCHOR:here + #[l1_handler] + fn ex_01_receive_message_from_l1( + ref self: ContractState, from_address: felt252, message: usize + ) { + // Selector: 0x274ab8abc4e270a94c36e1a54c794cd4dd537eeee371e7188c56ee768c4c0c4 + // Check that the sender is the correct L1 evaluator + assert(from_address == self.l1_evaluator_address.read(), 'WRONG L1 EVALUATOR'); + // Adding a check on the message, because why not? + assert(message > 168111, 'MESSAGE TOO SMALL'); + assert(message < 5627895, 'MESSAGE TOO BIG'); + + // Store the message received from L1 + let mut message_count = self.messages_count.read(); + self.messages.write(message_count, message); + message_count += 1; + self.messages_count.write(message_count); + } + //ANCHOR_END: here + //ANCHOR: l2l1 + + #[external(v0)] + #[generate_trait] + impl Evaluator of IEvaluator { + fn ex_02_send_message_to_l1(ref self: ContractState, value: usize) { + // Create the message payload + // By default it's an array of felt252 + let mut message_payload = ArrayTrait::new(); + // Adding the address of the caller on L2 + message_payload.append(get_caller_address().into()); + // Adding the value + message_payload.append(value.into()); + // Sending the message + send_message_to_l1_syscall(self.l1_evaluator_address.read(), message_payload.span()); + } + + fn get_l1_evaluator_address(self: @ContractState) -> felt252 { + self.l1_evaluator_address.read() + } + } +//ANCHOR_END: l2l1 + +} diff --git a/listings/ch99-starknet-smart-contracts/listing_99_04_interface.cairo b/listings/ch99-starknet-smart-contracts/listing_99_04_interface.cairo deleted file mode 100644 index 25a0eb7e9..000000000 --- a/listings/ch99-starknet-smart-contracts/listing_99_04_interface.cairo +++ /dev/null @@ -1,31 +0,0 @@ -use starknet::ContractAddress; - -#[abi] -trait IERC20 { - #[view] - fn name() -> felt252; - - #[view] - fn symbol() -> felt252; - - #[view] - fn decimals() -> u8; - - #[view] - fn total_supply() -> u256; - - #[view] - fn balance_of(account: ContractAddress) -> u256; - - #[view] - fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256; - - #[external] - fn transfer(recipient: ContractAddress, amount: u256) -> bool; - - #[external] - fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool; - - #[external] - fn approve(spender: ContractAddress, amount: u256) -> bool; -} diff --git a/listings/ch99-starknet-smart-contracts/listing_99_04_interface/.gitignore b/listings/ch99-starknet-smart-contracts/listing_99_04_interface/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_04_interface/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch99-starknet-smart-contracts/listing_99_04_interface/Scarb.toml b/listings/ch99-starknet-smart-contracts/listing_99_04_interface/Scarb.toml new file mode 100644 index 000000000..255afe574 --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_04_interface/Scarb.toml @@ -0,0 +1,9 @@ +[package] +name = "listing_99_04_interface" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } +starknet = ">=2.2.0" diff --git a/listings/ch99-starknet-smart-contracts/listing_99_04_interface/src/lib.cairo b/listings/ch99-starknet-smart-contracts/listing_99_04_interface/src/lib.cairo new file mode 100644 index 000000000..bcae4c36e --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_04_interface/src/lib.cairo @@ -0,0 +1,24 @@ +use starknet::ContractAddress; + +#[starknet::interface] +trait IERC20 { + fn name(self: @TContractState) -> felt252; + + fn symbol(self: @TContractState) -> felt252; + + fn decimals(self: @TContractState) -> u8; + + fn total_supply(self: @TContractState) -> u256; + + fn balance_of(self: @TContractState, account: ContractAddress) -> u256; + + fn allowance(self: @TContractState, owner: ContractAddress, spender: ContractAddress) -> u256; + + fn transfer(ref self: TContractState, recipient: ContractAddress, amount: u256) -> bool; + + fn transfer_from( + ref self: TContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool; + + fn approve(ref self: TContractState, spender: ContractAddress, amount: u256) -> bool; +} diff --git a/listings/ch99-starknet-smart-contracts/listing_99_05_dispatcher_trait/.gitignore b/listings/ch99-starknet-smart-contracts/listing_99_05_dispatcher_trait/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_05_dispatcher_trait/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch99-starknet-smart-contracts/listing_99_05_dispatcher_trait/Scarb.toml b/listings/ch99-starknet-smart-contracts/listing_99_05_dispatcher_trait/Scarb.toml new file mode 100644 index 000000000..727258076 --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_05_dispatcher_trait/Scarb.toml @@ -0,0 +1,9 @@ +[package] +name = "listing_99_05_dispatcher_trait" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } +starknet = ">=2.2.0" diff --git a/listings/ch99-starknet-smart-contracts/listing_99_05_dispatcher_trait.cairo b/listings/ch99-starknet-smart-contracts/listing_99_05_dispatcher_trait/src/lib.cairo similarity index 81% rename from listings/ch99-starknet-smart-contracts/listing_99_05_dispatcher_trait.cairo rename to listings/ch99-starknet-smart-contracts/listing_99_05_dispatcher_trait/src/lib.cairo index 497aae08f..de31d0d26 100644 --- a/listings/ch99-starknet-smart-contracts/listing_99_05_dispatcher_trait.cairo +++ b/listings/ch99-starknet-smart-contracts/listing_99_05_dispatcher_trait/src/lib.cairo @@ -1,4 +1,4 @@ -//does_not_compile +//TAG: does_not_compile use starknet::{ContractAddress}; trait IERC20DispatcherTrait { @@ -6,9 +6,9 @@ trait IERC20DispatcherTrait { fn transfer(self: T, recipient: ContractAddress, amount: u256); } -#[derive(Copy, Drop, storage_access::StorageAccess, Serde)] +#[derive(Copy, Drop, starknet::Store, Serde)] struct IERC20Dispatcher { - contract_address: starknet::ContractAddress, + contract_address: starknet::ContractAddress, } impl IERC20DispatcherImpl of IERC20DispatcherTrait { diff --git a/listings/ch99-starknet-smart-contracts/listing_99_06_sample_contract.cairo b/listings/ch99-starknet-smart-contracts/listing_99_06_sample_contract.cairo deleted file mode 100644 index 29758dc7d..000000000 --- a/listings/ch99-starknet-smart-contracts/listing_99_06_sample_contract.cairo +++ /dev/null @@ -1,54 +0,0 @@ -use starknet::ContractAddress; - -#[abi] -trait IERC20 { - #[view] - fn name() -> felt252; - - #[view] - fn symbol() -> felt252; - - #[view] - fn decimals() -> u8; - - #[view] - fn total_supply() -> u256; - - #[view] - fn balance_of(account: ContractAddress) -> u256; - - #[view] - fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256; - - #[external] - fn transfer(recipient: ContractAddress, amount: u256) -> bool; - - #[external] - fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool; - - #[external] - fn approve(spender: ContractAddress, amount: u256) -> bool; -} - -//ANCHOR: here -//**** Specify interface here ****// -#[contract] -mod Dispatcher { - use super::IERC20DispatcherTrait; - use super::IERC20Dispatcher; - use starknet::ContractAddress; - - #[view] - fn token_name(_contract_address: ContractAddress) -> felt252 { - IERC20Dispatcher { contract_address: _contract_address }.name() - } - - #[external] - fn transfer_token( - _contract_address: ContractAddress, recipient: ContractAddress, amount: u256 - ) -> bool { - IERC20Dispatcher { contract_address: _contract_address }.transfer(recipient, amount) - } -} -// ANCHOR_END: here - diff --git a/listings/ch99-starknet-smart-contracts/listing_99_06_sample_contract/.gitignore b/listings/ch99-starknet-smart-contracts/listing_99_06_sample_contract/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_06_sample_contract/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch99-starknet-smart-contracts/listing_99_06_sample_contract/Scarb.toml b/listings/ch99-starknet-smart-contracts/listing_99_06_sample_contract/Scarb.toml new file mode 100644 index 000000000..35cb2a4da --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_06_sample_contract/Scarb.toml @@ -0,0 +1,9 @@ +[package] +name = "listing_99_06_sample_contract" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } +starknet = ">=2.2.0" diff --git a/listings/ch99-starknet-smart-contracts/listing_99_06_sample_contract/src/lib.cairo b/listings/ch99-starknet-smart-contracts/listing_99_06_sample_contract/src/lib.cairo new file mode 100644 index 000000000..15cba2172 --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_06_sample_contract/src/lib.cairo @@ -0,0 +1,68 @@ +use starknet::ContractAddress; + +#[starknet::interface] +trait IERC20 { + fn name(self: @TContractState) -> felt252; + + fn symbol(self: @TContractState) -> felt252; + + fn decimals(self: @TContractState) -> u8; + + fn total_supply(self: @TContractState) -> u256; + + fn balance_of(self: @TContractState, account: ContractAddress) -> u256; + + fn allowance(self: @TContractState, owner: ContractAddress, spender: ContractAddress) -> u256; + + fn transfer(ref self: TContractState, recipient: ContractAddress, amount: u256) -> bool; + + fn transfer_from( + ref self: TContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256 + ) -> bool; + + fn approve(ref self: TContractState, spender: ContractAddress, amount: u256) -> bool; +} + +#[starknet::interface] +trait ITokenWrapper { + fn token_name(self: @TContractState, contract_address: ContractAddress) -> felt252; + + fn transfer_token( + ref self: TContractState, + contract_address: ContractAddress, + recipient: ContractAddress, + amount: u256 + ) -> bool; +} + + +//ANCHOR: here +//**** Specify interface here ****// +#[starknet::contract] +mod TokenWrapper { + use super::IERC20DispatcherTrait; + use super::IERC20Dispatcher; + use super::ITokenWrapper; + use starknet::ContractAddress; + + #[storage] + struct Storage {} + + impl TokenWrapper of ITokenWrapper { + fn token_name(self: @ContractState, contract_address: ContractAddress) -> felt252 { + IERC20Dispatcher { contract_address }.name() + } + + fn transfer_token( + ref self: ContractState, + contract_address: ContractAddress, + recipient: ContractAddress, + amount: u256 + ) -> bool { + IERC20Dispatcher { contract_address }.transfer(recipient, amount) + } + } +} +// ANCHOR_END: here + + diff --git a/listings/ch99-starknet-smart-contracts/listing_99_07_library_dispatcher/.gitignore b/listings/ch99-starknet-smart-contracts/listing_99_07_library_dispatcher/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_07_library_dispatcher/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch99-starknet-smart-contracts/listing_99_07_library_dispatcher/Scarb.toml b/listings/ch99-starknet-smart-contracts/listing_99_07_library_dispatcher/Scarb.toml new file mode 100644 index 000000000..3fde9e82f --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_07_library_dispatcher/Scarb.toml @@ -0,0 +1,9 @@ +[package] +name = "listing_99_07_library_dispatcher" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } +starknet = ">=2.2.0" diff --git a/listings/ch99-starknet-smart-contracts/listing_99_07_library_dispatcher.cairo b/listings/ch99-starknet-smart-contracts/listing_99_07_library_dispatcher/src/lib.cairo similarity index 83% rename from listings/ch99-starknet-smart-contracts/listing_99_07_library_dispatcher.cairo rename to listings/ch99-starknet-smart-contracts/listing_99_07_library_dispatcher/src/lib.cairo index 14a8495c3..eddc867f5 100644 --- a/listings/ch99-starknet-smart-contracts/listing_99_07_library_dispatcher.cairo +++ b/listings/ch99-starknet-smart-contracts/listing_99_07_library_dispatcher/src/lib.cairo @@ -1,4 +1,4 @@ -//does_not_compile +//TAG: does_not_compile use starknet::ContractAddress; trait IERC20DispatcherTrait { @@ -6,9 +6,9 @@ trait IERC20DispatcherTrait { fn transfer(self: T, recipient: ContractAddress, amount: u256); } -#[derive(Copy, Drop, storage_access::StorageAccess, Serde)] +#[derive(Copy, Drop, starknet::Store, Serde)] struct IERC20LibraryDispatcher { - class_hash: starknet::ClassHash, + class_hash: starknet::ClassHash, } impl IERC20LibraryDispatcherImpl of IERC20DispatcherTrait { diff --git a/listings/ch99-starknet-smart-contracts/listing_99_08_using_library_dispatcher.cairo b/listings/ch99-starknet-smart-contracts/listing_99_08_using_library_dispatcher.cairo deleted file mode 100644 index fedffeb86..000000000 --- a/listings/ch99-starknet-smart-contracts/listing_99_08_using_library_dispatcher.cairo +++ /dev/null @@ -1,54 +0,0 @@ -//**** Specify interface here ****// -use starknet::ContractAddress; - -#[abi] -trait IERC20 { - #[view] - fn name() -> felt252; - - #[view] - fn symbol() -> felt252; - - #[view] - fn decimals() -> u8; - - #[view] - fn total_supply() -> u256; - - #[view] - fn balance_of(account: ContractAddress) -> u256; - - #[view] - fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256; - - #[external] - fn transfer(recipient: ContractAddress, amount: u256) -> bool; - - #[external] - fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool; - - #[external] - fn approve(spender: ContractAddress, amount: u256) -> bool; -} - -//ANCHOR: here -#[contract] -mod contract { - use super::IERC20DispatcherTrait; - use super::IERC20LibraryDispatcher; - use starknet::ContractAddress; - - #[view] - fn token_name() -> felt252 { - IERC20LibraryDispatcher { class_hash: starknet::class_hash_const::<0x1234>() }.name() - } - - #[external] - fn transfer_token(recipient: ContractAddress, amount: u256) -> bool { - IERC20LibraryDispatcher { - class_hash: starknet::class_hash_const::<0x1234>() - }.transfer(recipient, amount) - } -} -//ANCHOR_END: here - diff --git a/listings/ch99-starknet-smart-contracts/listing_99_08_using_library_dispatcher/.gitignore b/listings/ch99-starknet-smart-contracts/listing_99_08_using_library_dispatcher/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_08_using_library_dispatcher/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch99-starknet-smart-contracts/listing_99_08_using_library_dispatcher/Scarb.toml b/listings/ch99-starknet-smart-contracts/listing_99_08_using_library_dispatcher/Scarb.toml new file mode 100644 index 000000000..e0ac69641 --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_08_using_library_dispatcher/Scarb.toml @@ -0,0 +1,9 @@ +[package] +name = "listing_99_08_using_library_dispatcher" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } +starknet = ">=2.2.0" diff --git a/listings/ch99-starknet-smart-contracts/listing_99_08_using_library_dispatcher/src/lib.cairo b/listings/ch99-starknet-smart-contracts/listing_99_08_using_library_dispatcher/src/lib.cairo new file mode 100644 index 000000000..b659b96fa --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_08_using_library_dispatcher/src/lib.cairo @@ -0,0 +1,35 @@ +//ANCHOR: here +use starknet::ContractAddress; +#[starknet::interface] +trait IContractB { + fn set_value(ref self: TContractState, value: u128); + + fn get_value(self: @TContractState) -> u128; +} + +#[starknet::contract] +mod ContractA { + use super::{IContractBDispatcherTrait, IContractBLibraryDispatcher}; + use starknet::ContractAddress; + + #[storage] + struct Storage { + value: u128 + } + + #[generate_trait] + #[external(v0)] + impl ContractA of IContractA { + fn set_value(ref self: ContractState, value: u128) { + IContractBLibraryDispatcher { class_hash: starknet::class_hash_const::<0x1234>() } + .set_value(value) + } + + fn get_value(self: @ContractState) -> u128 { + self.value.read() + } + } +} +//ANCHOR_END: here + + diff --git a/listings/ch99-starknet-smart-contracts/listing_99_09_call_contract_syscall.cairo b/listings/ch99-starknet-smart-contracts/listing_99_09_call_contract_syscall.cairo deleted file mode 100644 index ad7aa3919..000000000 --- a/listings/ch99-starknet-smart-contracts/listing_99_09_call_contract_syscall.cairo +++ /dev/null @@ -1,10 +0,0 @@ -#[contract] -mod Contract { - use array::ArrayTrait; - #[external] - fn transfer_token( - address: starknet::ContractAddress, selector: felt252, calldata: Array - ) -> Span:: { - starknet::call_contract_syscall(address, selector, calldata.span()).unwrap_syscall() - } -} diff --git a/listings/ch99-starknet-smart-contracts/listing_99_09_call_contract_syscall/.gitignore b/listings/ch99-starknet-smart-contracts/listing_99_09_call_contract_syscall/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_09_call_contract_syscall/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch99-starknet-smart-contracts/listing_99_09_call_contract_syscall/Scarb.toml b/listings/ch99-starknet-smart-contracts/listing_99_09_call_contract_syscall/Scarb.toml new file mode 100644 index 000000000..82d16d257 --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_09_call_contract_syscall/Scarb.toml @@ -0,0 +1,9 @@ +[package] +name = "listing_99_09_call_contract_syscall" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } +starknet = ">=2.2.0" diff --git a/listings/ch99-starknet-smart-contracts/listing_99_09_call_contract_syscall/src/lib.cairo b/listings/ch99-starknet-smart-contracts/listing_99_09_call_contract_syscall/src/lib.cairo new file mode 100644 index 000000000..fcf0294ed --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_09_call_contract_syscall/src/lib.cairo @@ -0,0 +1,31 @@ +#[starknet::interface] +trait ITokenWrapper { + fn transfer_token( + ref self: TContractState, + address: starknet::ContractAddress, + selector: felt252, + calldata: Array + ) -> bool; +} + +#[starknet::contract] +mod TokenWrapper { + use super::ITokenWrapper; + use starknet::SyscallResultTrait; + + #[storage] + struct Storage {} + + impl TokenWrapper of ITokenWrapper { + fn transfer_token( + ref self: ContractState, + address: starknet::ContractAddress, + selector: felt252, + calldata: Array + ) -> bool { + let mut res = starknet::call_contract_syscall(address, selector, calldata.span()) + .unwrap_syscall(); + Serde::::deserialize(ref res).unwrap() + } + } +} diff --git a/listings/ch99-starknet-smart-contracts/listing_99_10_assert_balance/.gitignore b/listings/ch99-starknet-smart-contracts/listing_99_10_assert_balance/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_10_assert_balance/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch99-starknet-smart-contracts/listing_99_10_assert_balance/Scarb.toml b/listings/ch99-starknet-smart-contracts/listing_99_10_assert_balance/Scarb.toml new file mode 100644 index 000000000..7ce7f8a04 --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_10_assert_balance/Scarb.toml @@ -0,0 +1,9 @@ +[package] +name = "listing_99_10_assert_balance" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } +starknet = ">=2.2.0" diff --git a/listings/ch99-starknet-smart-contracts/listing_99_10_assert_balance/src/lib.cairo b/listings/ch99-starknet-smart-contracts/listing_99_10_assert_balance/src/lib.cairo new file mode 100644 index 000000000..98e6ca3eb --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_10_assert_balance/src/lib.cairo @@ -0,0 +1,26 @@ +#[starknet::interface] +trait IContract { + fn withdraw(ref self: TContractState, amount: u256); +} + +#[starknet::contract] +mod contract { + use super::IContract; + #[storage] + struct Storage { + balance: u256 + } + + //ANCHOR: withdraw + impl Contract of IContract { + fn withdraw(ref self: ContractState, amount: u256) { + let current_balance = self.balance.read(); + + assert(self.balance.read() >= amount, 'Insufficient funds'); + + self.balance.write(current_balance - amount); + } + //ANCHOR_END: withdraw + + } +} diff --git a/listings/ch99-starknet-smart-contracts/listing_99_11_simple_access_control/.gitignore b/listings/ch99-starknet-smart-contracts/listing_99_11_simple_access_control/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_11_simple_access_control/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch99-starknet-smart-contracts/listing_99_11_simple_access_control/Scarb.toml b/listings/ch99-starknet-smart-contracts/listing_99_11_simple_access_control/Scarb.toml new file mode 100644 index 000000000..0bba51c7b --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_11_simple_access_control/Scarb.toml @@ -0,0 +1,9 @@ +[package] +name = "listing_99_11_simple_access_control" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } +starknet = ">=2.2.0" diff --git a/listings/ch99-starknet-smart-contracts/listing_99_11_simple_access_control/src/lib.cairo b/listings/ch99-starknet-smart-contracts/listing_99_11_simple_access_control/src/lib.cairo new file mode 100644 index 000000000..984589e6b --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_11_simple_access_control/src/lib.cairo @@ -0,0 +1,79 @@ +#[starknet::contract] +mod access_control_contract { + use starknet::ContractAddress; + use starknet::get_caller_address; + + trait IContract { + fn is_owner(self: @TContractState) -> bool; + fn is_role_a(self: @TContractState) -> bool; + fn only_owner(self: @TContractState); + fn only_role_a(self: @TContractState); + fn only_allowed(self: @TContractState); + fn set_role_a(ref self: TContractState, _target: ContractAddress, _active: bool); + fn role_a_action(ref self: ContractState); + fn allowed_action(ref self: ContractState); + } + + #[storage] + struct Storage { + // Role 'owner': only one address + owner: ContractAddress, + // Role 'role_a': a set of addresses + role_a: LegacyMap:: + } + + #[constructor] + fn constructor(ref self: ContractState) { + self.owner.write(get_caller_address()); + } + + // Guard functions to check roles + + impl Contract of IContract { + #[inline(always)] + fn is_owner(self: @ContractState) -> bool { + self.owner.read() == get_caller_address() + } + + #[inline(always)] + fn is_role_a(self: @ContractState) -> bool { + self.role_a.read(get_caller_address()) + } + + #[inline(always)] + fn only_owner(self: @ContractState) { + assert(Contract::is_owner(self), 'Not owner'); + } + + #[inline(always)] + fn only_role_a(self: @ContractState) { + assert(Contract::is_role_a(self), 'Not role A'); + } + + // You can easily combine guards to perfom complex checks + fn only_allowed(self: @ContractState) { + assert(Contract::is_owner(self) || Contract::is_role_a(self), 'Not allowed'); + } + + // Functions to manage roles + + fn set_role_a(ref self: ContractState, _target: ContractAddress, _active: bool) { + Contract::only_owner(@self); + self.role_a.write(_target, _active); + } + + // You can now focus on the business logic of your contract + // and reduce the complexity of your code by using guard functions + + fn role_a_action(ref self: ContractState) { + Contract::only_role_a(@self); + // ... + } + + fn allowed_action(ref self: ContractState) { + Contract::only_allowed(@self); + // ... + } + } +} + diff --git a/listings/ch99-starknet-smart-contracts/listing_99_12_vote_contract/.gitignore b/listings/ch99-starknet-smart-contracts/listing_99_12_vote_contract/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_12_vote_contract/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch99-starknet-smart-contracts/listing_99_12_vote_contract/Scarb.toml b/listings/ch99-starknet-smart-contracts/listing_99_12_vote_contract/Scarb.toml new file mode 100644 index 000000000..93227989c --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_12_vote_contract/Scarb.toml @@ -0,0 +1,9 @@ +[package] +name = "listing_99_12_vote_contract" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } +starknet = ">=2.2.0" diff --git a/listings/ch99-starknet-smart-contracts/listing_99_12_vote_contract/src/lib.cairo b/listings/ch99-starknet-smart-contracts/listing_99_12_vote_contract/src/lib.cairo new file mode 100644 index 000000000..89b67b7ad --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_12_vote_contract/src/lib.cairo @@ -0,0 +1,172 @@ +/// @dev Core Library Imports for the Traits outside the Starknet Contract +use starknet::ContractAddress; + +/// @dev Trait defining the functions that can be implemented or called by the Starknet Contract +#[starknet::interface] +trait VoteTrait { + /// @dev Function that returns the current vote status + fn get_vote_status(self: @T) -> (u8, u8, u8, u8); + /// @dev Function that checks if the user at the specified address is allowed to vote + fn voter_can_vote(self: @T, user_address: ContractAddress) -> bool; + /// @dev Function that checks if the specified address is registered as a voter + fn is_voter_registered(self: @T, address: ContractAddress) -> bool; + /// @dev Function that allows a user to vote + fn vote(ref self: T, vote: u8); +} + +/// @dev Starknet Contract allowing three registered voters to vote on a proposal +#[starknet::contract] +mod Vote { + use starknet::ContractAddress; + use starknet::get_caller_address; + + const YES: u8 = 1_u8; + const NO: u8 = 0_u8; + + /// @dev Structure that stores vote counts and voter states + #[storage] + struct Storage { + yes_votes: u8, + no_votes: u8, + can_vote: LegacyMap::, + registered_voter: LegacyMap::, + } + + /// @dev Contract constructor initializing the contract with a list of registered voters and 0 vote count + #[constructor] + fn constructor( + ref self: ContractState, + voter_1: ContractAddress, + voter_2: ContractAddress, + voter_3: ContractAddress + ) { + // Register all voters by calling the _register_voters function + self._register_voters(voter_1, voter_2, voter_3); + + // Initialize the vote count to 0 + self.yes_votes.write(0_u8); + self.no_votes.write(0_u8); + } + + /// @dev Event that gets emitted when a vote is cast + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + VoteCast: VoteCast, + UnauthorizedAttempt: UnauthorizedAttempt, + } + + /// @dev Represents a vote that was cast + #[derive(Drop, starknet::Event)] + struct VoteCast { + voter: ContractAddress, + vote: u8, + } + + /// @dev Represents an unauthorized attempt to vote + #[derive(Drop, starknet::Event)] + struct UnauthorizedAttempt { + unauthorized_address: ContractAddress, + } + + /// @dev Implementation of VoteTrait for ContractState + #[external(v0)] + impl VoteImpl of super::VoteTrait { + /// @dev Returns the voting results + fn get_vote_status(self: @ContractState) -> (u8, u8, u8, u8) { + let (n_yes, n_no) = self._get_voting_result(); + let (yes_percentage, no_percentage) = self._get_voting_result_in_percentage(); + return (n_yes, n_no, yes_percentage, no_percentage); + } + + /// @dev Check whether a voter is allowed to vote + fn voter_can_vote(self: @ContractState, user_address: ContractAddress) -> bool { + self.can_vote.read(user_address) + } + + /// @dev Check whether an address is registered as a voter + fn is_voter_registered(self: @ContractState, address: ContractAddress) -> bool { + self.registered_voter.read(address) + } + + /// @dev Submit a vote + fn vote(ref self: ContractState, vote: u8) { + assert(vote == NO || vote == YES, 'VOTE_0_OR_1'); + let caller: ContractAddress = get_caller_address(); + self._assert_allowed(caller); + self.can_vote.write(caller, false); + + if (vote == NO) { + self.no_votes.write(self.no_votes.read() + 1_u8); + } + if (vote == YES) { + self.yes_votes.write(self.yes_votes.read() + 1_u8); + } + + self.emit(VoteCast { voter: caller, vote: vote, }); + } + } + + /// @dev Internal Functions implementation for the Vote contract + #[generate_trait] + impl InternalFunctions of InternalFunctionsTrait { + /// @dev Registers the voters and initializes their voting status to true (can vote) + fn _register_voters( + ref self: ContractState, + voter_1: ContractAddress, + voter_2: ContractAddress, + voter_3: ContractAddress + ) { + self.registered_voter.write(voter_1, true); + self.can_vote.write(voter_1, true); + + self.registered_voter.write(voter_2, true); + self.can_vote.write(voter_2, true); + + self.registered_voter.write(voter_3, true); + self.can_vote.write(voter_3, true); + } + } + + /// @dev Asserts implementation for the Vote contract + #[generate_trait] + impl AssertsImpl of AssertsTrait { + // @dev Internal function that checks if an address is allowed to vote + fn _assert_allowed(ref self: ContractState, address: ContractAddress) { + let is_voter: bool = self.registered_voter.read((address)); + let can_vote: bool = self.can_vote.read((address)); + + if (can_vote == false) { + self.emit(UnauthorizedAttempt { unauthorized_address: address, }); + } + + assert(is_voter == true, 'USER_NOT_REGISTERED'); + assert(can_vote == true, 'USER_ALREADY_VOTED'); + } + } + + /// @dev Implement the VotingResultTrait for the Vote contract + #[generate_trait] + impl VoteResultFunctionsImpl of VoteResultFunctionsTrait { + // @dev Internal function to get the voting results (yes and no vote counts) + fn _get_voting_result(self: @ContractState) -> (u8, u8) { + let n_yes: u8 = self.yes_votes.read(); + let n_no: u8 = self.no_votes.read(); + + return (n_yes, n_no); + } + + // @dev Internal function to calculate the voting results in percentage + fn _get_voting_result_in_percentage(self: @ContractState) -> (u8, u8) { + let n_yes: u8 = self.yes_votes.read(); + let n_no: u8 = self.no_votes.read(); + + let total_votes: u8 = n_yes + n_no; + + let yes_percentage: u8 = (n_yes * 100_u8) / (total_votes); + let no_percentage: u8 = (n_no * 100_u8) / (total_votes); + + return (yes_percentage, no_percentage); + } + } +} diff --git a/listings/ch99-starknet-smart-contracts/listing_99_13_storage_packing/.gitignore b/listings/ch99-starknet-smart-contracts/listing_99_13_storage_packing/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_13_storage_packing/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch99-starknet-smart-contracts/listing_99_13_storage_packing/Scarb.toml b/listings/ch99-starknet-smart-contracts/listing_99_13_storage_packing/Scarb.toml new file mode 100644 index 000000000..95d3b7260 --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_13_storage_packing/Scarb.toml @@ -0,0 +1,9 @@ +[package] +name = "listing_99_13_storage_packing" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } +starknet = ">=2.2.0" diff --git a/listings/ch99-starknet-smart-contracts/listing_99_13_storage_packing/src/lib.cairo b/listings/ch99-starknet-smart-contracts/listing_99_13_storage_packing/src/lib.cairo new file mode 100644 index 000000000..ffa80369e --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/listing_99_13_storage_packing/src/lib.cairo @@ -0,0 +1,83 @@ +//ANCHOR:here +use starknet::{StorePacking}; +use integer::{u128_safe_divmod, u128_as_non_zero}; + +#[derive(Drop, Serde)] +struct Sizes { + tiny: u8, + small: u32, + medium: u64, +} + +const TWO_POW_8: u128 = 0x100; +const TWO_POW_40: u128 = 0x10000000000; + +const MASK_8: u128 = 0xff; +const MASK_32: u128 = 0xffffffff; + + +impl SizesStorePacking of StorePacking { + fn pack(value: Sizes) -> u128 { + value.tiny.into() + (value.small.into() * TWO_POW_8) + (value.medium.into() * TWO_POW_40) + } + + fn unpack(value: u128) -> Sizes { + let tiny = value & MASK_8; + let small = (value / TWO_POW_8) & MASK_32; + let medium = (value / TWO_POW_40); + + Sizes { + tiny: tiny.try_into().unwrap(), + small: small.try_into().unwrap(), + medium: medium.try_into().unwrap(), + } + } +} + +#[starknet::contract] +mod SizeFactory { + use super::Sizes; + use super::SizesStorePacking; //don't forget to import it! + + #[storage] + struct Storage { + remaining_sizes: Sizes + } + + #[external(v0)] + fn update_sizes(ref self: ContractState, sizes: Sizes) { + // This will automatically pack the + // struct into a single u128 + self.remaining_sizes.write(sizes); + } + + + #[external(v0)] + fn get_sizes(ref self: ContractState) -> Sizes { + // this will automatically unpack the + // packed-representation into the Sizes struct + self.remaining_sizes.read() + } +} + + +//ANCHOR_END:here + +#[cfg(test)] +mod tests { + use super::{SizesStorePacking, Sizes}; + use starknet::StorePacking; + #[test] + #[available_gas(200000)] + fn test_pack_unpack() { + let value = Sizes { tiny: 0x12, small: 0x12345678, medium: 0x1234567890, }; + + let packed = SizesStorePacking::pack(value); + assert(packed == 0x12345678901234567812, 'wrong packed value'); + + let unpacked = SizesStorePacking::unpack(packed); + assert(unpacked.tiny == 0x12, 'wrong unpacked tiny'); + assert(unpacked.small == 0x12345678, 'wrong unpacked small'); + assert(unpacked.medium == 0x1234567890, 'wrong unpacked medium'); + } +} diff --git a/listings/ch99-starknet-smart-contracts/no_listing_01_storage_mapping/.gitignore b/listings/ch99-starknet-smart-contracts/no_listing_01_storage_mapping/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/no_listing_01_storage_mapping/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch99-starknet-smart-contracts/no_listing_01_storage_mapping/Scarb.toml b/listings/ch99-starknet-smart-contracts/no_listing_01_storage_mapping/Scarb.toml new file mode 100644 index 000000000..20367ea36 --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/no_listing_01_storage_mapping/Scarb.toml @@ -0,0 +1,9 @@ +[package] +name = "no_listing_01_storage_mapping" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } +starknet = ">=2.2.0" diff --git a/listings/ch99-starknet-smart-contracts/no_listing_01_storage_mapping.cairo b/listings/ch99-starknet-smart-contracts/no_listing_01_storage_mapping/src/lib.cairo similarity index 61% rename from listings/ch99-starknet-smart-contracts/no_listing_01_storage_mapping.cairo rename to listings/ch99-starknet-smart-contracts/no_listing_01_storage_mapping/src/lib.cairo index 93796090b..d7d15ce48 100644 --- a/listings/ch99-starknet-smart-contracts/no_listing_01_storage_mapping.cairo +++ b/listings/ch99-starknet-smart-contracts/no_listing_01_storage_mapping/src/lib.cairo @@ -1,6 +1,8 @@ -#[contract] -mod Contract { +#[starknet::contract] +mod contract { + use starknet::ContractAddress; //ANCHOR: here + #[storage] struct Storage { allowances: LegacyMap::<(ContractAddress, ContractAddress), u256> } diff --git a/listings/ch99-starknet-smart-contracts/no_listing_99_02_explicit_internal_fn/.gitignore b/listings/ch99-starknet-smart-contracts/no_listing_99_02_explicit_internal_fn/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/no_listing_99_02_explicit_internal_fn/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch99-starknet-smart-contracts/no_listing_99_02_explicit_internal_fn/Scarb.toml b/listings/ch99-starknet-smart-contracts/no_listing_99_02_explicit_internal_fn/Scarb.toml new file mode 100644 index 000000000..9fb09db64 --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/no_listing_99_02_explicit_internal_fn/Scarb.toml @@ -0,0 +1,9 @@ +[package] +name = "no_listing_99_02_explicit_internal_fn" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } +starknet = ">=2.2.0" diff --git a/listings/ch99-starknet-smart-contracts/no_listing_99_02_explicit_internal_fn/src/lib.cairo b/listings/ch99-starknet-smart-contracts/no_listing_99_02_explicit_internal_fn/src/lib.cairo new file mode 100644 index 000000000..e70703a26 --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/no_listing_99_02_explicit_internal_fn/src/lib.cairo @@ -0,0 +1,57 @@ +//ANCHOR: all + +use starknet::ContractAddress; + +#[starknet::contract] +mod NameRegistry { + use starknet::{ContractAddress, get_caller_address}; + + #[storage] + struct Storage { + names: LegacyMap::, + total_names: u128, + owner: Person + } + + //ANCHOR: person + #[derive(Copy, Drop, Serde, starknet::Store)] + struct Person { + name: felt252, + address: ContractAddress + } + //ANCHOR_END: person + + //ANCHOR: event + #[event] + #[derive(Drop, starknet::Event)] + enum Event { + StoredName: StoredName, + } + + #[derive(Drop, starknet::Event)] + struct StoredName { + #[key] + user: ContractAddress, + name: felt252 + } + + // ANCHOR: state_internal + trait InternalFunctionsTrait { + fn _store_name(ref self: TContractState, user: ContractAddress, name: felt252); + } + impl InternalFunctions of InternalFunctionsTrait { + fn _store_name(ref self: ContractState, user: ContractAddress, name: felt252) { + let mut total_names = self.total_names.read(); + self.names.write(user, name); + self.total_names.write(total_names + 1); + //ANCHOR: emit_event + self.emit(Event::StoredName(StoredName { user: user, name: name })); + //ANCHOR_END: emit_event + + } + } +// ANCHOR: state_internal +} +//ANCHOR_END: all + + diff --git a/listings/ch99-starknet-smart-contracts/no_listing_event_trait/.gitignore b/listings/ch99-starknet-smart-contracts/no_listing_event_trait/.gitignore new file mode 100644 index 000000000..eb5a316cb --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/no_listing_event_trait/.gitignore @@ -0,0 +1 @@ +target diff --git a/listings/ch99-starknet-smart-contracts/no_listing_event_trait/Scarb.toml b/listings/ch99-starknet-smart-contracts/no_listing_event_trait/Scarb.toml new file mode 100644 index 000000000..c5fe7e10d --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/no_listing_event_trait/Scarb.toml @@ -0,0 +1,9 @@ +[package] +name = "no_listing_event_trait" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } +starknet = ">=2.2.0" diff --git a/listings/ch99-starknet-smart-contracts/no_listing_event_trait/src/lib.cairo b/listings/ch99-starknet-smart-contracts/no_listing_event_trait/src/lib.cairo new file mode 100644 index 000000000..bce820c13 --- /dev/null +++ b/listings/ch99-starknet-smart-contracts/no_listing_event_trait/src/lib.cairo @@ -0,0 +1,4 @@ +trait Event { + fn append_keys_and_data(self: T, ref keys: Array, ref data: Array); + fn deserialize(ref keys: Span, ref data: Span) -> Option; +} diff --git a/mdbook-cairo/Cargo.toml b/mdbook-cairo/Cargo.toml index 05cb14a19..1de3d3df1 100644 --- a/mdbook-cairo/Cargo.toml +++ b/mdbook-cairo/Cargo.toml @@ -1,16 +1,16 @@ [package] name = "mdbook-cairo" -version = "0.1.0" +version = "0.2.0" edition = "2021" license = "MIT" authors = ["Cairo-book community"] -description = "A tool for extracting cairo code from Markdown files as compilable cairo programs." +description = "A mdbook preprocessor to be used with cairo-verify" repository = "https://github.com/cairo-book/cairo-book.github.io" [dependencies] +clap = "4.3.5" +lazy_static = "1.4.0" mdbook = "0.4.28" -pulldown-cmark = { version = "0.9.2", default-features = false } -serde = "1.0.163" -serde_derive = "1.0.163" -lazy_static = "1.4" -regex = "1.8.1" +regex = "1.8.4" +semver = "1.0.17" +serde_json = "1.0.97" diff --git a/mdbook-cairo/README.md b/mdbook-cairo/README.md index a5871ff29..dda6dfaea 100644 --- a/mdbook-cairo/README.md +++ b/mdbook-cairo/README.md @@ -1,13 +1,9 @@ -# mdbook backend to generate cairo programs - -This backend aims at generating compilable Cairo programs from -Markdown code blocks. - -Only code blocks with ... - +# mdbook preprocessor for cairo program +This mdbook preprocessor removes the `// TAG` lines from the cairo code blocks in the markdown files. +It was made to be used with the `cairo-verify` tool. # Useful links: -- [Markdown backend documentation](https://rust-lang.github.io/mdBook/for_developers/backends.html) +- [Mdbook preprocessor documentation](https://rust-lang.github.io/mdBook/for_developers/preprocessors.html) diff --git a/mdbook-cairo/scripts/cairo_local_verify.sh b/mdbook-cairo/scripts/cairo_local_verify.sh deleted file mode 100644 index b74507532..000000000 --- a/mdbook-cairo/scripts/cairo_local_verify.sh +++ /dev/null @@ -1,36 +0,0 @@ -#!/bin/bash -# -# Runs locally a CI like workflow to test the Cairo code blocks in the cairo-book sources. -# -# This process is using docker, to be consistent with the CI. -# The version of the docker image must fit the one used in the CI to ensure consistency. -# -# This script must be executed being at the root of this repository. -# - - - -# https://hub.docker.com/r/starknet/cairo -STARKNET_CAIRO_IMAGE=starknet/cairo:1.1.0 - -# 1. Install mdbook-cairo locally. -cargo install --path mdbook-cairo --locked --force - -# 2. Cleanup existing book. As the docker is run as root, some outputed files are not -# accessible if not used with sudo, which makes mdbook clean unsuitable. -sudo rm -rf book - -# 3. Build the book to have the cairo mdbook backend running and extracting the programs. -mdbook build -d book - -# 4. The cairo_programs_verifier.sh script must be copied in order to be mounted in the -# docker container with the extracted cairo programs. -cp mdbook-cairo/scripts/cairo_programs_verifier.sh book/cairo/cairo-programs/ - -# 5. Run the docker image to actually run the cairo programs. -sudo docker run --rm \ - -v "$(pwd)"/book/cairo/cairo-programs:/cairo \ - --entrypoint sh \ - "$STARKNET_CAIRO_IMAGE" \ - /cairo/cairo_programs_verifier.sh true - diff --git a/mdbook-cairo/scripts/cairo_programs_verifier.sh b/mdbook-cairo/scripts/cairo_programs_verifier.sh deleted file mode 100644 index 598a97ee0..000000000 --- a/mdbook-cairo/scripts/cairo_programs_verifier.sh +++ /dev/null @@ -1,81 +0,0 @@ -#!/bin/bash - -IS_RUN_LOCALLY="$1" - -GREEN='\033[1;32m' -RED='\033[1;31m' -NC='\033[0m' - -cd /cairo -mkdir -p output -rm -rf output/* - -if [ "$IS_RUN_LOCALLY" = true ]; then - echo -e "\nStarting Cairo programs verifier...\n" -else - echo "# Cairo program verifier" - echo "" - echo "The list of cairo programs below is auto-generated from the markdown sources." - echo "Any code block with a main function will be compiled (except if the attribute does_not_compile is manually added)." - echo "Cairo-format is also executed to enforce consistent code style." - echo "" -fi - -has_error=false -has_format_error=false - -for prog in *.cairo; do - # Check compilation if needed - compile_code=0 - if [[ "$prog" =~ "_checkcomp" ]]; then - cairo-run --available-gas=20000000 "$prog" > output/"$prog".out 2> output/"$prog".err - compile_code="$?" - fi - - # Check format if needed - format_code=0 - if [[ $prog =~ "_checkfmt" ]]; then - cairo-format --check --print-parsing-errors "$prog" > output/"$prog".err - format_code="$?" - fi - - if [ $compile_code -ne 0 ] || [ $format_code -ne 0 ]; then - err="$(cat output/$prog.err)" - has_error=true - - if [ "$IS_RUN_LOCALLY" = true ]; then - echo -e "\n---- ${RED}${prog}${NC} ----\n" - echo "$err" - else - echo ":x: **$prog**" - echo "
$err
" - fi - - echo "" - echo "--- " - echo "" - fi - - -done - -if [ "$has_error" = false ] ; then - if [ "$IS_RUN_LOCALLY" = true ]; then - echo -e "\n${GREEN}All Cairo programs were compiled successfully and no formatting mistakes were found${NC}.\n" - else - echo ":heavy_check_mark: All Cairo programs were compiled successfully and no formatting mistakes were found." - echo "" - fi - - exit 0 -else - - if [ "$IS_RUN_LOCALLY" = true ]; then - echo -e "\n${RED}Some Cairo programs have errors, please check the list above.${NC}\n" - else - echo ":x: Some Cairo programs have errors, please check the list above." - echo "" - fi - - exit 1 -fi diff --git a/mdbook-cairo/src/lib.rs b/mdbook-cairo/src/lib.rs new file mode 100644 index 000000000..890a9407e --- /dev/null +++ b/mdbook-cairo/src/lib.rs @@ -0,0 +1,63 @@ +use lazy_static::lazy_static; +use mdbook::book::{Book, BookItem}; +use mdbook::errors::Error; +use mdbook::preprocess::{Preprocessor, PreprocessorContext}; +use regex::Regex; + +const TAG_REGEX_PATTERN: &str = r"^//\s*TAG"; + +lazy_static! { + static ref TAG_REGEX: Regex = Regex::new(TAG_REGEX_PATTERN).unwrap(); +} + +/// The actual implementation of the `Cairo` preprocessor. +pub struct Cairo; + +impl Cairo { + pub fn new() -> Cairo { + Cairo + } +} + +impl Default for Cairo { + fn default() -> Self { + Self::new() + } +} + +impl Preprocessor for Cairo { + fn name(&self) -> &str { + "cairo-preprocessor" + } + + fn run(&self, _ctx: &PreprocessorContext, mut book: Book) -> Result { + book.for_each_mut(|item: &mut BookItem| { + if let BookItem::Chapter(ref mut chapter) = *item { + let mut new_content = String::new(); + let lines = chapter.content.split_terminator('\n').peekable(); + let mut in_code_block = false; + + for line in lines { + in_code_block ^= line.starts_with("```"); + + if in_code_block && TAG_REGEX.is_match(line) { + // delete this line + continue; + } + + new_content.push_str(line); + new_content.push('\n'); + } + + chapter.content = new_content; + } + }); + + // Return updated version of the book + Ok(book) + } + + fn supports_renderer(&self, renderer: &str) -> bool { + renderer != "not-supported" + } +} diff --git a/mdbook-cairo/src/main.rs b/mdbook-cairo/src/main.rs index 5be533805..ab1143871 100644 --- a/mdbook-cairo/src/main.rs +++ b/mdbook-cairo/src/main.rs @@ -1,148 +1,68 @@ -use lazy_static::lazy_static; -use mdbook::book::{Book, BookItem, Chapter}; -use mdbook::renderer::RenderContext; -use pulldown_cmark::{CodeBlockKind, Event, Parser, Tag}; -use regex::Regex; -use serde::{Deserialize, Serialize}; -use std::fs::{create_dir_all, remove_dir_all, File}; -use std::io::{self, Write}; -use std::path::Path; - -/// The table header expected in book.toml. -const CAIRO_CONFIG_TABLE_HEADER: &str = "output.cairo"; - -/// An attribute added to a code block tag to ignore -/// the code extraction. -const CODE_BLOCK_DOES_NOT_COMPILE: &str = "does_not_compile"; - -/// An attribute added to a code block tag to ignore -/// the format check. -const CODE_BLOCK_IGNORE_FORMAT: &str = "ignore_format"; - -/// Main function expected in a code block to be a candidate -/// for the code extraction. -const CODE_BLOCK_MAIN_FUNCTION: &str = "fn main()"; - -/// Struct mapping fields expected in [output.cairo] from book.toml. -#[derive(Debug, Default, Serialize, Deserialize)] -#[serde(default, rename_all = "kebab-case")] -pub struct CairoConfig { - pub output_dir: String, +use clap::{Arg, ArgMatches, Command}; +use mdbook::errors::Error; +use mdbook::preprocess::{CmdPreprocessor, Preprocessor}; +use semver::{Version, VersionReq}; +use std::io; +use std::process; + +use mdbook_cairo::Cairo; + +pub fn make_app() -> Command { + Command::new("cairo-preprocessor") + .about("A mdbook preprocessor which remove '// TAG' lines in cairo code blocks") + .subcommand( + Command::new("supports") + .arg(Arg::new("renderer").required(true)) + .about("Check whether a renderer is supported by this preprocessor"), + ) } -// Statically initialize the regex to avoid rebuiling at each loop iteration. -lazy_static! { - static ref REGEX: Regex = - Regex::new(r"^ch(\d{2})-(\d{2})-(.*)$").expect("Failed to create regex"); -} - -/// Backend entry point, which received the mdbook content directly from stdin. fn main() { - let mut stdin = io::stdin(); - let ctx = RenderContext::from_json(&mut stdin) - .expect("Couldn't get mdbook render context from stdin."); - - // Execute the rendered only on english version. - if !ctx - .destination - .as_path() - .display() - .to_string() - .contains("/book/cairo") - { - println!("No default english build, skipping cairo output."); - return; - } - - let cfg: CairoConfig = ctx - .config - .get_deserialized_opt(CAIRO_CONFIG_TABLE_HEADER) - .expect("Couldn't deserialize cairo config from book.toml.") - .unwrap(); - - let output_path = Path::new(cfg.output_dir.as_str()); + let matches = make_app().get_matches(); - remove_dir_all(output_path) - .unwrap_or_else(|_| println!("Couldn't clean output directory, skip.")); + // Users will want to construct their own preprocessor here + let preprocessor = Cairo::new(); - create_dir_all(output_path).expect("Couldn't create output directory."); - - process_chapters(&ctx.book, &output_path); -} - -/// Processes all the chapters to search for code block. -fn process_chapters(book: &Book, output_dir: &Path) { - for item in book.iter() { - if let BookItem::Chapter(chapter) = item { - if let Some(chapter_prefix) = chapter_prefix_from_name(chapter) { - process_chapter(output_dir, &chapter_prefix, &chapter.content); - } - } + if let Some(sub_args) = matches.subcommand_matches("supports") { + handle_supports(&preprocessor, sub_args); + } else if let Err(e) = handle_preprocessing(&preprocessor) { + eprintln!("{}", e); + process::exit(1); } } -/// Extract the prefix of the chapter from filename string. -fn chapter_prefix_from_name(chapter: &Chapter) -> Option { - if let Some(p) = &chapter.path { - let file_name = p.to_string_lossy().to_string(); +fn handle_preprocessing(pre: &dyn Preprocessor) -> Result<(), Error> { + let (ctx, book) = CmdPreprocessor::parse_input(io::stdin())?; - if let Some(groups) = REGEX.captures(&file_name) { - if let (Some(c), Some(s)) = (groups.get(1), groups.get(2)) { - let c = c.as_str(); - let s = s.as_str(); - return Some(format!("ch{}_{}", c, s)); - } - } - } - - None -} + let book_version = Version::parse(&ctx.mdbook_version)?; + let version_req = VersionReq::parse(mdbook::MDBOOK_VERSION)?; -/// Processes the content of a chapter to parse code blocks and write them to a file. -fn process_chapter(output_dir: &Path, prefix: &str, content: &str) { - let parser = Parser::new(content); - - let mut program_counter = 1; - let mut in_code_block = false; - let mut is_compilable = false; - let mut enforce_format = true; - - for event in parser { - match event { - Event::Start(Tag::CodeBlock(x)) => { - in_code_block = true; - - if let CodeBlockKind::Fenced(tag_value) = x { - is_compilable = !tag_value.to_string().contains(CODE_BLOCK_DOES_NOT_COMPILE); - enforce_format = !tag_value.to_string().contains(CODE_BLOCK_IGNORE_FORMAT); - } - } - Event::Text(text) => { - if in_code_block && text.contains(CODE_BLOCK_MAIN_FUNCTION) { - if is_compilable || enforce_format { - let compile_tag = if is_compilable { "_checkcomp" } else { "" }; - let format_tag = if enforce_format { "_checkfmt" } else { "" }; - let file_name = format!( - "{}_{}{}{}.cairo", - prefix, program_counter, compile_tag, format_tag - ); + if !version_req.matches(&book_version) { + eprintln!( + "Warning: The {} plugin was built against version {} of mdbook, \ + but we're being called from version {}", + pre.name(), + mdbook::MDBOOK_VERSION, + ctx.mdbook_version + ); + } - let file_dir = &output_dir.join(file_name); - let mut file = File::create(file_dir).expect("Failed to create file."); + let processed_book = pre.run(&ctx, book)?; + serde_json::to_writer(io::stdout(), &processed_book)?; - file.write(text.as_bytes()).expect("Can't write to file."); - } + Ok(()) +} - // To facilitate the debugging, we always increment the counter when a - // main function is found in a code block. This helps contributors to - // easily locate the code, without having to skip the `does_not_compile` blocks. - program_counter += 1; - } - } - Event::End(Tag::CodeBlock(_)) => { - in_code_block = false; - } - _ => {} - } +fn handle_supports(pre: &dyn Preprocessor, sub_args: &ArgMatches) -> ! { + let renderer = sub_args + .get_one::("renderer") + .expect("Required argument"); + let supported = pre.supports_renderer(renderer); + + // Signal whether the renderer is supported by exiting with 1 or 0. + if supported { + process::exit(0); + } else { + process::exit(1); } } diff --git a/po/es.po b/po/es.po index d046f14dd..3c2e2702d 100644 --- a/po/es.po +++ b/po/es.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: The Cairo Programming Language\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2023-05-31 13:23+0100\n" +"PO-Revision-Date: 2023-06-26 00:08+0100\n" "Last-Translator: dami \n" "Language-Team: Spanish \n" "Language: es\n" @@ -168,51 +168,63 @@ msgstr "Errores Irrecuperables con pánico" msgid "Recoverable Errors with Result" msgstr "Errores Recuperables con Resultados" -#: src/SUMMARY.md:77 +#: src/SUMMARY.md:75 +msgid "Advanced Features" +msgstr "Funciones Avanzadas" + +#: src/SUMMARY.md:78 +msgid "Operator Overloading" +msgstr "Sobrecarga de Operadores" + +#: src/SUMMARY.md:82 msgid "Starknet Smart Contracts" msgstr "Starknet Smart Contracts" -#: src/SUMMARY.md:79 +#: src/SUMMARY.md:84 msgid "Introduction to smart-contracts" msgstr "Introducción a los smart-contracts" -#: src/SUMMARY.md:80 +#: src/SUMMARY.md:85 msgid "Writing Starknet Contracts" msgstr "Escribiendo Contratos en Starknet" -#: src/SUMMARY.md:81 +#: src/SUMMARY.md:86 msgid "ABIs and Cross-contract Interactions" msgstr "ABIs e Interacciones entre Contratos Multicapa" -#: src/SUMMARY.md:82 +#: src/SUMMARY.md:87 msgid "ABIs and Interfaces" msgstr "ABIs e interfaces" -#: src/SUMMARY.md:83 +#: src/SUMMARY.md:88 msgid "Contract Dispatchers, Library Dispachers and system calls" msgstr "Despachadores de contratos, despachadores de librerías y llamadas del sistema" -#: src/SUMMARY.md:85 +#: src/SUMMARY.md:89 +msgid "Security Considerations" +msgstr "Consideraciones de Seguridad" + +#: src/SUMMARY.md:91 msgid "Appendix" msgstr "Apéndice" -#: src/SUMMARY.md:86 +#: src/SUMMARY.md:92 msgid "A - Keywords" msgstr "A - Palabras clave" -#: src/SUMMARY.md:87 +#: src/SUMMARY.md:93 msgid "B - Operators and Symbols" msgstr "B - Operadores y Símbolos" -#: src/SUMMARY.md:88 +#: src/SUMMARY.md:94 msgid "C - Derivable Traits" msgstr "C - Traits Derivables" -#: src/SUMMARY.md:89 +#: src/SUMMARY.md:95 msgid "D - Useful Development Tools" msgstr "D - Herramientas de Desarrollo Útiles" -#: src/SUMMARY.md:90 +#: src/SUMMARY.md:96 msgid "E - Cairo Most Common Types and Traits" msgstr "E - Tipos y Traits más comunes en Cairo" @@ -229,8 +241,8 @@ msgstr "" "[OnlyDust](https://www.onlydust.xyz/), y [Voyager](https://voyager.online/) por apoyar la creación de este libro." #: src/title-page.md:5 -msgid "This version of the text assumes you’re using Cairo v1.0.0 (released 2023-05-15). See the “Installation” section of Chapter 1 to install or update Cairo." -msgstr "Esta versión del texto asume que estás usando Cairo v1.0.0 (publicado el 2023-05-15). Consulte la sección \"Instalación\" del Capítulo 1 para instalar o actualizar Cairo." +msgid "This version of the text assumes you’re using Cairo v1.1.0. See the “Installation” section of Chapter 1 to install or update Cairo." +msgstr "Esta versión del texto asume que estás usando Cairo v1.1.0. Consulte la sección \"Instalación\" del Capítulo 1 para instalar o actualizar Cairo." #: src/ch00-01-foreword.md:1 msgid "# Foreword" @@ -318,16 +330,16 @@ msgstr "## ¿Qué puedes hacer con Cairo?" msgid "" "Cairo allows you to compute trustworthy values on untrusted machines. One major usecase is Starknet, a solution to Ethereum scaling. Ethereum is a decentralized blockchain platform " "that enables the creation of decentralized applications where every single interaction between a user and a d-app is verified by all the participants. Starknet is a Layer 2 built on " -"top of Ethereum. Instead of having all the participants of the network to verify all user interactions, only one node, called the prover, execute the programs and generate proofs " -"that the computations were done correctly.These proofs are then verified by an Ethereum smart contract, requiring significantly less computational power compared to executing the " -"interactions themselves. This approach allows for increased throughput and reduced transaction costs but preserving Ethereum security." +"top of Ethereum. Instead of having all the participants of the network to verify all user interactions, only one node, called the prover, executes the programs and generates proofs " +"that the computations were done correctly. These proofs are then verified by an Ethereum smart contract, requiring significantly less computational power compared to executing the " +"interactions themselves. This approach allows for increased throughput and reduced transaction costs while preserving Ethereum security." msgstr "" -"Cairo te permite calcular valores confiables en máquinas no confiables. Un caso de uso importante es Starknet, una solución para la escalabilidad de Ethereum. Ethereum es una " -"plataforma blockchain descentralizada que permite la creación de aplicaciones descentralizadas donde cada interacción entre un usuario y una d-app es verificada por todos los " -"participantes. Starknet es una capa 2 construida sobre Ethereum. En lugar de que todos los participantes de la red verifiquen todas las interacciones del usuario, solo un nodo, " -"llamado el probador, ejecuta los programas y genera pruebas de que los cálculos se realizaron correctamente. Estas pruebas luego son verificadas por un contrato inteligente de " -"Ethereum, lo que requiere significativamente menos potencia de cálculo en comparación con la ejecución de las interacciones mismas. Este enfoque permite un mayor rendimiento y una " -"reducción en los costos de transacción, pero preservando la seguridad de Ethereum." +"Cairo permite calcular valores confiables en máquinas no confiables. Un caso de uso importante es Starknet, una solución para escalar Ethereum. Ethereum es una plataforma de " +"blockchain descentralizada que permite la creación de aplicaciones descentralizadas donde cada interacción entre un usuario y una dApp es verificada por todos los participantes. " +"Starknet es una capa 2 construida sobre Ethereum. En lugar de requerir que todos los participantes de la red verifiquen todas las interacciones del usuario, solo un nodo, llamado " +"probador (prover), ejecuta los programas y genera pruebas de que los cálculos se realizaron correctamente. Estas pruebas luego son verificadas por un contrato inteligente de " +"Ethereum, lo que requiere significativamente menos potencia de cómputo en comparación con ejecutar las interacciones en sí mismas. Este enfoque permite aumentar la capacidad de " +"procesamiento y reducir los costos de transacción, al tiempo que se preserva la seguridad de Ethereum." #: src/ch00-00-introduction.md:12 msgid "## What are the differences with other programming languages?" @@ -349,17 +361,18 @@ msgid "" "- When the generated proof is verified by a verifier, it is a bit different. This has to be as cheap as possible since it could potentially be verified on many very small machines. " "Fortunately verifying is faster than computing and Cairo has some unique advantages to improve it even more. A notable one is non-determinism. This is a topic you will cover in more " "detail later in this book, but the idea is that you can theoretically use a different algorithm for verifying than for computing. Currently, writing custom non-deterministic code is " -"not supported for the developers, but the standard library leverages non-determinism for improved performance. For example sorting an array in Cairo costs the same price than copying " +"not supported for the developers, but the standard library leverages non-determinism for improved performance. For example sorting an array in Cairo costs the same price as copying " "it. Because the verifier doesn't sort the array, it just checks that it is sorted, which is cheaper." msgstr "" -"- Cuando se ejecuta por el probador, es similar a cualquier otro lenguaje. Debido a que Cairo está virtualizado y porque las operaciones no se diseñaron específicamente para la " -"máxima eficiencia, esto puede llevar a una sobrecarga de rendimiento, pero no es la parte más relevante para optimizar.\n" +"- Cuando es ejecutado por el probador (prover), es similar a cualquier otro lenguaje. Debido a que Cairo es virtualizado y las operaciones no fueron diseñadas específicamente para " +"obtener la máxima eficiencia, esto puede generar cierta sobrecarga de rendimiento, pero no es la parte más relevante para optimizar.\n" "\n" -"- Cuando el probador genera la prueba, es un poco diferente. Esto tiene que ser lo más barato posible, ya que potencialmente se podría verificar en muchas máquinas muy pequeñas. " -"Afortunadamente, verificar es más rápido que computar y Cairo tiene algunas ventajas únicas para mejorar aún más. Uno notable es la no determinación. Este es un tema que cubrirás con " -"más detalle más adelante en este libro, pero la idea es que teóricamente puedes usar un algoritmo diferente para verificar que para calcular. Actualmente, escribir código " -"personalizado no determinista no está soportado para los desarrolladores, pero la biblioteca estándar aprovecha la no determinación para mejorar el rendimiento. Por ejemplo, ordenar " -"una matriz en Cairo cuesta lo mismo que copiarla. Debido a que el verificador no ordena la matriz, simplemente verifica que está ordenada, lo que es más barato." +"- Sin embargo, cuando la prueba generada es verificada por un verificador, es un poco diferente. Esto debe ser lo más económico posible, ya que potencialmente podría ser verificado " +"en muchas máquinas muy pequeñas. Afortunadamente, la verificación es más rápida que el cálculo y Cairo tiene algunas ventajas únicas para mejorar aún más este proceso. Una notable es " +"la no determinación. Este es un tema que se tratará con más detalle más adelante en este libro, pero la idea es que teóricamente puedes usar un algoritmo diferente para verificar que " +"para calcular. Actualmente, no se admite la escritura de código no determinista personalizado para los desarrolladores, pero la biblioteca estándar aprovecha la no determinación para " +"mejorar el rendimiento. Por ejemplo, ordenar un arreglo en Cairo tiene el mismo costo que copiarlo. Debido a que el verificador no ordena el arreglo, solo verifica que esté ordenado, " +"lo cual es más barato." #: src/ch00-00-introduction.md:20 msgid "" @@ -427,9 +440,10 @@ msgid "### Install" msgstr "### Instalación" #: src/ch01-01-installation.md:20 -msgid "If you wish to install a specific release of Cairo rather than the latest head, set the `CAIRO_GIT_TAG` environment variable (e.g. `export CAIRO_GIT_TAG=v1.0.0`)." +msgid "If you wish to install a specific release of Cairo rather than the latest head, set the `CAIRO_GIT_TAG` environment variable (e.g. `export CAIRO_GIT_TAG=v1.1.0`)." msgstr "" -"Si deseas instalar una versión específica de Cairo en lugar de la última versión, debes establecer la variable de entorno `CAIRO_GIT_TAG` (por ejemplo,`export CAIRO_GIT_TAG=v1.0.0`)." +"Si deseas instalar una versión específica de Cairo en lugar de la última versión disponible, puedes establecer la variable de entorno `CAIRO_GIT_TAG` (por ejemplo, `export " +"CAIRO_GIT_TAG=v1.1.0`)." #: src/ch01-01-installation.md:22 msgid "" @@ -709,7 +723,7 @@ msgid "" "# View tags (you can also do this in the cairo compiler repository)\n" "git describe --tags `git rev-list --tags`\n" "# Checkout the version you want\n" -"git checkout tags/v1.0.0\n" +"git checkout tags/v1.1.0\n" "\n" "# Generate release binaries\n" "cargo build --all --release\n" @@ -731,7 +745,7 @@ msgstr "" "# View tags (you can also do this in the cairo compiler repository)\n" "git describe --tags `git rev-list --tags`\n" "# Checkout the version you want\n" -"git checkout tags/v1.0.0\n" +"git checkout tags/v1.1.0\n" "\n" "# Generate release binaries\n" "cargo build --all --release\n" @@ -791,23 +805,30 @@ msgstr "#### Extensión VS Code" #: src/ch01-01-installation.md:188 msgid "" -"- Disable previous Cairo 0.x extension\n" -"- Install the Cairo 1 extension for proper syntax highlighting and code navigation.\n" -" Just follow the steps indicated [here](https://github.com/starkware-libs/cairo/blob/main/vscode-cairo/README.md)." +"- If you have the previous Cairo 0 extension installed, you can disable/uninstall it.\n" +"- Install the Cairo 1 extension for proper syntax highlighting and code navigation. You can find the link to the extension [here](https://marketplace.visualstudio.com/items?" +"itemName=starkware.cairo1&ssr=false), or just search for \"Cairo 1.0\" in the VS Code marketplace.\n" +"- The extension will work out of the box once you will have [Scarb](./ch01-03-hello-scarb.md) installed." msgstr "" -"- Deshabilite la extensión anterior Cairo 0.x\n" -"- Instale la extensión Cairo 1 para un correcto resaltado de sintaxis y navegación por el código.\n" -" Simplemente siga los pasos indicados [aquí](https://github.com/starkware-libs/cairo/blob/main/vscode-cairo/README.md)." +"- Si tienes instalada la extensión anterior de Cairo 0, puedes desactivarla/desinstalarla.\n" +"- Instala la extensión de Cairo 1 para tener resaltado de sintaxis y navegación de código adecuados. Puedes encontrar el enlace a la extensión [aquí](https://marketplace.visualstudio." +"com/items?itemName=starkware.cairo1&ssr=false), o simplemente busca \"Cairo 1.0\" en el marketplace de VS Code.\n" +"- La extensión funcionará automáticamente una vez que tengas instalado [Scarb](./ch01-03-hello-scarb.md)." #: src/ch01-01-installation.md:192 -msgid "#### Cairo Language Server" -msgstr "#### Servidor de Lenguaje de Cairo" +msgid "#### Cairo Language Server without Scarb" +msgstr "#### Servidor de Lenguaje con Scarb" #: src/ch01-01-installation.md:194 -msgid "From [Step 1](#step-1-install-cairo-10-guide-by-abdel), the `cairo-language-server` binary should be built and executing this command will copy its path into your clipboard." -msgstr "Desde [Paso 1](#step-1-install-cairo-10-guide-by-abdel), el binario `cairo-language-server` debe ser construido y ejecutando este comando se copiará su ruta en el portapapeles." +msgid "" +"If you don't want to depend on Scarb, you can still use the Cairo Language Server with the compiler binary.\n" +"From [Step 1](#installing-cairo-with-a-script-installer-by-fran), the `cairo-language-server` binary should be built and executing this command will copy its path into your clipboard." +msgstr "" +"Si no deseas depender de Scarb, aún puedes usar el Cairo Language Server con el binario del compilador.\n" +"A partir del [Paso 1](#installing-cairo-with-a-script-installer-by-fran), el binario `cairo-language-server` debería haber sido construido y ejecutar este comando copiará su ruta en " +"tu portapapeles." -#: src/ch01-01-installation.md:196 +#: src/ch01-01-installation.md:197 msgid "" "```bash\n" "which cairo-language-server | pbcopy\n" @@ -817,9 +838,9 @@ msgstr "" "which cairo-language-server | pbcopy\n" "```" -#: src/ch01-01-installation.md:200 -msgid "Update the `languageServerPath` of the Cairo 1.0 extension by pasting the path." -msgstr "Actualiza el `languageServerPath` de la extensión Cairo 1.0 pegando la ruta." +#: src/ch01-01-installation.md:201 +msgid "Update the `cairo1.languageServerPath` of the Cairo 1.0 extension by pasting the path." +msgstr "Actualiza la `cairo1.languageServerPath` de la extensión Cairo 1.0 pegando la ruta." #: src/ch01-02-hello-world.md:1 msgid "## Hello, World" @@ -842,15 +863,15 @@ msgid "" "> if you prefer to use an integrated development environment (IDE) instead of\n" "> the command line, feel free to use your favorite IDE. The Cairo team has developed\n" "> a VSCode extension for the Cairo language that you can use to get the features from\n" -"> the language server and code highlighting. See [Appendix B][devtools]\n" +"> the language server and code highlighting. See [Appendix D][devtools]\n" "> for more details." msgstr "" "> Nota: Este libro asume una familiaridad básica con la línea de comandos. Cairo no hace\n" "> ninguna demanda específica sobre su edición o herramientas o donde vive su código, así que\n" -"> si prefiere usar un entorno de desarrollo integrado (IDE) en lugar de la línea de comandos, > siéntase libre de hacerlo.\n" +"si prefiere usar un entorno de desarrollo integrado (IDE) en lugar de la línea de comandos, > siéntase libre de usar su IDE favorito.\n" "> la línea de comandos, siéntase libre de usar su IDE favorito. El equipo de Cairo ha desarrollado\n" "> una extensión VSCode para el lenguaje Cairo que puedes usar para obtener las características de\n" -"> el servidor de lenguajes y el resaltado de código. Ver [Apéndice A][devtools]\n" +"> el servidor de lenguajes y el resaltado de código. Ver [Apéndice D][devtools]\n" "> para más detalles." #: src/ch01-02-hello-world.md:15 @@ -1013,13 +1034,13 @@ msgstr "" #: src/ch01-02-hello-world.md:83 msgid "" -"```rust\n" +"```rust,ignore_format\n" "fn main() {\n" "\n" "}\n" "```" msgstr "" -"```rust\n" +"```rust,ignore_format\n" "fn main() {\n" "\n" "}\n" @@ -1052,14 +1073,14 @@ msgid "" "> Note: If you want to stick to a standard style across Cairo projects, you can\n" "> use the automatic formatter tool called `cairo-format` to format your code in a\n" "> particular style (more on `cairo-format` in\n" -"> [Appendix B][devtools]). The Cairo team has included this tool\n" +"> [Appendix D][devtools]). The Cairo team has included this tool\n" "> with the standard Cairo distribution, as `cairo-run` is, so it should already be\n" "> installed on your computer!" msgstr "" -"> Nota: Si quieres mantener un estilo estándar en todos los proyectos de Cairo, puedes\n" -"> usar la herramienta de formateo automático llamada `cairo-format` para formatear tu código \n" -"> en un estilo particular (más sobre `cairo-format` en\n" -"> [Apéndice A][devtools]). El equipo de Cairo ha incluido esta herramienta\n" +"> Nota: Si quieres mantener un estilo estándar en todos los proyectos de El Cairo, puedes\n" +"> usar la herramienta de formateo automático llamada `cairo-format` para formatear tu código en un\n" +"> estilo particular (más sobre `cairo-format` en\n" +"> [Apéndice D][devtools]). El equipo de Cairo ha incluido esta herramienta\n" "> con la distribución estándar de Cairo, como lo es `cairo-run`, así que ya debería estar\n" "> ¡instalada en tu ordenador!" @@ -1147,10 +1168,11 @@ msgstr "Scarb es el gestor de paquetes de Cairo y está fuertemente inspirado en #: src/ch01-03-hello-scarb.md:5 msgid "" -"Scarb handles a lot of tasks for you, such as building your code (either pure Cairo or Starknet contracts), downloading the libraries your code depends on, and building those " -"libraries." +"Scarb handles a lot of tasks for you, such as building your code (either pure Cairo or Starknet contracts), downloading the libraries your code depends on, building those libraries, " +"and provides LSP support for the VSCode Cairo 1 extension." msgstr "" -"Scarb maneja muchas tareas por ti, como construir tu código (ya sea Cairo puro o contratos Starknet), descargar las librerías de las que depende tu código, y construir esas librerías." +"Scarb se encarga de muchas tareas por ti, como construir tu código (ya sea en Cairo puro o contratos Starknet), descargar las bibliotecas en las que tu código depende, construir esas " +"bibliotecas y proporcionar soporte LSP (Language Server Protocol) para la extensión de Cairo 1 en VSCode." #: src/ch01-03-hello-scarb.md:7 msgid "" @@ -1182,58 +1204,54 @@ msgid "### Installation" msgstr "### Instalación" #: src/ch01-03-hello-scarb.md:19 -msgid "As for now, Scarb needs manual installation with the following steps:" -msgstr "Por ahora, Scarb necesita instalación manual con los siguientes pasos:" +msgid "" +"To install Scarb, please refer to the [installation instructions](https://docs.swmansion.com/scarb/download.html).\n" +"You can simply run the following command in your terminal, then follow the onscreen instructions. This will install the latest stable release." +msgstr "" +"Para instalar Scarb, por favor consulta las [instrucciones de instalación](https://docs.swmansion.com/scarb/docs/install.html).\n" +"Simplemente ejecuta el siguiente comando en tu terminal y sigue las instrucciones en pantalla. Esto instalará la última versión estable." -#: src/ch01-03-hello-scarb.md:21 +#: src/ch01-03-hello-scarb.md:22 +msgid "" +"```bash\n" +"curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | sh\n" +"```" +msgstr "" +"```bash\n" +"curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | sh\n" +"```" + +#: src/ch01-03-hello-scarb.md:26 msgid "" -"- Download the release archive matching your operating system and CPU architecture, from [Scarb releases on GitHub](https://github.com/software-mansion/scarb/releases)\n" -"- Extract it to a location where you would like to have Scarb installed, e.g. `~/scarb`\n" -"- Add path to the `scarb/bin` directory to your `PATH` environment variable.\n" -"\n" -" This depend on what shell you are using. Let’s take the example of [zsh](https://ohmyz.sh/) and you have extracted Scarb to `~/scarb`:\n" -"\n" -" - Open `~/.zshrc` file in your favorite editor\n" -" - Add the following line to the end of the file: `export PATH=\"$PATH:~/scarb/bin\"`\n" -"\n" "- Verify installation by running the following command in new terminal session, it should print both Scarb and Cairo language versions, e.g:\n" "\n" " ```bash\n" " $ scarb --version\n" -" scarb 0.1.0 (289137c24 2023-03-28)\n" -" cairo: 1.0.0-alpha.6\n" +" scarb 0.4.0 (f813517bf 2023-06-06)\n" +" cairo: 1.1.0 (43b83560d)\n" " ```" msgstr "" -"- Descargue el archivo de versiones correspondiente a su sistema operativo y arquitectura de CPU desde [Scarb releases on GitHub](https://github.com/software-mansion/scarb/releases)\n" -"- Extráigalo a una ubicación en la que desee tener Scarb instalado, por ejemplo. `~/scarb`\n" -"- Añada la ruta al directorio `scarb/bin` a su variable de entorno `PATH`.\n" -"\n" -" Esto depende del shell que esté utilizando. Tomemos el ejemplo de [zsh](https://ohmyz.sh/) y has extraido Scarb a `~/scarb`:\n" -"\n" -" - Abra el archivo `~/.zshrc` en su editor favorito\n" -" - Añada la siguiente línea al final del archivo: `export PATH=\"$PATH:~/scarb/bin\"`\n" -"\n" -"- Verifique la instalación ejecutando el siguiente comando en una nueva sesión de terminal, debería imprimir las versiones en Scarb y Cairo, por ejemplo:\n" +"- Verify installation by running the following command in new terminal session, it should print both Scarb and Cairo language versions, e.g:\n" "\n" " ```bash\n" " $ scarb --version\n" -" scarb 0.1.0 (289137c24 2023-03-28)\n" -" cairo: 1.0.0-alpha.6\n" +" scarb 0.4.0 (f813517bf 2023-06-06)\n" +" cairo: 1.1.0 (43b83560d)\n" " ```" -#: src/ch01-03-hello-scarb.md:38 +#: src/ch01-03-hello-scarb.md:34 msgid "### Creating a Project with Scarb" msgstr "### Creando un Proyecto con Scarb" -#: src/ch01-03-hello-scarb.md:40 +#: src/ch01-03-hello-scarb.md:36 msgid "Let’s create a new project using Scarb and look at how it differs from our original “Hello, world!” project." msgstr "Vamos a crear un nuevo proyecto utilizando Scarb y ver en qué se diferencia de nuestro proyecto original “Hello, world!”." -#: src/ch01-03-hello-scarb.md:42 +#: src/ch01-03-hello-scarb.md:38 msgid "Navigate back to your projects directory (or wherever you decided to store your code). Then run the following:" msgstr "Navegue de nuevo a su directorio de proyectos (o donde haya decidido almacenar su código). Luego ejecute lo siguiente:" -#: src/ch01-03-hello-scarb.md:44 +#: src/ch01-03-hello-scarb.md:40 msgid "" "```bash\n" "$ scarb new hello_scarb\n" @@ -1243,11 +1261,11 @@ msgstr "" "$ scarb new hello_scarb\n" "```" -#: src/ch01-03-hello-scarb.md:48 +#: src/ch01-03-hello-scarb.md:44 msgid "It creates a new directory and project called hello_scarb. We’ve named our project hello_scarb, and Scarb creates its files in a directory of the same name." msgstr "Crea un nuevo directorio y proyecto llamado hello_scarb. Hemos llamado a nuestro proyecto hello_scarb, y Scarb crea sus archivos en un directorio con el mismo nombre." -#: src/ch01-03-hello-scarb.md:50 +#: src/ch01-03-hello-scarb.md:46 msgid "" "Go into the hello_scarb directory with the command `cd hello_scarb`. You’ll see that Scarb has generated two files and one directory for us: a `Scarb.toml` file and a src directory " "with a `lib.cairo` file inside." @@ -1255,11 +1273,11 @@ msgstr "" "Entre en el directorio hello_scarb con el comando `cd hello_scarb`.Verás que Scarb ha generado dos archivos y un directorio para nosotros: un archivo `Scarb.toml` y un directorio src " "con un archivo `lib.cairo` dentro." -#: src/ch01-03-hello-scarb.md:52 +#: src/ch01-03-hello-scarb.md:48 msgid "It has also initialized a new Git repository along with a `.gitignore` file" msgstr "También ha inicializado un nuevo repositorio Git junto con un archivo `.gitignore`" -#: src/ch01-03-hello-scarb.md:54 +#: src/ch01-03-hello-scarb.md:50 msgid "" "> Note: Git is a common version control system. You can stop using version control system by using the `--vcs` flag.\n" "> Run `scarb new -help` to see the available options." @@ -1268,22 +1286,22 @@ msgstr "" "> usando la bandera `--vcs`.\n" "> Ejecute `scarb new -help` para ver las opciones disponibles." -#: src/ch01-03-hello-scarb.md:57 +#: src/ch01-03-hello-scarb.md:53 msgid "Open _Scarb.toml_ in your text editor of choice. It should look similar to the code in Listing 1-2." msgstr "Abra _Scarb.toml_ en su editor de texto preferido. Debería parecerse al código del Listado 1-2." -#: src/ch01-03-hello-scarb.md:59 +#: src/ch01-03-hello-scarb.md:55 msgid "Filename: Scarb.toml" msgstr "Filename: Scarb.toml" -#: src/ch01-03-hello-scarb.md:61 +#: src/ch01-03-hello-scarb.md:57 msgid "" "```toml\n" "[package]\n" "name = \"hello_scarb\"\n" "version = \"0.1.0\"\n" "\n" -"# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest\n" +"# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html\n" "\n" "[dependencies]\n" "# foo = { path = \"vendor/foo\" }\n" @@ -1294,21 +1312,21 @@ msgstr "" "name = \"hello_scarb\"\n" "version = \"0.1.0\"\n" "\n" -"# Vea más claves y sus definiciones en https://docs.swmansion.com/scarb/docs/reference/manifest\n" +"# Vea más claves y sus definiciones en https://docs.swmansion.com/scarb/docs/reference/manifest.html\n" "\n" "[dependencies]\n" "# foo = { path = \"vendor/foo\" }\n" "```" -#: src/ch01-03-hello-scarb.md:72 +#: src/ch01-03-hello-scarb.md:68 msgid "Listing 1-2: Contents of Scarb.toml generated by `scarb new`" msgstr "Listing 1-2: Contents of Scarb.toml generated by `scarb new`" -#: src/ch01-03-hello-scarb.md:74 +#: src/ch01-03-hello-scarb.md:70 msgid "This file is in the [TOML](https://toml.io/) (Tom’s Obvious, Minimal Language) format, which is Scarb’s configuration format." msgstr "Este archivo se encuentra en formato [TOML](https://toml.io/) (Tom’s Obvious, Minimal Language), que es el formato de configuración de Scarb." -#: src/ch01-03-hello-scarb.md:76 +#: src/ch01-03-hello-scarb.md:72 msgid "" "The first line, `[package]`, is a section heading that indicates that the following statements are configuring a package. As we add more information to this file, we’ll add other " "sections." @@ -1316,11 +1334,11 @@ msgstr "" "La primera línea, `[package]`, es un encabezado de sección que indica que las siguientes sentencias están configurando un paquete. A medida que agreguemos más información a este " "archivo, agregaremos otras secciones." -#: src/ch01-03-hello-scarb.md:78 +#: src/ch01-03-hello-scarb.md:74 msgid "The next two lines set the configuration information Scarb needs to compile your program: the name and the version of Scarb to use." msgstr "Las siguientes dos líneas establecen la información de configuración que Scarb necesita para compilar su programa: el nombre y la versión de Scarb a utilizar." -#: src/ch01-03-hello-scarb.md:80 +#: src/ch01-03-hello-scarb.md:76 msgid "" "The last line, `[dependencies]`, is the start of a section for you to list any of your project’s dependencies. In Cairo, packages of code are referred to as crates. We won’t need any " "other crates for this project." @@ -1328,11 +1346,19 @@ msgstr "" "La última línea, `[dependencies]`, es el comienzo de una sección para que puedas listar cualquiera de las dependencias de tu proyecto. En Cairo, los paquetes de código se conocen " "como crates. No necesitaremos ninguna otra crate para este proyecto." -#: src/ch01-03-hello-scarb.md:82 +#: src/ch01-03-hello-scarb.md:78 +msgid "" +"> Note: If you're building contracts for Starknet, you will need to add the `starknet` dependency as mentioned in the [Scarb documentation](https://docs.swmansion.com/scarb/docs/" +"starknet/starknet-package.html)." +msgstr "" +"> Nota: Si estás construyendo contratos para Starknet, deberás agregar la dependencia `starknet` como se menciona en la [documentación de Scarb](https://docs.swmansion.com/scarb/docs/" +"starknet/starknet-package.html)." + +#: src/ch01-03-hello-scarb.md:80 msgid "The other file created by Scarb is `src/lib.cairo`, let's delete all the content and put in the following content, we will explain the reason later." msgstr "El otro archivo creado por Scarb es `src/lib.cairo`, borremos todo el contenido y pongamos el siguiente contenido, explicaremos la razón más adelante." -#: src/ch01-03-hello-scarb.md:84 +#: src/ch01-03-hello-scarb.md:82 msgid "" "```rust\n" "mod hello_scarb;\n" @@ -1342,15 +1368,15 @@ msgstr "" "mod hello_scarb;\n" "```" -#: src/ch01-03-hello-scarb.md:88 +#: src/ch01-03-hello-scarb.md:86 msgid "Then create a new file called `src/hello_scarb.cairo` and put the following code in it:" msgstr "A continuación, cree un nuevo archivo llamado `src/hello_scarb.cairo` y ponle el siguiente código:" -#: src/ch01-03-hello-scarb.md:90 +#: src/ch01-03-hello-scarb.md:88 msgid "Filename: src/hello_scarb.cairo" msgstr "Filename: src/hello_scarb.cairo" -#: src/ch01-03-hello-scarb.md:92 +#: src/ch01-03-hello-scarb.md:90 msgid "" "```rust,file=hello_scarb.cairo\n" "use debug::PrintTrait;\n" @@ -1366,19 +1392,19 @@ msgstr "" "}\n" "```" -#: src/ch01-03-hello-scarb.md:99 +#: src/ch01-03-hello-scarb.md:97 msgid "" -"We have just created a file called `lib.cairo`, which contains a module declaration referencing another module named \"hello_scarb\", as well as the file `hello_scarb.cairo`," +"We have just created a file called `lib.cairo`, which contains a module declaration referencing another module named \"hello_scarb\", as well as the file `hello_scarb.cairo`, " "containing the implementation details of the \"hello_scarb\" module." msgstr "" "Acabamos de crear un archivo llamado `lib.cairo`, que contiene una declaración de módulo que hace referencia a otro módulo llamado \"hello_scarb\", así como el archivo `hello_scarb." "cairo`, que contiene los detalles de implementación del módulo \"hello_scarb\"." -#: src/ch01-03-hello-scarb.md:101 +#: src/ch01-03-hello-scarb.md:99 msgid "Scarb requires your source files to be located within the src directory." msgstr "Scarb requiere que sus archivos fuente se encuentren dentro del directorio src." -#: src/ch01-03-hello-scarb.md:103 +#: src/ch01-03-hello-scarb.md:101 msgid "" "The top-level project directory is reserved for README files, license information, configuration files, and any other non-code-related content.\n" "Scarb ensures a designated location for all project components, maintaining a structured organization." @@ -1387,7 +1413,7 @@ msgstr "" "otro contenido no relacionado con el código.\n" "Scarb asegura una ubicación designada para todos los componentes del proyecto, manteniendo una organización estructurada." -#: src/ch01-03-hello-scarb.md:106 +#: src/ch01-03-hello-scarb.md:104 msgid "" "If you started a project that doesn’t use Scarb, as we did with the “Hello, world!” project, you can convert it to a project that does use Scarb. Move the project code into the src " "directory and create an appropriate `Scarb.toml` file." @@ -1395,15 +1421,15 @@ msgstr "" "Si ha iniciado un proyecto que no utiliza Scarb, como hicimos con el proyecto “Hello, world!”, puede convertirlo en un proyecto que utilice Scarb. Mueva el código del proyecto al " "directorio src y cree un archivo `Scarb.toml` apropiado." -#: src/ch01-03-hello-scarb.md:108 +#: src/ch01-03-hello-scarb.md:106 msgid "### Building a Scarb Project" msgstr "### Creación de un proyecto Scarb" -#: src/ch01-03-hello-scarb.md:110 +#: src/ch01-03-hello-scarb.md:108 msgid "From your hello_scarb directory, build your project by entering the following command:" msgstr "Desde su directorio hello_scarb, construya su proyecto introduciendo el siguiente comando:" -#: src/ch01-03-hello-scarb.md:112 +#: src/ch01-03-hello-scarb.md:110 msgid "" "```bash\n" "$ scarb build\n" @@ -1417,15 +1443,15 @@ msgstr "" " Finished release target(s) in 0 seconds\n" "```" -#: src/ch01-03-hello-scarb.md:118 +#: src/ch01-03-hello-scarb.md:116 msgid "This command creates a `sierra` file in `target/release`, let's ignore the `sierra` file for now." msgstr "Este comando crea un archivo `sierra` en `target/release`, ignoremos el archivo `sierra` por ahora." -#: src/ch01-03-hello-scarb.md:120 +#: src/ch01-03-hello-scarb.md:118 msgid "If you have installed Cairo correctly, you should be able to run and see the following output:" msgstr "Si has instalado Cairo correctamente, deberías ser capaz de ejecutarlo y ver la siguiente salida:" -#: src/ch01-03-hello-scarb.md:122 +#: src/ch01-03-hello-scarb.md:120 msgid "" "```bash\n" "$ cairo-run src/lib.cairo\n" @@ -1441,7 +1467,7 @@ msgstr "" "Run completed successfully, returning []\n" "```" -#: src/ch01-03-hello-scarb.md:129 +#: src/ch01-03-hello-scarb.md:127 msgid "" "> Note: You will notice here that we didn't use a Scarb command, but rather a command from the Cairo binaries directly.\n" "> As Scarb doesn't have a command to execute Cairo code yet, we have to use the `cairo-run` command directly.\n" @@ -1451,11 +1477,11 @@ msgstr "" "> Como Scarb no tiene un comando para ejecutar código de Cairo, tenemos que usar el comando `cairo-run` directamente.\n" "> Usaremos este comando en el resto del tutorial, pero también usaremos comandos de Scarb para inicializar proyectos." -#: src/ch01-03-hello-scarb.md:133 +#: src/ch01-03-hello-scarb.md:131 msgid "### Defining Custom Scripts" msgstr "### Definición de scripts personalizados" -#: src/ch01-03-hello-scarb.md:135 +#: src/ch01-03-hello-scarb.md:133 msgid "" "We can define Scarb scripts in `Scarb.toml` file, which can be used to execute custom shell scripts.\n" "Add the following line to your `Scarb.toml` file:" @@ -1463,7 +1489,7 @@ msgstr "" "Podemos definir scripts scarb en el archivo `Scarb.toml`, que puede ser usado para ejecutar scripts shell personalizados.\n" "Añada la siguiente línea a su fichero `Scarb.toml`:" -#: src/ch01-03-hello-scarb.md:138 +#: src/ch01-03-hello-scarb.md:136 msgid "" "```toml\n" "[scripts]\n" @@ -1475,11 +1501,11 @@ msgstr "" "run-lib = \"cairo-run src/lib.cairo\"\n" "```" -#: src/ch01-03-hello-scarb.md:143 +#: src/ch01-03-hello-scarb.md:141 msgid "Now you can run the following command to run the project:" msgstr "Ahora puede ejecutar el siguiente comando para ejecutar el proyecto:" -#: src/ch01-03-hello-scarb.md:145 +#: src/ch01-03-hello-scarb.md:143 msgid "" "```bash\n" "$ scarb run run-lib\n" @@ -1495,15 +1521,15 @@ msgstr "" "Run completed successfully, returning []\n" "```" -#: src/ch01-03-hello-scarb.md:152 +#: src/ch01-03-hello-scarb.md:150 msgid "Using `scarb run` is a convenient way to run custom shell scripts that can be useful to run files and test your project." msgstr "Usar `scarb run` es una forma conveniente de ejecutar scripts de shell personalizados que pueden ser útiles para ejecutar archivos y probar su proyecto." -#: src/ch01-03-hello-scarb.md:154 +#: src/ch01-03-hello-scarb.md:152 msgid "Let’s recap what we’ve learned so far about Scarb:" msgstr "Recapitulemos lo que hemos aprendido hasta ahora sobre Scarb:" -#: src/ch01-03-hello-scarb.md:156 +#: src/ch01-03-hello-scarb.md:154 msgid "" "- We can create a project using `scarb new`.\n" "- We can build a project using `scarb build` to generate the compiled Sierra code.\n" @@ -1513,7 +1539,7 @@ msgstr "" "- Podemos construir un proyecto usando `scarb build` para generar el código Sierra compilado.\n" "- Podemos definir scripts personalizados en `Scarb.toml` y llamarlos con el comando `scarb run`." -#: src/ch01-03-hello-scarb.md:160 +#: src/ch01-03-hello-scarb.md:158 msgid "" "An additional advantage of using Scarb is that the commands are the same no matter which operating system you’re working on. So, at this point, we’ll no longer provide specific " "instructions for Linux and macOS versus Windows." @@ -1521,15 +1547,15 @@ msgstr "" "Una ventaja adicional de usar Scarb es que los comandos son los mismos sin importar el sistema operativo en el que estemos trabajando. Así que, en este punto, ya no proporcionaremos " "instrucciones específicas para Linux y macOS frente a Windows." -#: src/ch01-03-hello-scarb.md:162 +#: src/ch01-03-hello-scarb.md:160 msgid "# Summary" msgstr "# Resumen" -#: src/ch01-03-hello-scarb.md:164 +#: src/ch01-03-hello-scarb.md:162 msgid "You’re already off to a great start on your Cairo journey! In this chapter, you’ve learned how to:" msgstr "Ya has empezado con buen pie tu viaje en Cairo. En este capítulo, has aprendido cómo:" -#: src/ch01-03-hello-scarb.md:166 +#: src/ch01-03-hello-scarb.md:164 msgid "" "- Install the latest stable version of Cairo\n" "- Write and run a “Hello, world!” program using `cairo-run` directly\n" @@ -1539,7 +1565,7 @@ msgstr "" "- Escribir y ejecutar un programa \" Hello, world!\" usando `cairo-run` directamente\n" "- Crear y ejecutar un nuevo proyecto usando las convenciones de Scarb" -#: src/ch01-03-hello-scarb.md:170 +#: src/ch01-03-hello-scarb.md:168 msgid "This is a great time to build a more substantial program to get used to reading and writing Cairo code." msgstr "Este es un buen momento para construir un programa más sustancial para acostumbrarte a leer y escribir código de Cairo." @@ -1602,16 +1628,16 @@ msgstr "" "A continuación, en su nuevo directorio _variables_, abra _src/lib.cairo_ y sustituya \n" "su código por el siguiente, que todavía no compilará:" -#: src/ch02-01-variables-and-mutability.md:17 src/ch02-01-variables-and-mutability.md:76 src/ch02-01-variables-and-mutability.md:154 src/ch02-05-control-flow.md:130 -#: src/ch03-02-references-and-snapshots.md:23 src/ch03-02-references-and-snapshots.md:111 src/ch04-02-an-example-program-using-structs.md:7 -#: src/ch04-02-an-example-program-using-structs.md:48 src/ch04-02-an-example-program-using-structs.md:74 src/ch04-02-an-example-program-using-structs.md:106 -#: src/ch04-02-an-example-program-using-structs.md:142 src/ch04-03-method-syntax.md:18 src/ch04-03-method-syntax.md:93 src/ch04-03-method-syntax.md:135 src/ch04-03-method-syntax.md:192 -#: src/ch04-03-method-syntax.md:231 src/ch06-02-defining-modules-to-control-scope.md:90 src/ch06-02-defining-modules-to-control-scope.md:144 +#: src/ch02-01-variables-and-mutability.md:17 src/ch02-01-variables-and-mutability.md:77 src/ch02-01-variables-and-mutability.md:155 src/ch02-05-control-flow.md:130 +#: src/ch03-02-references-and-snapshots.md:23 src/ch03-02-references-and-snapshots.md:130 src/ch04-02-an-example-program-using-structs.md:7 +#: src/ch04-02-an-example-program-using-structs.md:48 src/ch04-02-an-example-program-using-structs.md:74 src/ch04-02-an-example-program-using-structs.md:103 +#: src/ch04-02-an-example-program-using-structs.md:136 src/ch04-03-method-syntax.md:18 src/ch04-03-method-syntax.md:93 src/ch04-03-method-syntax.md:135 src/ch04-03-method-syntax.md:192 +#: src/ch04-03-method-syntax.md:231 src/ch06-02-defining-modules-to-control-scope.md:90 src/ch06-02-defining-modules-to-control-scope.md:143 #: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:15 src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:62 -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:10 src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:35 -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:74 src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:131 -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:156 src/ch06-05-separating-modules-into-different-files.md:18 src/ch08-01-how-to-write-tests.md:426 -#: src/ch08-01-how-to-write-tests.md:464 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:10 src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:36 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:76 src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:132 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:206 src/ch06-05-separating-modules-into-different-files.md:18 src/ch08-01-how-to-write-tests.md:512 +#: src/ch08-01-how-to-write-tests.md:550 msgid "Filename: src/lib.cairo" msgstr "Filename: src/lib.cairo" @@ -1625,6 +1651,7 @@ msgid "" " x = 6;\n" " x.print();\n" "}\n" +"\n" "```" msgstr "" "```rust,does_not_compile\n" @@ -1635,9 +1662,10 @@ msgstr "" " x = 6;\n" " x.print();\n" "}\n" +"\n" "```" -#: src/ch02-01-variables-and-mutability.md:29 +#: src/ch02-01-variables-and-mutability.md:30 msgid "" "Save and run the program using `cairo-run src/lib.cairo`. You should receive an error message\n" "regarding an immutability error, as shown in this output:" @@ -1645,7 +1673,7 @@ msgstr "" "Guarde y ejecute el programa utilizando `cairo-run src/lib.cairo`. Debería recibir un mensaje \n" "de error relativo a un error de inmutabilidad, como se muestra en esta salida:" -#: src/ch02-01-variables-and-mutability.md:32 +#: src/ch02-01-variables-and-mutability.md:33 msgid "" "```console\n" "error: Cannot assign to an immutable variable.\n" @@ -1665,7 +1693,7 @@ msgstr "" "Error: failed to compile: src/lib.cairo\n" "```" -#: src/ch02-01-variables-and-mutability.md:41 +#: src/ch02-01-variables-and-mutability.md:42 msgid "" "This example shows how the compiler helps you find errors in your programs.\n" "Compiler errors can be frustrating, but really they only mean your program\n" @@ -1678,7 +1706,7 @@ msgstr "" "quiere que haga; ¡no significan que usted no sea un buen programador! Los Caironautas \n" "experimentados siguen teniendo errores de compilador." -#: src/ch02-01-variables-and-mutability.md:46 +#: src/ch02-01-variables-and-mutability.md:47 msgid "" "You received the error message `Cannot assign to an immutable variable.`\n" "because you tried to assign a second value to the immutable `x` variable." @@ -1686,7 +1714,7 @@ msgstr "" "Recibiste el mensaje de error `Cannot assign to an immutable variable.` porque \n" "intentaste asignar un segundo valor a la variable inmutable `x`." -#: src/ch02-01-variables-and-mutability.md:49 +#: src/ch02-01-variables-and-mutability.md:50 msgid "" "It’s important that we get compile-time errors when we attempt to change a\n" "value that’s designated as immutable because this specific situation can lead to\n" @@ -1709,7 +1737,7 @@ msgstr "" "cuando dices que un valor no cambiará, realmente no cambiará, por lo que no tiene que hacer \n" "un seguimiento. Su código es así más fácil de razonar." -#: src/ch02-01-variables-and-mutability.md:60 +#: src/ch02-01-variables-and-mutability.md:61 msgid "" "But mutability can be very useful, and can make code more convenient to write.\n" "Although variables are immutable by default, you can make them mutable by\n" @@ -1723,7 +1751,7 @@ msgstr "" "intención a los futuros lectores del código indicando que otras partes del código \n" "cambiarán el valor de esta variable." -#: src/ch02-01-variables-and-mutability.md:66 +#: src/ch02-01-variables-and-mutability.md:67 msgid "" "However, you might be wondering at this point what exactly happens when a variable\n" "is declared as `mut`, as we previously mentioned that Cairo's memory is immutable.\n" @@ -1743,11 +1771,11 @@ msgstr "" "de variables. La única diferencia es que en el nivel la variable no se vuelve a declarar, por lo \n" "que su tipo no puede cambiar." -#: src/ch02-01-variables-and-mutability.md:74 +#: src/ch02-01-variables-and-mutability.md:75 msgid "For example, let’s change _src/lib.cairo_ to the following:" msgstr "Por ejemplo, cambiemos _src/lib.cairo_ por lo siguiente:" -#: src/ch02-01-variables-and-mutability.md:78 +#: src/ch02-01-variables-and-mutability.md:79 msgid "" "```rust\n" "use debug::PrintTrait;\n" @@ -1769,11 +1797,11 @@ msgstr "" "}\n" "```" -#: src/ch02-01-variables-and-mutability.md:88 +#: src/ch02-01-variables-and-mutability.md:89 msgid "When we run the program now, we get this:" msgstr "Cuando ejecutamos el programa ahora, obtenemos esto:" -#: src/ch02-01-variables-and-mutability.md:90 +#: src/ch02-01-variables-and-mutability.md:91 msgid "" "```console\n" "❯ cairo-run src/lib.cairo\n" @@ -1793,7 +1821,7 @@ msgstr "" "Run completed successfully, returning []\n" "```" -#: src/ch02-01-variables-and-mutability.md:99 +#: src/ch02-01-variables-and-mutability.md:100 msgid "" "We’re allowed to change the value bound to `x` from `5` to `6` when `mut` is\n" "used. Ultimately, deciding whether to use mutability or not is up to you and\n" @@ -1803,11 +1831,11 @@ msgstr "" "En última instancia, la decisión de utilizar la mutabilidad o no es suya y depende \n" "de lo que usted piensa que es más claro en esa situación particular." -#: src/ch02-01-variables-and-mutability.md:103 +#: src/ch02-01-variables-and-mutability.md:104 msgid "### Constants" msgstr "##### Constantes" -#: src/ch02-01-variables-and-mutability.md:105 +#: src/ch02-01-variables-and-mutability.md:106 msgid "" "Like immutable variables, _constants_ are values that are bound to a name and\n" "are not allowed to change, but there are a few differences between constants\n" @@ -1817,7 +1845,7 @@ msgstr "" " vinculados a un nombre y no se les permite cambiar, pero hay algunas diferencias \n" "entre las constantes y las variables." -#: src/ch02-01-variables-and-mutability.md:109 +#: src/ch02-01-variables-and-mutability.md:110 msgid "" "First, you aren’t allowed to use `mut` with constants. Constants aren’t just\n" "immutable by default—they’re always immutable. You declare constants using the\n" @@ -1833,7 +1861,7 @@ msgstr "" " sección, [“Tipos de datos”][tipos-de-datos], así que no se preocupe por los \n" "detalles por ahora. Solo sepa que siempre debe anotar el tipo." -#: src/ch02-01-variables-and-mutability.md:116 +#: src/ch02-01-variables-and-mutability.md:117 msgid "" "Constants can only be declared in the global scope, which makes\n" "them useful for values that many parts of code need to know about." @@ -1841,7 +1869,7 @@ msgstr "" "Las constantes solo se pueden declarar en el ámbito global, lo que las hace \n" "útiles para valores que muchas partes del código deben conocer." -#: src/ch02-01-variables-and-mutability.md:119 +#: src/ch02-01-variables-and-mutability.md:120 msgid "" "The last difference is that constants may be set only to a constant expression,\n" "not the result of a value that could only be computed at runtime. Only literal constants\n" @@ -1851,21 +1879,21 @@ msgstr "" "constante, no al resultado de un valor que solo se podría calcular en tiempo de ejecución. \n" "Actualmente, solo se admiten constantes literales." -#: src/ch02-01-variables-and-mutability.md:123 +#: src/ch02-01-variables-and-mutability.md:124 msgid "Here’s an example of a constant declaration:" msgstr "Aquí hay un ejemplo de declaración de constante:" -#: src/ch02-01-variables-and-mutability.md:125 +#: src/ch02-01-variables-and-mutability.md:126 msgid "" "```rust\n" -"const ONE_HOUR_IN_SECONDS: u32 = 3600_u32;\n" +"const ONE_HOUR_IN_SECONDS: u32 = 3600;\n" "```" msgstr "" "```rust\n" -"const ONE_HOUR_IN_SECONDS: u32 = 3600_u32;\n" +"const ONE_HOUR_IN_SECONDS: u32 = 3600;\n" "```" -#: src/ch02-01-variables-and-mutability.md:129 +#: src/ch02-01-variables-and-mutability.md:130 msgid "" "Cairo's naming convention for constants is to use all uppercase with\n" "underscores between words." @@ -1873,7 +1901,7 @@ msgstr "" "La convención de nomenclatura de Cairo para las constantes es usar todas\n" " las mayúsculas con guiones bajos entre palabras." -#: src/ch02-01-variables-and-mutability.md:132 +#: src/ch02-01-variables-and-mutability.md:133 msgid "" "Constants are valid for the entire time a program runs, within the scope in\n" "which they were declared. This property makes constants useful for values in\n" @@ -1887,7 +1915,7 @@ msgstr "" "podrían necesitar conocer, como el número máximo de puntos que cualquier jugador de \n" "un juego puede ganar o la velocidad de la luz." -#: src/ch02-01-variables-and-mutability.md:138 +#: src/ch02-01-variables-and-mutability.md:139 msgid "" "Naming hardcoded values used throughout your program as constants is useful in\n" "conveying the meaning of that value to future maintainers of the code. It also\n" @@ -1899,11 +1927,11 @@ msgstr "" " del código. También ayuda a tener solo un lugar en su código donde tendría que cambiar\n" " si el valor codificado en duro necesitara ser actualizado en el futuro." -#: src/ch02-01-variables-and-mutability.md:143 +#: src/ch02-01-variables-and-mutability.md:144 msgid "### Shadowing" msgstr "### Shadowing" -#: src/ch02-01-variables-and-mutability.md:145 +#: src/ch02-01-variables-and-mutability.md:146 msgid "" "Variable shadowing refers to the declaration of a\n" "new variable with the same name as a previous variable. Caironautes say that the\n" @@ -1923,9 +1951,9 @@ msgstr "" "sombrear una variable usando el mismo nombre de la variable y repitiendo el uso de \n" "la palabra clave `let` de la siguiente manera:" -#: src/ch02-01-variables-and-mutability.md:156 +#: src/ch02-01-variables-and-mutability.md:157 msgid "" -"```swift\n" +"```rust\n" "use debug::PrintTrait;\n" "fn main() {\n" " let x = 5;\n" @@ -1940,7 +1968,7 @@ msgid "" "}\n" "```" msgstr "" -"```swift\n" +"```rust\n" "use debug::PrintTrait;\n" "fn main() {\n" " let x = 5;\n" @@ -1955,7 +1983,7 @@ msgstr "" "}\n" "```" -#: src/ch02-01-variables-and-mutability.md:171 +#: src/ch02-01-variables-and-mutability.md:172 msgid "" "This program first binds `x` to a value of `5`. Then it creates a new variable\n" "`x` by repeating `let x =`, taking the original value and adding `1` so the\n" @@ -1973,7 +2001,7 @@ msgstr "" "un valor de `12`. Cuando ese ámbito termina, la sombra interna termina y `x`\n" " vuelve a ser `6`. Al ejecutar este programa, se mostrará lo siguiente:" -#: src/ch02-01-variables-and-mutability.md:179 +#: src/ch02-01-variables-and-mutability.md:180 msgid "" "```console\n" "cairo-run src/lib.cairo\n" @@ -2003,7 +2031,7 @@ msgstr "" "Run completed successfully, returning []\n" "```" -#: src/ch02-01-variables-and-mutability.md:193 +#: src/ch02-01-variables-and-mutability.md:194 msgid "" "Shadowing is different from marking a variable as `mut` because we’ll get a\n" "compile-time error if we accidentally try to reassign to this variable without\n" @@ -2017,31 +2045,28 @@ msgstr "" "valor pero hacer que la variable sea inmutable después de que se hayan completado \n" "esas transformaciones." -#: src/ch02-01-variables-and-mutability.md:199 +#: src/ch02-01-variables-and-mutability.md:200 msgid "" "Another distinction between `mut` and shadowing is that when we use the `let` keyword again,\n" "we are effectively creating a new variable, which allows us to change the type of the\n" "value while reusing the same name. As mentioned before, variable shadowing and mutable variables\n" "are equivalent at the lower level.\n" -"The only difference is that by shadowing a variable, the compiler will not complain \n" +"The only difference is that by shadowing a variable, the compiler will not complain\n" "if you change its type. For example, say our program performs a type conversion between the\n" "`u64` and `felt252` types." msgstr "" -"Otra distinción entre `mut` y shadowing es que cuando usamos de nuevo la palabra clave `let\n" -"estamos creando una nueva variable, lo que nos permite cambiar el tipo del valor\n" -"reutilizando el mismo nombre. Como se mencionó antes, la sombra de variables y las variables mutables\n" -"son equivalentes en el nivel inferior.\n" -"La única diferencia es que al sombrear una variable, el compilador no se quejará\n" -"si cambias su tipo. Por ejemplo, digamos que nuestro programa realiza una conversión de tipo entre\n" -"`u64` y `felt252`." +"Otra distinción entre `mut` y el shadowing es que al usar nuevamente la palabra clave `let`, estamos creando efectivamente una nueva variable, lo que nos permite cambiar el tipo del " +"valor mientras reutilizamos el mismo nombre. Como se mencionó anteriormente, el shadowing de variables y las variables mutables son equivalentes a un nivel más bajo. La única " +"diferencia es que al hacer shadowing de una variable, el compilador no mostrará un error si cambias su tipo. Por ejemplo, supongamos que nuestro programa realiza una conversión de " +"tipo entre los tipos `u64` y `felt252`." -#: src/ch02-01-variables-and-mutability.md:207 +#: src/ch02-01-variables-and-mutability.md:208 msgid "" "```rust\n" "use debug::PrintTrait;\n" "use traits::Into;\n" "fn main() {\n" -" let x = 2_u64;\n" +" let x = 2;\n" " x.print();\n" " let x: felt252 = x.into(); // converts x to a felt, type annotation is required.\n" " x.print()\n" @@ -2052,14 +2077,14 @@ msgstr "" "use debug::PrintTrait;\n" "use traits::Into;\n" "fn main() {\n" -" let x = 2_u64;\n" +" let x = 2;\n" " x.print();\n" " let x: felt252 = x.into(); // converts x to a felt, type annotation is required.\n" " x.print()\n" "}\n" "```" -#: src/ch02-01-variables-and-mutability.md:218 +#: src/ch02-01-variables-and-mutability.md:219 msgid "" "The first `x` variable has a `u64` type while the second `x` variable has a `felt252` type.\n" "Shadowing thus spares us from having to come up with different names, such as `x_u64`\n" @@ -2071,13 +2096,13 @@ msgstr "" "en su lugar, podemos reutilizar el nombre más simple `x`. Sin embargo, si intentamos usar `mut` para esto, \n" "como se muestra aquí, obtendremos un error en tiempo de compilación:" -#: src/ch02-01-variables-and-mutability.md:223 +#: src/ch02-01-variables-and-mutability.md:224 msgid "" "```rust,does_not_compile\n" "use debug::PrintTrait;\n" "use traits::Into;\n" "fn main() {\n" -" let mut x = 2_u64;\n" +" let mut x = 2;\n" " x.print();\n" " x = x.into();\n" " x.print()\n" @@ -2088,18 +2113,18 @@ msgstr "" "use debug::PrintTrait;\n" "use traits::Into;\n" "fn main() {\n" -" let mut x = 2_u64;\n" +" let mut x = 2;\n" " x.print();\n" " x = x.into();\n" " x.print()\n" "}\n" "```" -#: src/ch02-01-variables-and-mutability.md:234 -msgid "The error says we’re were expecting a `u64` (the original type) but we got a different type:" -msgstr "El error dice que se esperaba un `u64` (el tipo original) pero se obtuvo un tipo diferente:" +#: src/ch02-01-variables-and-mutability.md:235 +msgid "The error says we were expecting a `u64` (the original type) but we got a different type:" +msgstr "El error indica que se esperaba un `u64` (el tipo original), pero se obtuvo un tipo diferente:" -#: src/ch02-01-variables-and-mutability.md:236 +#: src/ch02-01-variables-and-mutability.md:237 msgid "" "```console\n" "❯ cairo-run src/lib.cairo\n" @@ -2121,7 +2146,7 @@ msgstr "" "Error: failed to compile: src/lib.cairo\n" "```" -#: src/ch02-01-variables-and-mutability.md:246 +#: src/ch02-01-variables-and-mutability.md:247 msgid "" "Now that we’ve explored how variables work, let’s look at more data types they\n" "can have." @@ -2152,21 +2177,21 @@ msgstr "" #: src/ch02-02-data-types.md:10 msgid "" -"```Rust\n" +"```rust\n" "use traits::TryInto;\n" "use option::OptionTrait;\n" -"fn main(){\n" +"fn main() {\n" " let x: felt252 = 3;\n" -" let y:u32 = x.try_into().unwrap();\n" +" let y: u32 = x.try_into().unwrap();\n" "}\n" "```" msgstr "" -"```Rust\n" +"```rust\n" "use traits::TryInto;\n" "use option::OptionTrait;\n" -"fn main(){\n" +"fn main() {\n" " let x: felt252 = 3;\n" -" let y:u32 = x.try_into().unwrap();\n" +" let y: u32 = x.try_into().unwrap();\n" "}\n" "```" @@ -2369,7 +2394,7 @@ msgstr "" msgid "" "```rust\n" "fn main() {\n" -" // addition\n" +" // addition\n" " let sum = 5_u128 + 10_u128;\n" "\n" " // subtraction\n" @@ -2389,7 +2414,7 @@ msgid "" msgstr "" "```rust\n" "fn main() {\n" -" // addition\n" +" // addition\n" " let sum = 5_u128 + 10_u128;\n" "\n" " // subtraction\n" @@ -2416,18 +2441,14 @@ msgstr "" "un único valor, que se asigna a una variable." #: src/ch02-02-data-types.md:120 -msgid "" -"\n" -"" -msgstr "" -"\n" -"" +msgid "[Appendix B][appendix_b] contains a list of all operators that Cairo provides." +msgstr "[Apéndice B][appendix_b] contiene una lista de todos los operadores que Cairo proporciona." -#: src/ch02-02-data-types.md:123 +#: src/ch02-02-data-types.md:122 msgid "#### The Boolean Type" msgstr "#### El tipo Booleano" -#: src/ch02-02-data-types.md:125 +#: src/ch02-02-data-types.md:124 msgid "" "As in most other programming languages, a Boolean type in Cairo has two possible\n" "values: `true` and `false`. Booleans are one felt252 in size. The Boolean type in\n" @@ -2437,7 +2458,7 @@ msgstr "" "dos posibles valores: `true` y `false`. Los booleanos tienen un byte de tamaño. El tipo booleano \n" "en Cairo se especifica usando `bool`. Por ejemplo:" -#: src/ch02-02-data-types.md:129 +#: src/ch02-02-data-types.md:128 msgid "" "```rust\n" "fn main() {\n" @@ -2455,7 +2476,7 @@ msgstr "" "}\n" "```" -#: src/ch02-02-data-types.md:139 +#: src/ch02-02-data-types.md:136 msgid "" "The main way to use Boolean values is through conditionals, such as an `if`\n" "expression. We’ll cover how `if` expressions work in Cairo in the [“Control\n" @@ -2465,11 +2486,11 @@ msgstr "" "como una expresión `if` expresión. Cubriremos cómo funcionan las expresiones `if` \n" "en Cairo en la sección. [“Control de flujo”][control-de-flujo]" -#: src/ch02-02-data-types.md:143 +#: src/ch02-02-data-types.md:140 msgid "#### The Short String Type" msgstr "#### El tipo de Short String" -#: src/ch02-02-data-types.md:145 +#: src/ch02-02-data-types.md:142 msgid "" "Cairo doesn't have a native type for strings, but you can store characters forming what we call a \"short string\" inside `felt252`s. A short string has a max length of 31 chars. " "This is to ensure that it can fit in a single felt (a felt is 252 bits, one ASCII char is 8 bits).\n" @@ -2479,28 +2500,31 @@ msgstr "" "máxima de 31 caracteres. Esto es para asegurar que puede caber en un solo felt (un felt son 252 bits, un char ASCII son 8 bits).\n" "He aquí algunos ejemplos de declaración de valores entre comillas simples:" -#: src/ch02-02-data-types.md:148 +#: src/ch02-02-data-types.md:145 msgid "" "```rust\n" -"let my_first_char = 'C';\n" -"let my_first_string = 'Hello world';\n" +"# fn main() {\n" +" let my_first_char = 'C';\n" +" let my_first_string = 'Hello world';\n" +"# }\n" "```" msgstr "" "```rust\n" -"let my_first_char = 'C';\n" -"let my_first_string = 'Hello world';\n" +"# fn main() {\n" +" let my_first_char = 'C';\n" +" let my_first_string = 'Hello world';\n" +"# }\n" "```" -#: src/ch02-02-data-types.md:153 +#: src/ch02-02-data-types.md:152 msgid "### Type casting" msgstr "### Conversión de Tipos" -#: src/ch02-02-data-types.md:155 -msgid "In Cairo, you can convert values between common scalar types and `felt252` using the `try_into` and `into` methods provided by the `TryInto` and `Into` traits, respectively." -msgstr "" -"En Cairo, puedes convertir valores entre tipos escalares comunes y `felt252` usando los métodos `try_into` e `into` proporcionados por los traits `TryInto` e `Into`, respectivamente." +#: src/ch02-02-data-types.md:154 +msgid "In Cairo, you can convert types scalar types from one type to another by using the `try_into` and `into` methods provided by the `TryInto` and `Into` traits, respectively." +msgstr "En Cairo, puedes convertir tipos escalares de un tipo a otro utilizando los métodos `try_into` e `into` proporcionados por los traits `TryInto` e `Into`, respectivamente." -#: src/ch02-02-data-types.md:157 +#: src/ch02-02-data-types.md:156 msgid "" "The `try_into` method allows for safe type casting when the target type might not fit the source value. Keep in mind that `try_into` returns an `Option` type, which you'll need to " "unwrap to access the new value." @@ -2508,12 +2532,12 @@ msgstr "" "El método `try_into` permite una conversión de tipos segura cuando el tipo de destino puede no encajar con el valor de origen. Ten en cuenta que `try_into` devuelve un tipo " "`Option`, que tendrás que desenvolver para acceder al nuevo valor." -#: src/ch02-02-data-types.md:159 +#: src/ch02-02-data-types.md:158 msgid "On the other hand, the `into` method can be used for type casting when success is guaranteed, such as when the source type is smaller than the destination type." msgstr "" "Por otro lado, el método `into` se puede utilizar para la conversión de tipos cuando el éxito está garantizado, como cuando el tipo de destino es más pequeño que el tipo de origen." -#: src/ch02-02-data-types.md:161 +#: src/ch02-02-data-types.md:160 msgid "" "To perform the conversion, call `var.into()` or `var.try_into()` on the source value to cast it to another type. The new variable's type must be explicitly defined, as demonstrated " "in the example below." @@ -2521,24 +2545,26 @@ msgstr "" "Para realizar la conversión, llame a `var.into()` o `var.try_into()` sobre el valor fuente para convertirlo a otro tipo. El tipo de la nueva variable debe definirse explícitamente, " "como se muestra en el siguiente ejemplo." -#: src/ch02-02-data-types.md:163 +#: src/ch02-02-data-types.md:162 msgid "" "```rust\n" "use traits::TryInto;\n" "use traits::Into;\n" "use option::OptionTrait;\n" "\n" -"fn main(){\n" -" let my_felt = 10;\n" -" let my_u8: u8 = my_felt.try_into().unwrap(); // Since a felt252 might not fit in a u8, we need to unwrap the Option type\n" -" let my_u16: u16 = my_felt.try_into().unwrap();\n" -" let my_u32: u32 = my_felt.try_into().unwrap();\n" -" let my_u64: u64 = my_felt.try_into().unwrap();\n" -" let my_u128: u128 = my_felt.try_into().unwrap();\n" -" let my_u256: u256 = my_felt.into(); // As a felt252 is smaller than a u256, we can use the into() method\n" -" let my_usize: usize = my_felt.try_into().unwrap();\n" -" let my_felt2: felt252 = my_u8.into();\n" -" let my_felt3: felt252 = my_u16.into();\n" +"fn main() {\n" +" let my_felt252 = 10;\n" +" // Since a felt252 might not fit in a u8, we need to unwrap the Option type\n" +" let my_u8: u8 = my_felt252.try_into().unwrap();\n" +" let my_u16: u16 = my_u8.into();\n" +" let my_u32: u32 = my_u16.into();\n" +" let my_u64: u64 = my_u32.into();\n" +" let my_u128: u128 = my_u64.into();\n" +" // As a felt252 is smaller than a u256, we can use the into() method\n" +" let my_u256: u256 = my_felt252.into();\n" +" let my_usize: usize = my_felt252.try_into().unwrap();\n" +" let my_other_felt252: felt252 = my_u8.into();\n" +" let my_third_felt252: felt252 = my_u16.into();\n" "}\n" "```" msgstr "" @@ -2547,25 +2573,27 @@ msgstr "" "use traits::Into;\n" "use option::OptionTrait;\n" "\n" -"fn main(){\n" -" let my_felt = 10;\n" -" let my_u8: u8 = my_felt.try_into().unwrap(); // Since a felt252 might not fit in a u8, we need to unwrap the Option type\n" -" let my_u16: u16 = my_felt.try_into().unwrap();\n" -" let my_u32: u32 = my_felt.try_into().unwrap();\n" -" let my_u64: u64 = my_felt.try_into().unwrap();\n" -" let my_u128: u128 = my_felt.try_into().unwrap();\n" -" let my_u256: u256 = my_felt.into(); // As a felt252 is smaller than a u256, we can use the into() method\n" -" let my_usize: usize = my_felt.try_into().unwrap();\n" -" let my_felt2: felt252 = my_u8.into();\n" -" let my_felt3: felt252 = my_u16.into();\n" -"}\n" -"```" - -#: src/ch02-02-data-types.md:182 +"fn main() {\n" +" let my_felt252 = 10;\n" +" // Since a felt252 might not fit in a u8, we need to unwrap the Option type\n" +" let my_u8: u8 = my_felt252.try_into().unwrap();\n" +" let my_u16: u16 = my_u8.into();\n" +" let my_u32: u32 = my_u16.into();\n" +" let my_u64: u64 = my_u32.into();\n" +" let my_u128: u128 = my_u64.into();\n" +" // As a felt252 is smaller than a u256, we can use the into() method\n" +" let my_u256: u256 = my_felt252.into();\n" +" let my_usize: usize = my_felt252.try_into().unwrap();\n" +" let my_other_felt252: felt252 = my_u8.into();\n" +" let my_third_felt252: felt252 = my_u16.into();\n" +"}\n" +"```" + +#: src/ch02-02-data-types.md:183 msgid "### The Tuple Type" msgstr "### El Tipo Tupla" -#: src/ch02-02-data-types.md:184 +#: src/ch02-02-data-types.md:185 msgid "" "A _tuple_ is a general way of grouping together a number of values with a\n" "variety of types into one compound type. Tuples have a fixed length: once\n" @@ -2575,7 +2603,7 @@ msgstr "" "de tipos en un tipo compuesto. Las tuplas tienen una longitud fija: una vez declaradas, \n" "no pueden aumentar ni disminuir de tamaño." -#: src/ch02-02-data-types.md:188 +#: src/ch02-02-data-types.md:189 msgid "" "We create a tuple by writing a comma-separated list of values inside\n" "parentheses. Each position in the tuple has a type, and the types of the\n" @@ -2587,21 +2615,21 @@ msgstr "" " de la tupla no tienen por qué ser iguales. Hemos añadido anotaciones opcionales de \n" "tipo en este ejemplo:" -#: src/ch02-02-data-types.md:193 +#: src/ch02-02-data-types.md:194 msgid "" "```rust\n" "fn main() {\n" -" let tup: (u32,u64,bool) = (10,20,true);\n" +" let tup: (u32, u64, bool) = (10, 20, true);\n" "}\n" "```" msgstr "" "```rust\n" "fn main() {\n" -" let tup: (u32,u64,bool) = (10,20,true);\n" +" let tup: (u32, u64, bool) = (10, 20, true);\n" "}\n" "```" -#: src/ch02-02-data-types.md:199 +#: src/ch02-02-data-types.md:200 msgid "" "The variable `tup` binds to the entire tuple because a tuple is considered a\n" "single compound element. To get the individual values out of a tuple, we can\n" @@ -2611,7 +2639,7 @@ msgstr "" " elemento compuesto. Para obtener los valores individuales de una tupla, podemos \n" "utilizar la concordancia de patrones para desestructurar un valor de tupla, así:" -#: src/ch02-02-data-types.md:203 +#: src/ch02-02-data-types.md:204 msgid "" "```rust\n" "use debug::PrintTrait;\n" @@ -2639,7 +2667,7 @@ msgstr "" "}\n" "```" -#: src/ch02-02-data-types.md:216 +#: src/ch02-02-data-types.md:217 msgid "" "This program first creates a tuple and binds it to the variable `tup`. It then\n" "uses a pattern with `let` to take `tup` and turn it into three separate\n" @@ -2652,15 +2680,15 @@ msgstr "" " `x`, `y`, y `z`. Esto se llama _desestructuración_ porque divide la tupla en tres partes. \n" "Finalmente, el programa imprime `y es seis` ya que el valor de `y` es `6`." -#: src/ch02-02-data-types.md:222 +#: src/ch02-02-data-types.md:223 msgid "" -"We can also declare the tuple with value and name at the same time.\n" +"We can also declare the tuple with value and types at the same time.\n" "For example:" msgstr "" -"También podemos declarar la tupla con valor y nombre al mismo tiempo.\n" +"También podemos declarar la tupla con los valores y los tipos al mismo tiempo. \n" "Por ejemplo:" -#: src/ch02-02-data-types.md:225 +#: src/ch02-02-data-types.md:226 msgid "" "```rust\n" "fn main() {\n" @@ -2674,11 +2702,11 @@ msgstr "" "}\n" "```" -#: src/ch02-02-data-types.md:231 +#: src/ch02-02-data-types.md:232 msgid "### The unit type ()" msgstr "### The unit type ()" -#: src/ch02-02-data-types.md:233 +#: src/ch02-02-data-types.md:234 msgid "" "A _unit type_ is a type which has only one value `()`.\n" "It is represented by a tuple with no elements.\n" @@ -2688,7 +2716,7 @@ msgstr "" "Se representa mediante una tupla sin elementos.\n" "Su tamaño es siempre cero y se garantiza que no existe en el código compilado." -#: src/ch02-03-functions.md:1 src/ch99-01-02-writing-starknet-contracts.md:134 +#: src/ch02-03-functions.md:1 src/ch99-01-02-writing-starknet-contracts.md:137 msgid "## Functions" msgstr "## Funciones" @@ -2706,16 +2734,14 @@ msgstr "" #: src/ch02-03-functions.md:8 msgid "" -"Cairo code uses *snake case* as the conventional style for function and variable\n" +"Cairo code uses _snake case_ as the conventional style for function and variable\n" "names, in which all letters are lowercase and underscores separate words.\n" "Here’s a program that contains an example function definition:" msgstr "" -"El código de Cairo usa *snake case* como estilo convencional para los nombres de \n" -"funciones y variables, en el que todas las letras están en minúsculas y los guiones\n" -" bajos separan las palabras.\n" -"Aquí hay un programa que contiene un ejemplo de definición de función:" +"El código de Cairo utiliza el estilo _snake case_ como convención para los nombres de funciones y variables, en el cual todas las letras están en minúscula y los guiones bajos " +"separan las palabras. Aquí hay un programa que contiene un ejemplo de definición de función:" -#: src/ch02-03-functions.md:13 +#: src/ch02-03-functions.md:12 msgid "" "```rust\n" "use debug::PrintTrait;\n" @@ -2743,7 +2769,7 @@ msgstr "" "}\n" "```" -#: src/ch02-03-functions.md:26 +#: src/ch02-03-functions.md:25 msgid "" "We define a function in Cairo by entering `fn` followed by a function name and a\n" "set of parentheses. The curly brackets tell the compiler where the function\n" @@ -2753,33 +2779,33 @@ msgstr "" "conjunto de paréntesis. Las llaves indican al compilador dónde empieza y termina el\n" " cuerpo de la función." -#: src/ch02-03-functions.md:30 +#: src/ch02-03-functions.md:29 msgid "" "We can call any function we’ve defined by entering its name followed by a set\n" "of parentheses. Because `another_function` is defined in the program, it can be\n" "called from inside the `main` function. Note that we defined `another_function`\n" -"*before* the `main` function in the source code; we could have defined it after\n" +"_before_ the `main` function in the source code; we could have defined it after\n" "as well. Cairo doesn’t care where you define your functions, only that they’re\n" "defined somewhere in a scope that can be seen by the caller." msgstr "" -"Podemos llamar a cualquier función que hayamos definido introduciendo su nombre \n" -"seguido de un conjunto de paréntesis. Como `another_function` está definida en el \n" -"programa, puede ser llamada desde dentro de la función `main`. Ten en cuenta que \n" -"hemos definido \"another_function\" *antes* de la función `main` en el código fuente; \n" -"también podríamos haberla definido después. A Cairo no le importa dónde definas tus \n" -"funciones, sólo que estén definidas en algún lugar en un ámbito que pueda ser visto por quien las llama." +"Podemos llamar a cualquier función que hayamos definido introduciendo su nombre seguido de unos\n" +"de paréntesis. Como `otra_funcion` está definida en el programa, puede ser\n" +"llamada desde dentro de la función `main`. Tenga en cuenta que hemos definido \"otra_función\n" +"_antes_ de la función `main` en el código fuente; también podríamos haberla definido después.\n" +"también. A Cairo no le importa dónde definas tus funciones, sólo que estén\n" +"definidas en algún lugar en un ámbito que pueda ser visto por quien las llame." -#: src/ch02-03-functions.md:37 +#: src/ch02-03-functions.md:36 msgid "" -"Let’s start a new project with Scarb named *functions* to explore functions\n" -"further. Place the `another_function` example in *src/lib.cairo* and run it. You\n" +"Let’s start a new project with Scarb named _functions_ to explore functions\n" +"further. Place the `another_function` example in _src/lib.cairo_ and run it. You\n" "should see the following output:" msgstr "" -"Empecemos un nuevo proyecto con Scarb llamado *functions* para explorar las \n" -"funciones. Coloque el ejemplo `another_function` en *src/lib.cairo* y ejecútelo. Usted\n" +"Empecemos un nuevo proyecto con Scarb llamado _functions_ para explorar las funciones\n" +"más a fondo. Coloque el ejemplo `another_function` en _src/lib.cairo_ y ejecútelo. Usted\n" "Debería ver la siguiente salida:" -#: src/ch02-03-functions.md:41 +#: src/ch02-03-functions.md:40 msgid "" "```console\n" "$ cairo-run src/lib.cairo\n" @@ -2793,7 +2819,7 @@ msgstr "" "[DEBUG] Another function. (raw: 22265147635379277118623944509513687592494)\n" "```" -#: src/ch02-03-functions.md:47 +#: src/ch02-03-functions.md:46 msgid "" "The lines execute in the order in which they appear in the `main` function.\n" "First the “Hello, world!” message prints, and then `another_function` is called\n" @@ -2803,33 +2829,33 @@ msgstr "" "Primero se imprime el mensaje \" Hello, world!\", y luego se llama a `another_function`\n" " y se imprime su mensaje." -#: src/ch02-03-functions.md:51 +#: src/ch02-03-functions.md:50 msgid "### Parameters" msgstr "### Parámetros" -#: src/ch02-03-functions.md:53 +#: src/ch02-03-functions.md:52 msgid "" -"We can define functions to have *parameters*, which are special variables that\n" +"We can define functions to have _parameters_, which are special variables that\n" "are part of a function’s signature. When a function has parameters, you can\n" "provide it with concrete values for those parameters. Technically, the concrete\n" -"values are called *arguments*, but in casual conversation, people tend to use\n" -"the words *parameter* and *argument* interchangeably for either the variables\n" +"values are called _arguments_, but in casual conversation, people tend to use\n" +"the words _parameter_ and _argument_ interchangeably for either the variables\n" "in a function’s definition or the concrete values passed in when you call a\n" "function." msgstr "" -"Podemos definir funciones para que tengan *parámetros*, que son variables especiales \n" -"que forman parte de la firma de una función. Cuando una función tiene parámetros, \n" -"puede proporcionarle valores concretos para esos parámetros. Técnicamente, los valores\n" -"se llaman *argumentos*, pero en una conversación informal, la gente tiende a usar\n" -"las palabras *parámetro* y *argumento* indistintamente para las variables\n" -"en la definición de una función o los valores concretos pasados cuando se llama a una\n" +"Podemos definir funciones para que tengan _parameters_, que son variables especiales que\n" +"forman parte de la firma de una función. Cuando una función tiene parámetros, puede\n" +"proporcionarle valores concretos para esos parámetros. Técnicamente, los valores\n" +"valores concretos se llaman _arguments_, pero en la conversación informal, la gente tiende a usar\n" +"las palabras _parameters_ y _arguments_ indistintamente para las variables\n" +"en la definición de una función o los valores concretos que se pasan cuando se llama a una\n" "función." -#: src/ch02-03-functions.md:61 +#: src/ch02-03-functions.md:60 msgid "In this version of `another_function` we add a parameter:" msgstr "En esta versión de `another_function` añadimos un parámetro:" -#: src/ch02-03-functions.md:63 +#: src/ch02-03-functions.md:62 msgid "" "```rust\n" "use debug::PrintTrait;\n" @@ -2855,11 +2881,11 @@ msgstr "" "}\n" "```" -#: src/ch02-03-functions.md:75 +#: src/ch02-03-functions.md:74 msgid "Try running this program; you should get the following output:" msgstr "Intente ejecutar este programa; debería obtener la siguiente salida:" -#: src/ch02-03-functions.md:77 src/ch02-03-functions.md:250 +#: src/ch02-03-functions.md:76 src/ch02-03-functions.md:276 msgid "" "```console\n" "$ cairo-run src/lib.cairo\n" @@ -2871,7 +2897,7 @@ msgstr "" "[DEBUG] (raw: 5)\n" "```" -#: src/ch02-03-functions.md:82 +#: src/ch02-03-functions.md:81 msgid "" "The declaration of `another_function` has one parameter named `x`. The type of\n" "`x` is specified as `felt252`. When we pass `5` in to `another_function`, the\n" @@ -2881,21 +2907,21 @@ msgstr "" "`x` se especifica como `felt252`. Cuando pasamos `5` a `another_function`, la función\n" "`print()` muestra `5` en la consola." -#: src/ch02-03-functions.md:86 +#: src/ch02-03-functions.md:85 msgid "" -"In function signatures, you *must* declare the type of each parameter. This is\n" +"In function signatures, you _must_ declare the type of each parameter. This is\n" "a deliberate decision in Cairo’s design: requiring type annotations in function\n" "definitions means the compiler almost never needs you to use them elsewhere in\n" "the code to figure out what type you mean. The compiler is also able to give\n" "more helpful error messages if it knows what types the function expects." msgstr "" -"En las firmas de función, *debes* declarar el tipo de cada parámetro. Esta es\n" +"En las firmas de función, _must_ declarar el tipo de cada parámetro. Esta es\n" "una decisión deliberada en el diseño de Cairo: requerir anotaciones de tipo en las\n" "significa que el compilador casi nunca necesita usarlas en otra parte del código\n" "el código para averiguar a qué tipo se refiere. El compilador también es capaz de dar\n" "mensajes de error más útiles si sabe qué tipos espera la función." -#: src/ch02-03-functions.md:92 +#: src/ch02-03-functions.md:91 msgid "" "When defining multiple parameters, separate the parameter declarations with\n" "commas, like this:" @@ -2903,16 +2929,16 @@ msgstr "" "Cuando defina múltiples parámetros, separe las declaraciones de parámetros con\n" "comas, así:" -#: src/ch02-03-functions.md:95 +#: src/ch02-03-functions.md:94 msgid "" "```rust\n" "use debug::PrintTrait;\n" "\n" "fn main() {\n" -" another_function(5,6);\n" +" another_function(5, 6);\n" "}\n" "\n" -"fn another_function(x: felt252, y:felt252) {\n" +"fn another_function(x: felt252, y: felt252) {\n" " x.print();\n" " y.print();\n" "}\n" @@ -2922,16 +2948,16 @@ msgstr "" "use debug::PrintTrait;\n" "\n" "fn main() {\n" -" another_function(5,6);\n" +" another_function(5, 6);\n" "}\n" "\n" -"fn another_function(x: felt252, y:felt252) {\n" +"fn another_function(x: felt252, y: felt252) {\n" " x.print();\n" " y.print();\n" "}\n" "```" -#: src/ch02-03-functions.md:108 +#: src/ch02-03-functions.md:107 msgid "" "This example creates a function named `another_function` with two\n" "parameters. The first parameter is named `x` and is an `felt252`. The second is\n" @@ -2941,15 +2967,15 @@ msgstr "" "parámetro se llama `x` y es un `felt252`. El segundo se llama `y` y también es del tipo `felt252`. \n" "La función luego imprime el contenido del `x` y luego el contenido del `y`." -#: src/ch02-03-functions.md:112 +#: src/ch02-03-functions.md:111 msgid "" -"Let’s try running this code. Replace the program currently in your *functions*\n" -"project’s *src/lib.cairo* file with the preceding example and run it using `cairo-run src/lib.cairo`:" +"Let’s try running this code. Replace the program currently in your _functions_\n" +"project’s _src/lib.cairo_ file with the preceding example and run it using `cairo-run src/lib.cairo`:" msgstr "" -"Intentemos ejecutar este código. Reemplaza el programa actualmente en el archivo \n" -"*src/lib.cairo* de tu proyecto *functions* con el ejemplo anterior y ejecútalo usando `cairo-run src/lib.cairo`:" +"Intentemos ejecutar este código. Sustituye el programa que actualmente está en tu proyecto _functions_\n" +"de tu proyecto _src/lib.cairo_ con el ejemplo anterior y ejecútalo usando `cairo-run src/lib.cairo`:" -#: src/ch02-03-functions.md:115 +#: src/ch02-03-functions.md:114 msgid "" "```console\n" "$ cairo-run src/lib.cairo\n" @@ -2963,7 +2989,7 @@ msgstr "" "[DEBUG] (raw: 6)\n" "```" -#: src/ch02-03-functions.md:121 +#: src/ch02-03-functions.md:120 msgid "" "Because we called the function with `5` as the value for `x` and `6` as\n" "the value for `y`, the program output contains those values." @@ -2971,11 +2997,58 @@ msgstr "" "Debido a que llamamos a la función con `5` como valor para `x` y `6` como valor\n" " para `y`, la salida del programa contiene esos valores." -#: src/ch02-03-functions.md:124 +#: src/ch02-03-functions.md:123 +msgid "#### Named parameters" +msgstr "#### Parámetros con nombre" + +#: src/ch02-03-functions.md:125 +msgid "" +"In Cairo, named parameters allow you to specify the names of arguments when you call a function. This makes the function calls more readable and self-descriptive.\n" +"If you want to use named parameters, you need to specify the name of the parameter and the value you want to pass to it. The syntax is `parameter_name: value`. If you pass a variable " +"that has the same name as the parameter, you can simply write `:parameter_name` instead of `parameter_name: variable_name`." +msgstr "" +"En Cairo, los parámetros con nombre permiten especificar los nombres de los argumentos cuando se llama a una función. Esto hace que las llamadas a funciones sean más legibles y " +"autodescriptivas.\n" +"Si quieres usar parámetros con nombre, necesitas especificar el nombre del parámetro y el valor que quieres pasarle. La sintaxis es `parameter_name: value`. Si pasas una variable que " +"tiene el mismo nombre que el parámetro, puedes escribir simplemente `:parameter_name` en lugar de `parameter_name: variable_name`." + +#: src/ch02-03-functions.md:128 +msgid "Here is an example:" +msgstr "Aquí un ejemplo:" + +#: src/ch02-03-functions.md:130 +msgid "" +"```rust\n" +"fn foo(x: u8, y: u8) {}\n" +"\n" +"fn main() {\n" +" let first_arg = 3;\n" +" let second_arg = 4;\n" +" foo(x: first_arg, y: second_arg);\n" +" let x = 1;\n" +" let y = 2;\n" +" foo(:x, :y)\n" +"}\n" +"```" +msgstr "" +"```rust\n" +"fn foo(x: u8, y: u8) {}\n" +"\n" +"fn main() {\n" +" let first_arg = 3;\n" +" let second_arg = 4;\n" +" foo(x: first_arg, y: second_arg);\n" +" let x = 1;\n" +" let y = 2;\n" +" foo(:x, :y)\n" +"}\n" +"```" + +#: src/ch02-03-functions.md:143 msgid "### Statements and Expressions" msgstr "### Declaraciones y Expresiones" -#: src/ch02-03-functions.md:126 +#: src/ch02-03-functions.md:145 msgid "" "Function bodies are made up of a series of statements optionally ending in an\n" "expression. So far, the functions we’ve covered haven’t included an ending\n" @@ -2993,26 +3066,27 @@ msgstr "" "distinciones, así que veamos qué son las sentencias y expresiones y cómo sus diferencias \n" "afectan los cuerpos de las funciones." -#: src/ch02-03-functions.md:134 +#: src/ch02-03-functions.md:153 msgid "" -"* **Statements** are instructions that perform some action and do not return\n" +"- **Statements** are instructions that perform some action and do not return\n" " a value.\n" -"* **Expressions** evaluate to a resultant value. Let’s look at some examples." +"- **Expressions** evaluate to a resultant value. Let’s look at some examples." msgstr "" -"* **Declaraciones** son instrucciones que realizan alguna acción y no devuelven un valor.\n" -"* **Expresiones** se evalúan para producir un valor resultante. Veamos algunos ejemplos." +"- Las **Declaraciones** son instrucciones que realizan alguna acción y no devuelven\n" +" un valor.\n" +"- Las **Expresiones** se evalúan a un valor resultante. Veamos algunos ejemplos." -#: src/ch02-03-functions.md:138 +#: src/ch02-03-functions.md:157 msgid "" "We’ve actually already used statements and expressions. Creating a variable and\n" -"assigning a value to it with the `let` keyword is a statement. In Listing 3-1,\n" +"assigning a value to it with the `let` keyword is a statement. In Listing 2-1,\n" "`let y = 6;` is a statement." msgstr "" "De hecho, ya hemos utilizado declaraciones y expresiones. Crear una variable y \n" -"asignarle un valor con la palabra clave `let` es una declaración. En el Listado 3-1,\n" +"asignarle un valor con la palabra clave `let` es una declaración. En el Listado 2-1,\n" " `let y = 6;` es una declaración." -#: src/ch02-03-functions.md:142 +#: src/ch02-03-functions.md:161 msgid "" "```rust\n" "fn main() {\n" @@ -3026,11 +3100,11 @@ msgstr "" "}\n" "```" -#: src/ch02-03-functions.md:148 -msgid "Listing 3-1: A `main` function declaration containing one statement" -msgstr "Listing 3-1: A `main` function declaration containing one statement" +#: src/ch02-03-functions.md:167 +msgid "Listing 2-1: A `main` function declaration containing one statement" +msgstr "Listing 2-1: A `main` declaración de función que contiene una declaración" -#: src/ch02-03-functions.md:150 +#: src/ch02-03-functions.md:169 msgid "" "Function definitions are also statements; the entire preceding example is a\n" "statement in itself." @@ -3038,7 +3112,7 @@ msgstr "" "Las definiciones de funciones también son sentencias; todo el ejemplo anterior \n" "es una sentencia en sí misma." -#: src/ch02-03-functions.md:153 +#: src/ch02-03-functions.md:172 msgid "" "Statements do not return values. Therefore, you can’t assign a `let` statement\n" "to another variable, as the following code tries to do; you’ll get an error:" @@ -3046,25 +3120,25 @@ msgstr "" "Las Declaraciones no devuelven valores. Por lo tanto, no se puede asignar una sentencia \n" "`let` a otra variable, como intenta hacer el siguiente código; se producirá un error:" -#: src/ch02-03-functions.md:156 +#: src/ch02-03-functions.md:175 msgid "" -"```rust,does_not_compile\n" +"```rust,does_not_compile,ignore_format\n" "fn main() {\n" " let x = (let y = 6);\n" "}\n" "```" msgstr "" -"```rust,does_not_compile\n" +"```rust,does_not_compile,ignore_format\n" "fn main() {\n" " let x = (let y = 6);\n" "}\n" "```" -#: src/ch02-03-functions.md:161 +#: src/ch02-03-functions.md:181 msgid "When you run this program, the error you’ll get looks like this:" msgstr "Cuando ejecutes este programa, el error que obtendrás se verá así:" -#: src/ch02-03-functions.md:162 +#: src/ch02-03-functions.md:183 msgid "" "```console\n" "$ cairo-run src/lib.cairo\n" @@ -3110,7 +3184,7 @@ msgstr "" " let x = (let y = 6);\n" "```" -#: src/ch02-03-functions.md:184 +#: src/ch02-03-functions.md:205 msgid "" "The `let y = 6` statement does not return a value, so there isn’t anything for\n" "`x` to bind to. This is different from what happens in other languages, such as\n" @@ -3123,24 +3197,25 @@ msgstr "" "donde la asignación devuelve el valor de la asignación. En esos lenguajes, puedes escribir\n" " `x = y = 6` y tanto `x` como `y` tendrán el valor `6`; esto no es así en Cairo." -#: src/ch02-03-functions.md:190 +#: src/ch02-03-functions.md:211 msgid "" "Expressions evaluate to a value and make up most of the rest of the code that\n" "you’ll write in Cairo. Consider a math operation, such as `5 + 6`, which is an\n" "expression that evaluates to the value `11`. Expressions can be part of\n" -"statements: in Listing 3-1, the `6` in the statement `let y = 6;` is an\n" +"statements: in Listing 2-1, the `6` in the statement `let y = 6;` is an\n" "expression that evaluates to the value `6`. Calling a function is an\n" "expression. A new scope block created with\n" "curly brackets is an expression, for example:" msgstr "" -"Las expresiones evalúan a un valor y componen la mayor parte del código que \n" -"escribirás en Cairo. Considera una operación matemática, como `5 + 6`, que es \n" -"una expresión que evalúa al valor `11`. Las expresiones pueden formar parte de \n" -"las declaraciones: en el Listado 3-1, el `6` en la declaración `let y = 6;` es una expresión \n" -"que evalúa al valor `6`. Llamar a una función es una expresión. Un bloque de ámbito\n" -" nuevo creado con llaves es una expresión, por ejemplo:" +"Las expresiones se evalúan a un valor y forman la mayor parte del resto del código que escribirás en Cairo.\n" +"escribirás en Cairo. Considera una operación matemática, como `5 + 6`, que es una\n" +"expresión que se evalúa al valor `11`. Las expresiones pueden ser parte de\n" +"sentencias: en el Listado 2-1, el `6` en la sentencia `let y = 6;` es una\n" +"es una expresión que se evalúa al valor `6`. Llamar a una función es una\n" +"expresión. Un nuevo bloque de ámbito creado con\n" +"es una expresión, por ejemplo:" -#: src/ch02-03-functions.md:199 +#: src/ch02-03-functions.md:219 msgid "" "```rust\n" "use debug::PrintTrait;\n" @@ -3166,27 +3241,27 @@ msgstr "" "}\n" "```" -#: src/ch02-03-functions.md:211 +#: src/ch02-03-functions.md:231 msgid "This expression:" msgstr "Esta expresión:" -#: src/ch02-03-functions.md:212 +#: src/ch02-03-functions.md:233 msgid "" -"```rust\n" +"```rust, does_not_compile, ignore_format\n" "{\n" -" let x = 3;\n" -" x + 1\n" +" let x = 3;\n" +" x + 1\n" "}\n" "```" msgstr "" -"```rust\n" +"```rust, does_not_compile, ignore_format\n" "{\n" -" let x = 3;\n" -" x + 1\n" +" let x = 3;\n" +" x + 1\n" "}\n" "```" -#: src/ch02-03-functions.md:218 +#: src/ch02-03-functions.md:240 msgid "" "is a block that, in this case, evaluates to `4`. That value gets bound to `y`\n" "as part of the `let` statement. Note that the `x + 1` line doesn’t have a\n" @@ -3204,11 +3279,11 @@ msgstr "" "ese caso no se devolverá ningún valor. Tenlo en cuenta mientras exploras los \n" "valores de retorno de las funciones y las expresiones a continuación." -#: src/ch02-03-functions.md:225 +#: src/ch02-03-functions.md:248 msgid "### Functions with Return Values" msgstr "### Funciones con Valores de Retorno" -#: src/ch02-03-functions.md:226 +#: src/ch02-03-functions.md:250 msgid "" "Functions can return values to the code that calls them. We don’t name return\n" "values, but we must declare their type after an arrow (`->`). In Cairo, the\n" @@ -3225,13 +3300,13 @@ msgstr "" "palabra clave `return` y especificando un valor, pero la mayoría de las funciones devuelven\n" " la última expresión implícitamente. Aquí hay un ejemplo de una función que devuelve un valor:" -#: src/ch02-03-functions.md:234 +#: src/ch02-03-functions.md:258 msgid "" "```rust\n" "use debug::PrintTrait;\n" "\n" "fn five() -> u32 {\n" -" 5_u32\n" +" 5\n" "}\n" "\n" "fn main() {\n" @@ -3244,7 +3319,7 @@ msgstr "" "use debug::PrintTrait;\n" "\n" "fn five() -> u32 {\n" -" 5_u32\n" +" 5\n" "}\n" "\n" "fn main() {\n" @@ -3253,7 +3328,7 @@ msgstr "" "}\n" "```" -#: src/ch02-03-functions.md:246 +#: src/ch02-03-functions.md:271 msgid "" "There are no function calls, or even `let` statements in the `five`\n" "function—just the number `5` by itself. That’s a perfectly valid function in\n" @@ -3265,7 +3340,7 @@ msgstr "" " Observa que se especifica el tipo de retorno de la función como `-> u32`. Intenta\n" " ejecutar este código; la salida debería verse así:" -#: src/ch02-03-functions.md:254 +#: src/ch02-03-functions.md:281 msgid "" "The `5` in `five` is the function’s return value, which is why the return type\n" "is `u32`. Let’s examine this in more detail. There are two important bits:\n" @@ -3279,17 +3354,17 @@ msgstr "" "retorno de una función para inicializar una variable. Debido a que la función `five` \n" "devuelve un `5`, esa línea es lo mismo que:" -#: src/ch02-03-functions.md:259 +#: src/ch02-03-functions.md:287 msgid "" -"```rust\n" +"```rust, does_not_compile\n" "let x = 5;\n" "```" msgstr "" -"```rust\n" +"```rust, does_not_compile\n" "let x = 5;\n" "```" -#: src/ch02-03-functions.md:262 +#: src/ch02-03-functions.md:291 msgid "" "Second, the `five` function has no parameters and defines the type of the\n" "return value, but the body of the function is a lonely `5` with no semicolon\n" @@ -3301,19 +3376,19 @@ msgstr "" "porque es una expresión cuyo valor queremos devolver.\n" "Veamos otro ejemplo:" -#: src/ch02-03-functions.md:267 +#: src/ch02-03-functions.md:296 msgid "" "```rust\n" "use debug::PrintTrait;\n" "\n" "fn main() {\n" -" let x = plus_one(5_u32);\n" +" let x = plus_one(5);\n" "\n" " x.print();\n" "}\n" "\n" "fn plus_one(x: u32) -> u32 {\n" -" x + 1_u32\n" +" x + 1\n" "}\n" "```" msgstr "" @@ -3321,17 +3396,17 @@ msgstr "" "use debug::PrintTrait;\n" "\n" "fn main() {\n" -" let x = plus_one(5_u32);\n" +" let x = plus_one(5);\n" "\n" " x.print();\n" "}\n" "\n" "fn plus_one(x: u32) -> u32 {\n" -" x + 1_u32\n" +" x + 1\n" "}\n" "```" -#: src/ch02-03-functions.md:280 +#: src/ch02-03-functions.md:310 msgid "" "Running this code will print `[DEBUG] (raw: 6)`. But if we place a\n" "semicolon at the end of the line containing `x + 1`, changing it from an\n" @@ -3341,19 +3416,19 @@ msgstr "" "agregamos un punto y coma al final de la línea que contiene `x + 1`, cambiándola \n" "de una expresión a una declaración, obtendremos un error:" -#: src/ch02-03-functions.md:284 +#: src/ch02-03-functions.md:314 msgid "" "```rust,does_not_compile\n" "use debug::PrintTrait;\n" "\n" "fn main() {\n" -" let x = plus_one(5_u32);\n" +" let x = plus_one(5);\n" "\n" " x.print();\n" "}\n" "\n" "fn plus_one(x: u32) -> u32 {\n" -" x + 1_u32;\n" +" x + 1;\n" "}\n" "```" msgstr "" @@ -3361,21 +3436,21 @@ msgstr "" "use debug::PrintTrait;\n" "\n" "fn main() {\n" -" let x = plus_one(5_u32);\n" +" let x = plus_one(5);\n" "\n" " x.print();\n" "}\n" "\n" "fn plus_one(x: u32) -> u32 {\n" -" x + 1_u32;\n" +" x + 1;\n" "}\n" "```" -#: src/ch02-03-functions.md:298 +#: src/ch02-03-functions.md:328 msgid "Compiling this code produces an error, as follows:" msgstr "La compilación de este código produce un error, como se muestra a continuación:" -#: src/ch02-03-functions.md:299 +#: src/ch02-03-functions.md:330 msgid "" "```console\n" "error: Unexpected return type. Expected: \"core::integer::u32\", found: \"()\".\n" @@ -3385,7 +3460,7 @@ msgstr "" "error: Unexpected return type. Expected: \"core::integer::u32\", found: \"()\".\n" "```" -#: src/ch02-03-functions.md:302 +#: src/ch02-03-functions.md:334 msgid "" "The main error message, `Unexpected return type`, reveals the core issue with this\n" "code. The definition of the function `plus_one` says that it will return an\n" @@ -3520,11 +3595,11 @@ msgstr "Intentaré cambiar el valor de number por uno que haga que la condición #: src/ch02-05-control-flow.md:38 msgid "" -"```rust\n" +"```rust, does_not_compile\n" " let number = 5;\n" "```" msgstr "" -"```rust\n" +"```rust, does_not_compile\n" " let number = 5;\n" "```" @@ -3729,26 +3804,26 @@ msgstr "" #: src/ch02-05-control-flow.md:132 msgid "" -"```rust,ignore,does_not_compile\n" +"```rust\n" "use debug::PrintTrait;\n" "fn main() {\n" -" let mut i:usize = 0;\n" +" let mut i: usize = 0;\n" " loop {\n" -" if i > 10{\n" -" break();\n" +" if i > 10 {\n" +" break ();\n" " }\n" " 'again!'.print();\n" " }\n" "}\n" "```" msgstr "" -"```rust,ignore,does_not_compile\n" +"```rust\n" "use debug::PrintTrait;\n" "fn main() {\n" -" let mut i:usize = 0;\n" +" let mut i: usize = 0;\n" " loop {\n" -" if i > 10{\n" -" break();\n" +" if i > 10 {\n" +" break ();\n" " }\n" " 'again!'.print();\n" " }\n" @@ -3759,17 +3834,17 @@ msgstr "" msgid "" "When we run this program, we’ll see `again!` printed over and over continuously\n" "until we stop the program manually, because the stop condition is never reached.\n" -"While the compiler prevents us from writing programs without a stop condition (`break()` statement),\n" +"While the compiler prevents us from writing programs without a stop condition (`break` statement),\n" "the stop condition might never be reached, resulting in an infinite loop.\n" "Most terminals support the keyboard shortcut ctrl-c to interrupt a program that is\n" "stuck in a continual loop. Give it a try:" msgstr "" -"Cuando ejecutemos este programa, veremos impreso `¡otra vez!` una y otra vez continuamente\n" -"hasta que detengamos el programa manualmente, porque la condición de parada nunca se alcanza.\n" -"Aunque el compilador nos impide escribir programas sin una condición de parada (sentencia `break()`),\n" -"la condición de parada podría no alcanzarse nunca, dando lugar a un bucle infinito.\n" -"La mayoría de los terminales soportan el atajo de teclado ctrl-c para interrumpir un programa que está\n" -"en un bucle continuo. Pruébalo:" +"Cuando ejecutamos este programa, veremos que se imprime `again!` una y otra vez continuamente\n" +"hasta que detengamos el programa manualmente, porque la condición de parada nunca se cumple.\n" +"Si bien el compilador nos impide escribir programas sin una condición de parada (`break`),\n" +"es posible que la condición de parada nunca se cumpla, lo que resulta en un bucle infinito. \n" +"La mayoría de las terminales admiten el atajo de teclado ctrl-c para interrumpir un programa que está\n" +"atrapado en un bucle continuo. Pruébalo:" #: src/ch02-05-control-flow.md:152 msgid "" @@ -3819,11 +3894,11 @@ msgstr "" #: src/ch02-05-control-flow.md:170 msgid "" -"To break out of a loop, you can place the `break()` statement within the loop to tell the program when to stop\n" +"To break out of a loop, you can place the `break` statement within the loop to tell the program when to stop\n" "executing the loop. Let's fix the infinite loop by adding a making the stop condition `i > 10` reachable." msgstr "" -"Para salir de un bucle, puede colocar la sentencia `break()` dentro del bucle para indicar al programa cuándo debe detener la ejecución del bucle\n" -"la ejecución del bucle. Arreglemos el bucle infinito añadiendo una condición de parada `i > 10` alcanzable." +"Para salir de un bucle, puedes colocar la instrucción `break` dentro del bucle para indicarle al programa cuándo detener\n" +"la ejecución del bucle. Vamos a solucionar el bucle infinito haciendo que la condición de parada `i > 10` sea alcanzable." #: src/ch02-05-control-flow.md:173 msgid "" @@ -3856,10 +3931,60 @@ msgstr "" "```" #: src/ch02-05-control-flow.md:187 +msgid "" +"The `continue` keyword tells the program to go to the next iteration of the loop and to skip the rest of the code in this iteration. Let's add a `continue` statement to our loop to " +"skip the `print` statement when `i` is equal to `5`." +msgstr "" +"La palabra clave `continue` le indica al programa que pase a la siguiente iteración del bucle y omita el resto del código en esta iteración. Agreguemos una instrucción `continue` a " +"nuestro bucle para saltar la declaración `print` cuando `i` sea igual a `5`." + +#: src/ch02-05-control-flow.md:189 +msgid "" +"```rust\n" +"use debug::PrintTrait;\n" +"fn main() {\n" +" let mut i: usize = 0;\n" +" loop {\n" +" if i > 10 {\n" +" break ();\n" +" }\n" +" if i == 5 {\n" +" i += 1;\n" +" continue;\n" +" }\n" +" i.print();\n" +" i += 1;\n" +" }\n" +"}\n" +"```" +msgstr "" +"```rust\n" +"use debug::PrintTrait;\n" +"fn main() {\n" +" let mut i: usize = 0;\n" +" loop {\n" +" if i > 10 {\n" +" break ();\n" +" }\n" +" if i == 5 {\n" +" i += 1;\n" +" continue;\n" +" }\n" +" i.print();\n" +" i += 1;\n" +" }\n" +"}\n" +"```" + +#: src/ch02-05-control-flow.md:207 +msgid "Executing this program will not print the value of `i` when it is equal to `5`." +msgstr "Al ejecutar este programa, no se imprimirá el valor de `i` cuando sea igual a `5`." + +#: src/ch02-05-control-flow.md:209 msgid "#### Returning Values from Loops" msgstr "#### Devolución de Valores de Loops" -#: src/ch02-05-control-flow.md:189 +#: src/ch02-05-control-flow.md:211 msgid "" "One of the uses of a `loop` is to retry an operation you know might fail, such\n" "as checking whether an operation has succeeded. You might also need to pass\n" @@ -3875,7 +4000,7 @@ msgstr "" "para detener el bucle; ese valor será devuelto fuera del bucle para que pueda utilizarlo, \n" "como se muestra aquí:" -#: src/ch02-05-control-flow.md:196 +#: src/ch02-05-control-flow.md:218 msgid "" "```rust\n" "use debug::PrintTrait;\n" @@ -3911,7 +4036,7 @@ msgstr "" "}\n" "```" -#: src/ch02-05-control-flow.md:213 +#: src/ch02-05-control-flow.md:235 msgid "" "Before the loop, we declare a variable named `counter` and initialize it to\n" "`0`. Then we declare a variable named `result` to hold the value returned from\n" @@ -3962,8 +4087,8 @@ msgid "#### Creating an Array" msgstr "#### Crear un Array" #: src/ch02-06-common-collections.md:14 -msgid "Creating an Array is done with the `ArrayTrait::new()` call. Here is an example of creation of an array with 3 elements:" -msgstr "La creación de un Array se realiza con la llamada `ArrayTrait::new()`. He aquí un ejemplo de creación de un array con 3 elementos:" +msgid "Creating an Array is done with the `ArrayTrait::new()` call. Here is an example of the creation of an array to which we append 3 elements:" +msgstr "Crear una matriz se realiza con la llamada ArrayTrait::new()`. Aquí tienes un ejemplo de la creación de una matriz a la que agregamos 3 elementos:" #: src/ch02-06-common-collections.md:16 msgid "" @@ -3995,11 +4120,11 @@ msgstr "Puede pasar el tipo esperado de elementos dentro de la array al instanci #: src/ch02-06-common-collections.md:29 msgid "" -"```rust,\n" +"```rust, does_not_compile\n" "let mut arr = ArrayTrait::::new();\n" "```" msgstr "" -"```rust,\n" +"```rust, does_not_compile\n" "let mut arr = ArrayTrait::::new();\n" "```" @@ -4018,32 +4143,40 @@ msgstr "To add an element to the end of an array, you can use the `append()` met #: src/ch02-06-common-collections.md:39 msgid "" "```rust\n" -" let mut a = ArrayTrait::new();\n" -" a.append(10);\n" -" a.append(1);\n" -" a.append(2);\n" +"# use array::ArrayTrait;\n" +"# \n" +"# fn main() {\n" +"# let mut a = ArrayTrait::new();\n" +" a.append(0);\n" +"# a.append(1);\n" +"# a.append(2);\n" +"# }\n" "```" msgstr "" "```rust\n" -" let mut a = ArrayTrait::new();\n" -" a.append(10);\n" -" a.append(1);\n" -" a.append(2);\n" +"# use array::ArrayTrait;\n" +"# \n" +"# fn main() {\n" +"# let mut a = ArrayTrait::new();\n" +" a.append(0);\n" +"# a.append(1);\n" +"# a.append(2);\n" +"# }\n" "```" -#: src/ch02-06-common-collections.md:46 +#: src/ch02-06-common-collections.md:50 msgid "##### Removing Elements" msgstr "##### Eliminar Elementos" -#: src/ch02-06-common-collections.md:48 +#: src/ch02-06-common-collections.md:52 msgid "" -"To remove an element from the front of an array, you can use the `pop_front()` method.\n" +"You can only remove elements from the front of an array by using the `pop_front()` method.\n" "This method returns an `Option` containing the removed element, or `Option::None` if the array is empty." msgstr "" -"Para eliminar un elemento de la parte frontal de un array, puedes utilizar el método `pop_front()`.\n" +"Sólo se pueden eliminar elementos de la parte frontal de un array utilizando el método `pop_front()`.\n" "Este método devuelve un `Option` que contiene el elemento eliminado, o `Option::None` si el array está vacío." -#: src/ch02-06-common-collections.md:51 +#: src/ch02-06-common-collections.md:55 msgid "" "```rust\n" "use option::OptionTrait;\n" @@ -4077,11 +4210,11 @@ msgstr "" "}\n" "```" -#: src/ch02-06-common-collections.md:67 +#: src/ch02-06-common-collections.md:71 msgid "The above code will print `10` as we remove the first element that was added." msgstr "El código anterior imprimirá `10` cuando eliminemos el primer elemento añadido." -#: src/ch02-06-common-collections.md:69 +#: src/ch02-06-common-collections.md:73 msgid "" "In Cairo, memory is immutable, which means that it is not possible to modify the elements of an array once they've been added. You can only add elements to the end of an array and " "remove elements from the front of an array. These operations do not require memory mutation, as they involve updating pointers rather than directly modifying the memory cells." @@ -4090,18 +4223,18 @@ msgstr "" "un array y eliminar elementos de la parte frontal de un array. Estas operaciones no requieren mutación de memoria, ya que implican actualizar punteros en lugar de modificar " "directamente las celdas de memoria." -#: src/ch02-06-common-collections.md:71 +#: src/ch02-06-common-collections.md:75 msgid "#### Reading Elements from an Array" msgstr "#### Lectura de Elementos de un Array" -#: src/ch02-06-common-collections.md:73 +#: src/ch02-06-common-collections.md:77 msgid "" "To access array elements, you can use `get()` or `at()` array methods that return different types. Using `arr.at(index)` is equivalent to using the subscripting operator `arr[index]`." msgstr "" "Para acceder a los elementos de un array, puedes utilizar los métodos `get()` o `at()` que devuelven diferentes tipos. Utilizar `arr.at(index)` es equivalente a utilizar el operador " "de subíndice `arr[index]`." -#: src/ch02-06-common-collections.md:75 +#: src/ch02-06-common-collections.md:79 msgid "" "The `get` function returns an `Option>`, which means it returns an option to a Box type (Cairo's smart-pointer type) containing a snapshot to the element at the specified " "index if that element exists in the array. If the element doesn't exist, `get` returns `None`. This method is useful when you expect to access indices that may not be within the " @@ -4113,7 +4246,7 @@ msgstr "" "dentro de los límites del array y quieres manejar tales casos con gracia sin pánicos. Las instantáneas se explicarán con más detalle en el capítulo [Referencias y Snapshots](ch03-02-" "references-and-snapshots.md)." -#: src/ch02-06-common-collections.md:77 +#: src/ch02-06-common-collections.md:81 msgid "" "The `at` function, on the other hand, directly returns a snapshot to the element at the specified index using the `unbox()` operator to extract the value stored in a box. If the " "index is out of bounds, a panic error occurs. You should only use at when you want the program to panic if the provided index is out of the array's bounds, which can prevent " @@ -4123,13 +4256,13 @@ msgstr "" "caja. Si el índice está fuera de los límites, se produce un error de pánico. Sólo debe utilizar at cuando desee que el programa entre en pánico si el índice proporcionado está fuera " "de los límites del array, lo que puede evitar comportamientos inesperados." -#: src/ch02-06-common-collections.md:79 +#: src/ch02-06-common-collections.md:83 msgid "In summary, use `at` when you want to panic on out-of-bounds access attempts, and use `get` when you prefer to handle such cases gracefully without panicking." msgstr "" "En resumen, usa `at` cuando quieras que el programa entre en pánico ante intentos de acceso fuera de los límites, y usa `get` cuando prefieras manejar estos casos con gracia sin " "entrar en pánico." -#: src/ch02-06-common-collections.md:81 +#: src/ch02-06-common-collections.md:85 msgid "" "```rust\n" "use array::ArrayTrait;\n" @@ -4138,8 +4271,8 @@ msgid "" " a.append(0);\n" " a.append(1);\n" "\n" -" let first = *a.at(0_usize);\n" -" let second = *a.at(1_usize);\n" +" let first = *a.at(0);\n" +" let second = *a.at(1);\n" "}\n" "```" msgstr "" @@ -4150,12 +4283,12 @@ msgstr "" " a.append(0);\n" " a.append(1);\n" "\n" -" let first = *a.at(0_usize);\n" -" let second = *a.at(1_usize);\n" +" let first = *a.at(0);\n" +" let second = *a.at(1);\n" "}\n" "```" -#: src/ch02-06-common-collections.md:93 +#: src/ch02-06-common-collections.md:97 msgid "" "In this example, the variable named `first` will get the value `0` because that\n" "is the value at index `0` in the array. The variable named `second` will get\n" @@ -4165,24 +4298,25 @@ msgstr "" "valor del índice `0` del array. La variable llamada `second` obtendrá el valor `1` \n" "del índice `1` del array." -#: src/ch02-06-common-collections.md:97 +#: src/ch02-06-common-collections.md:101 msgid "Here is an example with the `get()` method:" msgstr "He aquí un ejemplo con el método `get()`:" -#: src/ch02-06-common-collections.md:99 +#: src/ch02-06-common-collections.md:103 msgid "" -"```rust\n" +"```rust,ignore_format\n" "use array::ArrayTrait;\n" "use box::BoxTrait;\n" "fn main() -> u128 {\n" " let mut arr = ArrayTrait::::new();\n" -" arr.append(100_u128);\n" +" arr.append(100);\n" " let index_to_access =\n" -" 1_usize; // Change this value to see different results, what would happen if the index doesn't exist ?\n" +" 1; // Change this value to see different results, what would happen if the index doesn't exist?\n" " match arr.get(index_to_access) {\n" " Option::Some(x) => {\n" -" *x.unbox() // Don't worry about * for now, if you are curious see Chapter 3.2 #desnap operator\n" -" // It basically means \"transform what get(idx) returned into a real value\"\n" +" *x.unbox()\n" +" // Don't worry about * for now, if you are curious see Chapter 3.2 #desnap operator\n" +" // It basically means \"transform what get(idx) returned into a real value\"\n" " },\n" " Option::None(_) => {\n" " let mut data = ArrayTrait::new();\n" @@ -4193,18 +4327,19 @@ msgid "" "}\n" "```" msgstr "" -"```rust\n" +"```rust,ignore_format\n" "use array::ArrayTrait;\n" "use box::BoxTrait;\n" "fn main() -> u128 {\n" " let mut arr = ArrayTrait::::new();\n" -" arr.append(100_u128);\n" +" arr.append(100);\n" " let index_to_access =\n" -" 1_usize; // Change this value to see different results, what would happen if the index doesn't exist ?\n" +" 1; // Change this value to see different results, what would happen if the index doesn't exist?\n" " match arr.get(index_to_access) {\n" " Option::Some(x) => {\n" -" *x.unbox() // Don't worry about * for now, if you are curious see Chapter 3.2 #desnap operator\n" -" // It basically means \"transform what get(idx) returned into a real value\"\n" +" *x.unbox()\n" +" // Don't worry about * for now, if you are curious see Chapter 3.2 #desnap operator\n" +" // It basically means \"transform what get(idx) returned into a real value\"\n" " },\n" " Option::None(_) => {\n" " let mut data = ArrayTrait::new();\n" @@ -4215,27 +4350,27 @@ msgstr "" "}\n" "```" -#: src/ch02-06-common-collections.md:121 +#: src/ch02-06-common-collections.md:126 msgid "#### Size related methods" msgstr "#### Métodos relacionados con el tamaño" -#: src/ch02-06-common-collections.md:123 +#: src/ch02-06-common-collections.md:128 msgid "To determine the number of elements in an array, use the `len()` method. The return is of type `usize`." msgstr "Para determinar el número de elementos de un array, utilice el método `len()`. El valor devuelto es de tipo `usize`." -#: src/ch02-06-common-collections.md:125 +#: src/ch02-06-common-collections.md:130 msgid "If you want to check if an array is empty or not, you can use the `is_empty()` method, which returns `true` if the array is empty and `false` otherwise." msgstr "Si quieres comprobar si un array está vacío o no, puedes utilizar el método `is_empty()`, que devuelve `true` si el array está vacío y `false` en caso contrario." -#: src/ch02-06-common-collections.md:127 +#: src/ch02-06-common-collections.md:132 msgid "#### Storing multiple types with Enums" msgstr "#### Almacenar multiples tipos con Enums" -#: src/ch02-06-common-collections.md:129 +#: src/ch02-06-common-collections.md:134 msgid "If you want to store elements of different types in an array, you can use an `Enum` to define a custom data type that can hold multiple types." msgstr "Si desea almacenar elementos de diferentes tipos en una array, puede utilizar un `Enum` para definir un tipo de datos personalizado que pueda contener múltiples tipos." -#: src/ch02-06-common-collections.md:131 +#: src/ch02-06-common-collections.md:136 msgid "" "```rust\n" "use array::ArrayTrait;\n" @@ -4250,9 +4385,9 @@ msgid "" "\n" "fn main() {\n" " let mut messages: Array = ArrayTrait::new();\n" -" messages.append(Data::Integer(100_u128));\n" +" messages.append(Data::Integer(100));\n" " messages.append(Data::Felt('hello world'));\n" -" messages.append(Data::Tuple((10_u32, 30_u32)));\n" +" messages.append(Data::Tuple((10, 30)));\n" "}\n" "```" msgstr "" @@ -4269,17 +4404,17 @@ msgstr "" "\n" "fn main() {\n" " let mut messages: Array = ArrayTrait::new();\n" -" messages.append(Data::Integer(100_u128));\n" +" messages.append(Data::Integer(100));\n" " messages.append(Data::Felt('hello world'));\n" -" messages.append(Data::Tuple((10_u32, 30_u32)));\n" +" messages.append(Data::Tuple((10, 30)));\n" "}\n" "```" -#: src/ch02-06-common-collections.md:150 +#: src/ch02-06-common-collections.md:155 msgid "#### Span" msgstr "#### Span" -#: src/ch02-06-common-collections.md:152 +#: src/ch02-06-common-collections.md:157 msgid "" "`Span` is a struct that represents a snapshot of an `Array`. It is designed to provide safe and controlled access to the elements of an array without modifying the original array. " "Span is particularly useful for ensuring data integrity and avoiding borrowing issues when passing arrays between functions or when performing read-only operations (cf. [References " @@ -4289,33 +4424,43 @@ msgstr "" "array original. Span es particularmente útil para asegurar la integridad de los datos y evitar problemas de préstamo cuando se pasan arrays entre funciones o cuando se realizan " "operaciones de sólo lectura (cf. [References and Snapshots](ch03-02-references-and-snapshots.md))" -#: src/ch02-06-common-collections.md:154 +#: src/ch02-06-common-collections.md:159 msgid "All methods provided by `Array` can also be used with `Span`, with the exception of the `append()` method." msgstr "Todos los métodos proporcionados por `Array` también se pueden utilizar con `Span`, a excepción del método `append()`." -#: src/ch02-06-common-collections.md:156 +#: src/ch02-06-common-collections.md:161 msgid "##### Turning an Array into span" msgstr "##### Convertir un Array en span" -#: src/ch02-06-common-collections.md:158 +#: src/ch02-06-common-collections.md:163 msgid "To create a `Span` of an `Array`, call the `span()` method:" msgstr "To create a `Span` of an `Array`, call the `span()` method:" -#: src/ch02-06-common-collections.md:160 +#: src/ch02-06-common-collections.md:165 msgid "" "```rust\n" -"let span = array.span();\n" +"# use array::ArrayTrait;\n" +"# \n" +"# fn main() {\n" +"# let mut array = ArrayTrait::new();\n" +" array.span()\n" +"# }\n" "```" msgstr "" "```rust\n" -"let span = array.span();\n" +"# use array::ArrayTrait;\n" +"# \n" +"# fn main() {\n" +"# let mut array = ArrayTrait::new();\n" +" array.span()\n" +"# }\n" "```" -#: src/ch02-06-common-collections.md:164 src/ch04-03-method-syntax.md:286 src/ch06-05-separating-modules-into-different-files.md:98 +#: src/ch02-06-common-collections.md:174 src/ch04-03-method-syntax.md:286 src/ch06-05-separating-modules-into-different-files.md:99 msgid "## Summary" msgstr "## Resumen" -#: src/ch02-06-common-collections.md:166 +#: src/ch02-06-common-collections.md:176 msgid "" "You made it! This was a sizable chapter: you learned about variables, data types, functions, comments,\n" "`if` expressions, loops, and common collections! To practice with the concepts discussed in this chapter,\n" @@ -4325,7 +4470,7 @@ msgstr "" "expresiones `if`, bucles y colecciones comunes. Para practicar con los conceptos discutidos en este capítulo,\n" "intenta construir programas para hacer lo siguiente:" -#: src/ch02-06-common-collections.md:170 +#: src/ch02-06-common-collections.md:180 msgid "" "- Generate the _n_-th Fibonacci number.\n" "- Compute the factorial of a number _n_." @@ -4333,7 +4478,7 @@ msgstr "" "- Generar el _n_-th número de Fibonacci.\n" "- Calcular el factorial de un número _n_." -#: src/ch02-06-common-collections.md:173 +#: src/ch02-06-common-collections.md:183 msgid "" "When you’re ready to move on, we’ll talk about a concept that Cairo shares with Rust and that _doesn’t_\n" "commonly exist in other programming languages: ownership." @@ -4456,32 +4601,36 @@ msgstr "" #: src/ch03-01-what-is-ownership.md:39 msgid "" "```rust\n" +"# fn main() {\n" " { // s is not valid here, it’s not yet declared\n" " let s = 'hello'; // s is valid from this point forward\n" "\n" " // do stuff with s\n" " } // this scope is now over, and s is no longer valid\n" +"# }\n" "```" msgstr "" "```rust\n" +"# fn main() {\n" " { // s is not valid here, it’s not yet declared\n" " let s = 'hello'; // s is valid from this point forward\n" "\n" " // do stuff with s\n" " } // this scope is now over, and s is no longer valid\n" +"# }\n" "```" -#: src/ch03-01-what-is-ownership.md:47 +#: src/ch03-01-what-is-ownership.md:49 msgid "" "Listing 3-1: A variable and the scope in which it is\n" "valid" msgstr "Lista 3-1: Una variable y el ámbito en el que es válida" -#: src/ch03-01-what-is-ownership.md:50 +#: src/ch03-01-what-is-ownership.md:52 msgid "In other words, there are two important points in time here:" msgstr "En otras palabras, hay dos puntos importantes en el tiempo aquí:" -#: src/ch03-01-what-is-ownership.md:52 +#: src/ch03-01-what-is-ownership.md:54 msgid "" "- When `s` comes _into_ scope, it is valid.\n" "- It remains valid until it goes _out of_ scope." @@ -4489,7 +4638,7 @@ msgstr "" "- Cuando `s` entra en el _ámbito_, es válida.\n" "- Permanece válida hasta que sale del _ámbito_." -#: src/ch03-01-what-is-ownership.md:55 +#: src/ch03-01-what-is-ownership.md:57 msgid "" "At this point, the relationship between scopes and when variables are valid is\n" "similar to that in other programming languages. Now we’ll build on top of this\n" @@ -4499,11 +4648,11 @@ msgstr "" "similar a la de otros lenguajes de programación. Ahora nos basaremos en este\n" "utilizando el tipo `Array` que introdujimos en el [capítulo anterior](ch02-06-common-collections.md)." -#: src/ch03-01-what-is-ownership.md:59 +#: src/ch03-01-what-is-ownership.md:61 msgid "### Ownership with the `Array` Type" msgstr "### Ownership con el tipo `Array" -#: src/ch03-01-what-is-ownership.md:61 +#: src/ch03-01-what-is-ownership.md:63 msgid "" "To illustrate the rules of ownership, we need a data type that is more complex.\n" "The types covered in the [“Data Types”][data-types] section\n" @@ -4511,35 +4660,40 @@ msgid "" "quickly and trivially copied to make a new, independent instance if another\n" "part of code needs to use the same value in a different scope, and can easily\n" "be dropped when they're no longer used. But what is the behavior with the `Array` type whose size\n" -"is unknown at compile time and which can't be trivially copied ?" +"is unknown at compile time and which can't be trivially copied?" msgstr "" -"Para ilustrar las reglas de propiedad, necesitamos un tipo de datos que sea más complejo.\n" -"Los tipos cubiertos en la sección [\"Tipos de datos\"][data-types]\n" -"del capítulo 2 tienen un tamaño conocido, pueden ser\n" -"pueden copiarse rápida y trivialmente para crear una instancia nueva e\n" -"si otra parte del código necesita utilizar el mismo valor en un ámbito diferente, y pueden\n" -"cuando ya no se utilizan. Pero ¿cuál es el comportamiento con el tipo `Array` cuyo tamaño\n" -"es desconocido en tiempo de compilación y que no puede copiarse trivialmente?" +"Para ilustrar las reglas de propiedad, necesitamos un tipo de datos más complejo. \n" +"Los tipos cubiertos en la sección [\"Tipos de datos\"][data-types]section\n" +"el Capítulo 2 son de un tamaño conocido, pueden ser copiados rápidamente y trivialmente para crear una nueva instancia independiente si otra \n" +"parte del código necesita usar el mismo valor en un ámbito diferente, y pueden ser fácilmente\n" +"eliminados cuando ya no se usan. Pero, ¿cuál es el comportamiento con el tipo `Array`, cuyo tamaño\n" +"es desconocido en tiempo de compilación y no puede ser copiado trivialmente?" -#: src/ch03-01-what-is-ownership.md:69 +#: src/ch03-01-what-is-ownership.md:71 msgid "Here is a short reminder of what an array looks like:" msgstr "Aquí tienes un breve recordatorio de cómo es un array:" -#: src/ch03-01-what-is-ownership.md:71 +#: src/ch03-01-what-is-ownership.md:73 msgid "" "```rust\n" -"let mut arr = ArrayTrait::::new();\n" -"arr.append(1);\n" -"arr.append(2);\n" +"# use array::ArrayTrait;\n" +"# fn main() {\n" +" let mut arr = ArrayTrait::::new();\n" +" arr.append(1);\n" +" arr.append(2);\n" +"# }\n" "```" msgstr "" "```rust\n" -"let mut arr = ArrayTrait::::new();\n" -"arr.append(1);\n" -"arr.append(2);\n" +"# use array::ArrayTrait;\n" +"# fn main() {\n" +" let mut arr = ArrayTrait::::new();\n" +" arr.append(1);\n" +" arr.append(2);\n" +"# }\n" "```" -#: src/ch03-01-what-is-ownership.md:77 +#: src/ch03-01-what-is-ownership.md:82 msgid "" "So, how does the ownership system ensure that each cell is never written to more than once?\n" "Consider the following code, where we try to pass the same instance of an array in two consecutive\n" @@ -4549,15 +4703,13 @@ msgstr "" "Consideremos el siguiente código, en el que intentamos pasar la misma instancia de un array en dos llamadas consecutivas a la función\n" "consecutivas:" -#: src/ch03-01-what-is-ownership.md:81 +#: src/ch03-01-what-is-ownership.md:86 msgid "" "```rust,does_not_compile\n" "use array::ArrayTrait;\n" -"fn foo(arr: Array) {\n" -"}\n" +"fn foo(arr: Array) {}\n" "\n" -"fn bar(arr:Array){\n" -"}\n" +"fn bar(arr: Array) {}\n" "\n" "fn main() {\n" " let mut arr = ArrayTrait::::new();\n" @@ -4568,11 +4720,9 @@ msgid "" msgstr "" "```rust,does_not_compile\n" "use array::ArrayTrait;\n" -"fn foo(arr: Array) {\n" -"}\n" +"fn foo(arr: Array) {}\n" "\n" -"fn bar(arr:Array){\n" -"}\n" +"fn bar(arr: Array) {}\n" "\n" "fn main() {\n" " let mut arr = ArrayTrait::::new();\n" @@ -4581,7 +4731,7 @@ msgstr "" "}\n" "```" -#: src/ch03-01-what-is-ownership.md:96 +#: src/ch03-01-what-is-ownership.md:99 msgid "" "In this case, we try to pass the same array instance `arr` by value to the functions `foo` and `bar`, which means\n" "that the parameter used in both function calls is the same instance of the array. If you append a value to the array\n" @@ -4599,11 +4749,11 @@ msgstr "" "`bar` con `arr` como parámetro, la propiedad de `arr` ya se movió a la primera llamada. El sistema de propiedad nos impide usar \n" "la misma instancia de `arr` en `foo`." -#: src/ch03-01-what-is-ownership.md:104 +#: src/ch03-01-what-is-ownership.md:107 msgid "Running the code above will result in a compile-time error:" msgstr "Ejecutar el código anterior resultará en un error en tiempo de compilación:" -#: src/ch03-01-what-is-ownership.md:106 +#: src/ch03-01-what-is-ownership.md:109 msgid "" "```console\n" "error: Variable was previously moved. Trait has no implementation in context: core::traits::Copy::>\n" @@ -4619,11 +4769,11 @@ msgstr "" " ^*****^\n" "```" -#: src/ch03-01-what-is-ownership.md:113 +#: src/ch03-01-what-is-ownership.md:116 msgid "### The `Copy` Trait" msgstr "### El Trait `Copy`" -#: src/ch03-01-what-is-ownership.md:115 +#: src/ch03-01-what-is-ownership.md:118 msgid "" "If a type implements the `Copy` trait, passing it to a function will not move the ownership of the value to the function called, but will instead pass a copy of the value.\n" "You can implement the `Copy` trait on your type by adding the `#[derive(Copy)]` annotation to your type definition. However, Cairo won't allow a type to be annotated with Copy if the " @@ -4635,9 +4785,9 @@ msgstr "" "si el tipo en sí mismo o cualquiera de sus componentes no implementan el trait `Copy`.\n" "Mientras que los Arrays y Diccionarios no pueden ser copiados, los tipos personalizados que no los contienen sí pueden serlo." -#: src/ch03-01-what-is-ownership.md:119 +#: src/ch03-01-what-is-ownership.md:122 msgid "" -"```rust\n" +"```rust,ignore_format\n" "#[derive(Copy, Drop)]\n" "struct Point {\n" " x: u128,\n" @@ -4655,7 +4805,7 @@ msgid "" "}\n" "```" msgstr "" -"```rust\n" +"```rust,ignore_format\n" "#[derive(Copy, Drop)]\n" "struct Point {\n" " x: u128,\n" @@ -4673,7 +4823,7 @@ msgstr "" "}\n" "```" -#: src/ch03-01-what-is-ownership.md:137 +#: src/ch03-01-what-is-ownership.md:140 msgid "" "In this example, we can pass `p1` twice to the foo function because the `Point` type implements the `Copy` trait. This means that when we pass `p1` to `foo`, we are actually passing " "a copy of `p1`, and the ownership of `p1` remains with the main function.\n" @@ -4683,15 +4833,15 @@ msgstr "" "estamos pasando una copia de `p1`, y la propiedad de `p1` permanece en la función principal.\n" "Si eliminamos la derivación del trait `Copy` del tipo `Point`, obtendremos un error en tiempo de compilación al intentar compilar el código." -#: src/ch03-01-what-is-ownership.md:140 +#: src/ch03-01-what-is-ownership.md:143 msgid "_Don't worry about the `Struct` keyword. We will introduce this in [Chapter 4](ch04-00-using-structs-to-structure-related-data.md)._" msgstr "_No te preocupes por la palabra clave `Struct`. La introduciremos en el [Capítulo 4](ch04-00-using-structs-to-structure-related-data.md)._" -#: src/ch03-01-what-is-ownership.md:142 +#: src/ch03-01-what-is-ownership.md:145 msgid "### The `Drop` Trait" msgstr "### El Trait `Drop`" -#: src/ch03-01-what-is-ownership.md:144 +#: src/ch03-01-what-is-ownership.md:147 msgid "" "You may have noticed that the `Point` type in the previous example also implements the `Drop` trait. In Cairo, a value cannot go out of scope unless it has been previously moved.\n" "For example, the following code will not compile, because the struct `A` is not moved before it goes out of scope:" @@ -4700,7 +4850,7 @@ msgstr "" "previamente.\n" "Por ejemplo, el siguiente código no se compilará porque la estructura `A` no se mueve antes de que salga del ámbito:" -#: src/ch03-01-what-is-ownership.md:147 +#: src/ch03-01-what-is-ownership.md:150 msgid "" "```rust,does_not_compile\n" "struct A {}\n" @@ -4718,25 +4868,25 @@ msgstr "" "}\n" "```" -#: src/ch03-01-what-is-ownership.md:155 +#: src/ch03-01-what-is-ownership.md:158 msgid "" "This is to ensure the soundness of Cairo programs. Soundness refers to the fact that if a\n" "statement during the execution of the program is false, no cheating prover can convince an\n" "honest verifier that it is true. In our case, we want to ensure the consistency of\n" "consecutive dictionary key updates during program execution, which is only checked when\n" -"the dictionaries are`squashed` - which moves the ownership of the dictionary to the\n" +"the dictionaries are `squashed` - which moves the ownership of the dictionary to the\n" "`squash` method, thus allowing the dictionary to go out of scope. Unsquashed dictionaries\n" "are dangerous, as a malicious prover could prove the correctness of inconsistent updates." msgstr "" -"En Cairo, esto se hace para garantizar la solidez de los programas. La solidez se refiere al hecho de\n" -" que si una declaración durante la ejecución del programa es falsa, ningún probador deshonesto puede\n" -" convencer a un verificador honesto de que es verdadera. En nuestro caso, queremos asegurar la consistencia \n" -"de las actualizaciones consecutivas de claves de un diccionario durante la ejecución del programa, lo cua\n" -"l solo se verifica cuando los diccionarios se \"aplastan\" - lo que mueve la propiedad del diccionario al método `squash`, \n" -"permitiendo que el diccionario salga de ámbito. Los diccionarios no \"aplastados\" son peligrosos, ya que un probador \n" -"malintencionado podría probar la corrección de actualizaciones inconsistentes." +"Con ello se pretende garantizar la solidez de los programas de Cairo. La solidez se refiere al hecho de que si una\n" +"durante la ejecución del programa es falsa, ningún probador tramposo puede convencer a un verificador honesto de que es verdadera.\n" +"verificador honesto de que es verdadera. En nuestro caso, queremos garantizar la coherencia de\n" +"actualizaciones consecutivas de las claves del diccionario durante la ejecución del programa, que sólo se comprueba cuando\n" +"los diccionarios son `squashed` - que mueve la propiedad del diccionario al método\n" +"`squash`, lo que permite que el diccionario salga del ámbito. Los diccionarios Unsquashed\n" +"son peligrosos, ya que un prover malicioso podría probar la corrección de actualizaciones inconsistentes." -#: src/ch03-01-what-is-ownership.md:163 +#: src/ch03-01-what-is-ownership.md:166 msgid "" "However, types that implement the `Drop` trait are allowed to go out of scope without being explicitly moved. When a value of a type that implements the `Drop` trait goes out of " "scope, the `Drop` implementation is called on the type, which moves the value to the `drop` function, allowing it to go out of scope - This is what we call \"dropping\" a value.\n" @@ -4748,17 +4898,17 @@ msgstr "" "Es importante tener en cuenta que la implementación de `Drop` es una \"operación nula\", lo que significa que no realiza ninguna acción aparte de permitir que el valor salga de " "ámbito." -#: src/ch03-01-what-is-ownership.md:166 +#: src/ch03-01-what-is-ownership.md:169 msgid "" -"The `Drop` implementation can be derived for all types, allowing them to be dropped when goint out of scope, except for dictionaries (`Felt252Dict`) and types containing " +"The `Drop` implementation can be derived for all types, allowing them to be dropped when going out of scope, except for dictionaries (`Felt252Dict`) and types containing " "dictionaries.\n" "For example, the following code compiles:" msgstr "" -"La implementación de `Drop` se puede derivar para todos los tipos, lo que les permite eliminarse al salir de ámbito, excepto para los diccionarios (`Felt252Dict`) y los tipos que " -"contienen diccionarios.\n" +"La implementación `Drop` puede ser derivada para todos los tipos, permitiéndoles ser descartados cuando salen del ámbito, excepto para los diccionarios (`Felt252Dict`) y los tipos " +"que contienen diccionarios.\n" "Por ejemplo, el siguiente código compila:" -#: src/ch03-01-what-is-ownership.md:169 +#: src/ch03-01-what-is-ownership.md:172 msgid "" "```rust\n" "#[derive(Drop)]\n" @@ -4778,11 +4928,11 @@ msgstr "" "}\n" "```" -#: src/ch03-01-what-is-ownership.md:178 +#: src/ch03-01-what-is-ownership.md:181 msgid "### The `Destruct` Trait" msgstr "### El Trait `Destruct`" -#: src/ch03-01-what-is-ownership.md:180 +#: src/ch03-01-what-is-ownership.md:183 msgid "" "Manually calling the `squash` method on a dictionary is not very convenient, and it is easy to forget to do so. To make it easier to use dictionaries, Cairo provides the `Destruct` " "trait, which allows you to specify the behavior of a type when it goes out of scope. While Dictionaries don't implement the `Drop` trait, they do implement the `Destruct` trait, " @@ -4793,11 +4943,11 @@ msgstr "" "`Destruct`, lo que les permite ser `aplastados` automáticamente cuando salen del ámbito. Esto significa que puedes usar diccionarios sin tener que llamar manualmente al método " "`squash`." -#: src/ch03-01-what-is-ownership.md:182 +#: src/ch03-01-what-is-ownership.md:185 msgid "Consider the following example, in which we define a custom type that contains a dictionary:" msgstr "Considera el siguiente ejemplo, en el que definimos un tipo personalizado que contiene un diccionario:" -#: src/ch03-01-what-is-ownership.md:184 +#: src/ch03-01-what-is-ownership.md:187 msgid "" "```rust,does_not_compile\n" "use dict::Felt252DictTrait;\n" @@ -4807,9 +4957,7 @@ msgid "" "}\n" "\n" "fn main() {\n" -" A {\n" -" dict: Felt252DictTrait::new()\n" -" };\n" +" A { dict: Felt252DictTrait::new() };\n" "}\n" "```" msgstr "" @@ -4821,17 +4969,15 @@ msgstr "" "}\n" "\n" "fn main() {\n" -" A {\n" -" dict: Felt252DictTrait::new()\n" -" };\n" +" A { dict: Felt252DictTrait::new() };\n" "}\n" "```" -#: src/ch03-01-what-is-ownership.md:198 +#: src/ch03-01-what-is-ownership.md:199 msgid "If you try to run this code, you will get a compile-time error:" msgstr "Si intenta ejecutar este código, obtendrá un error de tiempo de compilación:" -#: src/ch03-01-what-is-ownership.md:200 +#: src/ch03-01-what-is-ownership.md:201 msgid "" "```console\n" "error: Variable not dropped. Trait has no implementation in context: core::traits::Drop::. Trait has no implementation in context: core::traits::Destruct:: Note: in the following example, we need to import the `Clone` trait from the corelib `clone` module, and its implementation for the array type from the `array` module." msgstr "" "> Nota: en el siguiente ejemplo, necesitamos importar el rasgo `Clone` del módulo `clone` de la biblioteca estándar, y su implementación para el tipo `array` del módulo `array`." -#: src/ch03-01-what-is-ownership.md:235 +#: src/ch03-01-what-is-ownership.md:234 msgid "" "```rust\n" "use array::ArrayTrait;\n" "use clone::Clone;\n" "use array::ArrayTCloneImpl;\n" -"...\n" -"let arr1 = ArrayTrait::::new();\n" -"let arr2 = arr1.clone();\n" -"\n" +"fn main() {\n" +" let arr1 = ArrayTrait::::new();\n" +" let arr2 = arr1.clone();\n" +"}\n" "```" msgstr "" "```rust\n" "use array::ArrayTrait;\n" "use clone::Clone;\n" "use array::ArrayTCloneImpl;\n" -"...\n" -"let arr1 = ArrayTrait::::new();\n" -"let arr2 = arr1.clone();\n" -"\n" +"fn main() {\n" +" let arr1 = ArrayTrait::::new();\n" +" let arr2 = arr1.clone();\n" +"}\n" "```" -#: src/ch03-01-what-is-ownership.md:245 +#: src/ch03-01-what-is-ownership.md:244 msgid "> Note: you will need to run `cairo-run` with the `--available-gas=2000000` option to run this example, because it uses a loop and must be ran with a gas limit." msgstr "> Nota: necesitarás ejecutar `cairo-run` con la opción `--available-gas=2000000` para ejecutar este ejemplo, ya que utiliza un bucle y debe ser ejecutado con un límite de gas." -#: src/ch03-01-what-is-ownership.md:247 +#: src/ch03-01-what-is-ownership.md:246 msgid "" "When you see a call to `clone`, you know that some arbitrary code is being\n" "executed and that code may be expensive. It’s a visual indicator that something\n" @@ -4950,11 +5092,11 @@ msgstr "" "Cuando ves una llamada a `clone`, sabes que se está ejecutando algún código arbitrario\n" " y ese código puede ser costoso. Es un indicador visual de que algo diferente está sucediendo." -#: src/ch03-01-what-is-ownership.md:251 +#: src/ch03-01-what-is-ownership.md:250 msgid "### Ownership and Functions" msgstr "### Ownership y Funciones" -#: src/ch03-01-what-is-ownership.md:253 +#: src/ch03-01-what-is-ownership.md:252 msgid "" "Passing a variable to a function will either move it or copy it. As seen in the Array section, passing an `Array` as a function parameter transfers its ownership; let's see what " "happens with other types." @@ -4962,7 +5104,7 @@ msgstr "" "Pasar una variable a una función puede moverla o copiarla. Como se vio en la sección de Array, pasar un `Array` como parámetro de función transfiere su propiedad; veamos qué sucede " "con otros tipos." -#: src/ch03-01-what-is-ownership.md:255 +#: src/ch03-01-what-is-ownership.md:254 msgid "" "Listing 3-3 has an example with some annotations\n" "showing where variables go into and out of scope." @@ -4970,13 +5112,13 @@ msgstr "" "El Listado 3-3 tiene un ejemplo con algunas anotaciones \n" "que muestran dónde las variables entran y salen de ámbito." -#: src/ch03-01-what-is-ownership.md:258 src/ch03-01-what-is-ownership.md:300 src/ch03-01-what-is-ownership.md:353 +#: src/ch03-01-what-is-ownership.md:257 src/ch03-01-what-is-ownership.md:299 src/ch03-01-what-is-ownership.md:352 msgid "Filename: src/main.cairo" msgstr "Filename: src/main.cairo" -#: src/ch03-01-what-is-ownership.md:260 +#: src/ch03-01-what-is-ownership.md:259 msgid "" -"```rust\n" +"```rust,ignore_format\n" "#[derive(Drop)]\n" "struct MyStruct{}\n" "\n" @@ -4986,7 +5128,7 @@ msgid "" " takes_ownership(my_struct); // my_struct's value moves into the function...\n" " // ... and so is no longer valid here\n" "\n" -" let x = 5_u128; // x comes into scope\n" +" let x = 5; // x comes into scope\n" "\n" " makes_copy(x); // x would move into the function,\n" " // but u128 implements Copy, so it is okay to still\n" @@ -5002,7 +5144,7 @@ msgid "" "} // Here, some_integer goes out of scope and is dropped.\n" "```" msgstr "" -"```rust\n" +"```rust,ignore_format\n" "#[derive(Drop)]\n" "struct MyStruct{}\n" "\n" @@ -5012,7 +5154,7 @@ msgstr "" " takes_ownership(my_struct); // my_struct's value moves into the function...\n" " // ... and so is no longer valid here\n" "\n" -" let x = 5_u128; // x comes into scope\n" +" let x = 5; // x comes into scope\n" "\n" " makes_copy(x); // x would move into the function,\n" " // but u128 implements Copy, so it is okay to still\n" @@ -5028,7 +5170,7 @@ msgstr "" "} // Here, some_integer goes out of scope and is dropped.\n" "```" -#: src/ch03-01-what-is-ownership.md:286 +#: src/ch03-01-what-is-ownership.md:285 msgid "" "Listing 3-3: Functions with ownership and scope\n" "annotated" @@ -5036,7 +5178,7 @@ msgstr "" "Listing 3-3: Functions with ownership and scope\n" "annotated" -#: src/ch03-01-what-is-ownership.md:289 +#: src/ch03-01-what-is-ownership.md:288 msgid "" "If we tried to use `my_struct` after the call to `takes_ownership`, Cairo would throw a\n" "compile-time error. These static checks protect us from mistakes. Try adding\n" @@ -5048,11 +5190,11 @@ msgstr "" "agregar código a `main` que use `my_struct` y `x` para ver dónde puedes usarlos y dónde las \n" "reglas de propiedad te impiden hacerlo." -#: src/ch03-01-what-is-ownership.md:294 +#: src/ch03-01-what-is-ownership.md:293 msgid "### Return Values and Scope" msgstr "### Valores de retorno y alcance" -#: src/ch03-01-what-is-ownership.md:296 +#: src/ch03-01-what-is-ownership.md:295 msgid "" "Returning values can also transfer ownership. Listing 3-4 shows an example of a\n" "function that returns some value, with similar annotations as those in Listing\n" @@ -5061,17 +5203,17 @@ msgstr "" "La devolución de valores también puede transferir la propiedad. El Listado 3-4 muestra \n" "un ejemplo de una función que devuelve algún valor, con anotaciones similares a las del Listado 4-3." -#: src/ch03-01-what-is-ownership.md:302 +#: src/ch03-01-what-is-ownership.md:301 msgid "" -"```rust\n" +"```rust,ignore_format\n" "#[derive(Drop)]\n" -"struct A{}\n" +"struct A {}\n" "\n" "fn main() {\n" " let a1 = gives_ownership(); // gives_ownership moves its return\n" " // value into a1\n" "\n" -" let a2 = A{}; // a2 comes into scope\n" +" let a2 = A {}; // a2 comes into scope\n" "\n" " let a3 = takes_and_gives_back(a2); // a2 is moved into\n" " // takes_and_gives_back, which also\n" @@ -5084,7 +5226,7 @@ msgid "" " // return value into the function\n" " // that calls it\n" "\n" -" let some_a = A{}; // some_a comes into scope\n" +" let some_a = A {}; // some_a comes into scope\n" "\n" " some_a // some_a is returned and\n" " // moves ownership to the calling\n" @@ -5101,15 +5243,15 @@ msgid "" "}\n" "```" msgstr "" -"```rust\n" +"```rust,ignore_format\n" "#[derive(Drop)]\n" -"struct A{}\n" +"struct A {}\n" "\n" "fn main() {\n" " let a1 = gives_ownership(); // gives_ownership moves its return\n" " // value into a1\n" "\n" -" let a2 = A{}; // a2 comes into scope\n" +" let a2 = A {}; // a2 comes into scope\n" "\n" " let a3 = takes_and_gives_back(a2); // a2 is moved into\n" " // takes_and_gives_back, which also\n" @@ -5122,7 +5264,7 @@ msgstr "" " // return value into the function\n" " // that calls it\n" "\n" -" let some_a = A{}; // some_a comes into scope\n" +" let some_a = A {}; // some_a comes into scope\n" "\n" " some_a // some_a is returned and\n" " // moves ownership to the calling\n" @@ -5139,7 +5281,7 @@ msgstr "" "}\n" "```" -#: src/ch03-01-what-is-ownership.md:340 +#: src/ch03-01-what-is-ownership.md:339 msgid "" "Listing 3-4: Transferring ownership of return\n" "values" @@ -5147,11 +5289,11 @@ msgstr "" "Listado 3-4: Transferencia de propiedad de \n" "valores devueltos" -#: src/ch03-01-what-is-ownership.md:343 +#: src/ch03-01-what-is-ownership.md:342 msgid "When a variable goes out of scope, its value is dropped, unless ownership of the value has been moved to another variable." msgstr "Cuando una variable sale del ámbito, su valor se elimina, a menos que la propiedad del valor se haya transferido a otra variable." -#: src/ch03-01-what-is-ownership.md:345 +#: src/ch03-01-what-is-ownership.md:344 msgid "" "While this works, taking ownership and then returning ownership with every\n" "function is a bit tedious. What if we want to let a function use a value but\n" @@ -5165,11 +5307,11 @@ msgstr "" "también deba ser devuelto si queremos usarlo nuevamente, además de cualquier\n" " dato que resulte del cuerpo de la función que también podríamos querer devolver." -#: src/ch03-01-what-is-ownership.md:351 +#: src/ch03-01-what-is-ownership.md:350 msgid "Cairo does let us return multiple values using a tuple, as shown in Listing 3-5." msgstr "Cairo nos permite devolver múltiples valores usando una tupla, como se muestra en el Listado 3-5." -#: src/ch03-01-what-is-ownership.md:355 +#: src/ch03-01-what-is-ownership.md:354 msgid "" "```rust\n" "use array::ArrayTrait;\n" @@ -5201,11 +5343,11 @@ msgstr "" "}\n" "```" -#: src/ch03-01-what-is-ownership.md:370 +#: src/ch03-01-what-is-ownership.md:369 msgid "Listing 3-5: Returning ownership of parameters" msgstr "Listado 3-5: Devolviendo propiedad de los parámetros" -#: src/ch03-01-what-is-ownership.md:372 +#: src/ch03-01-what-is-ownership.md:371 msgid "" "But this is too much ceremony and a lot of work for a concept that should be\n" "common. Luckily for us, Cairo has two features for using a value without\n" @@ -5267,15 +5409,17 @@ msgstr "" #: src/ch03-02-references-and-snapshots.md:25 msgid "" -"```rust\n" +"```rust,ignore_format\n" "use array::ArrayTrait;\n" "use debug::PrintTrait;\n" "\n" "fn main() {\n" " let mut arr1 = ArrayTrait::::new();\n" " let first_snapshot = @arr1; // Take a snapshot of `arr1` at this point in time\n" -" arr1.append(1_u128); // Mutate `arr1` by appending a value\n" -" let first_length = calculate_length(first_snapshot); // Calculate the length of the array when the snapshot was taken\n" +" arr1.append(1); // Mutate `arr1` by appending a value\n" +" let first_length = calculate_length(\n" +" first_snapshot\n" +" ); // Calculate the length of the array when the snapshot was taken\n" " let second_length = calculate_length(@arr1); // Calculate the current length of the array\n" " first_length.print();\n" " second_length.print();\n" @@ -5286,15 +5430,17 @@ msgid "" "}\n" "```" msgstr "" -"```rust\n" +"```rust,ignore_format\n" "use array::ArrayTrait;\n" "use debug::PrintTrait;\n" "\n" "fn main() {\n" " let mut arr1 = ArrayTrait::::new();\n" " let first_snapshot = @arr1; // Take a snapshot of `arr1` at this point in time\n" -" arr1.append(1_u128); // Mutate `arr1` by appending a value\n" -" let first_length = calculate_length(first_snapshot); // Calculate the length of the array when the snapshot was taken\n" +" arr1.append(1); // Mutate `arr1` by appending a value\n" +" let first_length = calculate_length(\n" +" first_snapshot\n" +" ); // Calculate the length of the array when the snapshot was taken\n" " let second_length = calculate_length(@arr1); // Calculate the current length of the array\n" " first_length.print();\n" " second_length.print();\n" @@ -5305,7 +5451,7 @@ msgstr "" "}\n" "```" -#: src/ch03-02-references-and-snapshots.md:44 +#: src/ch03-02-references-and-snapshots.md:46 msgid "" "> Note: It is only possible to call the `len()` method on an array snapshot because it is defined as such in the `ArrayTrait` trait. If you try to call a method that is not defined " "for snapshots on a snapshot, you will get a compilation error. However, you can call methods expecting a snapshot on non-snapshot types." @@ -5313,11 +5459,11 @@ msgstr "" "> Nota: Solo es posible llamar al método `len()` en un snapshot de un array porque está definido así en el trait `ArrayTrait`. Si intentas llamar a un método que no está definido " "para snapshots en un snapshot, obtendrás un error de compilación. Sin embargo, puedes llamar a métodos que esperan un snapshot en tipos que no son snapshots." -#: src/ch03-02-references-and-snapshots.md:46 +#: src/ch03-02-references-and-snapshots.md:48 msgid "The output of this program is:" msgstr "La salida de este programa es:" -#: src/ch03-02-references-and-snapshots.md:48 +#: src/ch03-02-references-and-snapshots.md:50 msgid "" "```console\n" "[DEBUG]\t \t(raw: 0)\n" @@ -5335,7 +5481,7 @@ msgstr "" "Run completed successfully, returning []\n" "```" -#: src/ch03-02-references-and-snapshots.md:56 +#: src/ch03-02-references-and-snapshots.md:58 msgid "" "First, notice that all the tuple code in the variable declaration and the function return value is gone. Second, note\n" "that we pass `@arr1` into `calculate_length` and, in its definition, we take `@Array` rather than `Array`." @@ -5344,23 +5490,55 @@ msgstr "" "ha desaparecido. La segunda observación es que pasamos `@arr1` a `calculate_length` y, en su definición, tomamos\n" " `@Array` en lugar de `Array`." -#: src/ch03-02-references-and-snapshots.md:59 +#: src/ch03-02-references-and-snapshots.md:61 msgid "Let’s take a closer look at the function call here:" msgstr "Veamos más de cerca la llamada a la función aquí:" -#: src/ch03-02-references-and-snapshots.md:61 +#: src/ch03-02-references-and-snapshots.md:63 msgid "" "```rust\n" -"let mut arr1 = ArrayTrait::::new();\n" -"let second_length = calculate_length(@arr1); // Calculate the current length of the array\n" -"```" -msgstr "" -"```rust\n" -"let mut arr1 = ArrayTrait::::new();\n" -"let second_length = calculate_length(@arr1); // Calculate the current length of the array\n" +"# use array::ArrayTrait;\n" +"# use debug::PrintTrait;\n" +"# \n" +"# fn main() {\n" +"# let mut arr1 = ArrayTrait::::new();\n" +"# let first_snapshot = @arr1; // Take a snapshot of `arr1` at this point in time\n" +"# arr1.append(1); // Mutate `arr1` by appending a value\n" +"# let first_length = calculate_length(\n" +"# first_snapshot\n" +"# ); // Calculate the length of the array when the snapshot was taken\n" +" let second_length = calculate_length(@arr1); // Calculate the current length of the array\n" +"# first_length.print();\n" +"# second_length.print();\n" +"# }\n" +"# \n" +"# fn calculate_length(arr: @Array) -> usize {\n" +"# arr.len()\n" +"# }\n" +"```" +msgstr "" +"```rust\n" +"# use array::ArrayTrait;\n" +"# use debug::PrintTrait;\n" +"# \n" +"# fn main() {\n" +"# let mut arr1 = ArrayTrait::::new();\n" +"# let first_snapshot = @arr1; // Take a snapshot of `arr1` at this point in time\n" +"# arr1.append(1); // Mutate `arr1` by appending a value\n" +"# let first_length = calculate_length(\n" +"# first_snapshot\n" +"# ); // Calculate the length of the array when the snapshot was taken\n" +" let second_length = calculate_length(@arr1); // Calculate the current length of the array\n" +"# first_length.print();\n" +"# second_length.print();\n" +"# }\n" +"# \n" +"# fn calculate_length(arr: @Array) -> usize {\n" +"# arr.len()\n" +"# }\n" "```" -#: src/ch03-02-references-and-snapshots.md:66 +#: src/ch03-02-references-and-snapshots.md:84 msgid "" "The `@arr1` syntax lets us create a snapshot of the value in `arr1`. Because a snapshot is an immutable view of a value, the value it points to cannot be modified through the " "snapshot, and the value it refers to will not be dropped once the snapshot stops being used." @@ -5368,27 +5546,31 @@ msgstr "" "La sintaxis `@arr1` nos permite crear una instantánea (snapshot) del valor en `arr1`. Como una instantánea es una vista inmutable de un valor, el valor al que apunta no puede ser " "modificado a través de la instantánea y el valor al que se refiere no será eliminado una vez que la instantánea deje de ser usada." -#: src/ch03-02-references-and-snapshots.md:68 +#: src/ch03-02-references-and-snapshots.md:86 msgid "Similarly, the signature of the function uses `@` to indicate that the type of the parameter `arr` is a snapshot. Let’s add some explanatory annotations:" msgstr "De manera similar, la firma de la función utiliza `@` para indicar que el tipo del parámetro `arr` es una instantánea. Añadamos algunas anotaciones explicativas:" -#: src/ch03-02-references-and-snapshots.md:70 +#: src/ch03-02-references-and-snapshots.md:88 msgid "" "```rust\n" -"fn calculate_length(array_snapshot: @Array) -> usize { // array_snapshot is a snapshot of an Array\n" +"fn calculate_length(\n" +" array_snapshot: @Array\n" +") -> usize { // array_snapshot is a snapshot of an Array\n" " array_snapshot.len()\n" "} // Here, array_snapshot goes out of scope and is dropped.\n" "// However, because it is only a view of what the original array `arr` contains, the original `arr` can still be used.\n" "```" msgstr "" "```rust\n" -"fn calculate_length(array_snapshot: @Array) -> usize { // array_snapshot is a snapshot of an Array\n" +"fn calculate_length(\n" +" array_snapshot: @Array\n" +") -> usize { // array_snapshot is a snapshot of an Array\n" " array_snapshot.len()\n" "} // Here, array_snapshot goes out of scope and is dropped.\n" "// However, because it is only a view of what the original array `arr` contains, the original `arr` can still be used.\n" "```" -#: src/ch03-02-references-and-snapshots.md:77 +#: src/ch03-02-references-and-snapshots.md:97 msgid "" "The scope in which the variable `array_snapshot` is valid is the same as any function parameter’s scope, but the underlying value of the snapshot is not dropped when `array_snapshot` " "stops being used. When functions have snapshots as parameters instead of the actual values, we won’t need to return the values in order to give back ownership of the original value, " @@ -5398,7 +5580,7 @@ msgstr "" "`array_snapshot` deje de usarse. Cuando las funciones tienen snapshots como parámetros en lugar de los valores reales, no necesitamos devolver los valores para devolver la propiedad " "del valor original, porque nunca la tuvimos." -#: src/ch03-02-references-and-snapshots.md:79 +#: src/ch03-02-references-and-snapshots.md:99 msgid "" "Snapshots can be converted back into regular values using the `desnap` operator `*`, as long as the value type is copyable (which is not the case for Arrays, as they don't implement " "`Copy`). In the following example, we want to calculate the area of a rectangle, but we don't want to take ownership of the rectangle in the `calculate_area` function, because we " @@ -5410,26 +5592,25 @@ msgstr "" "`calculate_area`, porque podríamos querer usar el rectángulo de nuevo después de la llamada a la función. Dado que nuestra función no muta la instancia del rectángulo, podemos pasar " "el snapshot del rectángulo a la función, y luego transformar los snapshots de nuevo en valores usando el operador `desnap` `*`." -#: src/ch03-02-references-and-snapshots.md:81 +#: src/ch03-02-references-and-snapshots.md:101 msgid "The snapshot type is always copyable and droppable, so that you can use it multiple times without worrying about ownership transfers." msgstr "El tipo de snapshot siempre es copiable y eliminable, para que pueda usarlo varias veces sin preocuparse por las transferencias de propiedad." -#: src/ch03-02-references-and-snapshots.md:83 +#: src/ch03-02-references-and-snapshots.md:103 msgid "" "```rust\n" "use debug::PrintTrait;\n" "\n" -"#[derive(Copy,Drop)]\n" +"#[derive(Copy, Drop)]\n" "struct Rectangle {\n" " height: u64,\n" " width: u64,\n" "}\n" "\n" -"fn main(){\n" -" let rec = Rectangle{height:3_u64, width:10_u64};\n" +"fn main() {\n" +" let rec = Rectangle { height: 3, width: 10 };\n" " let area = calculate_area(@rec);\n" " area.print();\n" -"\n" "}\n" "\n" "fn calculate_area(rec: @Rectangle) -> u64 {\n" @@ -5444,17 +5625,16 @@ msgstr "" "```rust\n" "use debug::PrintTrait;\n" "\n" -"#[derive(Copy,Drop)]\n" +"#[derive(Copy, Drop)]\n" "struct Rectangle {\n" " height: u64,\n" " width: u64,\n" "}\n" "\n" -"fn main(){\n" -" let rec = Rectangle{height:3_u64, width:10_u64};\n" +"fn main() {\n" +" let rec = Rectangle { height: 3, width: 10 };\n" " let area = calculate_area(@rec);\n" " area.print();\n" -"\n" "}\n" "\n" "fn calculate_area(rec: @Rectangle) -> u64 {\n" @@ -5466,7 +5646,7 @@ msgstr "" "}\n" "```" -#: src/ch03-02-references-and-snapshots.md:108 +#: src/ch03-02-references-and-snapshots.md:127 msgid "" "But, what happens if we try to modify something we’re passing as snapshot? Try the code in\n" "Listing 3-6. Spoiler alert: it doesn’t work!" @@ -5474,17 +5654,18 @@ msgstr "" "Pero, ¿qué sucede si intentamos modificar algo que estamos pasando como instantánea? Prueba el código \n" "en la Lista 3-6. ¡Alerta de spoiler: no funciona!" -#: src/ch03-02-references-and-snapshots.md:113 +#: src/ch03-02-references-and-snapshots.md:132 msgid "" "```rust,does_not_compile\n" -"#[derive(Copy,Drop)]\n" +"// does_not_compile\n" +"#[derive(Copy, Drop)]\n" "struct Rectangle {\n" " height: u64,\n" " width: u64,\n" "}\n" "\n" -"fn main(){\n" -" let rec = Rectangle{height:3_u64, width:10_u64};\n" +"fn main() {\n" +" let rec = Rectangle { height: 3, width: 10 };\n" " flip(@rec);\n" "}\n" "\n" @@ -5496,14 +5677,15 @@ msgid "" "```" msgstr "" "```rust,does_not_compile\n" -"#[derive(Copy,Drop)]\n" +"// does_not_compile\n" +"#[derive(Copy, Drop)]\n" "struct Rectangle {\n" " height: u64,\n" " width: u64,\n" "}\n" "\n" -"fn main(){\n" -" let rec = Rectangle{height:3_u64, width:10_u64};\n" +"fn main() {\n" +" let rec = Rectangle { height: 3, width: 10 };\n" " flip(@rec);\n" "}\n" "\n" @@ -5514,15 +5696,15 @@ msgstr "" "}\n" "```" -#: src/ch03-02-references-and-snapshots.md:132 +#: src/ch03-02-references-and-snapshots.md:152 msgid "Listing 3-6: Attempting to modify a snapshot value" msgstr "Listado 3-6: Intentando modificar un valor de snapshot" -#: src/ch03-02-references-and-snapshots.md:134 +#: src/ch03-02-references-and-snapshots.md:154 msgid "Here’s the error:" msgstr "Aquí está el error:" -#: src/ch03-02-references-and-snapshots.md:136 +#: src/ch03-02-references-and-snapshots.md:156 msgid "" "```console\n" "error: Invalid left-hand side of assignment.\n" @@ -5538,15 +5720,15 @@ msgstr "" " ^********^\n" "```" -#: src/ch03-02-references-and-snapshots.md:143 +#: src/ch03-02-references-and-snapshots.md:163 msgid "The compiler prevents us from modifying values associated to snapshots." msgstr "El compilador nos impide modificar los valores asociados a las instantáneas." -#: src/ch03-02-references-and-snapshots.md:145 +#: src/ch03-02-references-and-snapshots.md:165 msgid "### Mutable References" msgstr "### Referencias Mutables" -#: src/ch03-02-references-and-snapshots.md:147 +#: src/ch03-02-references-and-snapshots.md:167 msgid "" "We can achieve the behavior we want in Listing 3-6 by using a _mutable reference_ instead of a snapshot. Mutable references are actually mutable values passed to a function that are " "implicitly returned at the end of the function, returning ownership to the calling context. By doing so, they allow you to mutate the value passed while keeping ownership of it by " @@ -5558,15 +5740,15 @@ msgstr "" "propiedad devolviéndolo automáticamente al final de la ejecución.\n" "En Cairo, se puede pasar un parámetro como _referencia mutable_ utilizando el modificador `ref`." -#: src/ch03-02-references-and-snapshots.md:150 +#: src/ch03-02-references-and-snapshots.md:170 msgid "> **Note**: In Cairo, a parameter can only be passed as _mutable reference_ using the `ref` modifier if the variable is declared as mutable with `mut`." msgstr "> **Nota**: En Cairo, un parámetro solo se puede pasar como _referencia mutable_ utilizando el modificador `ref` si la variable se declara como mutable con `mut`." -#: src/ch03-02-references-and-snapshots.md:152 +#: src/ch03-02-references-and-snapshots.md:172 msgid "In Listing 3-7, we use a mutable reference to modify the value of the `height` and `width` fields of the `Rectangle` instance in the `flip` function." msgstr "En el Listado 3-7, usamos una referencia mutable para modificar el valor del campo `height` de la instancia de `Rectangle` en la función `flip`." -#: src/ch03-02-references-and-snapshots.md:154 +#: src/ch03-02-references-and-snapshots.md:174 msgid "" "```rust\n" "use debug::PrintTrait;\n" @@ -5577,7 +5759,7 @@ msgid "" "}\n" "\n" "fn main() {\n" -" let mut rec = Rectangle { height: 3_u64, width: 10_u64 };\n" +" let mut rec = Rectangle { height: 3, width: 10 };\n" " flip(ref rec);\n" " rec.height.print();\n" " rec.width.print();\n" @@ -5599,7 +5781,7 @@ msgstr "" "}\n" "\n" "fn main() {\n" -" let mut rec = Rectangle { height: 3_u64, width: 10_u64 };\n" +" let mut rec = Rectangle { height: 3, width: 10 };\n" " flip(ref rec);\n" " rec.height.print();\n" " rec.width.print();\n" @@ -5612,11 +5794,11 @@ msgstr "" "}\n" "```" -#: src/ch03-02-references-and-snapshots.md:176 +#: src/ch03-02-references-and-snapshots.md:196 msgid "Listing 3-7: Use of a mutable reference to modify a value" msgstr "Listing 3-7: Uso de una referencia mutable para modificar un valor" -#: src/ch03-02-references-and-snapshots.md:178 +#: src/ch03-02-references-and-snapshots.md:198 msgid "" "First, we change `rec` to be `mut`. Then we pass a mutable reference of `rec` into `flip` with `ref rec`, and update the function signature to accept a mutable reference with `ref " "rec: Rectangle`. This makes it very clear that the `flip` function will mutate the value of the `Rectangle` instance passed as parameter." @@ -5624,11 +5806,11 @@ msgstr "" "Primero, cambiamos `rec` a `mut`. Luego, pasamos una referencia mutable de `rec` a `flip` con `ref rec` y actualizamos la firma de la función para aceptar una referencia mutable con " "`ref rec: Rectangle`. Esto deja muy claro que la función `flip` modificará el valor de la instancia de `Rectangle` pasada como parámetro." -#: src/ch03-02-references-and-snapshots.md:180 +#: src/ch03-02-references-and-snapshots.md:200 msgid "The output of the program is:" msgstr "La salida del programa es:" -#: src/ch03-02-references-and-snapshots.md:182 +#: src/ch03-02-references-and-snapshots.md:202 msgid "" "```console\n" "[DEBUG]\n" @@ -5644,19 +5826,19 @@ msgstr "" "[DEBUG]\t (raw: 3)\n" "```" -#: src/ch03-02-references-and-snapshots.md:189 +#: src/ch03-02-references-and-snapshots.md:209 msgid "As expected, the `height` and `width` fields of the `rec` variable have been swapped." msgstr "Como era de esperar, los campos `height` y `width` de la variable `rec` se han intercambiado." -#: src/ch03-02-references-and-snapshots.md:191 +#: src/ch03-02-references-and-snapshots.md:211 msgid "### Small recap" msgstr "### Pequeño resumen" -#: src/ch03-02-references-and-snapshots.md:193 +#: src/ch03-02-references-and-snapshots.md:213 msgid "Let’s recap what we’ve discussed about ownership, snapshots, and references:" msgstr "Como resumen, lo que hemos discutido acerca de ownership, snapshots y las referencias es:" -#: src/ch03-02-references-and-snapshots.md:195 +#: src/ch03-02-references-and-snapshots.md:215 msgid "" "- At any given time, a variable can only have one owner.\n" "- You can pass a variable by-value, by-snapshot, or by-reference to a function.\n" @@ -5718,8 +5900,8 @@ msgstr "" "agrupan. Después, entre llaves, definimos los nombres y tipos de los datos, que llamamos campos. Por ejemplo, el Listado 4-1 muestra una estructura que almacena información sobre una " "cuenta de usuario." -#: src/ch04-01-defining-and-instantiating-structs.md:7 src/ch04-01-defining-and-instantiating-structs.md:26 src/ch04-01-defining-and-instantiating-structs.md:50 -#: src/ch04-01-defining-and-instantiating-structs.md:72 src/ch04-01-defining-and-instantiating-structs.md:93 +#: src/ch04-01-defining-and-instantiating-structs.md:7 src/ch04-01-defining-and-instantiating-structs.md:26 src/ch04-01-defining-and-instantiating-structs.md:48 +#: src/ch04-01-defining-and-instantiating-structs.md:83 src/ch04-01-defining-and-instantiating-structs.md:118 msgid "Filename: structs.cairo" msgstr "Filename: structs.cairo" @@ -5777,12 +5959,10 @@ msgid "" "}\n" "fn main() {\n" " let user1 = User {\n" -" active: true,\n" -" username: 'someusername123',\n" -" email: 'someone@example.com',\n" -" sign_in_count: 1_u64,\n" +" active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" " };\n" "}\n" +"\n" "```" msgstr "" "```rust\n" @@ -5795,19 +5975,17 @@ msgstr "" "}\n" "fn main() {\n" " let user1 = User {\n" -" active: true,\n" -" username: 'someusername123',\n" -" email: 'someone@example.com',\n" -" sign_in_count: 1_u64,\n" +" active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" " };\n" "}\n" +"\n" "```" -#: src/ch04-01-defining-and-instantiating-structs.md:46 +#: src/ch04-01-defining-and-instantiating-structs.md:44 msgid "Listing 4-2: Creating an instance of the `User` struct" msgstr "Listado 4-2: Creando una instancia de la estructura `User`" -#: src/ch04-01-defining-and-instantiating-structs.md:48 +#: src/ch04-01-defining-and-instantiating-structs.md:46 msgid "" "To get a specific value from a struct, we use dot notation. For example, to access this user’s email address, we use `user1.email`. If the instance is mutable, we can change a value " "by using the dot notation and assigning into a particular field. Listing 4-3 shows how to change the value in the `email` field of a mutable `User` instance." @@ -5816,47 +5994,73 @@ msgstr "" "la instancia es mutable, podemos cambiar un valor usando la notación punto y asignándolo a un campo en particular. El listado 4-3 muestra cómo cambiar el valor en el campo `email`de " "una instancia mutable de `User`." -#: src/ch04-01-defining-and-instantiating-structs.md:52 +#: src/ch04-01-defining-and-instantiating-structs.md:50 msgid "" -"```rust,does_not_compile\n" +"```rust\n" +"# #[derive(Copy, Drop)]\n" +"# struct User {\n" +"# active: bool,\n" +"# username: felt252,\n" +"# email: felt252,\n" +"# sign_in_count: u64,\n" +"# }\n" "fn main() {\n" " let mut user1 = User {\n" -" active: true,\n" -" username: 'someusername123',\n" -" email: 'someone@example.com',\n" -" sign_in_count: 1_u64,\n" +" active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" " };\n" " user1.email = 'anotheremail@example.com';\n" "}\n" -"```" -msgstr "" -"```rust,does_not_compile\n" +"# \n" +"# fn build_user(email: felt252, username: felt252) -> User {\n" +"# User { active: true, username: username, email: email, sign_in_count: 1, }\n" +"# }\n" +"# \n" +"# fn build_user_short(email: felt252, username: felt252) -> User {\n" +"# User { active: true, username, email, sign_in_count: 1, }\n" +"# }\n" +"# \n" +"```" +msgstr "" +"```rust\n" +"# #[derive(Copy, Drop)]\n" +"# struct User {\n" +"# active: bool,\n" +"# username: felt252,\n" +"# email: felt252,\n" +"# sign_in_count: u64,\n" +"# }\n" "fn main() {\n" " let mut user1 = User {\n" -" active: true,\n" -" username: 'someusername123',\n" -" email: 'someone@example.com',\n" -" sign_in_count: 1_u64,\n" +" active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" " };\n" " user1.email = 'anotheremail@example.com';\n" "}\n" +"# \n" +"# fn build_user(email: felt252, username: felt252) -> User {\n" +"# User { active: true, username: username, email: email, sign_in_count: 1, }\n" +"# }\n" +"# \n" +"# fn build_user_short(email: felt252, username: felt252) -> User {\n" +"# User { active: true, username, email, sign_in_count: 1, }\n" +"# }\n" +"# \n" "```" -#: src/ch04-01-defining-and-instantiating-structs.md:64 +#: src/ch04-01-defining-and-instantiating-structs.md:75 msgid "Listing 4-3: Changing the value in the email field of a `User` instance" msgstr "Listado 4-3: Cambiando el valor del campo email de la instancia `User`" -#: src/ch04-01-defining-and-instantiating-structs.md:66 +#: src/ch04-01-defining-and-instantiating-structs.md:77 msgid "Note that the entire instance must be mutable; Cairo doesn’t allow us to mark only certain fields as mutable." msgstr "Tenga en cuenta que toda la instancia debe ser mutable; Cairo no nos permite marcar solo ciertos campos como mutables." -#: src/ch04-01-defining-and-instantiating-structs.md:68 +#: src/ch04-01-defining-and-instantiating-structs.md:79 msgid "As with any expression, we can construct a new instance of the struct as the last expression in the function body to implicitly return that new instance." msgstr "" "Como con cualquier expresión, podemos construir una nueva instancia de la estructura como la última expresión en el cuerpo de la función para devolver implícitamente esa nueva " "instancia." -#: src/ch04-01-defining-and-instantiating-structs.md:70 +#: src/ch04-01-defining-and-instantiating-structs.md:81 msgid "" "Listing 4-4 shows a `build_user` function that returns a `User` instance with the given email and username. The `active` field gets the value of `true`, and the `sign_in_count` gets " "a value of `1`." @@ -5864,35 +6068,63 @@ msgstr "" "Listado 4-4 muestra la función `build_user` que retorna una instancia de la estructura `User` con el email y el username. Al campo `active` se le asigna el valor `true`,y el campo " "`sign_in_count` obtiene el valor de `1`." -#: src/ch04-01-defining-and-instantiating-structs.md:74 +#: src/ch04-01-defining-and-instantiating-structs.md:85 msgid "" "```rust\n" +"# #[derive(Copy, Drop)]\n" +"# struct User {\n" +"# active: bool,\n" +"# username: felt252,\n" +"# email: felt252,\n" +"# sign_in_count: u64,\n" +"# }\n" +"# fn main() {\n" +"# let mut user1 = User {\n" +"# active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" +"# };\n" +"# user1.email = 'anotheremail@example.com';\n" +"# }\n" +"# \n" "fn build_user(email: felt252, username: felt252) -> User {\n" -" User {\n" -" active: true,\n" -" username: username,\n" -" email: email,\n" -" sign_in_count: 1,\n" -" }\n" -"}\n" -"```" -msgstr "" -"```rust\n" +" User { active: true, username: username, email: email, sign_in_count: 1, }\n" +"}\n" +"# \n" +"# fn build_user_short(email: felt252, username: felt252) -> User {\n" +"# User { active: true, username, email, sign_in_count: 1, }\n" +"# }\n" +"# \n" +"```" +msgstr "" +"```rust\n" +"# #[derive(Copy, Drop)]\n" +"# struct User {\n" +"# active: bool,\n" +"# username: felt252,\n" +"# email: felt252,\n" +"# sign_in_count: u64,\n" +"# }\n" +"# fn main() {\n" +"# let mut user1 = User {\n" +"# active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" +"# };\n" +"# user1.email = 'anotheremail@example.com';\n" +"# }\n" +"# \n" "fn build_user(email: felt252, username: felt252) -> User {\n" -" User {\n" -" active: true,\n" -" username: username,\n" -" email: email,\n" -" sign_in_count: 1,\n" -" }\n" +" User { active: true, username: username, email: email, sign_in_count: 1, }\n" "}\n" +"# \n" +"# fn build_user_short(email: felt252, username: felt252) -> User {\n" +"# User { active: true, username, email, sign_in_count: 1, }\n" +"# }\n" +"# \n" "```" -#: src/ch04-01-defining-and-instantiating-structs.md:85 +#: src/ch04-01-defining-and-instantiating-structs.md:110 msgid "Listing 4-4: A `build_user` function that takes an email and username and returns a `User` instance" msgstr "Listado 4-4: Función `build_user` que toma los argumentos email y username, y retorna una instancia de la estructura `User`" -#: src/ch04-01-defining-and-instantiating-structs.md:87 +#: src/ch04-01-defining-and-instantiating-structs.md:112 msgid "" "It makes sense to name the function parameters with the same name as the struct fields, but having to repeat the `email` and `username` field names and variables is a bit tedious. If " "the struct had more fields, repeating each name would get even more annoying. Luckily, there’s a convenient shorthand!" @@ -5900,11 +6132,11 @@ msgstr "" "Tiene sentido nombrar los parámetros de la función con el mismo nombre que los campos de la estructura, porque tener que repetir los nombres y variables de los campos `email`y " "`username` es un poco tedioso. Si la estructura tuviera más campos, repetir cada nombre sería aún más molesto. ¡Afortunadamente, hay una forma abreviada!" -#: src/ch04-01-defining-and-instantiating-structs.md:89 +#: src/ch04-01-defining-and-instantiating-structs.md:114 msgid "## Using the Field Init Shorthand" msgstr "## Usando la Abreviatura Field Init" -#: src/ch04-01-defining-and-instantiating-structs.md:91 +#: src/ch04-01-defining-and-instantiating-structs.md:116 msgid "" "Because the parameter names and the struct field names are exactly the same in Listing 4-4, we can use the field init shorthand syntax to rewrite `build_user` so it behaves exactly " "the same but doesn’t have the repetition of `username` and `email`, as shown in Listing 4-5." @@ -5912,38 +6144,66 @@ msgstr "" "Como los nombres de los parámetros y los nombres de los campos struct son exactamente los mismos en el Listado 4-4, podemos usar la sintaxis abreviada de field init para reescribir " "`build_user` de forma que se comporte exactamente igual pero sin la repetición de `username` y `email`, como se muestra en el Listado 4-5." -#: src/ch04-01-defining-and-instantiating-structs.md:95 -msgid "" -"```rust\n" -"fn build_user(email: felt252, username: felt252) -> User {\n" -" User {\n" -" active: true,\n" -" username,\n" -" email,\n" -" sign_in_count: 1_u64,\n" -" }\n" -"}\n" -"```" -msgstr "" -"```rust\n" -"fn build_user(email: felt252, username: felt252) -> User {\n" -" User {\n" -" active: true,\n" -" username,\n" -" email,\n" -" sign_in_count: 1_u64,\n" -" }\n" -"}\n" -"```" - -#: src/ch04-01-defining-and-instantiating-structs.md:106 +#: src/ch04-01-defining-and-instantiating-structs.md:120 +msgid "" +"```rust\n" +"# #[derive(Copy, Drop)]\n" +"# struct User {\n" +"# active: bool,\n" +"# username: felt252,\n" +"# email: felt252,\n" +"# sign_in_count: u64,\n" +"# }\n" +"# fn main() {\n" +"# let mut user1 = User {\n" +"# active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" +"# };\n" +"# user1.email = 'anotheremail@example.com';\n" +"# }\n" +"# \n" +"# fn build_user(email: felt252, username: felt252) -> User {\n" +"# User { active: true, username: username, email: email, sign_in_count: 1, }\n" +"# }\n" +"# \n" +"fn build_user_short(email: felt252, username: felt252) -> User {\n" +" User { active: true, username, email, sign_in_count: 1, }\n" +"}\n" +"# \n" +"```" +msgstr "" +"```rust\n" +"# #[derive(Copy, Drop)]\n" +"# struct User {\n" +"# active: bool,\n" +"# username: felt252,\n" +"# email: felt252,\n" +"# sign_in_count: u64,\n" +"# }\n" +"# fn main() {\n" +"# let mut user1 = User {\n" +"# active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" +"# };\n" +"# user1.email = 'anotheremail@example.com';\n" +"# }\n" +"# \n" +"# fn build_user(email: felt252, username: felt252) -> User {\n" +"# User { active: true, username: username, email: email, sign_in_count: 1, }\n" +"# }\n" +"# \n" +"fn build_user_short(email: felt252, username: felt252) -> User {\n" +" User { active: true, username, email, sign_in_count: 1, }\n" +"}\n" +"# \n" +"```" + +#: src/ch04-01-defining-and-instantiating-structs.md:145 msgid "" "Listing 4-5: A `build_user` function that uses field init shorthand because the `username` and `email` parameters have the same name as struct fields" msgstr "" "Lista 4-5: Una función `build_user` que utiliza la abreviatura field init porque los parámetros `username` y `email` tienen el mismo nombre que los campos " "struct" -#: src/ch04-01-defining-and-instantiating-structs.md:108 +#: src/ch04-01-defining-and-instantiating-structs.md:147 msgid "" "Here, we’re creating a new instance of the `User` struct, which has a field named `email`. We want to set the `email` field’s value to the value in the `email` parameter of the " "`build_user` function. Because the `email` field and the `email` parameter have the same name, we only need to write `email` rather than `email: email`." @@ -5976,8 +6236,8 @@ msgid "" "```rust\n" "use debug::PrintTrait;\n" "fn main() {\n" -" let width1 = 30_u64;\n" -" let height1 = 10_u64;\n" +" let width1 = 30;\n" +" let height1 = 10;\n" " let area = area(width1, height1);\n" " area.print();\n" "}\n" @@ -5990,8 +6250,8 @@ msgstr "" "```rust\n" "use debug::PrintTrait;\n" "fn main() {\n" -" let width1 = 30_u64;\n" -" let height1 = 10_u64;\n" +" let width1 = 30;\n" +" let height1 = 10;\n" " let area = area(width1, height1);\n" " area.print();\n" "}\n" @@ -6066,13 +6326,13 @@ msgid "" "```rust\n" "use debug::PrintTrait;\n" "fn main() {\n" -" let rectangle = (30_u64, 10_u64);\n" +" let rectangle = (30, 10);\n" " let area = area(rectangle);\n" " area.print(); // print out the area\n" "}\n" "\n" "fn area(dimension: (u64, u64)) -> u64 {\n" -" let (x,y) = dimension;\n" +" let (x, y) = dimension;\n" " x * y\n" "}\n" "```" @@ -6080,13 +6340,13 @@ msgstr "" "```rust\n" "use debug::PrintTrait;\n" "fn main() {\n" -" let rectangle = (30_u64, 10_u64);\n" +" let rectangle = (30, 10);\n" " let area = area(rectangle);\n" " area.print(); // print out the area\n" "}\n" "\n" "fn area(dimension: (u64, u64)) -> u64 {\n" -" let (x,y) = dimension;\n" +" let (x, y) = dimension;\n" " x * y\n" "}\n" "```" @@ -6125,7 +6385,7 @@ msgstr "" #: src/ch04-02-an-example-program-using-structs.md:76 msgid "" -"```rust\n" +"```rust,ignore_format\n" "use debug::PrintTrait;\n" "\n" "struct Rectangle {\n" @@ -6134,10 +6394,7 @@ msgid "" "}\n" "\n" "fn main() {\n" -" let rectangle = Rectangle {\n" -" width: 30_u64,\n" -" height: 10_u64,\n" -" };\n" +" let rectangle = Rectangle { width: 30, height: 10, };\n" " let area = area(rectangle);\n" " area.print(); // print out the area\n" "}\n" @@ -6147,7 +6404,7 @@ msgid "" "}\n" "```" msgstr "" -"```rust\n" +"```rust,ignore_format\n" "use debug::PrintTrait;\n" "\n" "struct Rectangle {\n" @@ -6156,10 +6413,7 @@ msgstr "" "}\n" "\n" "fn main() {\n" -" let rectangle = Rectangle {\n" -" width: 30_u64,\n" -" height: 10_u64,\n" -" };\n" +" let rectangle = Rectangle { width: 30, height: 10, };\n" " let area = area(rectangle);\n" " area.print(); // print out the area\n" "}\n" @@ -6169,11 +6423,11 @@ msgstr "" "}\n" "```" -#: src/ch04-02-an-example-program-using-structs.md:98 +#: src/ch04-02-an-example-program-using-structs.md:95 msgid "Listing 4-8: Defining a `Rectangle` struct" msgstr "Listado 4-8: Definición de una estructura llamada `Rectangle`" -#: src/ch04-02-an-example-program-using-structs.md:100 +#: src/ch04-02-an-example-program-using-structs.md:97 msgid "" "Here we’ve defined a struct and named it `Rectangle`. Inside the curly brackets, we defined the fields as `width` and `height`, both of which have type `u64`. Then, in `main`, we " "created a particular instance of `Rectangle` that has a width of `30` and a height of `10`. Our `area` function is now defined with one parameter, which we’ve named `rectangle` which " @@ -6185,11 +6439,11 @@ msgstr "" "llamado `rectangle` que es de tipo de la estructura `Rectangle`. Luego podemos acceder a los campos de la instancia con notación de punto, y dar nombres descriptivos a los valores en " "lugar de usar los valores de índice de tupla de `0` y `1`." -#: src/ch04-02-an-example-program-using-structs.md:102 +#: src/ch04-02-an-example-program-using-structs.md:99 msgid "## Adding Useful Functionality with Trait" msgstr "## Agregando Funcionalidades Útiles con Trait" -#: src/ch04-02-an-example-program-using-structs.md:104 +#: src/ch04-02-an-example-program-using-structs.md:101 msgid "" "It’d be useful to be able to print an instance of `Rectangle` while we’re debugging our program and see the values for all its fields. Listing 4-9 tries using the `print` as we have " "used in previous chapters. This won’t work." @@ -6197,9 +6451,9 @@ msgstr "" "Sería útil poder imprimir una instancia de `Rectangle` mientras estamos depurando nuestro programa y ver los valores de todos sus campos. El Listado 4-9 intenta usar `print` como lo " "hemos usado en capítulos anteriores. Esto no funcionará." -#: src/ch04-02-an-example-program-using-structs.md:108 +#: src/ch04-02-an-example-program-using-structs.md:105 msgid "" -"```rust,does_not_compile\n" +"```rust\n" "use debug::PrintTrait;\n" "\n" "struct Rectangle {\n" @@ -6208,15 +6462,12 @@ msgid "" "}\n" "\n" "fn main() {\n" -" let rectangle = Rectangle {\n" -" width: 30_u64,\n" -" height: 10_u64,\n" -" };\n" +" let rectangle = Rectangle { width: 30, height: 10, };\n" " rectangle.print();\n" "}\n" "```" msgstr "" -"```rust,does_not_compile\n" +"```rust\n" "use debug::PrintTrait;\n" "\n" "struct Rectangle {\n" @@ -6225,23 +6476,20 @@ msgstr "" "}\n" "\n" "fn main() {\n" -" let rectangle = Rectangle {\n" -" width: 30_u64,\n" -" height: 10_u64,\n" -" };\n" +" let rectangle = Rectangle { width: 30, height: 10, };\n" " rectangle.print();\n" "}\n" "```" -#: src/ch04-02-an-example-program-using-structs.md:125 +#: src/ch04-02-an-example-program-using-structs.md:119 msgid "Listing 4-9: Attempting to print a `Rectangle` instance" msgstr "Listado 4-9: Intentando imprimir una instancia de `Rectangle`" -#: src/ch04-02-an-example-program-using-structs.md:127 +#: src/ch04-02-an-example-program-using-structs.md:121 msgid "When we compile this code, we get an error with this message:" msgstr "Cuando compilamos este código, obtenemos un error con el siguiente mensaje:" -#: src/ch04-02-an-example-program-using-structs.md:129 +#: src/ch04-02-an-example-program-using-structs.md:123 msgid "" "```bash\n" "$ cairo-compile src/lib.cairo\n" @@ -6263,7 +6511,7 @@ msgstr "" "Error: Compilation failed.\n" "```" -#: src/ch04-02-an-example-program-using-structs.md:139 +#: src/ch04-02-an-example-program-using-structs.md:133 msgid "" "The `print` trait is implemented for many data types, but not for the `Rectangle` struct. We can fix this by implementing the `PrintTrait` trait on `Rectangle` as shown in Listing " "4-10.\n" @@ -6273,9 +6521,9 @@ msgstr "" "`Rectangle` como se muestra en el Listado 4-10.\n" "Para aprender más sobre traits,[Traits en Cairo](ch07-02-traits-in-cairo.md)." -#: src/ch04-02-an-example-program-using-structs.md:144 +#: src/ch04-02-an-example-program-using-structs.md:138 msgid "" -"```rust\n" +"```rust,ignore_format\n" "use debug::PrintTrait;\n" "\n" "struct Rectangle {\n" @@ -6284,10 +6532,7 @@ msgid "" "}\n" "\n" "fn main() {\n" -" let rectangle = Rectangle {\n" -" width: 30_u64,\n" -" height: 10_u64,\n" -" };\n" +" let rectangle = Rectangle { width: 30, height: 10, };\n" " rectangle.print();\n" "}\n" "\n" @@ -6299,7 +6544,7 @@ msgid "" "}\n" "```" msgstr "" -"```rust\n" +"```rust,ignore_format\n" "use debug::PrintTrait;\n" "\n" "struct Rectangle {\n" @@ -6308,10 +6553,7 @@ msgstr "" "}\n" "\n" "fn main() {\n" -" let rectangle = Rectangle {\n" -" width: 30_u64,\n" -" height: 10_u64,\n" -" };\n" +" let rectangle = Rectangle { width: 30, height: 10, };\n" " rectangle.print();\n" "}\n" "\n" @@ -6323,11 +6565,11 @@ msgstr "" "}\n" "```" -#: src/ch04-02-an-example-program-using-structs.md:168 +#: src/ch04-02-an-example-program-using-structs.md:159 msgid "Listing 4-10: Implementing the `PrintTrait` trait on `Rectangle`" msgstr "Listado 4-10: Implementación del trait `PrintTrait` en `Rectangle`" -#: src/ch04-02-an-example-program-using-structs.md:170 +#: src/ch04-02-an-example-program-using-structs.md:161 msgid "Nice! It’s not the prettiest output, but it shows the values of all the fields for this instance, which would definitely help during debugging." msgstr "¡Bien! No es el resultado más bonito, pero muestra los valores de todos los campos para esta instancia, lo que definitivamente ayudaría durante la depuración." @@ -6363,11 +6605,11 @@ msgstr "### Definición de Détodos" msgid "" "Let’s change the `area` function that has a `Rectangle` instance as a parameter\n" "and instead make an `area` method defined on the `RectangleTrait` trait, as shown\n" -"in Listing 5-13." +"in Listing 4-13." msgstr "" "Cambiemos la función `area` que tiene una instancia `Rectangle` como parámetro\n" -"y en su lugar hagamos un método `area` definido en el trait `RectangleTrait`, como se muestra\n" -" en el Listado 5-13." +"y en su lugar hagamos un método `area` definido en el rasgo `RectangleTrait`, como se muestra en el Listado 4-13.\n" +"en el Listado 4-13." #: src/ch04-03-method-syntax.md:20 msgid "" @@ -6390,7 +6632,7 @@ msgid "" "}\n" "\n" "fn main() {\n" -" let rect1 = Rectangle { width: 30_u64, height: 50_u64, };\n" +" let rect1 = Rectangle { width: 30, height: 50, };\n" "\n" " rect1.area().print();\n" "}\n" @@ -6415,7 +6657,7 @@ msgstr "" "}\n" "\n" "fn main() {\n" -" let rect1 = Rectangle { width: 30_u64, height: 50_u64, };\n" +" let rect1 = Rectangle { width: 30, height: 50, };\n" "\n" " rect1.area().print();\n" "}\n" @@ -6431,7 +6673,7 @@ msgstr "" #: src/ch04-03-method-syntax.md:48 msgid "" -"To define the function within the context of `Rectangle`, we start by definining a `trait`\n" +"To define the function within the context of `Rectangle`, we start by defining a `trait`\n" "block with the signature of the method that we want to implement. Traits are not linked to\n" "a specific type; only the `self` parameter of the method defines which type it can be used\n" "with. Then, we define an `impl` (implementation) block for `RectangleTrait`, that defines\n" @@ -6447,20 +6689,21 @@ msgid "" "instance. The method syntax goes after an instance: we add a dot followed by\n" "the method name, parentheses, and any arguments." msgstr "" -"Para definir la función dentro del contexto de `Rectangle`, comenzamos definiendo un `trait` \n" -"con la declaración del método que queremos implementar. Los *Traits* no están vinculados a un\n" -" tipo específico; solo el parámetro `self` del método define qué tipo se puede usar con dicho *trait*. \n" -"Luego, definimos un bloque con la palabra clave `impl` para `RectangleTrait`, que define el \n" -"comportamiento de los métodos implementados. Todo dentro de este bloque `impl` será asociado con \n" -"el tipo del parámetro `self` del método llamado. Si bien es técnicamente posible definir métodos para \n" -"múltiples tipos dentro del mismo bloque `impl`, no es una práctica recomendada, ya que puede producir\n" -" una confusión. Recomendamos que el tipo del parámetro `self` permanece consistente dentro del mismo\n" -" bloque `impl`. \n" -"Luego movemos la función `area` dentro de los corchetes `impl` y cambiamos el primer (y en\n" -" este caso, único) parámetro para ser `self` en la declaración y en todas partes dentro del cuerpo. En `main`,\n" -" donde llamamos a la función `area` y pasamos `rect1` como argumento, en su lugar, podemos usar la _sintaxis \n" -"del método_ para llamar al método `area` en nuestra instancia del `Rectangle`. La sintaxis del método va \n" -"después de una instancia: agregamos un punto seguido del nombre del método, los paréntesis y los argumentos." +"Para definir la función en el contexto de `Rectangle`, empezamos definiendo un bloque `trait`\n" +"con la firma del método que queremos implementar. Los traits no están vinculados a\n" +"sólo el parámetro `self` del método define con qué tipo se puede utilizar.\n" +"puede utilizar. A continuación, definimos un bloque `impl` (implementación) para `RectangleTrait`, que define\n" +"el comportamiento de los métodos implementados. Todo dentro de este bloque `impl` será\n" +"asociado con el tipo del parámetro `self` del método llamado. Aunque técnicamente es posible\n" +"definir métodos para múltiples tipos dentro del mismo bloque `impl`, no es una\n" +"una práctica recomendada, ya que puede dar lugar a confusión. Recomendamos que el tipo del parámetro `self\n" +"sea consistente dentro del mismo bloque `impl`.\n" +"Entonces movemos la función `area` dentro de las llaves `impl` y cambiamos el primer (y en este caso, único) parámetro\n" +"para que sea `self` en la firma y en todo el cuerpo. En\n" +"donde llamamos a la función `area` y pasamos `rect1` como argumento,\n" +"podemos usar la sintaxis _method_ para llamar al método `area` en nuestra instancia `Rectangle`.\n" +"de nuestro `Rectángulo`. La sintaxis de método va después de una instancia: añadimos un punto seguido de\n" +"el nombre del método, los paréntesis y los argumentos." #: src/ch04-03-method-syntax.md:64 msgid "" @@ -6550,12 +6793,12 @@ msgid "" "\n" "impl RectangleImpl of RectangleTrait {\n" " fn width(self: @Rectangle) -> bool {\n" -" (*self.width) > 0_u64\n" +" (*self.width) > 0\n" " }\n" "}\n" "\n" "fn main() {\n" -" let rect1 = Rectangle { width: 30_u64, height: 50_u64, };\n" +" let rect1 = Rectangle { width: 30, height: 50, };\n" " rect1.width().print();\n" "}\n" "```" @@ -6574,12 +6817,12 @@ msgstr "" "\n" "impl RectangleImpl of RectangleTrait {\n" " fn width(self: @Rectangle) -> bool {\n" -" (*self.width) > 0_u64\n" +" (*self.width) > 0\n" " }\n" "}\n" "\n" "fn main() {\n" -" let rect1 = Rectangle { width: 30_u64, height: 50_u64, };\n" +" let rect1 = Rectangle { width: 30, height: 50, };\n" " rect1.width().print();\n" "}\n" "```" @@ -6610,12 +6853,14 @@ msgid "" "of `Rectangle` and return `true` if the second `Rectangle` can fit completely\n" "within `self` (the first `Rectangle`); otherwise, it should return `false`.\n" "That is, once we’ve defined the `can_hold` method, we want to be able to write\n" -"the program shown in Listing 5-14." +"the program shown in Listing 4-14." msgstr "" -"Practiquemos el uso de métodos implementando un segundo método en la estructura `Rectangle`. \n" -"Esta vez queremos que una instancia de `Rectangle` tome otra instancia de `Rectangle` y devolver \n" -"`true` si el segundo `Rectangle` puede caber completamente dentro de `self` (el primer `Rectangle`); \n" -"de lo contrario, debería devolver `false`. Es decir, una vez que hemos definido el método `can_hold`, queremos poder escribir el programa que se muestra en el Listado 5-14." +"Practiquemos el uso de métodos implementando un segundo método en la estructura `Rectangle`.\n" +"struct. Esta vez queremos que una instancia de `Rectangle` tome otra instancia de `Rectangle\n" +"de `Rectangle` y devuelva `true` si el segundo `Rectangle` cabe completamente dentro de\n" +"dentro de `self` (el primer `Rectangle`); en caso contrario, devolverá `false`.\n" +"Es decir, una vez que hemos definido el método `can_hold`, queremos ser capaces de escribir\n" +"el programa mostrado en el Listado 4-14." #: src/ch04-03-method-syntax.md:137 msgid "" @@ -6628,9 +6873,9 @@ msgid "" "}\n" "\n" "fn main() {\n" -" let rect1 = Rectangle { width: 30_u64, height: 50_u64, };\n" -" let rect2 = Rectangle { width: 10_u64, height: 40_u64, };\n" -" let rect3 = Rectangle { width: 60_u64, height: 45_u64, };\n" +" let rect1 = Rectangle { width: 30, height: 50, };\n" +" let rect2 = Rectangle { width: 10, height: 40, };\n" +" let rect3 = Rectangle { width: 60, height: 45, };\n" "\n" " 'Can rect1 hold rect2?'.print();\n" " rect1.can_hold(@rect2).print();\n" @@ -6649,9 +6894,9 @@ msgstr "" "}\n" "\n" "fn main() {\n" -" let rect1 = Rectangle { width: 30_u64, height: 50_u64, };\n" -" let rect2 = Rectangle { width: 10_u64, height: 40_u64, };\n" -" let rect3 = Rectangle { width: 60_u64, height: 45_u64, };\n" +" let rect1 = Rectangle { width: 30, height: 50, };\n" +" let rect2 = Rectangle { width: 10, height: 40, };\n" +" let rect3 = Rectangle { width: 60, height: 45, };\n" "\n" " 'Can rect1 hold rect2?'.print();\n" " rect1.can_hold(@rect2).print();\n" @@ -6663,9 +6908,11 @@ msgstr "" #: src/ch04-03-method-syntax.md:158 msgid "" -"Listing 5-14: Using the as-yet-unwritten `can_hold`\n" +"Listing 4-14: Using the as-yet-unwritten `can_hold`\n" "method" -msgstr "Listing 5-14: Usando el método todavia no escrito `can_hold`" +msgstr "" +"Listado 4-14: Utilizando el método `can_hold` \n" +"aún no escrito" #: src/ch04-03-method-syntax.md:161 msgid "" @@ -6717,24 +6964,24 @@ msgid "" "Boolean, and the implementation will check whether the width and height of\n" "`self` are greater than the width and height of the other `Rectangle`,\n" "respectively. Let’s add the new `can_hold` method to the `trait` and `impl` blocks from\n" -"Listing 5-13, shown in Listing 5-15." +"Listing 4-13, shown in Listing 4-15." msgstr "" -"Sabemos que queremos definir un método, así que estará dentro de los bloques `trait RectangleTrait` y `impl RectangleImpl of RectangleTrait`.\n" +"Sabemos que queremos definir un método, así que estará dentro de los bloques `trait RectangleTrait`\n" "y `impl RectangleImpl of RectangleTrait`.\n" "El nombre del método será `can_hold`, y tomará una instantánea\n" "de otro `Rectangle` como parámetro. Podemos saber cuál será el tipo del parámetro\n" -"parámetro mirando el código que llama al método:\n" +"mirando el código que llama al método:\n" "rect1.can_hold(@rect2)` pasa `@rect2`, que es una instantánea de\n" "`rect2`, una instancia de `Rectangle`. Esto tiene sentido porque sólo necesitamos\n" "leer `rect2` (en lugar de escribir, lo que significaría que necesitaríamos un préstamo mutable),\n" "y queremos que `main` conserve la propiedad de `rect2` para poder volver a usarla después de\n" -"después de llamar al método `can_hold`. El valor de retorno de `can_hold` será un booleano\n" +"llamar al método `can_hold`. El valor de retorno de `can_hold` será un booleano\n" "y la implementación comprobará si la anchura y la altura de\n" "`self` son mayores que la anchura y la altura del otro `Rectangle`,\n" "respectivamente. Añadamos el nuevo método `can_hold` a los bloques `trait` e `impl` de\n" -"Listado 5-13, mostrados en el Listado 5-15." +"Listado 4-13, mostrados en el Listado 4-15." -#: src/ch04-03-method-syntax.md:194 +#: src/ch04-03-method-syntax.md:194 src/ch08-01-how-to-write-tests.md:134 msgid "" "```rust\n" "trait RectangleTrait {\n" @@ -6772,21 +7019,23 @@ msgstr "" #: src/ch04-03-method-syntax.md:211 msgid "" -"Listing 5-15: Implementing the `can_hold` method on\n" +"Listing 4-15: Implementing the `can_hold` method on\n" "`Rectangle` that takes another `Rectangle` instance as a parameter" -msgstr "Listing 4-15: Implementación del método `can_hold` en `Rectangle` que recibe una instancia de `Rectangle` como parámetro" +msgstr "" +"Listado 4-15: Implementación del método `can_hold` en\n" +"`Rectangle` que toma otra instancia de `Rectangle` como parámetro" #: src/ch04-03-method-syntax.md:214 msgid "" -"When we run this code with the `main` function in Listing 5-14, we’ll get our\n" +"When we run this code with the `main` function in Listing 4-14, we’ll get our\n" "desired output. Methods can take multiple parameters that we add to the\n" "signature after the `self` parameter, and those parameters work just like\n" "parameters in functions." msgstr "" -"Cuando ejecutemos este código con la función `main` del Listado 5-14, obtendremos la salida deseada.\n" +"Cuando ejecutemos este código con la función `main` del Listado 4-14, obtendremos\n" "salida deseada. Los métodos pueden tomar múltiples parámetros que añadimos a la firma\n" -"después del parámetro `self`, y esos parámetros funcionan igual que los parámetros de las funciones.\n" -"en las funciones." +"después del parámetro `self`, y esos parámetros funcionan igual que los\n" +"parámetros en las funciones." #: src/ch04-03-method-syntax.md:219 msgid "### Accessing implementation functions" @@ -6843,18 +7092,18 @@ msgstr "" #: src/ch04-03-method-syntax.md:245 msgid "" "To call this function, we use the `::` syntax with the implementation name;\n" -"`let square = RectangleImpl::square(10_u64);` is an example. This function is namespaced by\n" +"`let square = RectangleImpl::square(10);` is an example. This function is namespaced by\n" "the implementation; the `::` syntax is used for both trait functions and\n" "namespaces created by modules. We’ll discuss modules in [Chapter 7][modules]." msgstr "" -"Para llamar a esta función, usamos la sintaxis `::` con el nombre de implementación; por ejemplo, \n" -"`let square = RectangleImpl::square(10_u64);`. Esta función está espaciada por la implementación: l\n" -"a sintaxis `::` se usa tanto para funciones del *trait* y espacios de nombres creados por módulos. \n" -"Lo discutiremos en el [Capítulo 7][modules]." +"Para llamar a esta función, usamos la sintaxis `::` con el nombre\n" +"de implementación; `let square = RectangleImpl::square(10);` es un ejemplo. Esta función está en el espacio de nombres \n" +"de la implementación; la sintaxis `::` se utiliza tanto para las funciones \n" +"de los traits como para los espacios de nombres creados por los módulos. Discutiremos los módulos en el [Capítulo 7][modules]." #: src/ch04-03-method-syntax.md:250 -msgid "> Note: It is also possible to call this function using the trait name, with `RectangleTrait::square(10_u64)`." -msgstr "> Nota: También es posible llamar a esta función usando el nombre del *trait*, con `RectangleTrait::square(10_u64)`." +msgid "> Note: It is also possible to call this function using the trait name, with `RectangleTrait::square(10)`." +msgstr "> Nota: También es posible llamar a esta función utilizando el nombre del trait, con `RectangleTrait::square(10)`." #: src/ch04-03-method-syntax.md:252 msgid "### Multiple `impl` Blocks" @@ -6863,12 +7112,12 @@ msgstr "### Multiples Bloques con `impl`" #: src/ch04-03-method-syntax.md:254 msgid "" "Each struct is allowed to have multiple `trait` and `impl` blocks. For example, Listing\n" -"5-15 is equivalent to the code shown in Listing 5-16, which has each method in\n" +"5-15 is equivalent to the code shown in Listing 4-16, which has each method in\n" "its own `trait` and `impl` blocks." msgstr "" -"Cada estructura tiene permitido tener múltiples bloques con `trait` e `impl`. Por ejemplo,\n" -" en el Listado 5-15 es equivalente al código mostrado en el Listado 5-16, que tiene cada método \n" -"en su propio bloque de `trait` e `impl`." +"Cada estructura puede tener múltiples bloques `trait` e `impl`. Por ejemplo, el Listado \n" +"5-15 es equivalente al código mostrado en el Listado 4-16, que tiene cada método en\n" +"sus propios bloques `trait` e `impl`." #: src/ch04-03-method-syntax.md:258 msgid "" @@ -6916,9 +7165,9 @@ msgstr "" #: src/ch04-03-method-syntax.md:279 msgid "" -"Listing 5-16: Rewriting Listing 5-15 using multiple `impl`\n" +"Listing 4-16: Rewriting Listing 4-15 using multiple `impl`\n" "blocks" -msgstr "Listado 5-16: Reescribiendo el Listado 5-15 usando múltiples bloques de `impl`" +msgstr "Listado 4-16: Reescribiendo el Listado 4-15 usando múltiples bloques `impl`" #: src/ch04-03-method-syntax.md:282 msgid "" @@ -6978,7 +7227,7 @@ msgstr "Aquí hay un ejemplo sencillo de un enum:" #: src/ch05-01-enums.md:9 msgid "" -"```rs\n" +"```rust\n" "#[derive(Drop)]\n" "enum Direction {\n" " North: (),\n" @@ -6986,10 +7235,9 @@ msgid "" " South: (),\n" " West: (),\n" "}\n" -"\n" "```" msgstr "" -"```rs\n" +"```rust\n" "#[derive(Drop)]\n" "enum Direction {\n" " North: (),\n" @@ -6997,10 +7245,9 @@ msgstr "" " South: (),\n" " West: (),\n" "}\n" -"\n" "```" -#: src/ch05-01-enums.md:20 +#: src/ch05-01-enums.md:19 msgid "" "Unlike other languages like Rust, every variant has a type. In this example, we've defined an enum called `Direction` with four variants: `North`, `East`, `South`, and `West`. The " "naming convention is to use PascalCase for enum variants. Each variant represents a distinct value of the Direction type and is associated with a unit type `()`. One variant can be " @@ -7010,57 +7257,81 @@ msgstr "" "`West`. La convención de nomenclatura es utilizar PascalCase para las variantes del enum. Cada variante representa un valor distinto del tipo `Direction` y está asociada con un tipo " "unitario `()`. Una variante puede ser instanciada utilizando esta sintaxis:" -#: src/ch05-01-enums.md:22 +#: src/ch05-01-enums.md:21 msgid "" -"```rs\n" -"let direction = Direction::North(());\n" +"```rust\n" +"# #[derive(Drop)]\n" +"# enum Direction {\n" +"# North: (),\n" +"# East: (),\n" +"# South: (),\n" +"# West: (),\n" +"# }\n" +"# \n" +"# fn main() {\n" +" let direction = Direction::North(());\n" +"# }\n" +"# \n" +"# \n" "```" msgstr "" -"```rs\n" -"let direction = Direction::North(());\n" +"```rust\n" +"# #[derive(Drop)]\n" +"# enum Direction {\n" +"# North: (),\n" +"# East: (),\n" +"# South: (),\n" +"# West: (),\n" +"# }\n" +"# \n" +"# fn main() {\n" +" let direction = Direction::North(());\n" +"# }\n" +"# \n" +"# \n" "```" -#: src/ch05-01-enums.md:26 +#: src/ch05-01-enums.md:37 msgid "" "It's easy to write code that acts differently depending on the variant of an enum instance, in this example to run specific code according to a Direction. You can learn more about it " -"on the [The Match Control Flow Construct page](ch05-02-the-match-control-flow-construct.md)." +"on [The Match Control Flow Construct page](ch05-02-the-match-control-flow-construct.md)." msgstr "" -"Es fácil escribir código que se comporte de manera diferente según la variante de una instancia de un enum, como en este ejemplo, donde se ejecuta un código específico según una " -"dirección. Puedes obtener más información sobre esto en la página [The Match Control Flow Construct](ch05-02-the-match-control-flow-construct.md)." +"Es fácil escribir código que se comporte de manera diferente según la variante de una instancia de enum, en este ejemplo para ejecutar código específico según una dirección " +"(`Direction`). Puedes obtener más información al respecto en la página [La construcción de flujo de control Match](ch05-02-the-match-control-flow-construct.md)." -#: src/ch05-01-enums.md:28 +#: src/ch05-01-enums.md:39 msgid "## Enums Combined with Custom Types" msgstr "## Enums combinados con Tipos Personalizados" -#: src/ch05-01-enums.md:30 +#: src/ch05-01-enums.md:41 msgid "Enums can also be used to store more interesting data associated with each variant. For example:" msgstr "Los enums también pueden ser utilizados para almacenar datos más interesantes asociados con cada variante. Por ejemplo:" -#: src/ch05-01-enums.md:32 +#: src/ch05-01-enums.md:43 msgid "" -"```rs\n" +"```rust\n" "#[derive(Drop)]\n" "enum Message {\n" -" Quit : (),\n" -" Echo : felt252,\n" -" Move : (u128, u128),\n" +" Quit: (),\n" +" Echo: felt252,\n" +" Move: (u128, u128),\n" "}\n" "```" msgstr "" -"```rs\n" +"```rust\n" "#[derive(Drop)]\n" "enum Message {\n" -" Quit : (),\n" -" Echo : felt252,\n" -" Move : (u128, u128),\n" +" Quit: (),\n" +" Echo: felt252,\n" +" Move: (u128, u128),\n" "}\n" "```" -#: src/ch05-01-enums.md:41 +#: src/ch05-01-enums.md:52 msgid "In this example, the `Message` enum has three variants: `Quit`, `Echo` and `Move`, all with different types:" msgstr "En este ejemplo, el enum `Message` tiene tres variantes: `Quit`, `Echo` y `Move`, todas con tipos diferentes:" -#: src/ch05-01-enums.md:43 +#: src/ch05-01-enums.md:54 msgid "" "- `Quit` is the unit type - it has no data associated with it at all.\n" "- `Echo` is a single felt.\n" @@ -7070,15 +7341,15 @@ msgstr "" "- `Echo` incluye un solo campo.\n" "- `Move` incluye dos valores u128." -#: src/ch05-01-enums.md:47 +#: src/ch05-01-enums.md:58 msgid "You could even use a Struct or another Enum you defined inside one of your Enum variants." msgstr "Incluso puedes usar una estructura o otro enum que hayas definido dentro de una de las variantes de tu enum." -#: src/ch05-01-enums.md:49 +#: src/ch05-01-enums.md:60 msgid "## Trait Implementations for Enums" msgstr "## Implementaciones de Traits para Enums" -#: src/ch05-01-enums.md:51 +#: src/ch05-01-enums.md:62 msgid "" "In Cairo, you can define traits and implement them for your custom enums. This allows you to define methods and behaviors associated with the enum. Here's an example of defining a " "trait and implementing it for the previous `Message` enum:" @@ -7086,7 +7357,7 @@ msgstr "" "En Cairo, puedes definir traits e implementarlos para tus enums personalizados. Esto te permite definir métodos y comportamientos asociados con el enum. Aquí hay un ejemplo de cómo " "definir un trait e implementarlo para el enum `Message` anterior:" -#: src/ch05-01-enums.md:53 +#: src/ch05-01-enums.md:64 msgid "" "```rs\n" "trait Processing {\n" @@ -7132,31 +7403,93 @@ msgstr "" "}\n" "```" -#: src/ch05-01-enums.md:75 +#: src/ch05-01-enums.md:86 msgid "In this example, we implemented the `Processing` trait for `Message`. Here is how it could be used to process a Quit message:" msgstr "En este ejemplo, implementamos el trait `Processing` para `Message`. Así es cómo podría ser utilizado para procesar un mensaje Quit:" -#: src/ch05-01-enums.md:77 +#: src/ch05-01-enums.md:88 msgid "" "```rust\n" -"let msg: Message = Message::Quit(());\n" -"msg.process();\n" -"```" -msgstr "" -"```rust\n" -"let msg: Message = Message::Quit(());\n" -"msg.process();\n" -"```" - -#: src/ch05-01-enums.md:82 +"# use debug::PrintTrait;\n" +"# #[derive(Drop)]\n" +"# enum Message {\n" +"# Quit: (),\n" +"# Echo: felt252,\n" +"# Move: (u128, u128),\n" +"# }\n" +"# \n" +"# trait Processing {\n" +"# fn process(self: Message);\n" +"# }\n" +"# \n" +"# impl ProcessingImpl of Processing {\n" +"# fn process(self: Message) {\n" +"# match self {\n" +"# Message::Quit(()) => {\n" +"# 'quitting'.print();\n" +"# },\n" +"# Message::Echo(value) => {\n" +"# value.print();\n" +"# },\n" +"# Message::Move((x, y)) => {\n" +"# 'moving'.print();\n" +"# },\n" +"# }\n" +"# }\n" +"# }\n" +"# fn main() {\n" +" let msg: Message = Message::Quit(());\n" +" msg.process();\n" +"# }\n" +"# \n" +"# \n" +"```" +msgstr "" +"```rust\n" +"# use debug::PrintTrait;\n" +"# #[derive(Drop)]\n" +"# enum Message {\n" +"# Quit: (),\n" +"# Echo: felt252,\n" +"# Move: (u128, u128),\n" +"# }\n" +"# \n" +"# trait Processing {\n" +"# fn process(self: Message);\n" +"# }\n" +"# \n" +"# impl ProcessingImpl of Processing {\n" +"# fn process(self: Message) {\n" +"# match self {\n" +"# Message::Quit(()) => {\n" +"# 'quitting'.print();\n" +"# },\n" +"# Message::Echo(value) => {\n" +"# value.print();\n" +"# },\n" +"# Message::Move((x, y)) => {\n" +"# 'moving'.print();\n" +"# },\n" +"# }\n" +"# }\n" +"# }\n" +"# fn main() {\n" +" let msg: Message = Message::Quit(());\n" +" msg.process();\n" +"# }\n" +"# \n" +"# \n" +"```" + +#: src/ch05-01-enums.md:124 msgid "Running this code would print `quitting`." msgstr "Al ejecutar este código se imprimiría `quitting`." -#: src/ch05-01-enums.md:84 +#: src/ch05-01-enums.md:126 msgid "## The Option Enum and Its Advantages" msgstr "## El Enum Option y sus Ventajas" -#: src/ch05-01-enums.md:86 +#: src/ch05-01-enums.md:128 msgid "" "The Option enum is a standard Cairo enum that represents the concept of an optional value. It has two variants: `Some: T` and `None: ()`. `Some: T ` indicates that there's a value of " "type `T`, while `None` represents the absence of a value." @@ -7164,23 +7497,23 @@ msgstr "" "El enum Option es un enum estándar en Cairo que representa el concepto de un valor opcional. Tiene dos variantes: `Some: T` y `None: ()`. `Some: T` indica que hay un valor de tipo " "`T`, mientras que `None` representa la ausencia de un valor." -#: src/ch05-01-enums.md:88 +#: src/ch05-01-enums.md:130 src/ch05-02-the-match-control-flow-construct.md:136 src/ch07-01-generic-data-types.md:174 msgid "" -"```rs\n" +"```rust\n" "enum Option {\n" " Some: T,\n" " None: (),\n" "}\n" "```" msgstr "" -"```rs\n" +"```rust\n" "enum Option {\n" " Some: T,\n" " None: (),\n" "}\n" "```" -#: src/ch05-01-enums.md:95 +#: src/ch05-01-enums.md:137 msgid "" "The `Option` enum is helpful because it allows you to explicitly represent the possibility of a value being absent, making your code more expressive and easier to reason about. Using " "`Option` can also help prevent bugs caused by using uninitialized or unexpected `null` values." @@ -7188,15 +7521,15 @@ msgstr "" "El enum `Option` es útil porque te permite representar explícitamente la posibilidad de que un valor esté ausente, lo que hace que tu código sea más expresivo y fácil de entender. " "Usar `Option` también puede ayudar a prevenir errores causados por el uso de valores `null` no inicializados o inesperados." -#: src/ch05-01-enums.md:97 +#: src/ch05-01-enums.md:139 msgid "To give you an example, here is a function which returns the index of the first element of an array with a given value, or None if the element is not present." msgstr "Para darte un ejemplo, aquí hay una función que devuelve el índice del primer elemento de un arreglo con un valor dado, o `None` si el elemento no está presente." -#: src/ch05-01-enums.md:99 +#: src/ch05-01-enums.md:141 msgid "We are demonstrating two approaches for the above function:" msgstr "Estamos demostrando dos enfoques para la función anterior:" -#: src/ch05-01-enums.md:101 +#: src/ch05-01-enums.md:143 msgid "" "- Recursive Approach `find_value_recursive`\n" "- Iterative Approach `find_value_iterative`" @@ -7204,25 +7537,17 @@ msgstr "" "- Método recursivo `find_value_recursive`\n" "- Método iterativo find_value_iterative" -#: src/ch05-01-enums.md:104 +#: src/ch05-01-enums.md:146 msgid "> Note: in the future it would be nice to replace this example by something simpler using a loop and without gas related code." msgstr "> Nota: en el futuro sería bueno reemplazar este ejemplo con algo más simple que use un ciclo y sin código relacionado con el gas." -#: src/ch05-01-enums.md:106 +#: src/ch05-01-enums.md:148 msgid "" "```rust\n" "use array::ArrayTrait;\n" "use debug::PrintTrait;\n" +"use option::OptionTrait;\n" "fn find_value_recursive(arr: @Array, value: felt252, index: usize) -> Option {\n" -" match gas::withdraw_gas() {\n" -" Option::Some(_) => {},\n" -" Option::None(_) => {\n" -" let mut data = ArrayTrait::new();\n" -" data.append('OOG');\n" -" panic(data);\n" -" },\n" -" }\n" -"\n" " if index >= arr.len() {\n" " return Option::None(());\n" " }\n" @@ -7231,12 +7556,12 @@ msgid "" " return Option::Some(index);\n" " }\n" "\n" -" find_value_recursive(arr, value, index + 1_usize)\n" +" find_value_recursive(arr, value, index + 1)\n" "}\n" "\n" "fn find_value_iterative(arr: @Array, value: felt252) -> Option {\n" " let length = arr.len();\n" -" let mut index = 0_usize;\n" +" let mut index = 0;\n" " let mut found: Option = Option::None(());\n" " loop {\n" " if index < length {\n" @@ -7247,7 +7572,7 @@ msgid "" " } else {\n" " break ();\n" " }\n" -" index += 1_usize;\n" +" index += 1;\n" " };\n" " return found;\n" "}\n" @@ -7262,13 +7587,12 @@ msgid "" " my_array.append(5);\n" "\n" " let value_to_find = 7;\n" -" let result = find_value_recursive(@my_array, value_to_find, 0_usize);\n" +" let result = find_value_recursive(@my_array, value_to_find, 0);\n" " let result_i = find_value_iterative(@my_array, value_to_find);\n" "\n" -"\n" " match result {\n" " Option::Some(index) => {\n" -" if index == 1_usize {\n" +" if index == 1 {\n" " 'it worked'.print();\n" " }\n" " },\n" @@ -7278,7 +7602,7 @@ msgid "" " }\n" " match result_i {\n" " Option::Some(index) => {\n" -" if index == 1_usize {\n" +" if index == 1 {\n" " 'it worked'.print();\n" " }\n" " },\n" @@ -7293,16 +7617,8 @@ msgstr "" "```rust\n" "use array::ArrayTrait;\n" "use debug::PrintTrait;\n" +"use option::OptionTrait;\n" "fn find_value_recursive(arr: @Array, value: felt252, index: usize) -> Option {\n" -" match gas::withdraw_gas() {\n" -" Option::Some(_) => {},\n" -" Option::None(_) => {\n" -" let mut data = ArrayTrait::new();\n" -" data.append('OOG');\n" -" panic(data);\n" -" },\n" -" }\n" -"\n" " if index >= arr.len() {\n" " return Option::None(());\n" " }\n" @@ -7311,12 +7627,12 @@ msgstr "" " return Option::Some(index);\n" " }\n" "\n" -" find_value_recursive(arr, value, index + 1_usize)\n" +" find_value_recursive(arr, value, index + 1)\n" "}\n" "\n" "fn find_value_iterative(arr: @Array, value: felt252) -> Option {\n" " let length = arr.len();\n" -" let mut index = 0_usize;\n" +" let mut index = 0;\n" " let mut found: Option = Option::None(());\n" " loop {\n" " if index < length {\n" @@ -7327,7 +7643,7 @@ msgstr "" " } else {\n" " break ();\n" " }\n" -" index += 1_usize;\n" +" index += 1;\n" " };\n" " return found;\n" "}\n" @@ -7342,13 +7658,12 @@ msgstr "" " my_array.append(5);\n" "\n" " let value_to_find = 7;\n" -" let result = find_value_recursive(@my_array, value_to_find, 0_usize);\n" +" let result = find_value_recursive(@my_array, value_to_find, 0);\n" " let result_i = find_value_iterative(@my_array, value_to_find);\n" "\n" -"\n" " match result {\n" " Option::Some(index) => {\n" -" if index == 1_usize {\n" +" if index == 1 {\n" " 'it worked'.print();\n" " }\n" " },\n" @@ -7358,7 +7673,7 @@ msgstr "" " }\n" " match result_i {\n" " Option::Some(index) => {\n" -" if index == 1_usize {\n" +" if index == 1 {\n" " 'it worked'.print();\n" " }\n" " },\n" @@ -7370,7 +7685,7 @@ msgstr "" "\n" "```" -#: src/ch05-01-enums.md:186 +#: src/ch05-01-enums.md:219 msgid "Running this code would print `it worked`." msgstr "Al ejecutar este código se imprimiría `it worked`." @@ -7502,44 +7817,24 @@ msgstr "" #: src/ch05-02-the-match-control-flow-construct.md:43 msgid "" "```rust\n" -"fn value_in_cents(coin: Coin) -> felt252 {\n" -" match coin {\n" -" Coin::Penny(_) => {\n" -" ('Lucky penny!').print();\n" -" 1\n" -" },\n" -" Coin::Nickel(_) => 5,\n" -" Coin::Dime(_) => 10,\n" -" Coin::Quarter(_)=> 25,\n" -" }\n" -"}\n" +"\n" "```" msgstr "" "```rust\n" -"fn value_in_cents(coin: Coin) -> felt252 {\n" -" match coin {\n" -" Coin::Penny(_) => {\n" -" ('Lucky penny!').print();\n" -" 1\n" -" },\n" -" Coin::Nickel(_) => 5,\n" -" Coin::Dime(_) => 10,\n" -" Coin::Quarter(_)=> 25,\n" -" }\n" -"}\n" +"\n" "```" -#: src/ch05-02-the-match-control-flow-construct.md:57 +#: src/ch05-02-the-match-control-flow-construct.md:47 msgid "## Patterns That Bind to Values" msgstr "## Patrones que se Vinculan con Valores" -#: src/ch05-02-the-match-control-flow-construct.md:59 +#: src/ch05-02-the-match-control-flow-construct.md:49 msgid "Another useful feature of match arms is that they can bind to the parts of the values that match the pattern. This is how we can extract values out of enum variants." msgstr "" "Otra característica útil de los brazos de coincidencia es que pueden vincularse con las partes de los valores que coinciden con el patrón. Así es como podemos extraer valores de las " "variantes de una enum." -#: src/ch05-02-the-match-control-flow-construct.md:61 +#: src/ch05-02-the-match-control-flow-construct.md:51 msgid "" "As an example, let’s change one of our enum variants to hold data inside it. From 1999 through 2008, the United States minted quarters with different designs for each of the 50 " "states on one side. No other coins got state designs, so only quarters have this extra value. We can add this information to our `enum` by changing the `Quarter` variant to include a " @@ -7549,7 +7844,7 @@ msgstr "" "25 centavos con diseños diferentes para cada uno de los 50 estados en un lado. Ninguna otra moneda tenía diseños estatales, por lo que solo los cuartos tienen este valor adicional. " "Podemos agregar esta información a nuestra `enum` cambiando la variante `Quarter` para incluir un valor `UsState` almacenado en su interior, lo cual hemos hecho en la Lista 5-4." -#: src/ch05-02-the-match-control-flow-construct.md:63 +#: src/ch05-02-the-match-control-flow-construct.md:53 msgid "" "```rust\n" "#[derive(Drop)]\n" @@ -7563,7 +7858,7 @@ msgid "" " Penny: (),\n" " Nickel: (),\n" " Dime: (),\n" -" Quarter: (UsState),\n" +" Quarter: (UsState, ),\n" "}\n" "```" msgstr "" @@ -7579,15 +7874,15 @@ msgstr "" " Penny: (),\n" " Nickel: (),\n" " Dime: (),\n" -" Quarter: (UsState),\n" +" Quarter: (UsState, ),\n" "}\n" "```" -#: src/ch05-02-the-match-control-flow-construct.md:79 +#: src/ch05-02-the-match-control-flow-construct.md:69 msgid "Listing 5-4: A `Coin` enum in which the `Quarter` variant also holds a `UsState` value" msgstr "Listado 5-4: Un enum `Coin` en el que la variante `Quarter` también tiene un valor `UsState`" -#: src/ch05-02-the-match-control-flow-construct.md:81 +#: src/ch05-02-the-match-control-flow-construct.md:71 msgid "" "Let’s imagine that a friend is trying to collect all 50 state quarters. While we sort our loose change by coin type, we’ll also call out the name of the state associated with each " "quarter so that if it’s one our friend doesn’t have, they can add it to their collection." @@ -7595,7 +7890,7 @@ msgstr "" "Imaginemos que un amigo está tratando de recolectar todas las 50 monedas de cuarto de estado. Mientras clasificamos nuestro cambio suelto por tipo de moneda, también llamaremos el " "nombre del estado asociado con cada cuarto para que si es uno que nuestro amigo no tiene, puedan agregarlo a su colección." -#: src/ch05-02-the-match-control-flow-construct.md:83 +#: src/ch05-02-the-match-control-flow-construct.md:73 msgid "" "In the match expression for this code, we add a variable called `state` to the pattern that matches values of the variant `Coin::Quarter`. When a `Coin::Quarter` matches, the `state` " "variable will bind to the value of that quarter’s state. Then we can use `state` in the code for that arm, like so:" @@ -7603,7 +7898,7 @@ msgstr "" "En la expresión `match` de este código, agregamos una variable llamada `state` al patrón que coincide con los valores de la variante `Coin::Quarter`. Cuando se hace una coincidencia " "de `Coin::Quarter`, la variable `state` se vinculará al valor del estado de ese cuarto. Luego podemos usar `state` en el código para ese brazo, así:" -#: src/ch05-02-the-match-control-flow-construct.md:85 +#: src/ch05-02-the-match-control-flow-construct.md:75 msgid "" "```rust\n" "fn value_in_cents(coin: Coin) -> felt252 {\n" @@ -7611,7 +7906,7 @@ msgid "" " Coin::Penny(_) => 1,\n" " Coin::Nickel(_) => 5,\n" " Coin::Dime(_) => 10,\n" -" Coin::Quarter(state)=> {\n" +" Coin::Quarter(state) => {\n" " state.print();\n" " 25\n" " },\n" @@ -7625,7 +7920,7 @@ msgstr "" " Coin::Penny(_) => 1,\n" " Coin::Nickel(_) => 5,\n" " Coin::Dime(_) => 10,\n" -" Coin::Quarter(state)=> {\n" +" Coin::Quarter(state) => {\n" " state.print();\n" " 25\n" " },\n" @@ -7633,14 +7928,14 @@ msgstr "" "}\n" "```" -#: src/ch05-02-the-match-control-flow-construct.md:99 +#: src/ch05-02-the-match-control-flow-construct.md:89 msgid "To print the value of a variant of an enum in Cairo, we need to add an implementation for the `print` function for the `debug::PrintTrait`:" msgstr "Para imprimir el valor de una variante de un enum en Cairo, necesitamos agregar una implementación para la función `print` de `debug::PrintTrait`:" -#: src/ch05-02-the-match-control-flow-construct.md:101 +#: src/ch05-02-the-match-control-flow-construct.md:91 msgid "" "```rust\n" -"impl UsStatePrintImpl of PrintTrait:: {\n" +"impl UsStatePrintImpl of PrintTrait {\n" " fn print(self: UsState) {\n" " match self {\n" " UsState::Alabama(_) => ('Alabama').print(),\n" @@ -7651,7 +7946,7 @@ msgid "" "```" msgstr "" "```rust\n" -"impl UsStatePrintImpl of PrintTrait:: {\n" +"impl UsStatePrintImpl of PrintTrait {\n" " fn print(self: UsState) {\n" " match self {\n" " UsState::Alabama(_) => ('Alabama').print(),\n" @@ -7661,7 +7956,7 @@ msgstr "" "}\n" "```" -#: src/ch05-02-the-match-control-flow-construct.md:112 +#: src/ch05-02-the-match-control-flow-construct.md:102 msgid "" "If we were to call `value_in_cents(Coin::Quarter(UsState::Alaska(())))`, `coin` would be `Coin::Quarter(UsState::Alaska())`. When we compare that value with each of the match arms, " "none of them match until we reach `Coin::Quarter(state)`. At that point, the binding for state will be the value `UsState::Alaska()`. We can then use that binding in the " @@ -7671,11 +7966,11 @@ msgstr "" "`match`, ninguno coincide hasta que llegamos a `Coin::Quarter (state)`. En ese momento, la asignación para `state` será el valor `UsState::Alaska()`. Luego podemos usar esa " "asignación en el `PrintTrait`, obteniendo así el valor interno de estado fuera de la variante `Coin` para `Quarter`." -#: src/ch05-02-the-match-control-flow-construct.md:114 +#: src/ch05-02-the-match-control-flow-construct.md:104 msgid "## Matching with Options" msgstr "## Coincidencia Con Opciones" -#: src/ch05-02-the-match-control-flow-construct.md:116 +#: src/ch05-02-the-match-control-flow-construct.md:106 msgid "" "In the previous section, we wanted to get the inner `T` value out of the `Some` case when using `Option`; we can also handle `Option` using `match`, as we did with the `Coin` " "enum! Instead of comparing coins, we’ll compare the variants of `Option`, but the way the `match` expression works remains the same. You can use Options by importing the `option::" @@ -7685,19 +7980,19 @@ msgstr "" "`enum` `Coin`! En lugar de comparar monedas, compararemos las variantes de `Option`, pero la forma en que funciona la expresión `match` sigue siendo la misma. Puedes usar opciones " "importando el trait `option::OptionTrait`." -#: src/ch05-02-the-match-control-flow-construct.md:118 +#: src/ch05-02-the-match-control-flow-construct.md:108 msgid "" -"Let’s say we want to write a function that takes an `Option` and, if there’s a value inside, adds `1_u8` to that value. If there isn’t a value inside, the function should return " -"the `None` value and not attempt to perform any operations." +"Let’s say we want to write a function that takes an `Option` and, if there’s a value inside, adds `1` to that value. If there isn’t a value inside, the function should return the " +"`None` value and not attempt to perform any operations." msgstr "" -"Digamos que queremos escribir una función que tome una `Option` y, si hay un valor dentro, agregue `1_u8` a ese valor. Si no hay un valor dentro, la función debería devolver el " +"Digamos que queremos escribir una función que tome una `Opción` y, si hay un valor dentro, añada `1` a ese valor. Si no hay ningún valor dentro, la función debería devolver el " "valor `None` y no intentar realizar ninguna operación." -#: src/ch05-02-the-match-control-flow-construct.md:120 +#: src/ch05-02-the-match-control-flow-construct.md:110 msgid "This function is very easy to write, thanks to match, and will look like Listing 5-5." msgstr "Esta función es muy fácil de escribir, gracias a `match`, y se verá como en el listado 5-5." -#: src/ch05-02-the-match-control-flow-construct.md:122 +#: src/ch05-02-the-match-control-flow-construct.md:112 msgid "" "```rust\n" "use option::OptionTrait;\n" @@ -7705,13 +8000,13 @@ msgid "" "\n" "fn plus_one(x: Option) -> Option {\n" " match x {\n" -" Option::Some(val) => Option::Some(val + 1_u8),\n" +" Option::Some(val) => Option::Some(val + 1),\n" " Option::None(_) => Option::None(()),\n" " }\n" "}\n" "\n" "fn main() {\n" -" let five: Option = Option::Some(5_u8);\n" +" let five: Option = Option::Some(5);\n" " let six: Option = plus_one(five);\n" " six.unwrap().print();\n" " let none = plus_one(Option::None(()));\n" @@ -7725,13 +8020,13 @@ msgstr "" "\n" "fn plus_one(x: Option) -> Option {\n" " match x {\n" -" Option::Some(val) => Option::Some(val + 1_u8),\n" +" Option::Some(val) => Option::Some(val + 1),\n" " Option::None(_) => Option::None(()),\n" " }\n" "}\n" "\n" "fn main() {\n" -" let five: Option = Option::Some(5_u8);\n" +" let five: Option = Option::Some(5);\n" " let six: Option = plus_one(five);\n" " six.unwrap().print();\n" " let none = plus_one(Option::None(()));\n" @@ -7739,81 +8034,65 @@ msgstr "" "}\n" "```" -#: src/ch05-02-the-match-control-flow-construct.md:142 +#: src/ch05-02-the-match-control-flow-construct.md:132 msgid "Listing 5-5: A function that uses a match expression on an `Option`" msgstr "Listado 5-5: Una función que usa una expresión `match` en un `Option`" -#: src/ch05-02-the-match-control-flow-construct.md:144 +#: src/ch05-02-the-match-control-flow-construct.md:134 msgid "Note that your arms must respect the same order as the enum defined in the `OptionTrait` of the core Cairo lib." msgstr "Tenga en cuenta que los brazos (`arms`) deben respetar el mismo orden que el enum definido en `OptionTrait` de la librería central de Cairo." -#: src/ch05-02-the-match-control-flow-construct.md:146 -msgid "" -"```rust\n" -" enum Option {\n" -" Some: T,\n" -" None: (),\n" -" }\n" -"```" -msgstr "" -"```rust\n" -" enum Option {\n" -" Some: T,\n" -" None: (),\n" -" }\n" -"```" - -#: src/ch05-02-the-match-control-flow-construct.md:153 +#: src/ch05-02-the-match-control-flow-construct.md:143 msgid "" -"Let’s examine the first execution of `plus_one` in more detail. When we call `plus_one(five)`, the variable `x` in the body of `plus_one` will have the value `Some(5_u8)`. We then " +"Let’s examine the first execution of `plus_one` in more detail. When we call `plus_one(five)`, the variable `x` in the body of `plus_one` will have the value `Some(5)`. We then " "compare that against each match arm:" msgstr "" -"Estudiemos con más detalle la primera ejecución de `plus_one`. Cuando llamamos a `plus_one(five)`, la variable `x` en el cuerpo de `plus_one` tendrá el valor `Some(5_u8)`. Luego, lo " -"comparamos con cada rama del `match`:" +"Examinemos más detalladamente la primera ejecución de `plus_one`. Cuando llamamos a `plus_one(five)`, la variable `x` en el cuerpo de `plus_one` tendrá el valor `Some(5)`. Luego " +"comparamos eso con cada rama del `match`:" -#: src/ch05-02-the-match-control-flow-construct.md:155 src/ch05-02-the-match-control-flow-construct.md:163 +#: src/ch05-02-the-match-control-flow-construct.md:145 src/ch05-02-the-match-control-flow-construct.md:153 msgid "" "```rust\n" -" Option::Some(val) => Option::Some(val + 1_u8),\n" +" Option::Some(val) => Option::Some(val + 1),\n" "```" msgstr "" "```rust\n" -" Option::Some(val) => Option::Some(val + 1_u8),\n" +" Option::Some(val) => Option::Some(val + 1),\n" "```" -#: src/ch05-02-the-match-control-flow-construct.md:159 +#: src/ch05-02-the-match-control-flow-construct.md:149 msgid "" -"Does `Option::Some(5_u8)` value match the pattern `Option::Some(val)`? It does! We have the same variant. The `val` binds to the value contained in `Option::Some`, so `val` takes the " -"value `5_u8`. The code in the match arm is then executed, so we add `1_u8` to the value of `val` and create a new `Option::Some` value with our total `6_u8` inside. Because the first " -"arm matched, no other arms are compared." +"Does `Option::Some(5)` value match the pattern `Option::Some(val)`? It does! We have the same variant. The `val` binds to the value contained in `Option::Some`, so `val` takes the " +"value `5`. The code in the match arm is then executed, so we add `1` to the value of `val` and create a new `Option::Some` value with our total `6` inside. Because the first arm " +"matched, no other arms are compared." msgstr "" -"¿El valor `Option::Some(5_u8)` coincide con el patrón `Option::Some(val)`? ¡Sí! Tenemos la misma variante. `val` se vincula al valor contenido en `Option::Some`, por lo que `val` " -"toma el valor `5_u8`. Luego se ejecuta el código en el brazo del `match`, por lo que agregamos `1_u8` al valor de `val` y creamos un nuevo valor `Option::Some` con nuestro total " -"`6_u8` en su interior. Debido a que se ha realizado la primera coincidencia, no se comparan otros brazos." +"¿El valor `Option::Some(5)` coincide con el patrón `Option::Some(val)`? ¡Sí lo hace! Tenemos la misma variante. El `val` se enlaza al valor contenido en `Option::Some`, por lo que " +"`val` toma el valor `5`. Luego se ejecuta el código en el brazo del `match`, por lo que sumamos `1` al valor de `val` y creamos un nuevo valor `Option::Some` con nuestro total `6` en " +"su interior. Debido a que el primer brazo coincide, no se comparan los demás brazos." -#: src/ch05-02-the-match-control-flow-construct.md:161 +#: src/ch05-02-the-match-control-flow-construct.md:151 msgid "Now let’s consider the second call of `plus_one` in our main function, where `x` is `Option::None(())`. We enter the match and compare to the first arm:" msgstr "Ahora consideremos la segunda llamada de `plus_one` en nuestra función principal, donde `x` es `Option::None(())`. Entramos en el `match` y comparamos con el primer brazo:" -#: src/ch05-02-the-match-control-flow-construct.md:167 +#: src/ch05-02-the-match-control-flow-construct.md:157 msgid "The `Option::Some(val)` value doesn’t match the pattern `Option::None`, so we continue to the next arm:" msgstr "El valor `Option::Some(5_u8)` no coincide con el patrón `Option::None`, así que continuamos con el siguiente brazo:" -#: src/ch05-02-the-match-control-flow-construct.md:169 +#: src/ch05-02-the-match-control-flow-construct.md:159 msgid "" "```rust\n" -" Option::None(_) => Option::None(()),\n" +" Option::None(_) => Option::None(()),\n" "```" msgstr "" "```rust\n" -" Option::None(_) => Option::None(()),\n" +" Option::None(_) => Option::None(()),\n" "```" -#: src/ch05-02-the-match-control-flow-construct.md:173 +#: src/ch05-02-the-match-control-flow-construct.md:163 msgid "It matches! There’s no value to add to, so the program stops and returns the `Option::None(())` value on the right side of `=>`." msgstr "¡Coincide! No hay valor al que agregar, por lo que el programa se detiene y devuelve el valor `Option::None(())` en el lado derecho de `=>`." -#: src/ch05-02-the-match-control-flow-construct.md:175 +#: src/ch05-02-the-match-control-flow-construct.md:165 msgid "" "Combining `match` and enums is useful in many situations. You’ll see this pattern a lot in Cairo code: `match` against an enum, bind a variable to the data inside, and then execute " "code based on it. It’s a bit tricky at first, but once you get used to it, you’ll wish you had it in all languages. It’s consistently a user favorite." @@ -7822,11 +8101,11 @@ msgstr "" "internos y luego ejecuta código basado en ella. Es un poco complicado al principio, pero una vez que te acostumbras, desearás tenerlo en todos los lenguajes. Es consistentemente " "favorito de los usuarios." -#: src/ch05-02-the-match-control-flow-construct.md:177 +#: src/ch05-02-the-match-control-flow-construct.md:167 msgid "## Matches Are Exhaustive" msgstr "## Los Matches Son Exhaustivos" -#: src/ch05-02-the-match-control-flow-construct.md:179 +#: src/ch05-02-the-match-control-flow-construct.md:169 msgid "" "There’s one other aspect of match we need to discuss: the arms’ patterns must cover all possibilities. Consider this version of our `plus_one` function, which has a bug and won’t " "compile:" @@ -7834,7 +8113,25 @@ msgstr "" "Hay otro aspecto de los matches que necesitamos discutir: los patrones de los brazos deben cubrir todas las posibilidades. Considera esta versión de nuestra función `plus_one`, que " "tiene un error y no se compilará:" -#: src/ch05-02-the-match-control-flow-construct.md:181 +#: src/ch05-02-the-match-control-flow-construct.md:171 +msgid "" +"```rust\n" +"fn plus_one(x: Option) -> Option {\n" +" match x {\n" +" Option::Some(val) => Option::Some(val + 1), \n" +" }\n" +"}\n" +"```" +msgstr "" +"```rust\n" +"fn plus_one(x: Option) -> Option {\n" +" match x {\n" +" Option::Some(val) => Option::Some(val + 1), \n" +" }\n" +"}\n" +"```" + +#: src/ch05-02-the-match-control-flow-construct.md:179 msgid "" "```bash\n" "$ cairo-run src/test.cairo\n" @@ -7856,7 +8153,7 @@ msgstr "" " Error: failed to compile: ./src/test.cairo\n" "```" -#: src/ch05-02-the-match-control-flow-construct.md:191 +#: src/ch05-02-the-match-control-flow-construct.md:189 msgid "" "Cairo knows that we didn’t cover every possible case, and even knows which pattern we forgot! Matches in Cairo are exhaustive: we must exhaust every last possibility in order for the " "code to be valid. Especially in the case of `Option`, when Cairo prevents us from forgetting to explicitly handle the `None` case, it protects us from assuming that we have a " @@ -7866,26 +8163,26 @@ msgstr "" "código sea válido. Especialmente en el caso de `Option`, cuando Cairo nos impide olvidar manejar explícitamente el caso `None`, nos protege de asumir que tenemos un valor cuando " "podríamos tener nulo, lo que hace imposible el error de mil millones de dólares discutido anteriormente." -#: src/ch05-02-the-match-control-flow-construct.md:193 +#: src/ch05-02-the-match-control-flow-construct.md:191 msgid "## Match 0 and the \\_ Placeholder" msgstr "## Match 0 y el Comodín \\_" -#: src/ch05-02-the-match-control-flow-construct.md:195 +#: src/ch05-02-the-match-control-flow-construct.md:193 msgid "" "Using enums, we can also take special actions for a few particular values, but for all other values take one default action. Currently only `0` and the `_`operator are supported." msgstr "" "Usando enums, también podemos tomar acciones especiales para algunos valores particulares, pero para todos los demás valores tomar una acción predeterminada. Actualmente solo se " "admiten `0` y el operador `_`." -#: src/ch05-02-the-match-control-flow-construct.md:197 +#: src/ch05-02-the-match-control-flow-construct.md:195 msgid "" -"Imagine we’re implementing a game where, you get a random number between 0 and 7. If you have 0, you win. For all other values you loose. Here's a match that implements that logic, " +"Imagine we’re implementing a game where, you get a random number between 0 and 7. If you have 0, you win. For all other values you lose. Here's a match that implements that logic, " "with the number hardcoded rather than a random value." msgstr "" -"Imaginemos que estamos implementando un juego en el que obtienes un número aleatorio entre 0 y 7. Si tienes 0, ganas. Para todos los demás valores pierdes. Aquí hay un match que " -"implementa esa lógica, con el número codificado en lugar de un valor aleatorio." +"Imaginemos que estamos implementando un juego en el que obtienes un número aleatorio entre 0 y 7. Si tienes 0, ganas. Para todos los demás valores, pierdes. Aquí hay un `match` que " +"implementa esa lógica, con el número codificado en lugar de ser un valor aleatorio." -#: src/ch05-02-the-match-control-flow-construct.md:199 +#: src/ch05-02-the-match-control-flow-construct.md:197 msgid "" "```rust\n" "fn did_i_win(nb: felt252) {\n" @@ -7905,7 +8202,7 @@ msgstr "" "}\n" "```" -#: src/ch05-02-the-match-control-flow-construct.md:208 +#: src/ch05-02-the-match-control-flow-construct.md:206 msgid "" "The first arm, the pattern is the literal values 0. For the last arm that covers every other possible value, the pattern is the character `_`. This code compiles, even though we " "haven’t listed all the possible values a `felt252` can have, because the last pattern will match all values not specifically listed. This catch-all pattern meets the requirement that " @@ -7917,7 +8214,7 @@ msgstr "" "cumple el requisito de que `match` debe ser exhaustivo. Tenga en cuenta que tenemos que poner la rama catch-all en último lugar porque los patrones se evalúan en orden. Si pusiéramos " "el brazo catch-all antes, los otros brazos nunca se ejecutarían, ¡así que Cairo nos avisará si añadimos brazos después de un catch-all!" -#: src/ch05-02-the-match-control-flow-construct.md:210 +#: src/ch05-02-the-match-control-flow-construct.md:208 msgid "" msgstr "" @@ -8099,12 +8396,12 @@ msgid "" "- `src/` is the main directory where all the Cairo source files for the package will be stored.\n" "- `lib.cairo` is the default root module of the crate, which is also the main entry point of the package. By default, it is empty.\n" "- `Scarb.toml` is the package manifest file, which contains metadata and configuration options for the package, such as dependencies, package name, version, and authors. You can find " -"documentation about it on the [scarb reference](https://docs.swmansion.com/scarb/docs/reference/manifest)." +"documentation about it on the [scarb reference](https://docs.swmansion.com/scarb/docs/reference/manifest.html)." msgstr "" "- `src/` es el directorio principal donde se almacenarán todos los archivos de origen de Cairo para el paquete.\n" "- `lib.cairo` es el módulo raíz predeterminado del crate, que también es el punto de entrada principal del paquete. Por defecto, está vacío.\n" "- `Scarb.toml` es el archivo de manifiesto del paquete, que contiene metadatos y opciones de configuración para el paquete, como dependencias, nombre del paquete, versión y autores. " -"Puede encontrar documentación al respecto en la [referencia de Scarb](https://docs.swmansion.com/scarb/docs/reference/manifest)." +"Puede encontrar documentación al respecto en la [referencia de Scarb](https://docs.swmansion.com/scarb/docs/reference/manifest.html)." #: src/ch06-01-packages-and-crates.md:33 msgid "" @@ -8329,39 +8626,37 @@ msgstr "El archivo raíz de la caja en este caso es _src/lib.cairo_, y contiene: #: src/ch06-02-defining-modules-to-control-scope.md:92 msgid "" -"```rust,does_not_compile\n" +"```rust\n" +"// does_not_compile\n" "use garden::vegetables::Asparagus;\n" "\n" "mod garden;\n" "\n" -"fn main(){\n" -" let Asparagus = Asparagus{};\n" +"fn main() {\n" +" let Asparagus = Asparagus {};\n" "}\n" -"\n" -"\n" "```" msgstr "" -"```rust,does_not_compile\n" +"```rust\n" +"// does_not_compile\n" "use garden::vegetables::Asparagus;\n" "\n" "mod garden;\n" "\n" -"fn main(){\n" -" let Asparagus = Asparagus{};\n" +"fn main() {\n" +" let Asparagus = Asparagus {};\n" "}\n" -"\n" -"\n" "```" -#: src/ch06-02-defining-modules-to-control-scope.md:104 +#: src/ch06-02-defining-modules-to-control-scope.md:103 msgid "The `mod garden;` line tells the compiler to include the code it finds in _src/garden.cairo_, which is:" msgstr "La línea `mod garden;` le indica al compilador que incluya el código que encuentra en _src/garden.cairo_, que es:" -#: src/ch06-02-defining-modules-to-control-scope.md:106 +#: src/ch06-02-defining-modules-to-control-scope.md:105 msgid "Filename: src/garden.cairo" msgstr "Filename: src/garden.cairo" -#: src/ch06-02-defining-modules-to-control-scope.md:108 +#: src/ch06-02-defining-modules-to-control-scope.md:107 msgid "" "```rust\n" "mod vegetables;\n" @@ -8371,25 +8666,25 @@ msgstr "" "mod vegetables;\n" "```" -#: src/ch06-02-defining-modules-to-control-scope.md:112 +#: src/ch06-02-defining-modules-to-control-scope.md:111 msgid "" "Here, `mod vegetables;` means the code in _src/garden/vegetables.cairo_ is\n" "included too. That code is:" msgstr "Aquí, `mod vegetables;` significa que el código en _src/garden/vegetables.cairo_ también está incluido. Ese código es:" -#: src/ch06-02-defining-modules-to-control-scope.md:115 +#: src/ch06-02-defining-modules-to-control-scope.md:114 msgid "" "```rust\n" -"#[derive(Copy,Drop)]\n" -"struct Asparagus{}\n" +"#[derive(Copy, Drop)]\n" +"struct Asparagus {}\n" "```" msgstr "" "```rust\n" -"#[derive(Copy,Drop)]\n" -"struct Asparagus{}\n" +"#[derive(Copy, Drop)]\n" +"struct Asparagus {}\n" "```" -#: src/ch06-02-defining-modules-to-control-scope.md:120 +#: src/ch06-02-defining-modules-to-control-scope.md:119 msgid "" "The line `use garden::vegetables::Asparagus;` lets us use bring the `Asparagus` type into scope,\n" "so we can use it in the `main` function." @@ -8397,15 +8692,15 @@ msgstr "" "La línea `use garden::vegetables::Asparagus;` nos permite traer el tipo `Asparagus` al ámbito de alcance, \n" "para que podamos usarlo en la función `main`." -#: src/ch06-02-defining-modules-to-control-scope.md:123 +#: src/ch06-02-defining-modules-to-control-scope.md:122 msgid "Now let’s get into the details of these rules and demonstrate them in action!" msgstr "¡Ahora vamos a entrar en los detalles de estas reglas y demostrarlas en acción!" -#: src/ch06-02-defining-modules-to-control-scope.md:125 +#: src/ch06-02-defining-modules-to-control-scope.md:124 msgid "### Grouping Related Code in Modules" msgstr "### Agrupando el Código Relacionado en Módulos" -#: src/ch06-02-defining-modules-to-control-scope.md:127 +#: src/ch06-02-defining-modules-to-control-scope.md:126 msgid "" "_Modules_ let us organize code within a crate for readability and easy reuse.\n" "As an example, let’s write a library crate that provides the functionality of a\n" @@ -8419,7 +8714,7 @@ msgstr "" "vacíos para concentrarnos en la organización del código, en lugar de \n" "en la implementación de un restaurante." -#: src/ch06-02-defining-modules-to-control-scope.md:133 +#: src/ch06-02-defining-modules-to-control-scope.md:132 msgid "" "In the restaurant industry, some parts of a restaurant are referred to as\n" "_front of house_ and others as _back of house_. Front of house is where\n" @@ -8435,7 +8730,7 @@ msgstr "" "chefs y cocineros trabajan en la cocina, los lavaplatos limpian y los gerentes hacen\n" " trabajo administrativo." -#: src/ch06-02-defining-modules-to-control-scope.md:140 +#: src/ch06-02-defining-modules-to-control-scope.md:139 msgid "" "To structure our crate in this way, we can organize its functions into nested\n" "modules. Create a new package named `restaurant` by running `scarb new restaurant`; then enter the code in Listing 6-1 into _src/lib.cairo_ to\n" @@ -8445,7 +8740,7 @@ msgstr "" "anidados. Cree un nuevo paquete llamado `restaurant` ejecutando el comando `scarb new restaurant`; luego ingrese el código en el Listado 6-1 en _src/lib.cairo_ para definir algunos " "módulos y firmas de funciones. Aquí está la sección de front of house:" -#: src/ch06-02-defining-modules-to-control-scope.md:146 +#: src/ch06-02-defining-modules-to-control-scope.md:145 msgid "" "```rust\n" "mod front_of_house {\n" @@ -8483,7 +8778,7 @@ msgstr "" "}\n" "```" -#: src/ch06-02-defining-modules-to-control-scope.md:164 +#: src/ch06-02-defining-modules-to-control-scope.md:163 msgid "" "Listing 6-1: A `front_of_house` module containing other\n" "modules that then contain functions" @@ -8491,7 +8786,7 @@ msgstr "" "Listado 6-1: Un módulo `front_of_house` que contiene otros \n" "módulos que a su vez contienen funciones" -#: src/ch06-02-defining-modules-to-control-scope.md:167 +#: src/ch06-02-defining-modules-to-control-scope.md:166 msgid "" "We define a module with the `mod` keyword followed by the name of the module\n" "(in this case, `front_of_house`). The body of the module then goes inside curly\n" @@ -8507,7 +8802,7 @@ msgstr "" " elementos, como structs, enums, constantes, traits y, como en el Listado \n" "6-1, funciones." -#: src/ch06-02-defining-modules-to-control-scope.md:174 +#: src/ch06-02-defining-modules-to-control-scope.md:173 msgid "" "By using modules, we can group related definitions together and name why\n" "they’re related. Programmers using this code can navigate the code based on the\n" @@ -8521,7 +8816,7 @@ msgstr "" "encontrar las definiciones relevantes para ellos. Los programadores que agregan nueva funcionalidad \n" "a este código sabrían dónde colocar el código para mantener el programa organizado." -#: src/ch06-02-defining-modules-to-control-scope.md:180 +#: src/ch06-02-defining-modules-to-control-scope.md:179 msgid "" "Earlier, we mentioned that _src/lib.cairo_ is called the crate\n" "root. The reason for this name is that the content of this file form a module named after the crate name at the root of the crate’s module structure,\n" @@ -8531,11 +8826,11 @@ msgstr "" "caja. La razón de este nombre es que el contenido de este archivo forma un módulo con el nombre de la caja en la raíz de la estructura de módulos de la caja, conocido como el _árbol " "de módulos_." -#: src/ch06-02-defining-modules-to-control-scope.md:184 +#: src/ch06-02-defining-modules-to-control-scope.md:183 msgid "Listing 6-2 shows the module tree for the structure in Listing 6-1." msgstr "El Listado 6-2 muestra el árbol de módulos para la estructura en el Listado 6-1." -#: src/ch06-02-defining-modules-to-control-scope.md:186 +#: src/ch06-02-defining-modules-to-control-scope.md:185 msgid "" "```text\n" "restaurant\n" @@ -8561,7 +8856,7 @@ msgstr "" " └── take_payment\n" "```" -#: src/ch06-02-defining-modules-to-control-scope.md:198 +#: src/ch06-02-defining-modules-to-control-scope.md:197 msgid "" "Listing 6-2: The module tree for the code in Listing\n" "6-1" @@ -8569,7 +8864,7 @@ msgstr "" "Listing 6-2: El árbol de módulos para el código en el Listado\n" "6-1" -#: src/ch06-02-defining-modules-to-control-scope.md:201 +#: src/ch06-02-defining-modules-to-control-scope.md:200 msgid "" "This tree shows how some of the modules nest inside one another; for example,\n" "`hosting` nests inside `front_of_house`. The tree also shows that some modules\n" @@ -8587,7 +8882,7 @@ msgstr "" "y que el módulo B es el _padre_ del módulo A. Observa que todo el árbol de módulos \n" "está enraizado en el nombre explícito del paquete `restaurant`." -#: src/ch06-02-defining-modules-to-control-scope.md:209 +#: src/ch06-02-defining-modules-to-control-scope.md:208 msgid "" "The module tree might remind you of the filesystem’s directory tree on your\n" "computer; this is a very apt comparison! Just like directories in a filesystem,\n" @@ -8657,7 +8952,7 @@ msgid "" "}\n" "\n" "\n" -"pub fn eat_at_restaurant() {\n" +"fn eat_at_restaurant() {\n" " // Absolute path\n" " restaurant::front_of_house::hosting::add_to_waitlist(); // ✅ Compiles\n" "\n" @@ -8684,7 +8979,7 @@ msgstr "" "}\n" "\n" "\n" -"pub fn eat_at_restaurant() {\n" +"fn eat_at_restaurant() {\n" " // Absolute path\n" " restaurant::front_of_house::hosting::add_to_waitlist(); // ✅ Compiles\n" "\n" @@ -8798,6 +9093,7 @@ msgstr "" #: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:12 msgid "" "```rust\n" +"// does_not_compile\n" "mod front_of_house {\n" " mod hosting {\n" " fn add_to_waitlist() {}\n" @@ -8812,6 +9108,7 @@ msgid "" "```" msgstr "" "```rust\n" +"// does_not_compile\n" "mod front_of_house {\n" " mod hosting {\n" " fn add_to_waitlist() {}\n" @@ -8825,7 +9122,7 @@ msgstr "" "}\n" "```" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:26 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:27 msgid "" "Listing 6-5: Bringing a module into scope with\n" "`use`" @@ -8833,7 +9130,7 @@ msgstr "" "Listado 6-5: Introducir un módulo en el ámbito con\n" "`use`" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:29 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:30 msgid "" "Adding use and a path in a scope is similar to creating a symbolic link in the filesystem. By adding `use restaurant::front_of_house::hosting` in the crate root, hosting is now a " "valid name in that scope, just as though the `hosting` module had been defined in the crate root." @@ -8841,7 +9138,7 @@ msgstr "" "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." -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:31 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:32 msgid "" "Note that `use` only creates the shortcut for the particular scope in which the `use` occurs. Listing 6-6 moves the `eat_at_restaurant` function into a new\n" "child module named `customer`, which is then a different scope than the `use`\n" @@ -8852,9 +9149,10 @@ msgstr "" "módulo hijo llamado `customer`, que es un ámbito diferente al de la sentencia `use\n" "por lo que el cuerpo de la función no compilará:" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:37 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:38 msgid "" "```rust\n" +"// does_not_compile\n" "mod front_of_house {\n" " mod hosting {\n" " fn add_to_waitlist() {}\n" @@ -8871,6 +9169,7 @@ msgid "" "```" msgstr "" "```rust\n" +"// does_not_compile\n" "mod front_of_house {\n" " mod hosting {\n" " fn add_to_waitlist() {}\n" @@ -8886,7 +9185,7 @@ msgstr "" "}\n" "```" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:53 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:55 msgid "" "Listing 6-6: A `use` statement only applies in the scope\n" "it’s in" @@ -8894,7 +9193,7 @@ msgstr "" "Listado 6-6: Una sentencia `use` sólo se aplica en el ámbito\n" "en el que se encuentra" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:56 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:58 msgid "" "The compiler error shows that the shortcut no longer applies within the\n" "`customer` module:" @@ -8902,7 +9201,7 @@ msgstr "" "El error del compilador muestra que el acceso directo ya no se aplica dentro del módulo\n" "módulo `customer`:" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:59 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:61 msgid "" "```console\n" "❯ scarb build\n" @@ -8920,11 +9219,11 @@ msgstr "" " ^*****^\n" "```" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:67 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:69 msgid "## Creating Idiomatic `use` Paths" msgstr "## Crear Rutas idiomáticas `use`" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:69 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:71 msgid "" "In Listing 6-5, you might have wondered why we specified `use\n" "restaurant::front_of_house::hosting` and then called `hosting::add_to_waitlist` in\n" @@ -8936,39 +9235,37 @@ msgstr "" "en `eat_at_restaurant` en lugar de especificar la ruta `use\n" "la función `add_to_waitlist` para conseguir el mismo resultado, como en el Listado 6-7." -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:76 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:78 msgid "" "```rust\n" "mod front_of_house {\n" -" pub mod hosting {\n" -" pub fn add_to_waitlist() {}\n" +" mod hosting {\n" +" fn add_to_waitlist() {}\n" " }\n" "}\n" "\n" "use restaurant::front_of_house::hosting::add_to_waitlist;\n" "\n" -"pub fn eat_at_restaurant() {\n" +"fn eat_at_restaurant() {\n" " add_to_waitlist();\n" "}\n" -"\n" "```" msgstr "" "```rust\n" "mod front_of_house {\n" -" pub mod hosting {\n" -" pub fn add_to_waitlist() {}\n" +" mod hosting {\n" +" fn add_to_waitlist() {}\n" " }\n" "}\n" "\n" "use restaurant::front_of_house::hosting::add_to_waitlist;\n" "\n" -"pub fn eat_at_restaurant() {\n" +"fn eat_at_restaurant() {\n" " add_to_waitlist();\n" "}\n" -"\n" "```" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:91 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:92 msgid "" "Listing 6-7: Bringing the `add_to_waitlist` function\n" "into scope with `use`, which is unidiomatic" @@ -8976,7 +9273,7 @@ msgstr "" "Listado 6-7: Introduciendo la función `add_to_waitlist\n" "con `use`, que es poco idiomático" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:94 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:95 msgid "" "Although both Listing 6-5 and 6-7 accomplish the same task, Listing 6-5 is\n" "the idiomatic way to bring a function into scope with `use`. Bringing the\n" @@ -8994,7 +9291,7 @@ msgstr "" "a la vez que minimiza la repetición de la ruta completa. El código del Listado 6-7 es\n" "no está claro dónde está definido `add_to_waitlist`." -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:102 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:103 msgid "" "On the other hand, when bringing in structs, enums, traits, and other items with `use`,\n" "it’s idiomatic to specify the full path. Listing 6-8 shows the idiomatic way\n" @@ -9004,7 +9301,7 @@ msgstr "" "es idiomático especificar la ruta completa. El listado 6-8 muestra la forma idiomática\n" "de traer el trait `ArrayTrait` de la librería core al ámbito." -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:106 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:107 msgid "" "```rust\n" "use array::ArrayTrait;\n" @@ -9024,7 +9321,7 @@ msgstr "" "}\n" "```" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:115 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:116 msgid "" "Listing 6-8: Bringing `ArrayTrait` into scope in an\n" "idiomatic way" @@ -9032,7 +9329,7 @@ msgstr "" "Listado 6-8: Introducir `ArrayTrait` en el ámbito de forma\n" "forma idiomática" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:118 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:119 msgid "" "There’s no strong reason behind this idiom: it’s just the convention that has\n" "emerged in the Rust community, and folks have gotten used to reading and writing Rust code this way.\n" @@ -9042,7 +9339,7 @@ msgstr "" "surgido en la comunidad Rust y la gente se ha acostumbrado a leer y escribir código Rust de esta manera.\n" "Como Cairo comparte muchos modismos con Rust, nosotros también seguimos esta convención." -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:122 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:123 msgid "" "The exception to this idiom is if we’re bringing two items with the same name\n" "into scope with `use` statements, because Cairo doesn’t allow that." @@ -9050,11 +9347,11 @@ msgstr "" "La excepción a este modismo es si estamos trayendo dos elementos con el mismo nombre\n" "con sentencias `use`, porque Cairo no lo permite." -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:125 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:126 msgid "### Providing New Names with the `as` Keyword" msgstr "### Proporcionar nuevos nombres con la Palabra Clave `as`" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:127 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:128 msgid "" "There’s another solution to the problem of bringing two types of the same name\n" "into the same scope with `use`: after the path, we can specify `as` and a new\n" @@ -9064,12 +9361,12 @@ msgstr "" "en el mismo ámbito con `use`: después de la ruta, podemos especificar `as` y un nuevo\n" "nombre local, o _alias_, para el tipo. El listado 6-9 muestra cómo puedes renombrar una importación con `as`:" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:133 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:134 msgid "" "```rust\n" "use array::ArrayTrait as Arr;\n" "\n" -"fn main(){\n" +"fn main() {\n" " let mut arr = Arr::new(); // ArrayTrait was renamed to Arr\n" " arr.append(1);\n" "}\n" @@ -9078,13 +9375,13 @@ msgstr "" "```rust\n" "use array::ArrayTrait as Arr;\n" "\n" -"fn main(){\n" +"fn main() {\n" " let mut arr = Arr::new(); // ArrayTrait was renamed to Arr\n" " arr.append(1);\n" "}\n" "```" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:142 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:143 msgid "" "Listing 6-9: Renaming a trait when it’s brought into\n" "scope with the `as` keyword" @@ -9092,47 +9389,153 @@ msgstr "" "Listado 6-9: Renombrar un trait cuando es traído a\n" "scope con la palabra clave `as`" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:145 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:146 msgid "Here, we brought `ArrayTrait` into scope with the alias `Arr`. We can now access the trait's methods with the `Arr` identifier." msgstr "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`." -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:147 -msgid "## Re-exporting Names in Module Files" -msgstr "## Re-exportación de Nombres en Archivos de Módulo" +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:148 +msgid "### Importing multiple items from the same module" +msgstr "### Importar varios elementos desde el mismo módulo" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:149 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:150 msgid "" -"When we bring a name into scope with the `use` keyword, the name available in\n" -"the new scope can be imported as if it had been defined in that code’s scope.\n" -"This technique is called _re-exporting_ because we’re bringing an item into scope,\n" -"but also making that item available for others to bring into their scope." +"When you want to import multiple items (like functions, structs or enums)\n" +"from the same module in Cairo, you can use curly braces `{}` to list all of\n" +"the items that you want to import. This helps to keep your code clean and easy\n" +"to read by avoiding a long list of individual use statements." msgstr "" -"Cuando traemos un nombre al ámbito con la palabra clave `use`, el nombre disponible en\n" -"el nuevo ámbito puede ser importado como si hubiera sido definido en el ámbito de ese código.\n" -"Esta técnica se llama _re-exporting_ porque estamos trayendo un elemento al ámbito,\n" -"pero también haciendo que ese elemento esté disponible para que otros lo introduzcan en su ámbito." +"Cuando quieras importar múltiples elementos (como funciones, structs o enums)\n" +"del mismo módulo en Cairo, puede usar llaves `{}` para listar todos los\n" +"los elementos que desea importar. Esto ayuda a mantener su código limpio y fácil\n" +"de leer evitando una larga lista de sentencias use individuales." -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:154 -msgid "For example, let's re-export the `add_to_waitlist` function in the restaurant example:" -msgstr "Por ejemplo, reexportemos la función `add_to_waitlist` del ejemplo del restaurante:" +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:155 +msgid "The general syntax for importing multiple items from the same module is:" +msgstr "La sintaxis general para importar varios elementos del mismo módulo es:" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:158 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:157 msgid "" -"```rs\n" -"mod front_of_house {\n" -" mod hosting {\n" -" fn add_to_waitlist() {}\n" -" }\n" -"}\n" -"\n" -"use restaurant::front_of_house::hosting;\n" -"\n" -"fn eat_at_restaurant() {\n" -" hosting::add_to_waitlist();\n" -"}\n" +"```rust\n" +"use module::{item1, item2, item3};\n" "```" msgstr "" -"```rs\n" +"```rust\n" +"use module::{item1, item2, item3};\n" +"```" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:161 +msgid "Here is an example where we import three structures from the same module:" +msgstr "He aquí un ejemplo en el que importamos tres estructuras del mismo módulo:" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:163 +msgid "" +"```rust\n" +"// Assuming we have a module called `shapes` with the structures `Square`, `Circle`, and `Triangle`.\n" +"mod shapes {\n" +" #[derive(Drop)]\n" +" struct Square {\n" +" side: u32\n" +" }\n" +"\n" +" #[derive(Drop)]\n" +" struct Circle {\n" +" radius: u32\n" +" }\n" +"\n" +" #[derive(Drop)]\n" +" struct Triangle {\n" +" base: u32,\n" +" height: u32,\n" +" }\n" +"}\n" +"\n" +"// We can import the structures `Square`, `Circle`, and `Triangle` from the `shapes` module like this:\n" +"use shapes::{Square, Circle, Triangle};\n" +"\n" +"// Now we can directly use `Square`, `Circle`, and `Triangle` in our code.\n" +"fn main() {\n" +" let sq = Square { side: 5 };\n" +" let cr = Circle { radius: 3 };\n" +" let tr = Triangle { base: 5, height: 2 };\n" +"// ...\n" +"}\n" +"```" +msgstr "" +"```rust\n" +"// Assuming we have a module called `shapes` with the structures `Square`, `Circle`, and `Triangle`.\n" +"mod shapes {\n" +" #[derive(Drop)]\n" +" struct Square {\n" +" side: u32\n" +" }\n" +"\n" +" #[derive(Drop)]\n" +" struct Circle {\n" +" radius: u32\n" +" }\n" +"\n" +" #[derive(Drop)]\n" +" struct Triangle {\n" +" base: u32,\n" +" height: u32,\n" +" }\n" +"}\n" +"\n" +"// We can import the structures `Square`, `Circle`, and `Triangle` from the `shapes` module like this:\n" +"use shapes::{Square, Circle, Triangle};\n" +"\n" +"// Now we can directly use `Square`, `Circle`, and `Triangle` in our code.\n" +"fn main() {\n" +" let sq = Square { side: 5 };\n" +" let cr = Circle { radius: 3 };\n" +" let tr = Triangle { base: 5, height: 2 };\n" +"// ...\n" +"}\n" +"```" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:195 +msgid "Listing 6-10: Importing multiple items from the same module" +msgstr "Listado 6-10 Importación de varios elementos del mismo módulo" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:197 +msgid "## Re-exporting Names in Module Files" +msgstr "## Re-exportación de Nombres en Archivos de Módulo" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:199 +msgid "" +"When we bring a name into scope with the `use` keyword, the name available in\n" +"the new scope can be imported as if it had been defined in that code’s scope.\n" +"This technique is called _re-exporting_ because we’re bringing an item into scope,\n" +"but also making that item available for others to bring into their scope." +msgstr "" +"Cuando traemos un nombre al ámbito con la palabra clave `use`, el nombre disponible en\n" +"el nuevo ámbito puede ser importado como si hubiera sido definido en el ámbito de ese código.\n" +"Esta técnica se llama _re-exporting_ porque estamos trayendo un elemento al ámbito,\n" +"pero también haciendo que ese elemento esté disponible para que otros lo introduzcan en su ámbito." + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:204 +msgid "For example, let's re-export the `add_to_waitlist` function in the restaurant example:" +msgstr "Por ejemplo, reexportemos la función `add_to_waitlist` del ejemplo del restaurante:" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:208 +msgid "" +"```rust\n" +"// does_not_compile\n" +"mod front_of_house {\n" +" mod hosting {\n" +" fn add_to_waitlist() {}\n" +" }\n" +"}\n" +"\n" +"use restaurant::front_of_house::hosting;\n" +"\n" +"fn eat_at_restaurant() {\n" +" hosting::add_to_waitlist();\n" +"}\n" +"```" +msgstr "" +"```rust\n" +"// does_not_compile\n" "mod front_of_house {\n" " mod hosting {\n" " fn add_to_waitlist() {}\n" @@ -9146,15 +9549,15 @@ msgstr "" "}\n" "```" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:172 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:223 msgid "" -"Listing 6-10: Making a name available for any code to use\n" +"Listing 6-11: Making a name available for any code to use\n" "from a new scope with `pub use`" msgstr "" -"Listado 6-10: Poner un nombre a disposición de cualquier código\n" -"desde un nuevo ámbito con `pub use`." +"Listado 6-11: Hacer que un nombre esté disponible para que lo use cualquier código\n" +"desde un nuevo ámbito con `pub use`" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:175 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:226 msgid "" "Before this change, external code would have to call the `add_to_waitlist`\n" "function by using the path\n" @@ -9168,7 +9571,7 @@ msgstr "" "ha reexportado el módulo `hosting` desde el módulo raíz, el código externo\n" "puede usar la ruta `restaurant::hosting::add_to_waitlist()` en su lugar." -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:181 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:232 msgid "" "Re-exporting is useful when the internal structure of your code is different\n" "from how programmers calling your code would think about the domain. For\n" @@ -9188,19 +9591,19 @@ msgstr "" "Esto hace que nuestra biblioteca esté bien organizada para los programadores que trabajan \n" "en ella y para los programadores que la llaman." -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:190 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:241 msgid "## Using External Packages in Cairo with Scarb" msgstr "## Usando Paquetes Externos en Cairo con Scarb" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:192 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:243 msgid "You might need to use external packages to leverage the functionality provided by the community. To use an external package in your project with Scarb, follow these steps:" msgstr "" "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:" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:194 -msgid "> The dependencies system is still a work in progress. You can check the official [documentation](https://docs.swmansion.com/scarb/docs/guides/dependencies)." -msgstr "> El sistema de dependencias es todavía un trabajo en curso. Puede consultar la [documentación oficial](https://docs.swmansion.com/scarb/docs/guides/dependencies)." +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:245 +msgid "> The dependencies system is still a work in progress. You can check the official [documentation](https://docs.swmansion.com/scarb/docs/guides/dependencies.html)." +msgstr "> El sistema de dependencias es todavía un trabajo en curso. Puede consultar la [documentación oficial](https://docs.swmansion.com/scarb/docs/guides/dependencies.html)." #: src/ch06-05-separating-modules-into-different-files.md:1 msgid "## Separating Modules into Different Files" @@ -9218,12 +9621,12 @@ msgstr "" #: src/ch06-05-separating-modules-into-different-files.md:7 msgid "" -"For example, let’s start from the code in Listing 6-10 that had multiple\n" +"For example, let’s start from the code in Listing 6-11 that had multiple\n" "restaurant modules. We’ll extract modules into files instead of having all the\n" "modules defined in the crate root file. In this case, the crate root file is\n" "_src/lib.cairo_." msgstr "" -"Por ejemplo, partamos del código del Listado 6-10 que tenía múltiples\n" +"Por ejemplo, partamos del código del Listado 6-11 que tenía múltiples\n" "módulos de restaurante. Extraeremos los módulos en archivos en lugar de tener todos los\n" "módulos definidos en el archivo raíz del crate. En este caso, el archivo raíz es\n" "_src/lib.cairo_." @@ -9233,62 +9636,64 @@ msgid "" "First, we’ll extract the `front_of_house` module to its own file. Remove the\n" "code inside the curly brackets for the `front_of_house` module, leaving only\n" "the `mod front_of_house;` declaration, so that _src/lib.cairo_ contains the code\n" -"shown in Listing 6-11. Note that this won’t compile until we create the\n" -"_src/front_of_house.cairo_ file in Listing 6-12." +"shown in Listing 6-12. Note that this won’t compile until we create the\n" +"_src/front_of_house.cairo_ file in Listing 6-13." msgstr "" "Primero, extraeremos el módulo `front_of_house` a su propio archivo. Elimina el código\n" -"dentro de las llaves del módulo `front_of_house`, dejando sólo\n" +"dentro de las llaves del módulo `front_of_house`, dejando sólo la declaración\n" "la declaración `mod front_of_house;`, de forma que _src/lib.cairo_ contenga el código\n" -"mostrado en el Listado 6-11. Ten en cuenta que esto no compilará hasta que creemos el módulo\n" -"_src/front_of_house.cairo_ del Listado 6-12." +"mostrado en el Listado 6-12. Ten en cuenta que esto no compilará hasta que creemos el módulo\n" +"_src/front_of_house.cairo_ del Listado 6-13." #: src/ch06-05-separating-modules-into-different-files.md:20 msgid "" "```rust\n" +"// does_not_compile\n" "mod front_of_house;\n" "\n" "use restaurant::front_of_house::hosting;\n" "\n" -"pub fn eat_at_restaurant() {\n" +"fn eat_at_restaurant() {\n" " hosting::add_to_waitlist();\n" "}\n" "```" msgstr "" "```rust\n" +"// does_not_compile\n" "mod front_of_house;\n" "\n" "use restaurant::front_of_house::hosting;\n" "\n" -"pub fn eat_at_restaurant() {\n" +"fn eat_at_restaurant() {\n" " hosting::add_to_waitlist();\n" "}\n" "```" -#: src/ch06-05-separating-modules-into-different-files.md:30 +#: src/ch06-05-separating-modules-into-different-files.md:31 msgid "" -"Listing 6-11: Declaring the `front_of_house` module whose\n" +"Listing 6-12: Declaring the `front_of_house` module whose\n" "body will be in _src/front_of_house.cairo_" msgstr "" -"Listado 6-11: Declarando el módulo `front_of_house` cuyo\n" +"Listado 6-12: Declarando el módulo `front_of_house` cuyo\n" "cuerpo estará en _src/front_of_house.cairo_" -#: src/ch06-05-separating-modules-into-different-files.md:33 +#: src/ch06-05-separating-modules-into-different-files.md:34 msgid "" "Next, place the code that was in the curly brackets into a new file named\n" -"_src/front_of_house.cairo_, as shown in Listing 6-12. The compiler knows to look\n" +"_src/front_of_house.cairo_, as shown in Listing 6-13. The compiler knows to look\n" "in this file because it came across the module declaration in the crate root\n" "with the name `front_of_house`." msgstr "" "A continuación, coloque el código que estaba entre llaves en un nuevo archivo llamado\n" -"_src/front_of_house.cairo_, como se muestra en el Listado 6-12. El compilador sabe que debe buscar\n" +"_src/front_of_house.cairo_, como se muestra en el Listado 6-13. El compilador sabe que debe buscar\n" "en este archivo porque se encontró con la declaración del módulo en la raíz del crate\n" "con el nombre `front_of_house`." -#: src/ch06-05-separating-modules-into-different-files.md:38 src/ch06-05-separating-modules-into-different-files.md:66 +#: src/ch06-05-separating-modules-into-different-files.md:39 src/ch06-05-separating-modules-into-different-files.md:67 msgid "Filename: src/front_of_house.cairo" msgstr "Filename: src/front_of_house.cairo" -#: src/ch06-05-separating-modules-into-different-files.md:40 +#: src/ch06-05-separating-modules-into-different-files.md:41 msgid "" "```rust,\n" "mod hosting {\n" @@ -9302,15 +9707,15 @@ msgstr "" "}\n" "```" -#: src/ch06-05-separating-modules-into-different-files.md:46 +#: src/ch06-05-separating-modules-into-different-files.md:47 msgid "" -"Listing 6-12: Definitions inside the `front_of_house`\n" +"Listing 6-13: Definitions inside the `front_of_house`\n" "module in _src/front_of_house.cairo_" msgstr "" -"Listado 6-12: Definiciones dentro del módulo `front_of_house`\n" +"Listado 6-13: Definiciones dentro del módulo `front_of_house`\n" "en _src/front_of_house.cairo_" -#: src/ch06-05-separating-modules-into-different-files.md:49 +#: src/ch06-05-separating-modules-into-different-files.md:50 msgid "" "Note that you only need to load a file using a `mod` declaration _once_ in your\n" "module tree. Once the compiler knows the file is part of the project (and knows\n" @@ -9330,7 +9735,7 @@ msgstr "" "`mod` no es una operación \"include\" que pueda haber visto en otros \n" "lenguajes de programación." -#: src/ch06-05-separating-modules-into-different-files.md:58 +#: src/ch06-05-separating-modules-into-different-files.md:59 msgid "" "Next, we’ll extract the `hosting` module to its own file. The process is a bit\n" "different because `hosting` is a child module of `front_of_house`, not of the\n" @@ -9342,7 +9747,7 @@ msgstr "" "módulo raíz. Colocaremos el archivo para `hosting` en un nuevo directorio que será\n" "nombre de sus antepasados en el árbol de módulos, en este caso _src/front_of_house/_." -#: src/ch06-05-separating-modules-into-different-files.md:63 +#: src/ch06-05-separating-modules-into-different-files.md:64 msgid "" "To start moving `hosting`, we change _src/front_of_house.cairo_ to contain only the\n" "declaration of the `hosting` module:" @@ -9350,7 +9755,7 @@ msgstr "" "Para empezar a mover `hosting`, cambiamos _src/front_of_house.cairo_ para que contenga sólo la\n" "declaración del módulo `hosting`:" -#: src/ch06-05-separating-modules-into-different-files.md:68 +#: src/ch06-05-separating-modules-into-different-files.md:69 msgid "" "```rust\n" "mod hosting;\n" @@ -9360,7 +9765,7 @@ msgstr "" "mod hosting;\n" "```" -#: src/ch06-05-separating-modules-into-different-files.md:72 +#: src/ch06-05-separating-modules-into-different-files.md:73 msgid "" "Then we create a _src/front_of_house_ directory and a file _hosting.cairo_ to\n" "contain the definitions made in the `hosting` module:" @@ -9368,21 +9773,21 @@ msgstr "" "Luego creamos un directorio _src/front_of_house_ y un archivo _hosting.cairo_ para\n" "contener las definiciones hechas en el módulo `hosting`:" -#: src/ch06-05-separating-modules-into-different-files.md:75 +#: src/ch06-05-separating-modules-into-different-files.md:76 msgid "Filename: src/front_of_house/hosting.cairo" msgstr "Filename: src/front_of_house/hosting.cairo" -#: src/ch06-05-separating-modules-into-different-files.md:77 +#: src/ch06-05-separating-modules-into-different-files.md:78 msgid "" "```rust\n" -"pub fn add_to_waitlist() {}\n" +"fn add_to_waitlist() {}\n" "```" msgstr "" "```rust\n" -"pub fn add_to_waitlist() {}\n" +"fn add_to_waitlist() {}\n" "```" -#: src/ch06-05-separating-modules-into-different-files.md:81 +#: src/ch06-05-separating-modules-into-different-files.md:82 msgid "" "If we instead put _hosting.cairo_ in the _src_ directory, the compiler would\n" "expect the _hosting.cairo_ code to be in a `hosting` module declared in the crate\n" @@ -9396,7 +9801,7 @@ msgstr "" "reglas del compilador sobre qué archivos comprobar para qué código de los módulos significa que los\n" "directorios y archivos se ajustan más al árbol de módulos." -#: src/ch06-05-separating-modules-into-different-files.md:87 +#: src/ch06-05-separating-modules-into-different-files.md:88 msgid "" "We’ve moved each module’s code to a separate file, and the module tree remains\n" "the same. The function calls in `eat_at_restaurant` will work without any\n" @@ -9408,7 +9813,7 @@ msgstr "" "aunque las definiciones estén en archivos diferentes. Esta\n" "técnica le permite mover módulos a nuevos archivos a medida que crecen en tamaño." -#: src/ch06-05-separating-modules-into-different-files.md:92 +#: src/ch06-05-separating-modules-into-different-files.md:93 msgid "" "Note that the `use restaurant::front_of_house::hosting` statement in\n" "_src/lib.cairo_ also hasn’t changed, nor does `use` have any impact on what files\n" @@ -9422,7 +9827,7 @@ msgstr "" "busca en un fichero con el mismo nombre que el módulo el código que va en \n" "ese módulo." -#: src/ch06-05-separating-modules-into-different-files.md:100 +#: src/ch06-05-separating-modules-into-different-files.md:101 msgid "" "Cairo lets you split a package into multiple crates and a crate into modules\n" "so you can refer to items defined in one module from another module. You can do\n" @@ -9436,14 +9841,6 @@ msgstr "" "con una sentencia `use` para que pueda utilizar una ruta más corta para múltiples usos\n" "del elemento en ese ámbito. El código del módulo es público por defecto." -#: src/ch06-05-separating-modules-into-different-files.md:106 -msgid "" -"In the next chapter, we’ll look at some collection data structures in the\n" -"standard library that you can use in your neatly organized code." -msgstr "" -"En el próximo capítulo, veremos algunas estructuras de datos de colección en la\n" -"biblioteca estándar que puedes utilizar en tu código bien organizado." - #: src/ch07-00-generic-types-and-traits.md:1 msgid "# Generic Types and Traits" msgstr "# Tipos Genéricos y Traits" @@ -9489,11 +9886,11 @@ msgstr "# Tipos de Datos Genéricos" #: src/ch07-01-generic-data-types.md:3 msgid "" "We use generics to create definitions for item declarations, such as structs and functions, which we can then use with many different concrete data types. In Cairo we can use " -"generics when defining functions, structs, enums, traits, implementations and methods! In this chapter we are going to take a look on how to effectively use generic types with all of " +"generics when defining functions, structs, enums, traits, implementations and methods! In this chapter we are going to take a look at how to effectively use generic types with all of " "them." msgstr "" -"Usamos genéricos para crear definiciones de declaraciones de elementos, como structs y funciones, que luego podemos usar con muchos tipos de datos concretos diferentes. ¡En Cairo " -"podemos usar genéricos al definir funciones, structs, enums, traits, implementaciones y métodos! En este capítulo vamos a ver cómo usar efectivamente tipos genéricos con todos ellos." +"Usamos genéricos para crear definiciones de elementos, como estructuras y funciones, que luego podemos utilizar con muchos tipos de datos concretos diferentes. En Cairo podemos usar " +"genéricos al definir funciones, structs, enums, traits, implementaciones y métodos. En este capítulo vamos a ver cómo utilizar de manera efectiva los tipos genéricos con todos ellos." #: src/ch07-01-generic-data-types.md:5 msgid "## Generic Functions" @@ -9502,17 +9899,17 @@ msgstr "## Funciones Genéricas" #: src/ch07-01-generic-data-types.md:7 msgid "" "When defining a function that uses generics, we place the generics in the function signature, where we would usually specify the data types of the parameter and return value. For " -"example, imagine we want to create a function which given two `Array` of items, will return the largest one. If we need to perform this operations for lists of different types, then " +"example, imagine we want to create a function which given two `Array` of items, will return the largest one. If we need to perform this operation for lists of different types, then " "we would have to redefine the function each time. Luckily we can implement the function once using generics and move on to other tasks." msgstr "" -"Al definir una función que utiliza genéricos, colocamos los genéricos en la firma de la función, donde normalmente especificaríamos los tipos de datos del parámetro y el valor de " -"retorno. Por ejemplo, imaginemos que queremos crear una función que, dadas dos matrices (`Array`) de elementos, devolverá la más grande. Si necesitamos realizar esta operación para " -"listas de diferentes tipos, tendríamos que redefinir la función cada vez. Afortunadamente, podemos implementar la función una vez usando genéricos y seguir adelante con otras tareas." +"Cuando definimos una función que utiliza genéricos, colocamos los genéricos en la firma de la función, donde normalmente especificaríamos los tipos de datos del parámetro y del valor " +"de retorno. Por ejemplo, imaginemos que queremos crear una función que, dados dos `Array` de elementos, devuelva el mayor de ellos. Si necesitamos realizar esta operación para listas " +"de distintos tipos, tendríamos que redefinir la función cada vez. Por suerte podemos implementar la función una vez usando genéricos y pasar a otras tareas." #: src/ch07-01-generic-data-types.md:9 msgid "" -"```rust,does_not_compile\n" -"// This code does not compile!\n" +"```rust\n" +"// does_not_compile\n" "\n" "use array::ArrayTrait;\n" "\n" @@ -9542,8 +9939,8 @@ msgid "" "}\n" "```" msgstr "" -"```rust,does_not_compile\n" -"// This code does not compile!\n" +"```rust\n" +"// does_not_compile\n" "\n" "use array::ArrayTrait;\n" "\n" @@ -9576,18 +9973,19 @@ msgstr "" #: src/ch07-01-generic-data-types.md:40 msgid "" "The `largest_list` function compares two lists of the same type and returns the one with more elements and drops the other. If you compile the previous code, you will notice that it " -"will fail with an error saying that there are no traits defined for droping an array of a generic type. This happens because the compiler has no way to guarantee that an `Array` " -"is droppable when executing the `main` function. In order to drop an array of `T`, the compiler must first know how to drop `T`. This can be fixed by specifiying in the function " +"will fail with an error saying that there are no traits defined for dropping an array of a generic type. This happens because the compiler has no way to guarantee that an `Array` " +"is droppable when executing the `main` function. In order to drop an array of `T`, the compiler must first know how to drop `T`. This can be fixed by specifying in the function " "signature of `largest_list` that `T` must implement the drop trait. The correct function definition of `largest_list` is as follows:" msgstr "" -"La función `largest_list` compara dos listas del mismo tipo y devuelve aquella con más elementos y elimina la otra. Si se compila el código anterior, se notará que fallará con un " -"error diciendo que no se han definido traits para eliminar un array de un tipo genérico. Esto sucede porque el compilador no tiene forma de garantizar que un `Array` sea " -"eliminable al ejecutar la función `main`. Para eliminar un array de `T`, el compilador primero debe saber cómo eliminar `T`. Esto se puede solucionar especificando en la firma de la " -"función `largest_list` que `T` debe implementar el trait de eliminación. La definición correcta de la función `largest_list` es la siguiente:" +"La función `largest_list` compara dos listas del mismo tipo y devuelve la que tiene más elementos y elimina la otra. Si compilas el código anterior, notarás que fallará con un error " +"diciendo que no hay traits definidos para soltar un array de un tipo genérico. Esto ocurre porque el compilador no tiene forma de garantizar que un `Array` es soltable al ejecutar " +"la función `main`. Para poder soltar un array de `T`, el compilador debe saber primero como soltar `T`. Esto puede solucionarse especificando en la firma de la función `largest_list` " +"que `T` debe implementar el rasgo drop. La definición correcta de la función `largest_list` es la siguiente:" #: src/ch07-01-generic-data-types.md:42 msgid "" "```rust\n" +"use array::ArrayTrait;\n" "fn largest_list>(l1: Array, l2: Array) -> Array {\n" " if l1.len() > l2.len() {\n" " l1\n" @@ -9598,6 +9996,7 @@ msgid "" "```" msgstr "" "```rust\n" +"use array::ArrayTrait;\n" "fn largest_list>(l1: Array, l2: Array) -> Array {\n" " if l1.len() > l2.len() {\n" " l1\n" @@ -9607,7 +10006,7 @@ msgstr "" "}\n" "```" -#: src/ch07-01-generic-data-types.md:52 +#: src/ch07-01-generic-data-types.md:53 msgid "" "The new `largest_list` function includes in its definition the requirement that whatever generic type is placed there, it must be droppable. The `main` function remains unchanged, " "the compiler is smart enough to deduct which concrete type is being used and if it implements the `Drop` trait." @@ -9615,11 +10014,11 @@ msgstr "" "La nueva función `largest_list` incluye en su definición el requisito de que cualquier tipo genérico que se coloque allí debe poder eliminarse. La función `main` sigue sin cambios, " "el compilador es lo suficientemente inteligente como para deducir qué tipo concreto se está utilizando y si implementa el trait `Drop`." -#: src/ch07-01-generic-data-types.md:54 +#: src/ch07-01-generic-data-types.md:55 msgid "### Constraints for Generic Types" msgstr "### Restricciones para Tipos Genéricos" -#: src/ch07-01-generic-data-types.md:56 +#: src/ch07-01-generic-data-types.md:57 msgid "" "When defining generic types, it is useful to have information about them. Knowing which traits a generic type implements allow us to use them more effectively in a functions logic at " "the cost of constraining the generic types that can be used with the function. We saw an example of this previously by adding the `TDrop` implementation as part of the generic " @@ -9629,7 +10028,7 @@ msgstr "" "a costa de limitar los tipos genéricos que se pueden usar con la función. Vimos un ejemplo de esto anteriormente al agregar la implementación de `TDrop` como parte de los argumentos " "genéricos de `largest_list`. Si bien `TDrop` se agregó para cumplir con los requisitos del compilador, también podemos agregar restricciones para beneficiar nuestra lógica de función." -#: src/ch07-01-generic-data-types.md:58 +#: src/ch07-01-generic-data-types.md:59 msgid "" "Imagine that we want, given a list of elements of some generic type `T`, find the smallest element among them. Initially, we know that for an element of type `T` to be comparable, it " "must implement the `PartialOrd` trait. The resulting function would be:" @@ -9637,25 +10036,25 @@ msgstr "" "Imaginemos que queremos, dado una lista de elementos de algún tipo genérico `T`, encontrar el elemento más pequeño entre ellos. Inicialmente, sabemos que para que un elemento de tipo " "`T` sea comparable, debe implementar el trait `PartialOrd`. La función resultante sería:" -#: src/ch07-01-generic-data-types.md:60 +#: src/ch07-01-generic-data-types.md:61 msgid "" -"```rust,does_not_compile\n" -"// This code does not compile!\n" -"use array:ArrayTrait;\n" +"```rust\n" +"// does_not_compile\n" +"use array::ArrayTrait;\n" "\n" "// Given a list of T get the smallest one.\n" "// The PartialOrd trait implements comparison operations for T\n" "fn smallest_element>(list: @Array) -> T {\n" " // This represents the smallest element through the iteration\n" " // Notice that we use the desnap (*) operator\n" -" let mut smallest = *list[0_usize];\n" +" let mut smallest = *list[0];\n" "\n" " // The index we will use to move through the list\n" -" let mut index = 1_usize;\n" +" let mut index = 1;\n" "\n" " // Iterate through the whole list storing the smallest\n" " loop {\n" -" if index >= list.len(){\n" +" if index >= list.len() {\n" " break smallest;\n" " }\n" " if *list[index] < smallest {\n" @@ -9665,36 +10064,35 @@ msgid "" " }\n" "}\n" "\n" -"fn main() {\n" -" let mut list = ArrayTrait::new();\n" -" list.append(5_u8);\n" -" list.append(3_u8);\n" -" list.append(10_u8);\n" +"fn main() {\n" +" let mut list: Array = ArrayTrait::new();\n" +" list.append(5);\n" +" list.append(3);\n" +" list.append(10);\n" "\n" " // We need to specify that we are passing a snapshot of `list` as an argument\n" " let s = smallest_element(@list);\n" -" assert(s == 3_u8, 0);\n" -"\n" +" assert(s == 3, 0);\n" "}\n" "```" msgstr "" -"```rust,does_not_compile\n" -"// This code does not compile!\n" -"use array:ArrayTrait;\n" +"```rust\n" +"// does_not_compile\n" +"use array::ArrayTrait;\n" "\n" "// Given a list of T get the smallest one.\n" "// The PartialOrd trait implements comparison operations for T\n" "fn smallest_element>(list: @Array) -> T {\n" " // This represents the smallest element through the iteration\n" " // Notice that we use the desnap (*) operator\n" -" let mut smallest = *list[0_usize];\n" +" let mut smallest = *list[0];\n" "\n" " // The index we will use to move through the list\n" -" let mut index = 1_usize;\n" +" let mut index = 1;\n" "\n" " // Iterate through the whole list storing the smallest\n" " loop {\n" -" if index >= list.len(){\n" +" if index >= list.len() {\n" " break smallest;\n" " }\n" " if *list[index] < smallest {\n" @@ -9704,22 +10102,21 @@ msgstr "" " }\n" "}\n" "\n" -"fn main() {\n" -" let mut list = ArrayTrait::new();\n" -" list.append(5_u8);\n" -" list.append(3_u8);\n" -" list.append(10_u8);\n" +"fn main() {\n" +" let mut list: Array = ArrayTrait::new();\n" +" list.append(5);\n" +" list.append(3);\n" +" list.append(10);\n" "\n" " // We need to specify that we are passing a snapshot of `list` as an argument\n" " let s = smallest_element(@list);\n" -" assert(s == 3_u8, 0);\n" -"\n" +" assert(s == 3, 0);\n" "}\n" "```" #: src/ch07-01-generic-data-types.md:99 msgid "" -"The `smallest_element` function uses a generic type `T` that implements the `PartialOrd` trait, takes an snapshot of an `Array` as a parameter and returns a copy of the smallest " +"The `smallest_element` function uses a generic type `T` that implements the `PartialOrd` trait, takes a snapshot of an `Array` as a parameter and returns a copy of the smallest " "element. Because the parameter is of type `@Array`, we no longer need to drop it at the end of the execution and so we don't require to implement the `Drop` trait for `T` as well. " "Why it does not compile then?" msgstr "" @@ -9742,11 +10139,14 @@ msgstr "" #: src/ch07-01-generic-data-types.md:103 msgid "" "```rs\n" -"fn smallest_element, impl TCopy: Copy, impl TDrop: Drop>(list: @Array) -> T {\n" -" let mut smallest = *list[0_usize];\n" -" let mut index = 1_usize;\n" +"use array::ArrayTrait;\n" +"fn smallest_element, impl TCopy: Copy, impl TDrop: Drop>(\n" +" list: @Array\n" +") -> T {\n" +" let mut smallest = *list[0];\n" +" let mut index = 1;\n" " loop {\n" -" if index >= list.len(){\n" +" if index >= list.len() {\n" " break smallest;\n" " }\n" " if *list[index] < smallest {\n" @@ -9758,11 +10158,14 @@ msgid "" "```" msgstr "" "```rs\n" -"fn smallest_element, impl TCopy: Copy, impl TDrop: Drop>(list: @Array) -> T {\n" -" let mut smallest = *list[0_usize];\n" -" let mut index = 1_usize;\n" +"use array::ArrayTrait;\n" +"fn smallest_element, impl TCopy: Copy, impl TDrop: Drop>(\n" +" list: @Array\n" +") -> T {\n" +" let mut smallest = *list[0];\n" +" let mut index = 1;\n" " loop {\n" -" if index >= list.len(){\n" +" if index >= list.len() {\n" " break smallest;\n" " }\n" " if *list[index] < smallest {\n" @@ -9773,11 +10176,11 @@ msgstr "" "}\n" "```" -#: src/ch07-01-generic-data-types.md:119 +#: src/ch07-01-generic-data-types.md:122 msgid "## Structs" msgstr "## Structs (Estructuras)" -#: src/ch07-01-generic-data-types.md:121 +#: src/ch07-01-generic-data-types.md:124 msgid "" "We can also define structs to use a generic type parameter for one or more fields using the `<>` syntax, similar to function definitions. First we declare the name of the type " "parameter inside the angle brackets just after the name of the struct. Then we use the generic type in the struct definition where we would otherwise specify concrete data types. The " @@ -9787,73 +10190,63 @@ msgstr "" "el nombre del parámetro de tipo dentro de los corchetes angulares justo después del nombre de la estructura. Luego usamos el tipo genérico en la definición de la estructura donde de " "otra manera especificaríamos tipos de datos concretos. El siguiente ejemplo de código muestra la definición de `Wallet` que tiene un campo `balance` de tipo `T`." -#: src/ch07-01-generic-data-types.md:123 +#: src/ch07-01-generic-data-types.md:126 msgid "" -"```rust,does_not_compile\n" -"// This code does not compile!\n" -"\n" +"```rust\n" "#[derive(Drop)]\n" "struct Wallet {\n" -" balance: T,\n" +" balance: T\n" "}\n" "\n" "\n" "fn main() {\n" -" let w = Wallet{ balance: 3_u128};\n" +" let w = Wallet { balance: 3 };\n" "}\n" "```" msgstr "" -"```rust,does_not_compile\n" -"// This code does not compile!\n" -"\n" +"```rust\n" "#[derive(Drop)]\n" "struct Wallet {\n" -" balance: T,\n" +" balance: T\n" "}\n" "\n" "\n" "fn main() {\n" -" let w = Wallet{ balance: 3_u128};\n" +" let w = Wallet { balance: 3 };\n" "}\n" "```" -#: src/ch07-01-generic-data-types.md:137 -msgid "Compiling the above code would error due to the `derive` macro not working well with generics. When using generic types is best to directly write the traits you want to use:" -msgstr "" -"La compilación del código anterior daría un error debido a que la macro `derive` no funciona bien con tipos genéricos. Cuando se usan tipos genéricos, es mejor escribir directamente " -"los traits que se quieren utilizar:" - -#: src/ch07-01-generic-data-types.md:139 -msgid "" -msgstr "" +#: src/ch07-01-generic-data-types.md:138 +msgid "The above code derives the `Drop` trait for the `Wallet` type automatically. It is equivalent to writing the following code:" +msgstr "El código anterior deriva el trait `Drop` para el tipo `Wallet` automáticamente. Es equivalente a escribir el siguiente código:" -#: src/ch07-01-generic-data-types.md:141 +#: src/ch07-01-generic-data-types.md:140 msgid "" "```rust\n" "struct Wallet {\n" -" balance: T,\n" +" balance: T\n" "}\n" "\n" "impl WalletDrop> of Drop>;\n" "\n" "fn main() {\n" -" let w = Wallet { balance: 3_u128 };\n" +" let w = Wallet { balance: 3 };\n" "}\n" "```" msgstr "" "```rust\n" "struct Wallet {\n" -" balance: T,\n" +" balance: T\n" "}\n" "\n" "impl WalletDrop> of Drop>;\n" "\n" "fn main() {\n" -" let w = Wallet { balance: 3_u128 };\n" +" let w = Wallet { balance: 3 };\n" "}\n" "```" -#: src/ch07-01-generic-data-types.md:153 +#: src/ch07-01-generic-data-types.md:152 msgid "" "We avoid using the `derive` macro for `Drop` implementation of `Wallet` and instead define our own `WalletDrop` implementation. Notice that we must define, just like functions, an " "additional generic type for `WalletDrop` saying that `T` implements the `Drop` trait as well. We are basically saying that the struct `Wallet` is droppable as long as `T` is also " @@ -9863,79 +10256,59 @@ msgstr "" "al igual que en las funciones, un tipo genérico adicional para `WalletDrop` diciendo que `T` también implementa el trait `Drop`. Básicamente estamos diciendo que la estructura " "`Wallet` es dropeable siempre y cuando `T` también lo sea." -#: src/ch07-01-generic-data-types.md:155 +#: src/ch07-01-generic-data-types.md:154 msgid "" -"Finally, if we want to add a field to `Wallet` representing its Cairo address and we want that field to be different than `T` but generic as well, we can simply add another generic " -"type between the `<>`:" +"Finally, if we want to add a field to `Wallet` representing its address and we want that field to be different than `T` but generic as well, we can simply add another generic type " +"between the `<>`:" msgstr "" -"Finalmente, si queremos agregar un campo a `Wallet` que represente su dirección de Cairo y queremos que ese campo sea diferente a `T` pero también genérico, simplemente podemos " -"agregar otro tipo genérico entre los `<>`:" +"Finalmente, si queremos añadir un campo a `Wallet` que represente su dirección y queremos que ese campo sea diferente de `T` pero genérico también, podemos simplemente añadir otro " +"tipo genérico entre el `<>`:" -#: src/ch07-01-generic-data-types.md:157 +#: src/ch07-01-generic-data-types.md:156 msgid "" "```rust\n" +"#[derive(Drop)]\n" "struct Wallet {\n" " balance: T,\n" " address: U,\n" "}\n" "\n" -"impl WalletDrop, U, impl UDrop: Drop> of Drop>;\n" -"\n" "fn main() {\n" -" let w = Wallet { balance: 3_u128, address: 14 };\n" +" let w = Wallet { balance: 3, address: 14 };\n" "}\n" "```" msgstr "" "```rust\n" +"#[derive(Drop)]\n" "struct Wallet {\n" " balance: T,\n" " address: U,\n" "}\n" "\n" -"impl WalletDrop, U, impl UDrop: Drop> of Drop>;\n" -"\n" "fn main() {\n" -" let w = Wallet { balance: 3_u128, address: 14 };\n" +" let w = Wallet { balance: 3, address: 14 };\n" "}\n" "```" -#: src/ch07-01-generic-data-types.md:170 +#: src/ch07-01-generic-data-types.md:168 msgid "" -"We add to `Wallet` struct definiton a new generic type `U` and then assign this type to the new field member `address`.\n" -"Then we adapt the `WalletDrop` trait to work with the new generic type `U`. Notice that when initializing the struct inside `main` it automatically infers that `T` is a `u128` and " -"`U` is a `felt252` and since they are both droppable, `Wallet` is droppable as well!" +"We add to `Wallet` struct definition a new generic type `U` and then assign this type to the new field member `address`. Notice that the derive attribute for the `Drop` trait works " +"for `U` as well." msgstr "" -"Agregamos a la definición de la estructura `Wallet` un nuevo tipo genérico `U` y luego asignamos este tipo al nuevo miembro del campo `address`. Luego adaptamos el trait `WalletDrop` " -"para que funcione con el nuevo tipo genérico `U`. ¡Observa que al inicializar la estructura dentro de `main`, automáticamente infiere que `T` es un `u128` y `U` es un `felt252` y " -"como ambos son droppable, `Wallet` también lo es!" +"Añadimos a la definición de la estructura `Wallet` un nuevo tipo genérico `U` y asignamos este tipo al nuevo campo miembro `address`. Observa que el atributo derive del rasgo `Drop` " +"también funciona para `U`." -#: src/ch07-01-generic-data-types.md:173 +#: src/ch07-01-generic-data-types.md:170 msgid "## Enums" msgstr "## Enums (Enumeraciones)" -#: src/ch07-01-generic-data-types.md:175 +#: src/ch07-01-generic-data-types.md:172 msgid "As we did with structs, we can define enums to hold generic data types in their variants. For example the `Option` enum provided by the Cairo core library:" msgstr "" "Como hicimos con las estructuras, podemos definir enumeraciones para contener tipos de datos genéricos en sus variantes. Por ejemplo, la enumeración `Option` proporcionada por la " "biblioteca central de Cairo:" -#: src/ch07-01-generic-data-types.md:177 -msgid "" -"```rust\n" -"enum Option {\n" -" Some(T),\n" -" None,\n" -"}\n" -"```" -msgstr "" -"```rust\n" -"enum Option {\n" -" Some(T),\n" -" None,\n" -"}\n" -"```" - -#: src/ch07-01-generic-data-types.md:184 +#: src/ch07-01-generic-data-types.md:181 msgid "" "The `Option` enum is generic over a type `T` and has two variants: `Some`, which holds one value of type `T` and `None` that doesn't hold any value. By using the `Option` enum, " "it is possible for us to express the abstract concept of an optional value and because the value has a generic type `T` we can use this abstraction with any type." @@ -9943,27 +10316,27 @@ msgstr "" "El enum `Option` es genérico sobre un tipo `T` y tiene dos variantes: `Some`, que contiene un valor de tipo `T`, y `None`, que no contiene ningún valor. Al utilizar el enum " "`Option`, es posible expresar el concepto abstracto de un valor opcional y debido a que el valor tiene un tipo genérico `T`, podemos utilizar esta abstracción con cualquier tipo." -#: src/ch07-01-generic-data-types.md:186 +#: src/ch07-01-generic-data-types.md:183 msgid "Enums can use multiple generic types as well, like definition of the `Result` enum that the core library provides:" msgstr "Los Enums también pueden utilizar múltiples tipos genéricos, como la definición del enum `Result` que proporciona la biblioteca estándar:" -#: src/ch07-01-generic-data-types.md:188 src/ch09-02-error-handling.md:11 +#: src/ch07-01-generic-data-types.md:185 src/ch09-02-recoverable-errors.md:11 msgid "" "```rust\n" "enum Result {\n" -" Ok(T),\n" -" Err(E),\n" +" Ok: T,\n" +" Err: E,\n" "}\n" "```" msgstr "" "```rust\n" "enum Result {\n" -" Ok(T),\n" -" Err(E),\n" +" Ok: T,\n" +" Err: E,\n" "}\n" "```" -#: src/ch07-01-generic-data-types.md:195 src/ch09-02-error-handling.md:18 +#: src/ch07-01-generic-data-types.md:192 src/ch09-02-recoverable-errors.md:18 msgid "" "The `Result` enum has two generic types, `T` and `E`, and two variants: `Ok` which holds the value of type `T` and `Err` which holds the value of type `E`. This definition " "makes it convenient to use the `Result` enum anywhere we have an operation that might succeed (by returning a value of type `T`) or fail (by returning a value of type `E`)." @@ -9971,11 +10344,11 @@ msgstr "" "El enum `Result` tiene dos tipos genéricos, `T` y `E`, y dos variantes: `Ok` que tiene el valor de tipo `T` y `Err` que tiene el valor de tipo `E`. Esta definición hace que sea " "conveniente usar el enum `Result` en cualquier lugar donde tengamos una operación que pueda tener éxito (devolviendo un valor de tipo `T`) o fallar (devolviendo un valor de tipo `E`)." -#: src/ch07-01-generic-data-types.md:197 +#: src/ch07-01-generic-data-types.md:194 msgid "## Generic Methods" msgstr "## Métodos Genéricos" -#: src/ch07-01-generic-data-types.md:199 +#: src/ch07-01-generic-data-types.md:196 msgid "" "We can implement methods on structs and enums, and use the generic types in their definition, too. Using our previous definition of `Wallet` struct, we define a `balance` method " "for it:" @@ -9983,16 +10356,14 @@ msgstr "" "También podemos implementar métodos en structs y enums, y usar los tipos genéricos en su definición. Utilizando nuestra definición anterior de la struct `Wallet`, definimos un " "método `balance` para ella:" -#: src/ch07-01-generic-data-types.md:201 +#: src/ch07-01-generic-data-types.md:198 msgid "" "```rust\n" +"#[derive(Copy, Drop)]\n" "struct Wallet {\n" -" balance: T,\n" +" balance: T\n" "}\n" "\n" -"impl WalletDrop> of Drop>;\n" -"impl WalletCopy> of Copy>;\n" -"\n" "trait WalletTrait {\n" " fn balance(self: @Wallet) -> T;\n" "}\n" @@ -10010,13 +10381,11 @@ msgid "" "```" msgstr "" "```rust\n" +"#[derive(Copy, Drop)]\n" "struct Wallet {\n" -" balance: T,\n" +" balance: T\n" "}\n" "\n" -"impl WalletDrop> of Drop>;\n" -"impl WalletCopy> of Copy>;\n" -"\n" "trait WalletTrait {\n" " fn balance(self: @Wallet) -> T;\n" "}\n" @@ -10033,7 +10402,7 @@ msgstr "" "}\n" "```" -#: src/ch07-01-generic-data-types.md:225 +#: src/ch07-01-generic-data-types.md:220 msgid "" "We first define `WalletTrait` trait using a generic type `T` which defines a method that returns a snapshot of the field `address` from `Wallet`. Then we give an implementation " "for the trait in `WalletImpl`. Note that you need to include a generic type in both definitions of the trait and the implementation." @@ -10041,7 +10410,7 @@ msgstr "" "Primero definimos la clase `WalletTrait` usando un tipo genérico `T` que define un método que devuelve una instantánea del campo `address` de `Wallet`. Luego, damos una " "implementación de la clase en `WalletImpl`. Ten en cuenta que debes incluir un tipo genérico en ambas definiciones de la clase y la implementación." -#: src/ch07-01-generic-data-types.md:227 +#: src/ch07-01-generic-data-types.md:222 msgid "" "We can also specify constraints on generic types when defining methods on the type. We could, for example, implement methods only for `Wallet` instances rather than " "`Wallet`. In the code example we define an implementation for wallets which have a concrete type of `u128` for the `balance` field." @@ -10049,14 +10418,14 @@ msgstr "" "También podemos especificar restricciones en los tipos genéricos al definir métodos en la clase. Por ejemplo, podríamos implementar métodos solo para instancias de `Wallet` en " "lugar de `Wallet`. En el ejemplo de código, definimos una implementación para carteras que tienen un tipo concreto de `u128` para el campo `balance`." -#: src/ch07-01-generic-data-types.md:229 +#: src/ch07-01-generic-data-types.md:224 msgid "" "```rust\n" +"#[derive(Copy, Drop)]\n" "struct Wallet {\n" -" balance: T,\n" +" balance: T\n" "}\n" -"impl WalletDrop> of Drop>;\n" -"impl WalletCopy> of Copy>;\n" +"\n" "/// Generic trait for wallets\n" "trait WalletTrait {\n" " fn balance(self: @Wallet) -> T;\n" @@ -10080,20 +10449,20 @@ msgid "" "}\n" "\n" "fn main() {\n" -" let mut w = Wallet { balance: 50_u128 };\n" -" assert(w.balance() == 50_u128, 0);\n" +" let mut w = Wallet { balance: 50 };\n" +" assert(w.balance() == 50, 0);\n" "\n" -" w.receive(100_u128);\n" -" assert(w.balance() == 150_u128, 0);\n" +" w.receive(100);\n" +" assert(w.balance() == 150, 0);\n" "}\n" "```" msgstr "" "```rust\n" +"#[derive(Copy, Drop)]\n" "struct Wallet {\n" -" balance: T,\n" +" balance: T\n" "}\n" -"impl WalletDrop> of Drop>;\n" -"impl WalletCopy> of Copy>;\n" +"\n" "/// Generic trait for wallets\n" "trait WalletTrait {\n" " fn balance(self: @Wallet) -> T;\n" @@ -10117,15 +10486,15 @@ msgstr "" "}\n" "\n" "fn main() {\n" -" let mut w = Wallet { balance: 50_u128 };\n" -" assert(w.balance() == 50_u128, 0);\n" +" let mut w = Wallet { balance: 50 };\n" +" assert(w.balance() == 50, 0);\n" "\n" -" w.receive(100_u128);\n" -" assert(w.balance() == 150_u128, 0);\n" +" w.receive(100);\n" +" assert(w.balance() == 150, 0);\n" "}\n" "```" -#: src/ch07-01-generic-data-types.md:266 +#: src/ch07-01-generic-data-types.md:261 msgid "" "The new method `receive` increments the size of the balance of any instance of a `Wallet`. Notice that we changed the `main` function making `w` a mutable variable in order for " "it to be able to update its balance. If we were to change the initialization of `w` by changing the type of `balance` the previous code wouldn't compile." @@ -10133,37 +10502,38 @@ msgstr "" "El nuevo método `receive` incrementa el tamaño del saldo de cualquier instancia de una `Wallet`. Observe que se cambió la función `main` haciendo que `w` sea una variable " "mutable para que pueda actualizar su saldo. Si cambiáramos la inicialización de `w` cambiando el tipo de `balance`, el código anterior no se compilaría." -#: src/ch07-01-generic-data-types.md:268 +#: src/ch07-01-generic-data-types.md:263 msgid "" "Cairo allows us to define generic methods inside generic traits as well. Using the past implementation from `Wallet` we are going to define a trait that picks two wallets of " -"different generic types and create a new one with a generic type of each. First, lets rewrite the struct definiton:" +"different generic types and create a new one with a generic type of each. First, let's rewrite the struct definition:" msgstr "" "Cairo nos permite definir métodos genéricos dentro de traits genéricos también. Usando la implementación previa de `Wallet`, vamos a definir un trait que tome dos wallets de " "diferentes tipos genéricos y cree uno nuevo con un tipo genérico de cada uno. Primero, reescribamos la definición de la estructura:" -#: src/ch07-01-generic-data-types.md:270 +#: src/ch07-01-generic-data-types.md:265 msgid "" "```rust\n" +"// does_not_compile\n" "struct Wallet {\n" " balance: T,\n" " address: U,\n" -"}\n" "```" msgstr "" "```rust\n" +"// does_not_compile\n" "struct Wallet {\n" " balance: T,\n" " address: U,\n" -"}\n" "```" -#: src/ch07-01-generic-data-types.md:277 +#: src/ch07-01-generic-data-types.md:272 msgid "Next we are going to naively define the mixup trait and implementation:" msgstr "A continuación vamos a definir ingenuamente el rasgo mixup y su implementación:" -#: src/ch07-01-generic-data-types.md:279 +#: src/ch07-01-generic-data-types.md:274 msgid "" "```rust\n" +"\n" "// This does not compile!\n" "trait WalletMixTrait {\n" " fn mixup(self: Wallet, other: Wallet) -> Wallet;\n" @@ -10173,10 +10543,11 @@ msgid "" " fn mixup(self: Wallet, other: Wallet) -> Wallet {\n" " Wallet { balance: self.balance, address: other.address }\n" " }\n" -"}\n" +"\n" "```" msgstr "" "```rust\n" +"\n" "// This does not compile!\n" "trait WalletMixTrait {\n" " fn mixup(self: Wallet, other: Wallet) -> Wallet;\n" @@ -10186,22 +10557,22 @@ msgstr "" " fn mixup(self: Wallet, other: Wallet) -> Wallet {\n" " Wallet { balance: self.balance, address: other.address }\n" " }\n" -"}\n" +"\n" "```" -#: src/ch07-01-generic-data-types.md:292 +#: src/ch07-01-generic-data-types.md:288 msgid "" "We are creating a trait `WalletMixTrait` with the `mixup` methods which given an instance of `Wallet` and `Wallet` creates a new `Wallet`. As " "`mixup` signature specify, both `self` and `other` are getting dropped at the end of the function, which is the reason for this code not to compile. If you have been following from " -"the start until now you would know that we must add a requirement for all the generic types specifiying that they will implement the `Drop` trait in order for the compiler to know " -"how to drop instances of `Wallet`. The updated implementation is as follow:" +"the start until now you would know that we must add a requirement for all the generic types specifying that they will implement the `Drop` trait in order for the compiler to know how " +"to drop instances of `Wallet`. The updated implementation is as follow:" msgstr "" "Estamos creando un trait `WalletMixTrait` con el método `mixup` que, dada una instancia de `Wallet` y `Wallet`, crea un nuevo `Wallet`. Como " "especifica la firma de `mixup`, tanto `self` como `other` se están eliminando al final de la función, lo que hace que este código no se compile. Si has estado siguiendo desde el " "principio hasta ahora, sabrás que debemos agregar un requisito para todos los tipos genéricos especificando que implementarán el trait `Drop` para que el compilador sepa cómo " "eliminar las instancias de `Wallet`. La implementación actualizada es la siguiente:" -#: src/ch07-01-generic-data-types.md:294 +#: src/ch07-01-generic-data-types.md:290 msgid "" "```rust\n" "trait WalletMixTrait {\n" @@ -10235,7 +10606,7 @@ msgstr "" "}\n" "```" -#: src/ch07-01-generic-data-types.md:310 +#: src/ch07-01-generic-data-types.md:306 msgid "" "We add the requirements for `T1` and `U1` to be droppable on `WalletMixImpl` declaration. Then we do the same for `T2` and `U2`, this time as part of `mixup` signature. We can now " "try the `mixup` function:" @@ -10243,33 +10614,33 @@ msgstr "" "Sí, agregamos los requisitos para que `T1` y `U1` sean droppables en la declaración de `WalletMixImpl`. Luego hacemos lo mismo para `T2` y `U2`, esta vez como parte de la firma de " "`mixup`. Ahora podemos probar la función `mixup`:" -#: src/ch07-01-generic-data-types.md:312 +#: src/ch07-01-generic-data-types.md:308 msgid "" -"```rs, does_not_compile\n" +"```rust\n" "fn main() {\n" -" let w1 = Wallet { balance: true, address: 10_u128 };\n" -" let w2 = Wallet { balance: 32, address: 100_u8 };\n" +" let w1 = Wallet { balance: true, address: 10 };\n" +" let w2 = Wallet { balance: 32, address: 100 };\n" "\n" " let w3 = w1.mixup(w2);\n" "\n" " assert(w3.balance == true, 0);\n" -" assert(w3.address == 100_u8, 0);\n" +" assert(w3.address == 100, 0);\n" "}\n" "```" msgstr "" -"```rs, does_not_compile\n" +"```rust\n" "fn main() {\n" -" let w1 = Wallet { balance: true, address: 10_u128 };\n" -" let w2 = Wallet { balance: 32, address: 100_u8 };\n" +" let w1 = Wallet { balance: true, address: 10 };\n" +" let w2 = Wallet { balance: 32, address: 100 };\n" "\n" " let w3 = w1.mixup(w2);\n" "\n" " assert(w3.balance == true, 0);\n" -" assert(w3.address == 100_u8, 0);\n" +" assert(w3.address == 100, 0);\n" "}\n" "```" -#: src/ch07-01-generic-data-types.md:324 +#: src/ch07-01-generic-data-types.md:320 msgid "We first create two instances: one of `Wallet` and the other of `Wallet`. Then, we call `mixup` and create a new `Wallet` instance." msgstr "Primero creamos dos instancias: una de `Wallet` y la otra de `Wallet`. Luego, llamamos a `mixup` y creamos una nueva instancia de `Wallet`." @@ -10342,7 +10713,7 @@ msgid "" "```rust\n" "impl RectangleGeometry of ShapeGeometry {\n" "\tfn boundary(self: Rectangle) -> u64 {\n" -" 2_u64 * (self.height + self.width)\n" +" 2 * (self.height + self.width)\n" " }\n" "\tfn area(self: Rectangle) -> u64 {\n" "\t\tself.height * self.width\n" @@ -10353,7 +10724,7 @@ msgstr "" "```rust\n" "impl RectangleGeometry of ShapeGeometry {\n" "\tfn boundary(self: Rectangle) -> u64 {\n" -" 2_u64 * (self.height + self.width)\n" +" 2 * (self.height + self.width)\n" " }\n" "\tfn area(self: Rectangle) -> u64 {\n" "\t\tself.height * self.width\n" @@ -10436,18 +10807,18 @@ msgid "" "```rust\n" "use debug::PrintTrait;\n" "\n" -"#[derive(Copy,Drop)]\n" -"struct Rectangle{\n" +"#[derive(Copy, Drop)]\n" +"struct Rectangle {\n" " height: u64,\n" " width: u64,\n" "}\n" "\n" -"#[derive(Copy,Drop)]\n" -"struct Circle{\n" -" radius: u64,\n" +"#[derive(Copy, Drop)]\n" +"struct Circle {\n" +" radius: u64\n" "}\n" "\n" -"// Here T is an alias type which will be provided buring implementation\n" +"// Here T is an alias type which will be provided during implementation\n" "trait ShapeGeometry {\n" " fn boundary(self: T) -> u64;\n" " fn area(self: T) -> u64;\n" @@ -10457,7 +10828,7 @@ msgid "" "// to implement the trait for that type\n" "impl RectangleGeometry of ShapeGeometry {\n" " fn boundary(self: Rectangle) -> u64 {\n" -" 2_u64 * (self.height + self.width)\n" +" 2 * (self.height + self.width)\n" " }\n" " fn area(self: Rectangle) -> u64 {\n" " self.height * self.width\n" @@ -10468,19 +10839,19 @@ msgid "" "// which can use the same trait spec\n" "impl CircleGeometry of ShapeGeometry {\n" " fn boundary(self: Circle) -> u64 {\n" -" (2_u64 * 314_u64 * self.radius) / 100_u64\n" +" (2 * 314 * self.radius) / 100\n" " }\n" " fn area(self: Circle) -> u64 {\n" -" (314_u64 * self.radius * self.radius) / 100_u64\n" +" (314 * self.radius * self.radius) / 100\n" " }\n" "}\n" "\n" "fn main() {\n" -" let rect = Rectangle { height: 5_u64, width: 7_u64 };\n" +" let rect = Rectangle { height: 5, width: 7 };\n" " rect.area().print(); // 35\n" " rect.boundary().print(); // 24\n" "\n" -" let circ = Circle { radius: 5_u64 };\n" +" let circ = Circle { radius: 5 };\n" " circ.area().print(); // 78\n" " circ.boundary().print(); // 31\n" "}\n" @@ -10489,18 +10860,18 @@ msgstr "" "```rust\n" "use debug::PrintTrait;\n" "\n" -"#[derive(Copy,Drop)]\n" -"struct Rectangle{\n" +"#[derive(Copy, Drop)]\n" +"struct Rectangle {\n" " height: u64,\n" " width: u64,\n" "}\n" "\n" -"#[derive(Copy,Drop)]\n" -"struct Circle{\n" -" radius: u64,\n" +"#[derive(Copy, Drop)]\n" +"struct Circle {\n" +" radius: u64\n" "}\n" "\n" -"// Here T is an alias type which will be provided buring implementation\n" +"// Here T is an alias type which will be provided during implementation\n" "trait ShapeGeometry {\n" " fn boundary(self: T) -> u64;\n" " fn area(self: T) -> u64;\n" @@ -10510,7 +10881,7 @@ msgstr "" "// to implement the trait for that type\n" "impl RectangleGeometry of ShapeGeometry {\n" " fn boundary(self: Rectangle) -> u64 {\n" -" 2_u64 * (self.height + self.width)\n" +" 2 * (self.height + self.width)\n" " }\n" " fn area(self: Rectangle) -> u64 {\n" " self.height * self.width\n" @@ -10521,19 +10892,19 @@ msgstr "" "// which can use the same trait spec\n" "impl CircleGeometry of ShapeGeometry {\n" " fn boundary(self: Circle) -> u64 {\n" -" (2_u64 * 314_u64 * self.radius) / 100_u64\n" +" (2 * 314 * self.radius) / 100\n" " }\n" " fn area(self: Circle) -> u64 {\n" -" (314_u64 * self.radius * self.radius) / 100_u64\n" +" (314 * self.radius * self.radius) / 100\n" " }\n" "}\n" "\n" "fn main() {\n" -" let rect = Rectangle { height: 5_u64, width: 7_u64 };\n" +" let rect = Rectangle { height: 5, width: 7 };\n" " rect.area().print(); // 35\n" " rect.boundary().print(); // 24\n" "\n" -" let circ = Circle { radius: 5_u64 };\n" +" let circ = Circle { radius: 5 };\n" " circ.area().print(); // 78\n" " circ.boundary().print(); // 31\n" "}\n" @@ -10566,7 +10937,7 @@ msgstr "Si el código estuviera organizado en módulos de esta manera," #: src/ch07-02-traits-in-cairo.md:125 msgid "" -"```rust, does_not_compile\n" +"```rust,does_not_compile,ignore_format\n" "use debug::PrintTrait;\n" "\n" "// struct Circle { ... } and struct Rectangle { ... }\n" @@ -10586,14 +10957,14 @@ msgid "" "mod circle {\n" " use super::geometry::ShapeGeometry;\n" " use super::Circle;\n" -" impl CircleGeometry of ShapeGeometry:: {\n" +" impl CircleGeometry of ShapeGeometry {\n" " // ...\n" " }\n" "}\n" "\n" "fn main() {\n" -" let rect = Rectangle { height: 5_u64, width: 7_u64 };\n" -" let circ = Circle { radius: 5_u64 };\n" +" let rect = Rectangle { height: 5, width: 7 };\n" +" let circ = Circle { radius: 5 };\n" " // Fails with this error\n" " // Method `area` not found on... Did you import the correct trait and impl?\n" " rect.area().print();\n" @@ -10601,7 +10972,7 @@ msgid "" "}\n" "```" msgstr "" -"```rust, does_not_compile\n" +"```rust,does_not_compile,ignore_format\n" "use debug::PrintTrait;\n" "\n" "// struct Circle { ... } and struct Rectangle { ... }\n" @@ -10621,14 +10992,14 @@ msgstr "" "mod circle {\n" " use super::geometry::ShapeGeometry;\n" " use super::Circle;\n" -" impl CircleGeometry of ShapeGeometry:: {\n" +" impl CircleGeometry of ShapeGeometry {\n" " // ...\n" " }\n" "}\n" "\n" "fn main() {\n" -" let rect = Rectangle { height: 5_u64, width: 7_u64 };\n" -" let circ = Circle { radius: 5_u64 };\n" +" let rect = Rectangle { height: 5, width: 7 };\n" +" let circ = Circle { radius: 5 };\n" " // Fails with this error\n" " // Method `area` not found on... Did you import the correct trait and impl?\n" " rect.area().print();\n" @@ -10694,8 +11065,8 @@ msgstr "" #: src/ch08-01-how-to-write-tests.md:11 msgid "" -"Let’s look at the features Cairo provides specifically for writing tests that take these actions, which include the `test` attribute, the `assert` function, and and the " -"`should_panic` attribute." +"Let’s look at the features Cairo provides specifically for writing tests that take these actions, which include the `test` attribute, the `assert` function, and the `should_panic` " +"attribute." msgstr "" "Veamos las características específicas que Cairo proporciona para escribir pruebas que realizan estas acciones, que incluyen el atributo `test`, la función `assert` y el atributo " "`should_panic`." @@ -10770,41 +11141,35 @@ msgstr "" msgid "In _lib.cairo_, let's add a first test, as shown in Listing 8-1." msgstr "En _lib.cairo_, agreguemos una primera prueba, como se muestra en el Listado 8-1." -#: src/ch08-01-how-to-write-tests.md:43 src/ch08-01-how-to-write-tests.md:79 src/ch08-01-how-to-write-tests.md:140 src/ch08-01-how-to-write-tests.md:162 -#: src/ch08-01-how-to-write-tests.md:201 src/ch08-01-how-to-write-tests.md:274 src/ch08-01-how-to-write-tests.md:355 src/ch08-02-test-organization.md:19 +#: src/ch08-01-how-to-write-tests.md:43 src/ch08-01-how-to-write-tests.md:76 src/ch08-01-how-to-write-tests.md:132 src/ch08-01-how-to-write-tests.md:155 +#: src/ch08-01-how-to-write-tests.md:221 src/ch08-01-how-to-write-tests.md:319 src/ch08-01-how-to-write-tests.md:411 src/ch08-02-test-organization.md:19 #: src/ch09-01-unrecoverable-errors-with-panic.md:9 msgid "Filename: lib.cairo" msgstr "Filename: lib.cairo" -#: src/ch08-01-how-to-write-tests.md:45 src/ch08-02-test-organization.md:21 +#: src/ch08-01-how-to-write-tests.md:45 msgid "" "```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" " #[test]\n" " fn it_works() {\n" " let result = 2 + 2;\n" " assert(result == 4, 'result is not 4');\n" " }\n" -"}\n" "```" msgstr "" "```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" " #[test]\n" " fn it_works() {\n" " let result = 2 + 2;\n" " assert(result == 4, 'result is not 4');\n" " }\n" -"}\n" "```" -#: src/ch08-01-how-to-write-tests.md:56 -msgid "Listing 8-1: A test module and function" -msgstr "Listado 8-1: Un módulo y función de prueba" +#: src/ch08-01-how-to-write-tests.md:53 +msgid "Listing 8-1: A test module and function" +msgstr "Listing 8-1: Un módulo de test y función" -#: src/ch08-01-how-to-write-tests.md:58 +#: src/ch08-01-how-to-write-tests.md:55 msgid "" "For now, let’s ignore the top two lines and focus on the function. Note the `#[test]` annotation: this attribute indicates this is a test function, so the test runner knows to treat " "this function as a test. We might also have non-test functions in the tests module to help set up common scenarios or perform common operations, so we always need to indicate which " @@ -10814,7 +11179,7 @@ msgstr "" "runner de pruebas sabe que debe tratar esta función como una prueba. También podríamos tener funciones que no son de prueba en el módulo de pruebas para ayudar a configurar " "escenarios comunes o realizar operaciones comunes, por lo que siempre debemos indicar qué funciones son pruebas." -#: src/ch08-01-how-to-write-tests.md:60 +#: src/ch08-01-how-to-write-tests.md:57 msgid "" "The example function body uses the `assert` function, which contains the result of adding 2 and 2, equals 4. This assertion serves as an example of the format for a typical test. " "Let’s run it to see that this test passes." @@ -10822,11 +11187,11 @@ msgstr "" "El cuerpo de la función de ejemplo utiliza la función `assert`, que comprueba que el resultado de sumar 2 y 2 es igual a 4. Esta afirmación sirve como ejemplo del formato de una " "prueba típica. Ejecutémoslo para ver que esta prueba pasa." -#: src/ch08-01-how-to-write-tests.md:62 +#: src/ch08-01-how-to-write-tests.md:59 msgid "The `cairo-test .` command runs all tests in our project, as shown in Listing 8-2." msgstr "El comando `cairo-test .` ejecuta todas las pruebas en nuestro proyecto, como se muestra en el Listado 8-2." -#: src/ch08-01-how-to-write-tests.md:64 +#: src/ch08-01-how-to-write-tests.md:61 msgid "" "```shell\n" "$ cairo-test .\n" @@ -10842,11 +11207,11 @@ msgstr "" "test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" "```" -#: src/ch08-01-how-to-write-tests.md:71 -msgid "Listing 8-2: The output from running a test" -msgstr "Listado 8-2: Resultados de la ejecución de una prueba" +#: src/ch08-01-how-to-write-tests.md:68 +msgid "Listing 8-2: The output from running a test" +msgstr "Listado 8-2: El resultado de ejecutar una prueba" -#: src/ch08-01-how-to-write-tests.md:73 +#: src/ch08-01-how-to-write-tests.md:70 msgid "" "`cairo-test` compiled and ran the test. We see the line `running 1 tests`. The next line shows the name of the generated test function, called `it_works`, and that the result of " "running that test is `ok`. The overall summary `test result: ok.` means that all the tests passed, and the portion that reads `1 passed; 0 failed` totals the number of tests that " @@ -10856,7 +11221,7 @@ msgstr "" "resultado de ejecutar esa prueba es `ok`. El resumen general `test result: ok.` significa que todas las pruebas pasaron, y la porción que lee `1 passed; 0 failed` totaliza el número " "de pruebas que pasaron o fallaron." -#: src/ch08-01-how-to-write-tests.md:75 +#: src/ch08-01-how-to-write-tests.md:72 msgid "" "It’s possible to mark a test as ignored so it doesn’t run in a particular instance; we’ll cover that in the [Ignoring Some Tests Unless Specifically Requested](#ignoring-some-tests-" "unless-specifically-requested) section later in this chapter. Because we haven’t done that here, the summary shows `0 ignored`. We can also pass an argument to the `cairo-test` " @@ -10868,39 +11233,33 @@ msgstr "" "podemos pasar un argumento al comando `cairo-test` para ejecutar solo una prueba cuyo nombre coincida con una cadena; esto se llama filtrado y lo cubriremos en la sección [Ejecución " "de pruebas individuales](#running-single-tests). Tampoco hemos filtrado las pruebas que se ejecutan, por lo que el final del resumen muestra `0 filtradas`." -#: src/ch08-01-how-to-write-tests.md:77 +#: src/ch08-01-how-to-write-tests.md:74 msgid "Let’s start to customize the test to our own needs. First change the name of the `it_works` function to a different name, such as `exploration`, like so:" msgstr "Comencemos a personalizar la prueba según nuestras necesidades. Primero, cambie el nombre de la función `it_works` a un nombre diferente, como `exploration`, así:" -#: src/ch08-01-how-to-write-tests.md:81 +#: src/ch08-01-how-to-write-tests.md:78 msgid "" "```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" " #[test]\n" " fn exploration() {\n" " let result = 2 + 2;\n" " assert(result == 4, 'result is not 4');\n" " }\n" -"}\n" "```" msgstr "" "```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" " #[test]\n" " fn exploration() {\n" " let result = 2 + 2;\n" " assert(result == 4, 'result is not 4');\n" " }\n" -"}\n" "```" -#: src/ch08-01-how-to-write-tests.md:92 +#: src/ch08-01-how-to-write-tests.md:86 msgid "Then run `cairo-test -- --path src` again. The output now shows `exploration` instead of `it_works`:" msgstr "A continuación, ejecute `cairo-test -- --path src` de nuevo. La salida muestra ahora `exploration` en lugar de `it_works`:" -#: src/ch08-01-how-to-write-tests.md:94 +#: src/ch08-01-how-to-write-tests.md:88 msgid "" "```shell\n" "$ cairo-test .\n" @@ -10916,7 +11275,7 @@ msgstr "" "test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" "```" -#: src/ch08-01-how-to-write-tests.md:101 +#: src/ch08-01-how-to-write-tests.md:95 msgid "" "Now we’ll add another test, but this time we’ll make a test that fails! Tests fail when something in the test function panics. Each test is run in a new thread, and when the main " "thread sees that a test thread has died, the test is marked as failed. Enter the new test as a function named `another`, so your _src/lib.cairo_ file looks like Listing 8-3." @@ -10925,35 +11284,31 @@ msgstr "" "nuevo y cuando el hilo principal ve que un hilo de prueba ha muerto, la prueba se marca como fallida. Agregue la nueva prueba como una función llamada `another`, de modo que su " "archivo _src/lib.cairo_ se vea como en el Listado 8-3." -#: src/ch08-01-how-to-write-tests.md:103 +#: src/ch08-01-how-to-write-tests.md:97 msgid "" "```rust\n" -"#[cfg(test)]\n" -"mod tests{\n" " #[test]\n" " fn another() {\n" " let result = 2 + 2;\n" " assert(result == 6, 'Make this test fail');\n" " }\n" -"}\n" +"\n" "```" msgstr "" "```rust\n" -"#[cfg(test)]\n" -"mod tests{\n" " #[test]\n" " fn another() {\n" " let result = 2 + 2;\n" " assert(result == 6, 'Make this test fail');\n" " }\n" -"}\n" +"\n" "```" -#: src/ch08-01-how-to-write-tests.md:114 -msgid "Listing 8-3: Adding a second test that will fail" -msgstr "Lista 8-3: Agregando una segunda prueba que fallará" +#: src/ch08-01-how-to-write-tests.md:106 +msgid "Listing 8-3: Adding a second test that will fail" +msgstr "Lista 8-3: Agregando una segunda prueba que fallará" -#: src/ch08-01-how-to-write-tests.md:116 +#: src/ch08-01-how-to-write-tests.md:108 msgid "" "```shell\n" "$ cairo-test .\n" @@ -10975,11 +11330,11 @@ msgstr "" "Error: test result: FAILED. 1 passed; 1 failed; 0 ignored\n" "```" -#: src/ch08-01-how-to-write-tests.md:126 -msgid "Listing 8-4: Test results when one test passes and one test fails" -msgstr "Listing 8-4: Resultados de las pruebas cuando una pasa y otra falla" +#: src/ch08-01-how-to-write-tests.md:118 +msgid "Listing 8-4: Test results when one test passes and one test fails" +msgstr "Listing 8-4: Resultados de las pruebas cuando una pasa y otra falla" -#: src/ch08-01-how-to-write-tests.md:128 +#: src/ch08-01-how-to-write-tests.md:120 msgid "" "Instead of `ok`, the line `adder::lib::tests::another` shows `fail`. A new section appears between the individual results and the summary. It displays the detailed reason for each " "test failure. In this case, we get the details that `another` failed because it panicked with `[1725643816656041371866211894343434536761780588 ('Make this test fail'), ]` in the _src/" @@ -10989,19 +11344,19 @@ msgstr "" "falla de prueba. En este caso, obtenemos los detalles de que `another` falló porque falló con un pánico con `[1725643816656041371866211894343434536761780588 ('Make this test " "fail'), ]` en el archivo _src/lib.cairo_." -#: src/ch08-01-how-to-write-tests.md:130 +#: src/ch08-01-how-to-write-tests.md:122 msgid "The summary line displays at the end: overall, our test result is `FAILED`. We had one test pass and one test fail." msgstr "La línea de resumen se muestra al final: en general, nuestro resultado de prueba es `FAILED`. Tuvimos una prueba que pasó y otra que falló." -#: src/ch08-01-how-to-write-tests.md:132 +#: src/ch08-01-how-to-write-tests.md:124 msgid "Now that you’ve seen what the test results look like in different scenarios, let’s look at some functions that are useful in tests." msgstr "Ahora que ha visto cómo son los resultados de las pruebas en diferentes escenarios, veamos algunas funciones que son útiles en las pruebas." -#: src/ch08-01-how-to-write-tests.md:134 +#: src/ch08-01-how-to-write-tests.md:126 msgid "## Checking Results with the assert function" msgstr "## Verificar Resultados con la función assert" -#: src/ch08-01-how-to-write-tests.md:136 +#: src/ch08-01-how-to-write-tests.md:128 msgid "" "The `assert` function, provided by Cairo, is useful when you want to ensure that some condition in a test evaluates to `true`. We give the `assert` function a first argument that " "evaluates to a Boolean. If the value is `true`, nothing happens and the test passes. If the value is `false`, the assert function calls `panic()` to cause the test to fail with a " @@ -11012,7 +11367,7 @@ msgstr "" "la prueba falle con un mensaje que definimos como segundo argumento de la función `assert`. Usar la función `assert` nos ayuda a verificar que nuestro código funciona de la manera " "que pretendemos." -#: src/ch08-01-how-to-write-tests.md:138 +#: src/ch08-01-how-to-write-tests.md:130 msgid "" "In [Chapter 4, Listing 5-15](ch04-03-method-syntax.md#multiple-impl-blocks), we used a `Rectangle` struct and a `can_hold` method, which are repeated here in Listing 8-5. Let’s put " "this code in the _src/lib.cairo_ file, then write some tests for it using the `assert` function." @@ -11020,105 +11375,124 @@ msgstr "" "En [Capítulo 4, Lista 5-15](ch04-03-method-syntax.md#multiple-impl-blocks), usamos una estructura `Rectangle` y un método `can_hold`, que se repiten aquí en la Lista 8-5. Colocaremos " "este código en el archivo _src/lib.cairo_, luego escribiremos algunas pruebas para él usando la función `assert`." -#: src/ch08-01-how-to-write-tests.md:142 -msgid "" -"```rust\n" -"trait RectangleTrait {\n" -" fn area(self: @Rectangle) -> u64;\n" -" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" -"}\n" -"\n" -"impl RectangleImpl of RectangleTrait {\n" -" fn area(self: @Rectangle) -> u64 {\n" -" *self.width * *self.height\n" -" }\n" -" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" -" *self.width > *other.width & *self.height > *other.height\n" -" }\n" -"}\n" -"```" -msgstr "" -"```rust\n" -"trait RectangleTrait {\n" -" fn area(self: @Rectangle) -> u64;\n" -" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" -"}\n" -"\n" -"impl RectangleImpl of RectangleTrait {\n" -" fn area(self: @Rectangle) -> u64 {\n" -" *self.width * *self.height\n" -" }\n" -" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" -" *self.width > *other.width & *self.height > *other.height\n" -" }\n" -"}\n" -"```" - -#: src/ch08-01-how-to-write-tests.md:158 -msgid "Listing 8-5: Using the `Rectangle` struct and its `can_hold` method from Chapter 5" -msgstr "Lista 8-5: Uso de la estructura `Rectangle` y su método `can_hold` del Capítulo 5" - -#: src/ch08-01-how-to-write-tests.md:160 -msgid "" -"The `can_hold` method returns a `Boolean`, which means it’s a perfect use case for the assert function. In Listing 8-6, we write a test that exercises the `can_hold` method by " -"creating a `Rectangle` instance that has a width of `8_u64` and a height of `7_u64` and asserting that it can hold another `Rectangle` instance that has a width of `5_u64` and a " -"height of `1_u64`." -msgstr "" -"El método `can_hold` devuelve un valor booleano, lo que significa que es un caso de uso perfecto para la función `assert`. En el Listado 8-6, escribimos una prueba que ejerce el " -"método `can_hold` creando una instancia de `Rectangle` que tiene un ancho de `8_u64` y una altura de `7_u64` y asegurando que puede contener otra instancia de `Rectangle` que tiene " -"un ancho de `5_u64` y una altura de `1_u64`." - -#: src/ch08-01-how-to-write-tests.md:164 -msgid "" -"```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" -" use super::Rectangle;\n" -" use super::RectangleTrait;\n" -"\n" +#: src/ch08-01-how-to-write-tests.md:151 +msgid "Listing 8-5: Using the `Rectangle` struct and its `can_hold` method from Chapter 5" +msgstr "Lista 8-5: Uso de la estructura `Rectangle` y su método `can_hold` del Capítulo 5" + +#: src/ch08-01-how-to-write-tests.md:153 +msgid "" +"The `can_hold` method returns a `bool`, which means it’s a perfect use case for the assert function. In Listing 8-6, we write a test that exercises the `can_hold` method by creating " +"a `Rectangle` instance that has a width of `8` and a height of `7` and asserting that it can hold another `Rectangle` instance that has a width of `5` and a height of `1`." +msgstr "" +"El método `can_hold` devuelve un `bool`, lo que significa que es un caso de uso perfecto para la función assert. En el Listado 8-6, escribimos una prueba que ejercita el método " +"`can_hold` creando una instancia de `Rectangle` que tiene una anchura de `8` y una altura de `7` y afirmando que puede contener otra instancia de `Rectangle` que tiene una anchura de " +"`5` y una altura de `1`." + +#: src/ch08-01-how-to-write-tests.md:157 +msgid "" +"```rust\n" +"# use debug::PrintTrait;\n" +"# #[derive(Copy, Drop)]\n" +"# struct Rectangle {\n" +"# width: u64,\n" +"# height: u64,\n" +"# }\n" +"# \n" +"# trait RectangleTrait {\n" +"# fn area(self: @Rectangle) -> u64;\n" +"# fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" +"# }\n" +"# \n" +"# impl RectangleImpl of RectangleTrait {\n" +"# fn area(self: @Rectangle) -> u64 {\n" +"# *self.width * *self.height\n" +"# }\n" +"# \n" +"# fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +"# *self.width > *other.width & *self.height > *other.height\n" +"# }\n" +"# }\n" +"# \n" +"# #[cfg(test)]\n" +"# mod tests {\n" +"# use super::Rectangle;\n" +"# use super::RectangleTrait;\n" +"# \n" +"# \n" " #[test]\n" " fn larger_can_hold_smaller() {\n" -" let larger = Rectangle {\n" -" height: 7_u64,\n" -" width: 8_u64,\n" -" };\n" -" let smaller = Rectangle {\n" -" height: 1_u64,\n" -" width: 5_u64,\n" -" };\n" +" let larger = Rectangle { height: 7, width: 8, };\n" +" let smaller = Rectangle { height: 1, width: 5, };\n" "\n" " assert(larger.can_hold(@smaller), 'rectangle cannot hold');\n" " }\n" -"}\n" -"```" -msgstr "" -"```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" -" use super::Rectangle;\n" -" use super::RectangleTrait;\n" -"\n" +"# \n" +"# #[test]\n" +"# fn smaller_cannot_hold_larger() {\n" +"# let larger = Rectangle { height: 7, width: 8, };\n" +"# let smaller = Rectangle { height: 1, width: 5, };\n" +"# \n" +"# assert(!smaller.can_hold(@larger), 'rectangle cannot hold');\n" +"# }\n" +"# }\n" +"# \n" +"# \n" +"```" +msgstr "" +"```rust\n" +"# use debug::PrintTrait;\n" +"# #[derive(Copy, Drop)]\n" +"# struct Rectangle {\n" +"# width: u64,\n" +"# height: u64,\n" +"# }\n" +"# \n" +"# trait RectangleTrait {\n" +"# fn area(self: @Rectangle) -> u64;\n" +"# fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" +"# }\n" +"# \n" +"# impl RectangleImpl of RectangleTrait {\n" +"# fn area(self: @Rectangle) -> u64 {\n" +"# *self.width * *self.height\n" +"# }\n" +"# \n" +"# fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +"# *self.width > *other.width & *self.height > *other.height\n" +"# }\n" +"# }\n" +"# \n" +"# #[cfg(test)]\n" +"# mod tests {\n" +"# use super::Rectangle;\n" +"# use super::RectangleTrait;\n" +"# \n" +"# \n" " #[test]\n" " fn larger_can_hold_smaller() {\n" -" let larger = Rectangle {\n" -" height: 7_u64,\n" -" width: 8_u64,\n" -" };\n" -" let smaller = Rectangle {\n" -" height: 1_u64,\n" -" width: 5_u64,\n" -" };\n" +" let larger = Rectangle { height: 7, width: 8, };\n" +" let smaller = Rectangle { height: 1, width: 5, };\n" "\n" " assert(larger.can_hold(@smaller), 'rectangle cannot hold');\n" " }\n" -"}\n" +"# \n" +"# #[test]\n" +"# fn smaller_cannot_hold_larger() {\n" +"# let larger = Rectangle { height: 7, width: 8, };\n" +"# let smaller = Rectangle { height: 1, width: 5, };\n" +"# \n" +"# assert(!smaller.can_hold(@larger), 'rectangle cannot hold');\n" +"# }\n" +"# }\n" +"# \n" +"# \n" "```" -#: src/ch08-01-how-to-write-tests.md:186 -msgid "Listing 8-6: A test for `can_hold` that checks whether a larger rectangle can indeed hold a smaller rectangle" -msgstr "Lista 8-6: Un test para `can_hold` que verifica si un rectángulo más grande realmente puede contener un rectángulo más pequeño" +#: src/ch08-01-how-to-write-tests.md:206 +msgid "Listing 8-6: A test for `can_hold` that checks whether a larger rectangle can indeed hold a smaller rectangle" +msgstr "Lista 8-6: Un test para `can_hold` que verifica si un rectángulo más grande realmente puede contener un rectángulo más pequeño" -#: src/ch08-01-how-to-write-tests.md:188 +#: src/ch08-01-how-to-write-tests.md:208 msgid "" "Note that we’ve added two new lines inside the tests module: `use super::Rectangle;` and `use super::RectangleTrait;`. The tests module is a regular module that follows the usual " "visibility rules. Because the tests module is an inner module, we need to bring the code under test in the outer module into the scope of the inner module." @@ -11126,7 +11500,7 @@ msgstr "" "Note que hemos agregado dos nuevas líneas dentro del módulo de pruebas: `use super::Rectangle;` y `use super::RectangleTrait;`. El módulo de pruebas es un módulo regular que sigue " "las reglas normales de visibilidad. Debido a que el módulo de pruebas es un módulo interno, necesitamos traer el código bajo prueba en el módulo externo al ámbito del módulo interno." -#: src/ch08-01-how-to-write-tests.md:190 +#: src/ch08-01-how-to-write-tests.md:210 msgid "" "We’ve named our test `larger_can_hold_smaller`, and we’ve created the two `Rectangle` instances that we need. Then we called the assert function and passed it the result of calling " "`larger.can_hold(@smaller)`. This expression is supposed to return `true`, so our test should pass. Let’s find out!" @@ -11134,7 +11508,7 @@ msgstr "" "Hemos nombrado nuestro test `larger_can_hold_smaller`, y hemos creado los dos instancias de `Rectangle` que necesitamos. Luego llamamos a la función assert y le pasamos el resultado " "de llamar a `larger.can_hold(@smaller)`. Esta expresión se supone que devuelve `true`, por lo que nuestra prueba debería pasar. ¡Descubramoslo!" -#: src/ch08-01-how-to-write-tests.md:192 +#: src/ch08-01-how-to-write-tests.md:212 msgid "" "```shell\n" "$ cairo-test .\n" @@ -11150,67 +11524,111 @@ msgstr "" "test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" "```" -#: src/ch08-01-how-to-write-tests.md:199 +#: src/ch08-01-how-to-write-tests.md:219 msgid "It does pass! Let’s add another test, this time asserting that a smaller rectangle cannot hold a larger rectangle:" msgstr "¡Pasó la prueba! Ahora agreguemos otra prueba, esta vez afirmamos que un rectángulo más pequeño no puede contener un rectángulo más grande:" -#: src/ch08-01-how-to-write-tests.md:203 -msgid "" -"```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" -" use super::Rectangle;\n" -" use super::RectangleTrait;\n" -"\n" -" #[test]\n" -" fn larger_can_hold_smaller() {\n" -" // --snip--\n" -" }\n" -"\n" +#: src/ch08-01-how-to-write-tests.md:223 +msgid "" +"```rust\n" +"# use debug::PrintTrait;\n" +"# #[derive(Copy, Drop)]\n" +"# struct Rectangle {\n" +"# width: u64,\n" +"# height: u64,\n" +"# }\n" +"# \n" +"# trait RectangleTrait {\n" +"# fn area(self: @Rectangle) -> u64;\n" +"# fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" +"# }\n" +"# \n" +"# impl RectangleImpl of RectangleTrait {\n" +"# fn area(self: @Rectangle) -> u64 {\n" +"# *self.width * *self.height\n" +"# }\n" +"# \n" +"# fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +"# *self.width > *other.width & *self.height > *other.height\n" +"# }\n" +"# }\n" +"# \n" +"# #[cfg(test)]\n" +"# mod tests {\n" +"# use super::Rectangle;\n" +"# use super::RectangleTrait;\n" +"# \n" +"# \n" +"# #[test]\n" +"# fn larger_can_hold_smaller() {\n" +"# let larger = Rectangle { height: 7, width: 8, };\n" +"# let smaller = Rectangle { height: 1, width: 5, };\n" +"# \n" +"# assert(larger.can_hold(@smaller), 'rectangle cannot hold');\n" +"# }\n" +"# \n" " #[test]\n" " fn smaller_cannot_hold_larger() {\n" -" let larger = Rectangle {\n" -" height: 7_u64,\n" -" width: 8_u64,\n" -" };\n" -" let smaller = Rectangle {\n" -" height: 1_u64,\n" -" width: 5_u64,\n" -" };\n" +" let larger = Rectangle { height: 7, width: 8, };\n" +" let smaller = Rectangle { height: 1, width: 5, };\n" "\n" " assert(!smaller.can_hold(@larger), 'rectangle cannot hold');\n" " }\n" -"}\n" -"```" -msgstr "" -"```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" -" use super::Rectangle;\n" -" use super::RectangleTrait;\n" -"\n" -" #[test]\n" -" fn larger_can_hold_smaller() {\n" -" // --snip--\n" -" }\n" -"\n" +"# }\n" +"# \n" +"# \n" +"```" +msgstr "" +"```rust\n" +"# use debug::PrintTrait;\n" +"# #[derive(Copy, Drop)]\n" +"# struct Rectangle {\n" +"# width: u64,\n" +"# height: u64,\n" +"# }\n" +"# \n" +"# trait RectangleTrait {\n" +"# fn area(self: @Rectangle) -> u64;\n" +"# fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" +"# }\n" +"# \n" +"# impl RectangleImpl of RectangleTrait {\n" +"# fn area(self: @Rectangle) -> u64 {\n" +"# *self.width * *self.height\n" +"# }\n" +"# \n" +"# fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +"# *self.width > *other.width & *self.height > *other.height\n" +"# }\n" +"# }\n" +"# \n" +"# #[cfg(test)]\n" +"# mod tests {\n" +"# use super::Rectangle;\n" +"# use super::RectangleTrait;\n" +"# \n" +"# \n" +"# #[test]\n" +"# fn larger_can_hold_smaller() {\n" +"# let larger = Rectangle { height: 7, width: 8, };\n" +"# let smaller = Rectangle { height: 1, width: 5, };\n" +"# \n" +"# assert(larger.can_hold(@smaller), 'rectangle cannot hold');\n" +"# }\n" +"# \n" " #[test]\n" " fn smaller_cannot_hold_larger() {\n" -" let larger = Rectangle {\n" -" height: 7_u64,\n" -" width: 8_u64,\n" -" };\n" -" let smaller = Rectangle {\n" -" height: 1_u64,\n" -" width: 5_u64,\n" -" };\n" +" let larger = Rectangle { height: 7, width: 8, };\n" +" let smaller = Rectangle { height: 1, width: 5, };\n" "\n" " assert(!smaller.can_hold(@larger), 'rectangle cannot hold');\n" " }\n" -"}\n" +"# }\n" +"# \n" +"# \n" "```" -#: src/ch08-01-how-to-write-tests.md:230 +#: src/ch08-01-how-to-write-tests.md:272 msgid "" "Because the correct result of the `can_hold` function in this case is `false`, we need to negate that result before we pass it to the assert function. As a result, our test will pass " "if `can_hold` returns false:" @@ -11218,7 +11636,7 @@ msgstr "" "Como el resultado correcto de la función `can_hold` en este caso es `false`, debemos negar ese resultado antes de pasarlo a la función `assert`. Como resultado, nuestro test pasará " "si `can_hold` devuelve false:" -#: src/ch08-01-how-to-write-tests.md:232 +#: src/ch08-01-how-to-write-tests.md:274 msgid "" "```shell\n" "$ cairo-test .\n" @@ -11236,7 +11654,7 @@ msgstr "" " test result: ok. 2 passed; 0 failed; 0 ignored; 0 filtered out;\n" "```" -#: src/ch08-01-how-to-write-tests.md:240 +#: src/ch08-01-how-to-write-tests.md:282 msgid "" "Two tests that pass! Now let’s see what happens to our test results when we introduce a bug in our code. We’ll change the implementation of the `can_hold` method by replacing the " "greater-than sign with a less-than sign when it compares the widths:" @@ -11244,31 +11662,37 @@ msgstr "" "¡Dos pruebas que pasan! Ahora veamos qué sucede con los resultados de nuestras pruebas cuando introducimos un error en nuestro código. Cambiaremos la implementación del método " "`can_hold` reemplazando el signo mayor que (`>`) por un signo menor que (`<`) cuando compara los anchos:" -#: src/ch08-01-how-to-write-tests.md:242 +#: src/ch08-01-how-to-write-tests.md:284 msgid "" "```rust\n" -"// --snip--\n" "impl RectangleImpl of RectangleTrait {\n" -" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" -" *self.width < *other.width & *self.height > *other.height\n" +" fn area(self: @Rectangle) -> u64 {\n" +" *self.width * *self.height\n" +" }\n" +"\n" +" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +" *self.width < *other.width & *self.height > *other.height\n" " }\n" "}\n" "```" msgstr "" "```rust\n" -"// --snip--\n" "impl RectangleImpl of RectangleTrait {\n" +" fn area(self: @Rectangle) -> u64 {\n" +" *self.width * *self.height\n" +" }\n" +"\n" " fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" " *self.width < *other.width & *self.height > *other.height\n" " }\n" "}\n" "```" -#: src/ch08-01-how-to-write-tests.md:251 +#: src/ch08-01-how-to-write-tests.md:296 msgid "Running the tests now produces the following:" msgstr "Ejecutando los test ahora produce lo siguiente:" -#: src/ch08-01-how-to-write-tests.md:253 +#: src/ch08-01-how-to-write-tests.md:298 msgid "" "```shell\n" "$ cairo-test .\n" @@ -11292,29 +11716,27 @@ msgstr "" "Error: test result: FAILED. 1 passed; 1 failed; 0 ignored\n" "```" -#: src/ch08-01-how-to-write-tests.md:264 -msgid "" -"Our tests caught the bug! Because `larger.width` is `8_u64` and `smaller.width` is `5_u64`, the comparison of the widths in `can_hold` now returns `false`: `8_u64` is not less than " -"`5_u64`." +#: src/ch08-01-how-to-write-tests.md:309 +msgid "Our tests caught the bug! Because `larger.width` is `8` and `smaller.width` is `5`, the comparison of the widths in `can_hold` now returns `false`: `8` is not less than `5`." msgstr "" -"Nuestros tests detectaron el error! Debido a que `larger.width` es `8_u64` y `smaller.width` es `5_u64`, la comparación de anchuras en `can_hold` ahora devuelve `false`: `8_u64` no " -"es menor que `5_u64`." +"Nuestras pruebas han detectado el error. Como `mayor.anchura` es `8` y `menor.anchura` es `5`, la comparación de las anchuras en `can_hold` ahora devuelve `false`: `8` no es menor " +"que `5`." -#: src/ch08-01-how-to-write-tests.md:266 +#: src/ch08-01-how-to-write-tests.md:311 msgid "## Checking for Panics with `should_panic`" msgstr "## Comprobando los pánicos con `should_panic`" -#: src/ch08-01-how-to-write-tests.md:268 +#: src/ch08-01-how-to-write-tests.md:313 msgid "" "In addition to checking return values, it’s important to check that our code handles error conditions as we expect. For example, consider the Guess type in Listing 8-8. Other code " -"that uses `Guess` depends on the guarantee that `Guess` instances will contain only values between `1_u64` and `100_u64`. We can write a test that ensures that attempting to create a " -"`Guess` instance with a value outside that range panics." +"that uses `Guess` depends on the guarantee that `Guess` instances will contain only values between `1` and `100`. We can write a test that ensures that attempting to create a `Guess` " +"instance with a value outside that range panics." msgstr "" -"Además de verificar los valores de retorno, es importante verificar que nuestro código maneje las condiciones de error como esperamos. Por ejemplo, consideremos el tipo Guess en el " -"Listing 8-8. Otro código que usa `Guess` depende de la garantía de que las instancias de `Guess` contengan solo valores entre `1_u64` y `100_u64`. Podemos escribir un test que " -"asegure que al intentar crear una instancia de `Guess` con un valor fuera de ese rango, el programa entra en pánico." +"Además de comprobar los valores de retorno, es importante comprobar que nuestro código maneja las condiciones de error como esperamos. Por ejemplo, considere el tipo Adivinar del " +"Listado 8-8. Otro código que utiliza `Guess` depende de la garantía de que las instancias de `Guess` contendrán sólo valores entre `1` y `100`. Podemos escribir una prueba que " +"asegure que al intentar crear una instancia de `Guess` con un valor fuera de ese rango se produzca un pánico." -#: src/ch08-01-how-to-write-tests.md:270 +#: src/ch08-01-how-to-write-tests.md:315 msgid "" "We do this by adding the attribute `should_panic` to our test function. The test passes if the code inside the function panics; the test fails if the code inside the function doesn’t " "panic." @@ -11322,18 +11744,18 @@ msgstr "" "Lo hacemos agregando el atributo `should_panic` a nuestra función de prueba. La prueba pasa si el código dentro de la función entra en pánico; la prueba falla si el código dentro de " "la función no entra en pánico." -#: src/ch08-01-how-to-write-tests.md:272 +#: src/ch08-01-how-to-write-tests.md:317 msgid "Listing 8-8 shows a test that checks that the error conditions of `GuessTrait::new` happen when we expect them to." msgstr "El Listing 8-8 muestra una prueba que verifica que las condiciones de error de `GuessTrait::new` ocurren cuando esperamos que sucedan." -#: src/ch08-01-how-to-write-tests.md:276 +#: src/ch08-01-how-to-write-tests.md:321 msgid "" "```rust\n" "use array::ArrayTrait;\n" "\n" "#[derive(Copy, Drop)]\n" "struct Guess {\n" -" value: u64,\n" +" value: u64, \n" "}\n" "\n" "trait GuessTrait {\n" @@ -11342,7 +11764,7 @@ msgid "" "\n" "impl GuessImpl of GuessTrait {\n" " fn new(value: u64) -> Guess {\n" -" if value < 1_u64 | value > 100 {\n" +" if value < 1 | value > 100 {\n" " let mut data = ArrayTrait::new();\n" " data.append('Guess must be >= 1 and <= 100');\n" " panic(data);\n" @@ -11359,7 +11781,7 @@ msgid "" " #[test]\n" " #[should_panic]\n" " fn greater_than_100() {\n" -" GuessTrait::new(200_u64);\n" +" GuessTrait::new(200);\n" " }\n" "}\n" "```" @@ -11369,7 +11791,7 @@ msgstr "" "\n" "#[derive(Copy, Drop)]\n" "struct Guess {\n" -" value: u64,\n" +" value: u64, \n" "}\n" "\n" "trait GuessTrait {\n" @@ -11378,7 +11800,7 @@ msgstr "" "\n" "impl GuessImpl of GuessTrait {\n" " fn new(value: u64) -> Guess {\n" -" if value < 1_u64 | value > 100 {\n" +" if value < 1 | value > 100 {\n" " let mut data = ArrayTrait::new();\n" " data.append('Guess must be >= 1 and <= 100');\n" " panic(data);\n" @@ -11395,20 +11817,20 @@ msgstr "" " #[test]\n" " #[should_panic]\n" " fn greater_than_100() {\n" -" GuessTrait::new(200_u64);\n" +" GuessTrait::new(200);\n" " }\n" "}\n" "```" -#: src/ch08-01-how-to-write-tests.md:312 -msgid "Listing 8-8: Testing that a condition will cause a panic" -msgstr "Listing 8-8: Probando que una condición causará un pánico" +#: src/ch08-01-how-to-write-tests.md:357 +msgid "Listing 8-8: Testing that a condition will cause a panic" +msgstr "Listing 8-8: Probando que una condición causará un pánico" -#: src/ch08-01-how-to-write-tests.md:314 +#: src/ch08-01-how-to-write-tests.md:359 msgid "We place the `#[should_panic]` attribute after the `#[test]` attribute and before the test function it applies to. Let’s look at the result when this test passes:" msgstr "Colocamos el atributo `#[should_panic]` después del atributo `#[test]` y antes de la función de prueba a la que se aplica. Veamos el resultado cuando esta prueba pasa:" -#: src/ch08-01-how-to-write-tests.md:316 +#: src/ch08-01-how-to-write-tests.md:361 msgid "" "```shell\n" "$ cairo-test .\n" @@ -11424,47 +11846,69 @@ msgstr "" "test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" "```" -#: src/ch08-01-how-to-write-tests.md:323 -msgid "Looks good! Now let’s introduce a bug in our code by removing the condition that the new function will panic if the value is greater than `100_u64`:" -msgstr "Looks good! Now let’s introduce a bug in our code by removing the condition that the new function will panic if the value is greater than `100_u64`:" +#: src/ch08-01-how-to-write-tests.md:368 +msgid "Looks good! Now let’s introduce a bug in our code by removing the condition that the new function will panic if the value is greater than `100`:" +msgstr "¡Tiene buena pinta! Ahora vamos a introducir un error en nuestro código eliminando la condición de que la nueva función entre en pánico si el valor es mayor que `100`:" -#: src/ch08-01-how-to-write-tests.md:325 +#: src/ch08-01-how-to-write-tests.md:370 msgid "" "```rust\n" -"// --snip--\n" +"# use array::ArrayTrait;\n" +"# \n" +"# #[derive(Copy, Drop)]\n" +"# struct Guess {\n" +"# value: u64, \n" +"# }\n" +"# \n" +"# trait GuessTrait {\n" +"# fn new(value: u64) -> Guess;\n" +"# }\n" +"# \n" "impl GuessImpl of GuessTrait {\n" " fn new(value: u64) -> Guess {\n" -" if value < 1_u64 {\n" +" if value < 1 {\n" " let mut data = ArrayTrait::new();\n" " data.append('Guess must be >= 1 and <= 100');\n" " panic(data);\n" " }\n" "\n" -" Guess { value, }\n" +" Guess { value, }\n" " }\n" "}\n" +"# \n" "```" msgstr "" "```rust\n" -"// --snip--\n" +"# use array::ArrayTrait;\n" +"# \n" +"# #[derive(Copy, Drop)]\n" +"# struct Guess {\n" +"# value: u64, \n" +"# }\n" +"# \n" +"# trait GuessTrait {\n" +"# fn new(value: u64) -> Guess;\n" +"# }\n" +"# \n" "impl GuessImpl of GuessTrait {\n" " fn new(value: u64) -> Guess {\n" -" if value < 1_u64 {\n" +" if value < 1 {\n" " let mut data = ArrayTrait::new();\n" " data.append('Guess must be >= 1 and <= 100');\n" " panic(data);\n" " }\n" "\n" -" Guess { value, }\n" +" Guess { value, }\n" " }\n" "}\n" +"# \n" "```" -#: src/ch08-01-how-to-write-tests.md:340 +#: src/ch08-01-how-to-write-tests.md:396 msgid "When we run the test in Listing 8-8, it will fail:" msgstr "Cuando ejecutamos la prueba en el Listado 8-8, fallará:" -#: src/ch08-01-how-to-write-tests.md:342 +#: src/ch08-01-how-to-write-tests.md:398 msgid "" "```shell\n" "$ cairo-test .\n" @@ -11484,7 +11928,7 @@ msgstr "" "Error: test result: FAILED. 0 passed; 1 failed; 0 ignored\n" "```" -#: src/ch08-01-how-to-write-tests.md:351 +#: src/ch08-01-how-to-write-tests.md:407 msgid "" "We don’t get a very helpful message in this case, but when we look at the test function, we see that it’s annotated with `#[should_panic]`. The failure we got means that the code in " "the test function did not cause a panic." @@ -11492,7 +11936,7 @@ msgstr "" "En este caso, no obtenemos un mensaje muy útil, pero cuando miramos la función de prueba, vemos que está anotada con `#[should_panic]`. La falla que obtuvimos significa que el código " "en la función de prueba no causó un pánico." -#: src/ch08-01-how-to-write-tests.md:353 +#: src/ch08-01-how-to-write-tests.md:409 msgid "" "Tests that use `should_panic` can be imprecise. A `should_panic` test would pass even if the test panics for a different reason from the one we were expecting. To make `should_panic` " "tests more precise, we can add an optional expected parameter to the `should_panic` attribute. The test harness will make sure that the failure message contains the provided text. " @@ -11503,23 +11947,130 @@ msgstr "" "que el mensaje de error contenga el texto proporcionado. Por ejemplo, considere el código modificado para `Guess` en el Listado 8-9, donde la nueva función genera un pánico con " "mensajes diferentes dependiendo de si el valor es demasiado pequeño o demasiado grande." -#: src/ch08-01-how-to-write-tests.md:357 +#: src/ch08-01-how-to-write-tests.md:413 +msgid "" +"```rust\n" +"# use array::ArrayTrait;\n" +"# \n" +"# #[derive(Copy, Drop)]\n" +"# struct Guess {\n" +"# value: u64, \n" +"# }\n" +"# \n" +"# trait GuessTrait {\n" +"# fn new(value: u64) -> Guess;\n" +"# }\n" +"# \n" +"# impl GuessImpl of GuessTrait {\n" +"# fn new(value: u64) -> Guess {\n" +"# if value < 1 {\n" +"# let mut data = ArrayTrait::new();\n" +"# data.append('Guess must be <= 100');\n" +"# panic(data);\n" +"# } else if value > 100 {\n" +"# let mut data = ArrayTrait::new();\n" +"# data.append('Guess must be >= 1');\n" +"# panic(data);\n" +"# }\n" +"# \n" +"# Guess { value, }\n" +"# }\n" +"# }\n" +"# \n" +"# #[cfg(test)]\n" +"# mod tests {\n" +"# use super::Guess;\n" +"# use super::GuessTrait;\n" +"# \n" +" #[test]\n" +" #[should_panic(expected: ('Guess must be <= 100', ))]\n" +" fn greater_than_100() {\n" +" GuessTrait::new(200);\n" +" }\n" +"# }\n" +"# \n" +"# \n" +"```" +msgstr "" +"```rust\n" +"# use array::ArrayTrait;\n" +"# \n" +"# #[derive(Copy, Drop)]\n" +"# struct Guess {\n" +"# value: u64, \n" +"# }\n" +"# \n" +"# trait GuessTrait {\n" +"# fn new(value: u64) -> Guess;\n" +"# }\n" +"# \n" +"# impl GuessImpl of GuessTrait {\n" +"# fn new(value: u64) -> Guess {\n" +"# if value < 1 {\n" +"# let mut data = ArrayTrait::new();\n" +"# data.append('Guess must be <= 100');\n" +"# panic(data);\n" +"# } else if value > 100 {\n" +"# let mut data = ArrayTrait::new();\n" +"# data.append('Guess must be >= 1');\n" +"# panic(data);\n" +"# }\n" +"# \n" +"# Guess { value, }\n" +"# }\n" +"# }\n" +"# \n" +"# #[cfg(test)]\n" +"# mod tests {\n" +"# use super::Guess;\n" +"# use super::GuessTrait;\n" +"# \n" +" #[test]\n" +" #[should_panic(expected: ('Guess must be <= 100', ))]\n" +" fn greater_than_100() {\n" +" GuessTrait::new(200);\n" +" }\n" +"# }\n" +"# \n" +"# \n" +"```" + +#: src/ch08-01-how-to-write-tests.md:456 +msgid "Listing 8-9: Testing for a panic with a panic message containing the error message string" +msgstr "Listado 8-9: Prueba para una excepción con un mensaje de excepción que contiene la cadena del mensaje de error" + +#: src/ch08-01-how-to-write-tests.md:458 +msgid "" +"This test will pass because the value we put in the `should_panic` attribute’s expected parameter is the array of string of the message that the `Guess::new` function panics with. We " +"need to specify the entire panic message that we expect." +msgstr "" +"Esta prueba pasará porque el valor que ponemos en el parámetro esperado del atributo `should_panic` es la matriz de cadenas del mensaje con el que la función `Guess::new` genera la " +"excepción. Necesitamos especificar el mensaje completo de la excepción que esperamos." + +#: src/ch08-01-how-to-write-tests.md:460 +msgid "" +"To see what happens when a `should_panic` test with an expected message fails, let’s again introduce a bug into our code by swapping the bodies of the if `value < 1` and the else if " +"`value > 100` blocks:" +msgstr "" +"Para ver qué ocurre cuando falla una prueba `should_panic` con un mensaje esperado, introduzcamos de nuevo un error en nuestro código intercambiando los cuerpos de los bloques if " +"`value < 1` y else if `value > 100`:" + +#: src/ch08-01-how-to-write-tests.md:462 msgid "" "```rust\n" -"// --snip--\n" "impl GuessImpl of GuessTrait {\n" " fn new(value: u64) -> Guess {\n" -" if value < 1_u64 {\n" +" if value < 1 {\n" " let mut data = ArrayTrait::new();\n" " data.append('Guess must be >= 1');\n" " panic(data);\n" -" } else if value > 100_u64 {\n" +" } else if value > 100 {\n" " let mut data = ArrayTrait::new();\n" " data.append('Guess must be <= 100');\n" " panic(data);\n" " }\n" "\n" -" Guess { value, }\n" +" Guess { value, }\n" " }\n" "}\n" "\n" @@ -11531,26 +12082,25 @@ msgid "" " #[test]\n" " #[should_panic(expected: ('Guess must be <= 100', ))]\n" " fn greater_than_100() {\n" -" GuessTrait::new(200_u64);\n" +" GuessTrait::new(200);\n" " }\n" "}\n" "```" msgstr "" "```rust\n" -"// --snip--\n" "impl GuessImpl of GuessTrait {\n" " fn new(value: u64) -> Guess {\n" -" if value < 1_u64 {\n" +" if value < 1 {\n" " let mut data = ArrayTrait::new();\n" " data.append('Guess must be >= 1');\n" " panic(data);\n" -" } else if value > 100_u64 {\n" +" } else if value > 100 {\n" " let mut data = ArrayTrait::new();\n" " data.append('Guess must be <= 100');\n" " panic(data);\n" " }\n" "\n" -" Guess { value, }\n" +" Guess { value, }\n" " }\n" "}\n" "\n" @@ -11562,62 +12112,16 @@ msgstr "" " #[test]\n" " #[should_panic(expected: ('Guess must be <= 100', ))]\n" " fn greater_than_100() {\n" -" GuessTrait::new(200_u64);\n" +" GuessTrait::new(200);\n" " }\n" "}\n" "```" -#: src/ch08-01-how-to-write-tests.md:388 -msgid "Listing 8-9: Testing for a panic with a panic message containing the error message string" -msgstr "Listado 8-9: Prueba para una excepción con un mensaje de excepción que contiene la cadena del mensaje de error" - -#: src/ch08-01-how-to-write-tests.md:390 -msgid "" -"This test will pass because the value we put in the `should_panic` attribute’s expected parameter is the array of string of the message that the `Guess::new` function panics with. We " -"need to specify the entire panic message that we expect." -msgstr "" -"Esta prueba pasará porque el valor que ponemos en el parámetro esperado del atributo `should_panic` es la matriz de cadenas del mensaje con el que la función `Guess::new` genera la " -"excepción. Necesitamos especificar el mensaje completo de la excepción que esperamos." - -#: src/ch08-01-how-to-write-tests.md:392 -msgid "" -"To see what happens when a `should_panic` test with an expected message fails, let’s again introduce a bug into our code by swapping the bodies of the if `value < 1_u64` and the else " -"if `value > 100_u64` blocks:" -msgstr "" -"Para ver qué sucede cuando una prueba `should_panic` con un mensaje esperado falla, introduzcamos de nuevo un error en nuestro código cambiando los cuerpos de los bloques if `value < " -"1_u64` y else if `value > 100_u64`:" - -#: src/ch08-01-how-to-write-tests.md:394 -msgid "" -"```rust\n" -"if value < 1_u64 {\n" -" let mut data = ArrayTrait::new();\n" -" data.append('Guess must be <= 100');\n" -" panic(data);\n" -"} else if value > 100_u64 {\n" -" let mut data = ArrayTrait::new();\n" -" data.append('Guess must be >= 1');\n" -" panic(data);\n" -"}\n" -"```" -msgstr "" -"```rust\n" -"if value < 1_u64 {\n" -" let mut data = ArrayTrait::new();\n" -" data.append('Guess must be <= 100');\n" -" panic(data);\n" -"} else if value > 100_u64 {\n" -" let mut data = ArrayTrait::new();\n" -" data.append('Guess must be >= 1');\n" -" panic(data);\n" -"}\n" -"```" - -#: src/ch08-01-how-to-write-tests.md:406 +#: src/ch08-01-how-to-write-tests.md:492 msgid "This time when we run the `should_panic` test, it will fail:" msgstr "Esta vez, cuando ejecutamos la prueba `should_panic`, fallará:" -#: src/ch08-01-how-to-write-tests.md:408 +#: src/ch08-01-how-to-write-tests.md:494 msgid "" "```shell\n" "$ cairo-test .\n" @@ -11639,7 +12143,7 @@ msgstr "" "Error: test result: FAILED. 0 passed; 1 failed; 0 ignored\n" "```" -#: src/ch08-01-how-to-write-tests.md:418 +#: src/ch08-01-how-to-write-tests.md:504 msgid "" "The failure message indicates that this test did indeed panic as we expected, but the panic message did not include the expected string. The panic message that we did get in this " "case was `Guess must be >= 1`. Now we can start figuring out where our bug is!" @@ -11647,11 +12151,11 @@ msgstr "" "El mensaje de fallo indica que este test realmente causó un pánico como esperábamos, pero el mensaje de pánico no incluyó la cadena esperada. El mensaje de pánico que obtuvimos en " "este caso fue `Guess must be >= 1`. ¡Ahora podemos comenzar a descubrir dónde está nuestro error!" -#: src/ch08-01-how-to-write-tests.md:420 +#: src/ch08-01-how-to-write-tests.md:506 msgid "## Running Single Tests" msgstr "## Ejecución de Pruebas Individuales" -#: src/ch08-01-how-to-write-tests.md:422 +#: src/ch08-01-how-to-write-tests.md:508 msgid "" "Sometimes, running a full test suite can take a long time. If you’re working on code in a particular area, you might want to run only the tests pertaining to that code. You can " "choose which tests to run by passing `cairo-test` the name of the test you want to run as an argument." @@ -11659,11 +12163,11 @@ msgstr "" "A veces, ejecutar un conjunto completo de pruebas puede llevar mucho tiempo. Si está trabajando en código en un área particular, es posible que desee ejecutar solo las pruebas " "relacionadas con ese código. Puede elegir qué pruebas ejecutar pasando el nombre de la prueba que desea ejecutar como argumento a `cairo-test`." -#: src/ch08-01-how-to-write-tests.md:424 +#: src/ch08-01-how-to-write-tests.md:510 msgid "To demonstrate how to run a single test, we’ll first create two tests functions, as shown in Listing 8-10, and choose which ones to run." msgstr "Para demostrar cómo ejecutar una sola prueba, primero crearemos dos funciones de prueba, como se muestra en el Listado 8-10, y elegiremos cuáles ejecutar." -#: src/ch08-01-how-to-write-tests.md:428 +#: src/ch08-01-how-to-write-tests.md:514 msgid "" "```rust\n" "#[cfg(test)]\n" @@ -11699,15 +12203,15 @@ msgstr "" "}\n" "```" -#: src/ch08-01-how-to-write-tests.md:445 -msgid "Listing 8-10: Two tests with two different names" -msgstr "Listado 8-10: Dos pruebas con dos nombres diferentes" +#: src/ch08-01-how-to-write-tests.md:531 +msgid "Listing 8-10: Two tests with two different names" +msgstr "Listado 8-10: Dos pruebas con dos nombres diferentes" -#: src/ch08-01-how-to-write-tests.md:447 +#: src/ch08-01-how-to-write-tests.md:533 msgid "We can pass the name of any test function to `cairo-test` to run only that test using the `-f` flag:" msgstr "Podemos pasar el nombre de cualquier función de prueba a `cairo-test` para ejecutar solo esa prueba usando la bandera `-f`:" -#: src/ch08-01-how-to-write-tests.md:449 +#: src/ch08-01-how-to-write-tests.md:535 msgid "" "```shell\n" "$ cairo-test . -f add_two_and_two\n" @@ -11723,7 +12227,7 @@ msgstr "" "test result: ok. 1 passed; 0 failed; 0 ignored; 1 filtered out;\n" "```" -#: src/ch08-01-how-to-write-tests.md:456 +#: src/ch08-01-how-to-write-tests.md:542 msgid "" "Only the test with the name `add_two_and_two` ran; the other test didn’t match that name. The test output lets us know we had one more test that didn’t run by displaying 1 filtered " "out at the end." @@ -11731,15 +12235,15 @@ msgstr "" "Solo se ejecutó la prueba con el nombre `add_two_and_two`; la otra prueba no coincidía con ese nombre. La salida de la prueba nos indica que tuvimos una prueba más que no se ejecutó " "al mostrar \"1 filtrado\" al final." -#: src/ch08-01-how-to-write-tests.md:458 +#: src/ch08-01-how-to-write-tests.md:544 msgid "We can also specify part of a test name, and any test whose name contains that value will be run." msgstr "También podemos especificar parte del nombre de una prueba y se ejecutarán todas las pruebas cuyo nombre contenga ese valor." -#: src/ch08-01-how-to-write-tests.md:460 +#: src/ch08-01-how-to-write-tests.md:546 msgid "## Ignoring Some Tests Unless Specifically Requested" msgstr "## Ignorar Algunos Test a menos que se Soliciten Específicamente" -#: src/ch08-01-how-to-write-tests.md:462 +#: src/ch08-01-how-to-write-tests.md:548 msgid "" "Sometimes a few specific tests can be very time-consuming to execute, so you might want to exclude them during most runs of `cairo-test`. Rather than listing as arguments all tests " "you do want to run, you can instead annotate the time-consuming tests using the `ignore` attribute to exclude them, as shown here:" @@ -11748,7 +12252,7 @@ msgstr "" "enumerar como argumentos todas las pruebas que desea ejecutar, puede anotar las pruebas que consumen mucho tiempo utilizando el atributo `ignore` para excluirlos, como se muestra " "aquí:" -#: src/ch08-01-how-to-write-tests.md:466 +#: src/ch08-01-how-to-write-tests.md:552 msgid "" "```rust\n" "#[cfg(test)]\n" @@ -11761,8 +12265,7 @@ msgid "" "\n" " #[test]\n" " #[ignore]\n" -" fn expensive_test() {\n" -" // code that takes an hour to run\n" +" fn expensive_test() {// code that takes an hour to run\n" " }\n" "}\n" "```" @@ -11778,18 +12281,17 @@ msgstr "" "\n" " #[test]\n" " #[ignore]\n" -" fn expensive_test() {\n" -" // code that takes an hour to run\n" +" fn expensive_test() {// code that takes an hour to run\n" " }\n" "}\n" "```" -#: src/ch08-01-how-to-write-tests.md:483 +#: src/ch08-01-how-to-write-tests.md:568 msgid "After `#[test]` we add the `#[ignore]` line to the test we want to exclude. Now when we run our tests, `it_works` runs, but `expensive_test` doesn’t:" msgstr "" "Después de `#[test]` agregamos la línea `#[ignore]` al test que queremos excluir. Ahora, cuando ejecutamos nuestros tests, `it_works` se ejecuta pero `expensive_test` no lo hace:" -#: src/ch08-01-how-to-write-tests.md:485 +#: src/ch08-01-how-to-write-tests.md:570 msgid "" "```shell\n" "$ cairo-test .\n" @@ -11807,11 +12309,11 @@ msgstr "" "test result: ok. 1 passed; 0 failed; 1 ignored; 0 filtered out;\n" "```" -#: src/ch08-01-how-to-write-tests.md:493 +#: src/ch08-01-how-to-write-tests.md:578 msgid "The `expensive_test` function is listed as ignored." msgstr "La función `expensive_test` está listada como ignorada." -#: src/ch08-01-how-to-write-tests.md:495 +#: src/ch08-01-how-to-write-tests.md:580 msgid "" "When you’re at a point where it makes sense to check the results of the ignored tests and you have time to wait for the results, you can run `cairo-test --include-ignored` to run all " "tests whether they’re ignored or not." @@ -11873,6 +12375,30 @@ msgstr "" msgid "Recall that when we created the new `adder` project in the first section of this chapter, we wrote this first test:" msgstr "Recuerde que cuando creamos el nuevo proyecto `adder` en la primera sección de este capítulo, escribimos esta primera prueba:" +#: src/ch08-02-test-organization.md:21 +msgid "" +"```rust\n" +"#[cfg(test)]\n" +"mod tests {\n" +" #[test]\n" +" fn it_works() {\n" +" let result = 2 + 2;\n" +" assert(result == 4, 'result is not 4');\n" +" }\n" +"}\n" +"```" +msgstr "" +"```rust\n" +"#[cfg(test)]\n" +"mod tests {\n" +" #[test]\n" +" fn it_works() {\n" +" let result = 2 + 2;\n" +" assert(result == 4, 'result is not 4');\n" +" }\n" +"}\n" +"```" + #: src/ch08-02-test-organization.md:32 msgid "" "The attribute `cfg` stands for configuration and tells Cairo that the following item should only be included given a certain configuration option. In this case, the configuration " @@ -11964,8 +12490,8 @@ msgstr "" "```" #: src/ch08-02-test-organization.md:70 -msgid "Enter the code in Listing 11-13 into the _tests/integration_test.cairo_ file:" -msgstr "Ingrese el código del Listado 11-13 en el archivo _tests/integration_test.cairo_:" +msgid "Enter the code in Listing 8-11 into the _tests/integration_test.cairo_ file:" +msgstr "Ingrese el código del Listado 8-11 en el archivo _tests/integration_test.cairo_:" #: src/ch08-02-test-organization.md:72 msgid "Filename: tests/integration_test.cairo" @@ -11974,23 +12500,23 @@ msgstr "Filename: tests/integration_test.cairo" #: src/ch08-02-test-organization.md:74 msgid "" "```rust\n" -"use adder::main;\n" -"\n" "#[test]\n" "fn internal() {\n" -" assert(main::internal_adder(2_u32, 2_u32) == 4_u32, 'internal_adder failed');\n" +" assert(main::internal_adder(2, 2) == 4, 'internal_adder failed');\n" "}\n" "```" msgstr "" "```rust\n" -"use adder::main;\n" -"\n" "#[test]\n" "fn internal() {\n" -" assert(main::internal_adder(2_u32, 2_u32) == 4_u32, 'internal_adder failed');\n" +" assert(main::internal_adder(2, 2) == 4, 'internal_adder failed');\n" "}\n" "```" +#: src/ch08-02-test-organization.md:81 +msgid "Listing 8-11: Testing functions from other modules" +msgstr "Listado 8-11: Probando funciones de otros módulos" + #: src/ch08-02-test-organization.md:83 msgid "" "Each file in the tests directory is a separate crate, so we need to bring our library into each test crate’s scope. For that reason we add `use adder::main` at the top of the code, " @@ -12053,11 +12579,11 @@ msgstr "" #: src/ch09-01-unrecoverable-errors-with-panic.md:5 msgid "" -"When a panic occurs, it leads to an abrupt termination of the program. The `panic` function take an array as argument, which can be used to provide an error message and performs an " +"When a panic occurs, it leads to an abrupt termination of the program. The `panic` function takes an array as argument, which can be used to provide an error message and performs an " "unwind process where all variables are dropped and dictionaries squashed to ensure the soundness of the program to safely terminate the execution." msgstr "" -"Cuando se produce un pánico, se produce una terminación abrupta del programa. La función `panic` toma un array como argumento, que puede utilizarse para proporcionar un mensaje de " -"error y realiza un proceso de desenrollado en el que todas las variables se eliminan y los diccionarios se aplastan para garantizar la solidez del programa y terminar la ejecución de " +"Cuando se produce un pánico, se produce una terminación abrupta del programa. La función `panic` toma como argumento un array, que puede utilizarse para proporcionar un mensaje de " +"error y realiza un proceso de desenrollado en el que se eliminan todas las variables y se aplastan los diccionarios para garantizar la solidez del programa y terminar la ejecución de " "forma segura." #: src/ch09-01-unrecoverable-errors-with-panic.md:7 @@ -12066,51 +12592,55 @@ msgstr "Así es como podemos `panic` desde dentro de un programa y devolver el c #: src/ch09-01-unrecoverable-errors-with-panic.md:11 msgid "" -"```rust,does_not_compile\n" +"```rust\n" "use array::ArrayTrait;\n" "use debug::PrintTrait;\n" "\n" "fn main() {\n" " let mut data = ArrayTrait::new();\n" " data.append(2);\n" -" panic(data);\n" -" 'This line isn't reached'.print();\n" +" if true == true {\n" +" panic(data);\n" +" }\n" +" 'This line isn\\'t reached'.print();\n" "}\n" "```" msgstr "" -"```rust,does_not_compile\n" +"```rust\n" "use array::ArrayTrait;\n" "use debug::PrintTrait;\n" "\n" "fn main() {\n" " let mut data = ArrayTrait::new();\n" " data.append(2);\n" -" panic(data);\n" -" 'This line isn't reached'.print();\n" +" if true == true {\n" +" panic(data);\n" +" }\n" +" 'This line isn\\'t reached'.print();\n" "}\n" "```" -#: src/ch09-01-unrecoverable-errors-with-panic.md:23 +#: src/ch09-01-unrecoverable-errors-with-panic.md:25 msgid "Running the program will produce the following output:" msgstr "La ejecución del programa producirá el siguiente resultado:" -#: src/ch09-01-unrecoverable-errors-with-panic.md:25 +#: src/ch09-01-unrecoverable-errors-with-panic.md:27 msgid "" "```console\n" "$ cairo-run test.cairo\n" -"Run panicked with err values: [2]\n" +"Run panicked with [2 (''), ].\n" "```" msgstr "" "```console\n" "$ cairo-run test.cairo\n" -"Run panicked with err values: [2]\n" +"Run panicked with [2 (''), ].\n" "```" -#: src/ch09-01-unrecoverable-errors-with-panic.md:30 +#: src/ch09-01-unrecoverable-errors-with-panic.md:32 msgid "As you can notice in the output, the print statement is never reached, as the program terminates after encountering the `panic` statement." msgstr "Como se puede observar en la salida, la sentencia print nunca se alcanza, ya que el programa termina después de encontrar la sentencia `panic`." -#: src/ch09-01-unrecoverable-errors-with-panic.md:32 +#: src/ch09-01-unrecoverable-errors-with-panic.md:34 msgid "" "An alternative and more idiomatic approach to panic in Cairo would be to use the `panic_with_felt252` function. This function serves as an abstraction of the array-defining process " "and is often preferred due to its clearer and more concise expression of intent. By using `panic_with_felt252`, developers can panic in a one-liner by providing a felt252 error " @@ -12120,11 +12650,11 @@ msgstr "" "arrays y a menudo se prefiere debido a su expresión más clara y concisa de la intención. Usando `panic_with_felt252`, los desarrolladores pueden entrar en pánico en una sola línea " "proporcionando un mensaje de error felt252 como argumento, haciendo el código más legible y mantenible." -#: src/ch09-01-unrecoverable-errors-with-panic.md:34 +#: src/ch09-01-unrecoverable-errors-with-panic.md:36 msgid "Let's consider an example:" msgstr "Veamos un ejemplo:" -#: src/ch09-01-unrecoverable-errors-with-panic.md:36 +#: src/ch09-01-unrecoverable-errors-with-panic.md:38 msgid "" "```rust\n" "fn main() {\n" @@ -12138,7 +12668,7 @@ msgstr "" "}\n" "```" -#: src/ch09-01-unrecoverable-errors-with-panic.md:42 +#: src/ch09-01-unrecoverable-errors-with-panic.md:44 msgid "" "Executing this program will yield the same error message as before. In that case, if there is no need for an array and multiple values to be returned within the error, so " "`panic_with_felt252` is a more succinct alternative." @@ -12146,21 +12676,21 @@ msgstr "" "Ejecutando este programa se obtendrá el mismo mensaje de error que antes. En ese caso, si no hay necesidad de una matriz y múltiples valores a devolver dentro del error, por lo que " "`panic_with_felt252` es una alternativa más sucinta." -#: src/ch09-01-unrecoverable-errors-with-panic.md:44 +#: src/ch09-01-unrecoverable-errors-with-panic.md:46 msgid "## nopanic notation" msgstr "## notación nopanic" -#: src/ch09-01-unrecoverable-errors-with-panic.md:46 +#: src/ch09-01-unrecoverable-errors-with-panic.md:48 msgid "You can use the `nopanic` notation to indicate that a function will never panic. Only `nopanic` functions can be called in a function annotated as `nopanic`." msgstr "" "Puede utilizar la anotación `nopanic` para indicar que una función nunca entrará en pánico. Sólo las funciones `nopanic` pueden ser llamadas en una función anotada como `nopanic`." -#: src/ch09-01-unrecoverable-errors-with-panic.md:48 src/ch09-01-unrecoverable-errors-with-panic.md:83 src/appendix-03-derivable-traits.md:17 src/appendix-03-derivable-traits.md:42 +#: src/ch09-01-unrecoverable-errors-with-panic.md:50 src/ch09-01-unrecoverable-errors-with-panic.md:86 src/appendix-03-derivable-traits.md:17 src/appendix-03-derivable-traits.md:42 #: src/appendix-03-derivable-traits.md:63 src/appendix-03-derivable-traits.md:85 src/appendix-03-derivable-traits.md:118 msgid "Example:" msgstr "Ejemplo:" -#: src/ch09-01-unrecoverable-errors-with-panic.md:50 +#: src/ch09-01-unrecoverable-errors-with-panic.md:52 msgid "" "```rust\n" "fn function_never_panic() -> felt252 nopanic {\n" @@ -12174,31 +12704,33 @@ msgstr "" "}\n" "```" -#: src/ch09-01-unrecoverable-errors-with-panic.md:56 +#: src/ch09-01-unrecoverable-errors-with-panic.md:58 msgid "Wrong example:" msgstr "Ejemplo incorrecto:" -#: src/ch09-01-unrecoverable-errors-with-panic.md:58 +#: src/ch09-01-unrecoverable-errors-with-panic.md:60 msgid "" "```rust\n" +"// does_not_compile\n" "fn function_never_panic() nopanic {\n" " assert(1 == 1, 'what');\n" "}\n" "```" msgstr "" "```rust\n" +"// does_not_compile\n" "fn function_never_panic() nopanic {\n" " assert(1 == 1, 'what');\n" "}\n" "```" -#: src/ch09-01-unrecoverable-errors-with-panic.md:64 +#: src/ch09-01-unrecoverable-errors-with-panic.md:67 msgid "If you write the following function that includes a function that may panic you will get the following error:" msgstr "Si escribes la siguiente función que incluye una función que puede entrar en pánico obtendrás el siguiente error:" -#: src/ch09-01-unrecoverable-errors-with-panic.md:66 +#: src/ch09-01-unrecoverable-errors-with-panic.md:69 msgid "" -"```bash\n" +"```console\n" "error: Function is declared as nopanic but calls a function that may panic.\n" " --> test.cairo:2:12\n" " assert(1 == 1, 'what');\n" @@ -12209,7 +12741,7 @@ msgid "" " ^********************^\n" "```" msgstr "" -"```bash\n" +"```console\n" "error: Function is declared as nopanic but calls a function that may panic.\n" " --> test.cairo:2:12\n" " assert(1 == 1, 'what');\n" @@ -12220,15 +12752,15 @@ msgstr "" " ^********************^\n" "```" -#: src/ch09-01-unrecoverable-errors-with-panic.md:77 +#: src/ch09-01-unrecoverable-errors-with-panic.md:80 msgid "Note that there are two functions that may panic here, assert and equality." msgstr "Tenga en cuenta que hay dos funciones que pueden entrar en pánico aquí, assert e equality." -#: src/ch09-01-unrecoverable-errors-with-panic.md:79 +#: src/ch09-01-unrecoverable-errors-with-panic.md:82 msgid "## panic_with macro" msgstr "## macro panic_with" -#: src/ch09-01-unrecoverable-errors-with-panic.md:81 +#: src/ch09-01-unrecoverable-errors-with-panic.md:84 msgid "" "You can use the `panic_with` macro to mark a function that returns an `Option` or `Result`. This macro takes two arguments, which are the data that is passed as the panic reason as " "well as the name for a wrapping function. It will create a wrapper for your annotated function which will panic if the function returns `None` or `Err`, the panic function will be " @@ -12238,7 +12770,7 @@ msgstr "" "pánico, así como el nombre de una función envolvente. Creará una envoltura para su función anotada que entrará en pánico si la función devuelve `None` o `Err`, la función de pánico " "será llamada con los datos dados." -#: src/ch09-01-unrecoverable-errors-with-panic.md:85 +#: src/ch09-01-unrecoverable-errors-with-panic.md:88 msgid "" "```rust\n" "use option::OptionTrait;\n" @@ -12276,11 +12808,11 @@ msgstr "" "}\n" "```" -#: src/ch09-01-unrecoverable-errors-with-panic.md:103 +#: src/ch09-01-unrecoverable-errors-with-panic.md:106 msgid "## Using assert" msgstr "## Usando assert" -#: src/ch09-01-unrecoverable-errors-with-panic.md:105 +#: src/ch09-01-unrecoverable-errors-with-panic.md:108 msgid "" "The assert function from the Cairo core library is actually a utility function based on panics. It asserts that a boolean expression is true at runtime, and if it is not, it calls " "the panic function with an error value. The assert function takes two arguments: the boolean expression to verify, and the error value. The error value is specified as a felt252, so " @@ -12290,11 +12822,11 @@ msgstr "" "si no lo es, llama a la función panic con un valor de error. La función assert toma dos argumentos: la expresión booleana a verificar y el valor de error. El valor de error se " "especifica como un felt252, por lo que cualquier cadena que se pase debe caber dentro de un felt252." -#: src/ch09-01-unrecoverable-errors-with-panic.md:107 +#: src/ch09-01-unrecoverable-errors-with-panic.md:110 msgid "Here is an example of its usage:" msgstr "He aquí un ejemplo de su uso:" -#: src/ch09-01-unrecoverable-errors-with-panic.md:109 +#: src/ch09-01-unrecoverable-errors-with-panic.md:112 msgid "" "```rust\n" "fn main() {\n" @@ -12316,7 +12848,7 @@ msgstr "" "}\n" "```" -#: src/ch09-01-unrecoverable-errors-with-panic.md:119 +#: src/ch09-01-unrecoverable-errors-with-panic.md:122 msgid "" "We are asserting in main that `my_number` is not zero to ensure that we're not performing a division by 0.\n" "In this example, `my_number` is zero so the assertion will fail, and the program will panic\n" @@ -12326,15 +12858,15 @@ msgstr "" "En este ejemplo, `my_number` es cero por lo que la afirmación fallará, y el programa entrará en pánico\n" "con la cadena 'number is zero' (como felt252) y no se realizará la división." -#: src/ch09-02-error-handling.md:1 +#: src/ch09-02-recoverable-errors.md:1 msgid "# Recoverable Errors with `Result`" msgstr "# Errores Recuperables con `Result`" -#: src/ch09-02-error-handling.md:3 src/ch09-02-error-handling.md:56 +#: src/ch09-02-recoverable-errors.md:3 src/ch09-02-recoverable-errors.md:56 msgid "
" msgstr "
" -#: src/ch09-02-error-handling.md:5 +#: src/ch09-02-recoverable-errors.md:5 msgid "" "Most errors aren’t serious enough to require the program to stop entirely. Sometimes, when a function fails, it’s for a reason that you can easily interpret and respond to. For " "example, if you try to add two large integers and the operation overflows because the sum exceeds the maximum representable value, you might want to return an error or a wrapped " @@ -12344,21 +12876,21 @@ msgstr "" "interpretar fácilmente y a la que puede responder. Por ejemplo, si intenta sumar dos enteros grandes y la operación se desborda porque la suma excede el valor máximo representable, " "es posible que desee devolver un error o un resultado envuelto en lugar de causar un comportamiento indefinido o terminar el proceso." -#: src/ch09-02-error-handling.md:7 +#: src/ch09-02-recoverable-errors.md:7 msgid "## The `Result` enum" msgstr "## El enum `Result`" -#: src/ch09-02-error-handling.md:9 +#: src/ch09-02-recoverable-errors.md:9 msgid "Recall from [“Generic data types”](ch07-01-generic-data-types.md#enums) in Chapter 7 that the `Result` enum is defined as having two variants, `Ok` and `Err`, as follows:" msgstr "" "Recordemos de [\"Tipos de datos genéricos\"](ch07-01-generic-data-types.md#enums) en el Capítulo 7 que el enum `Result` se define como teniendo dos variantes, `Ok` y `Err`, como " "sigue:" -#: src/ch09-02-error-handling.md:20 +#: src/ch09-02-recoverable-errors.md:20 msgid "## The `ResultTrait`" msgstr "## El `ResultTrait`" -#: src/ch09-02-error-handling.md:22 +#: src/ch09-02-recoverable-errors.md:22 msgid "" "The `ResultTrait` trait provides methods for working with the `Result` enum, such as unwrapping values, checking whether the `Result` is `Ok` or `Err`, and panicking with a " "custom message. The `ResultTraitImpl` implementation defines the logic of these methods." @@ -12366,7 +12898,7 @@ msgstr "" "El rasgo `ResultTrait` proporciona métodos para trabajar con el enum `Result`, como desenvolver valores, comprobar si el `Result` es `Ok` o `Err`, y entrar en pánico con un " "mensaje personalizado. La implementación de `ResultTraitImpl` define la lógica de estos métodos." -#: src/ch09-02-error-handling.md:24 +#: src/ch09-02-recoverable-errors.md:24 msgid "" "```rust\n" "trait ResultTrait {\n" @@ -12400,7 +12932,7 @@ msgstr "" "}\n" "```" -#: src/ch09-02-error-handling.md:40 +#: src/ch09-02-recoverable-errors.md:40 msgid "" "The `expect` and `unwrap` methods are similar in that they both attempt to extract the value of type `T` from a `Result` when it is in the `Ok` variant. If the `Result` is " "`Ok(x)`, both methods return the value `x`. However, the key difference between the two methods lies in their behavior when the `Result` is in the `Err` variant. The `expect` method " @@ -12412,7 +12944,7 @@ msgstr "" "`expect` te permite proporcionar un mensaje de error personalizado (como un valor `felt252`) que se utilizará cuando se produzca el pánico, dándote más control y contexto sobre el " "pánico. Por otro lado, el método `unwrap` entra en pánico con un mensaje de error por defecto, proporcionando menos información sobre la causa del pánico." -#: src/ch09-02-error-handling.md:42 +#: src/ch09-02-recoverable-errors.md:42 msgid "" "The `expect_err` and `unwrap_err` have the exact opposite behavior. If the `Result` is `Err(x)`, both methods return the value `x`. However, the key difference between the two " "methods is in case of `Result::Ok()`. The `expect_err` method allows you to provide a custom error message (as a `felt252` value) that will be used when panicking, giving you more " @@ -12423,7 +12955,7 @@ msgstr "" "utilizará cuando se produzca el pánico, dándote más control y contexto sobre el pánico. Por otro lado, el método `unwrap_err` entra en pánico con un mensaje de error por defecto, " "proporcionando menos información sobre la causa del pánico." -#: src/ch09-02-error-handling.md:44 +#: src/ch09-02-recoverable-errors.md:44 msgid "" "A careful reader may have noticed the `>` and `>` in the first four methods signatures. This syntax represents generic type constraints in the " "Cairo language. These constraints indicate that the associated functions require an implementation of the `Drop` trait for the generic types `T` and `E`, respectively." @@ -12432,11 +12964,11 @@ msgstr "" "genérico en el lenguaje Cairo. Estas restricciones indican que las funciones asociadas requieren una implementación del rasgo `Drop` para los tipos genéricos `T` y `E`, " "respectivamente." -#: src/ch09-02-error-handling.md:46 +#: src/ch09-02-recoverable-errors.md:46 msgid "Finally, the `is_ok` and `is_err` methods are utility functions provided by the `ResultTrait` trait to check the variant of a `Result` enum value." msgstr "Por último, los métodos `is_ok` y `is_err` son funciones de utilidad proporcionadas por el rasgo `ResultTrait` para comprobar la variante de un valor del enum `Result`." -#: src/ch09-02-error-handling.md:48 +#: src/ch09-02-recoverable-errors.md:48 msgid "" "`is_ok` takes a snapshot of a `Result` value and returns `true` if the `Result` is the `Ok` variant, meaning the operation was successful. If the `Result` is the `Err` variant, " "it returns `false`." @@ -12444,7 +12976,7 @@ msgstr "" "`is_ok` toma una instantánea de un valor `Result` y devuelve `true` si el `Result` es la variante `Ok`, lo que significa que la operación se ha realizado correctamente. Si el " "`Resultado` es la variante `Err`, devuelve `false`." -#: src/ch09-02-error-handling.md:50 +#: src/ch09-02-recoverable-errors.md:50 msgid "" "`is_err` takes a reference to a `Result` value and returns `true` if the `Result` is the `Err` variant, meaning the operation encountered an error. If the `Result` is the `Ok` " "variant, it returns `false`." @@ -12452,7 +12984,7 @@ msgstr "" "`is_err` toma una referencia a un valor `Result` y devuelve `true` si el `Result` es la variante `Err`, lo que significa que la operación ha encontrado un error. Si el " "`Resultado` es la variante `Ok`, devuelve `false`." -#: src/ch09-02-error-handling.md:52 +#: src/ch09-02-recoverable-errors.md:52 msgid "" "These methods are helpful when you want to check the success or failure of an operation without consuming the Result value, allowing you to perform additional operations or make " "decisions based on the variant without unwrapping it." @@ -12460,19 +12992,19 @@ msgstr "" "Estos métodos son útiles cuando se desea comprobar el éxito o el fracaso de una operación sin consumir el valor del Resultado, lo que permite realizar operaciones adicionales o tomar " "decisiones basadas en la variante sin desenvolverla." -#: src/ch09-02-error-handling.md:54 +#: src/ch09-02-recoverable-errors.md:54 msgid "You can find the implementation ot the `ResultTrait` [here](https://github.com/starkware-libs/cairo/blob/main/corelib/src/result.cairo#L20)." msgstr "Puede encontrar la implementación del `ResultTrait` [aquí](https://github.com/starkware-libs/cairo/blob/main/corelib/src/result.cairo#L20)." -#: src/ch09-02-error-handling.md:58 +#: src/ch09-02-recoverable-errors.md:58 msgid "It is always easier to understand with examples." msgstr "Siempre es más fácil entender con ejemplos." -#: src/ch09-02-error-handling.md:60 +#: src/ch09-02-recoverable-errors.md:60 msgid "Have a look at this function signature:" msgstr "Eche un vistazo a la firma de esta función:" -#: src/ch09-02-error-handling.md:62 +#: src/ch09-02-recoverable-errors.md:62 msgid "" "```rust\n" "fn u128_overflowing_add(a: u128, b: u128) -> Result;\n" @@ -12482,7 +13014,7 @@ msgstr "" "fn u128_overflowing_add(a: u128, b: u128) -> Result;\n" "```" -#: src/ch09-02-error-handling.md:66 +#: src/ch09-02-recoverable-errors.md:66 msgid "" "It takes two u128 integers, a and b, and returns a `Result` where the `Ok` variant holds the sum if the addition does not overflow, and the `Err` variant holds the " "overflowed value if the addition does overflow." @@ -12490,11 +13022,11 @@ msgstr "" "Toma dos enteros u128, a y b, y devuelve un `Result` donde la variante `Ok` contiene la suma si la suma no se desborda, y la variante `Err` contiene el valor desbordado " "si la suma se desborda." -#: src/ch09-02-error-handling.md:68 +#: src/ch09-02-recoverable-errors.md:68 msgid "Now, we can use this function elsewhere. For instance:" msgstr "Ahora, podemos utilizar esta función en otros lugares. Por ejemplo:" -#: src/ch09-02-error-handling.md:70 +#: src/ch09-02-recoverable-errors.md:70 msgid "" "```rust\n" "fn u128_checked_add(a: u128, b: u128) -> Option {\n" @@ -12514,7 +13046,7 @@ msgstr "" "}\n" "```" -#: src/ch09-02-error-handling.md:79 +#: src/ch09-02-recoverable-errors.md:79 msgid "" "Here, it accepts two u128 integers, a and b, and returns an `Option`. It uses the `Result` returned by `u128_overflowing_add` to determine the success or failure of the " "addition operation. The match expression checks the `Result` from `u128_overflowing_add`. If the result is `Ok(r)`, it returns `Option::Some(r)` containing the sum. If the result is " @@ -12524,7 +13056,7 @@ msgstr "" "addition operation. The match expression checks the `Result` from `u128_overflowing_add`. If the result is `Ok(r)`, it returns `Option::Some(r)` containing the sum. If the result is " "`Err(r)`, it returns `Option::None(())` to indicate that the operation has failed due to overflow. The function does not panic in case of an overflow." -#: src/ch09-02-error-handling.md:81 +#: src/ch09-02-recoverable-errors.md:81 msgid "" "Let's take another example demonstrating the use of `unwrap`.\n" "First we import the necessary modules:" @@ -12532,7 +13064,7 @@ msgstr "" "Veamos otro ejemplo que demuestra el uso de `unwrap`.\n" "Primero importamos los módulos necesarios:" -#: src/ch09-02-error-handling.md:84 +#: src/ch09-02-recoverable-errors.md:84 msgid "" "```rust\n" "use core::traits::Into;\n" @@ -12550,7 +13082,7 @@ msgstr "" "use result::ResultTraitImpl;\n" "```" -#: src/ch09-02-error-handling.md:92 +#: src/ch09-02-recoverable-errors.md:92 msgid "" "In this example, the `parse_u8` function takes a `felt252` integer and tries to convert it into a `u8` integer using the `try_into` method. If successful, it returns `Result::" "Ok(value)`, otherwise it returns `Result::Err('Invalid integer')`." @@ -12558,7 +13090,7 @@ msgstr "" "En este ejemplo, la función `parse_u8` toma un entero `felt252` e intenta convertirlo en un entero `u8` utilizando el método `try_into`. Si tiene éxito, devuelve `Result::Ok(value)`, " "en caso contrario devuelve `Result::Err('Invalid integer')`." -#: src/ch09-02-error-handling.md:94 +#: src/ch09-02-recoverable-errors.md:94 msgid "" "```rust\n" "fn parse_u8(s: felt252) -> Result {\n" @@ -12578,45 +13110,83 @@ msgstr "" "}\n" "```" -#: src/ch09-02-error-handling.md:103 +#: src/ch09-02-recoverable-errors.md:103 +msgid "Listing 9-1: Using the Result type" +msgstr "Listado 9-1: Utilización del tipo de resultado" + +#: src/ch09-02-recoverable-errors.md:105 msgid "Our two test cases are:" msgstr "Nuestros dos casos de prueba son:" -#: src/ch09-02-error-handling.md:105 +#: src/ch09-02-recoverable-errors.md:107 msgid "" "```rust\n" -"#[test]\n" -"fn test_felt252_to_u8() {\n" -" let number: felt252 = 5_felt252;\n" -" // should not panic\n" -" let res = parse_u8(number).unwrap();\n" -"}\n" +"# use traits::TryInto;\n" +"# \n" +"# fn parse_u8(s: felt252) -> Result {\n" +"# match s.try_into() {\n" +"# Option::Some(value) => Result::Ok(value),\n" +"# Option::None(_) => Result::Err('Invalid integer'),\n" +"# }\n" +"# }\n" +"# \n" +"#[cfg(test)]\n" +"mod tests {\n" +" use super::parse_u8;\n" +" use result::ResultTrait;\n" +" #[test]\n" +" fn test_felt252_to_u8() {\n" +" let number: felt252 = 5_felt252;\n" +" // should not panic\n" +" let res = parse_u8(number).unwrap();\n" +" }\n" "\n" -"#[test]\n" -"fn test_felt252_to_u8_panic() {\n" -" let number: felt252 = 256_felt252;\n" -" // should panic\n" -" let res = parse_u8(number).unwrap();\n" +" #[test]\n" +" #[should_panic]\n" +" fn test_felt252_to_u8_panic() {\n" +" let number: felt252 = 256_felt252;\n" +" // should panic\n" +" let res = parse_u8(number).unwrap();\n" +" }\n" "}\n" +"# \n" +"# \n" "```" msgstr "" "```rust\n" -"#[test]\n" -"fn test_felt252_to_u8() {\n" -" let number: felt252 = 5_felt252;\n" -" // should not panic\n" -" let res = parse_u8(number).unwrap();\n" -"}\n" +"# use traits::TryInto;\n" +"# \n" +"# fn parse_u8(s: felt252) -> Result {\n" +"# match s.try_into() {\n" +"# Option::Some(value) => Result::Ok(value),\n" +"# Option::None(_) => Result::Err('Invalid integer'),\n" +"# }\n" +"# }\n" +"# \n" +"#[cfg(test)]\n" +"mod tests {\n" +" use super::parse_u8;\n" +" use result::ResultTrait;\n" +" #[test]\n" +" fn test_felt252_to_u8() {\n" +" let number: felt252 = 5_felt252;\n" +" // should not panic\n" +" let res = parse_u8(number).unwrap();\n" +" }\n" "\n" -"#[test]\n" -"fn test_felt252_to_u8_panic() {\n" -" let number: felt252 = 256_felt252;\n" -" // should panic\n" -" let res = parse_u8(number).unwrap();\n" +" #[test]\n" +" #[should_panic]\n" +" fn test_felt252_to_u8_panic() {\n" +" let number: felt252 = 256_felt252;\n" +" // should panic\n" +" let res = parse_u8(number).unwrap();\n" +" }\n" "}\n" +"# \n" +"# \n" "```" -#: src/ch09-02-error-handling.md:121 +#: src/ch09-02-recoverable-errors.md:140 msgid "" "The first one tests a valid conversion from `felt252` to `u8`, expecting the `unwrap` method not to panic. The second test function attempts to convert a value that is out of the " "`u8` range, expecting the `unwrap` method to panic with the error message 'Invalid integer'." @@ -12624,15 +13194,15 @@ msgstr "" "La primera prueba una conversión válida de `felt252` a `u8`, esperando que el método `unwrap` no entre en pánico. La segunda función de prueba intenta convertir un valor que está " "fuera del rango `u8`, esperando que el método `unwrap` entre en pánico con el mensaje de error 'Invalid integer'." -#: src/ch09-02-error-handling.md:123 +#: src/ch09-02-recoverable-errors.md:142 msgid "> We could have also used the #[should_panic] attribute here." msgstr "> También podríamos haber utilizado aquí el atributo #[should_panic]." -#: src/ch09-02-error-handling.md:125 +#: src/ch09-02-recoverable-errors.md:144 msgid "### The `?` operator ?" msgstr "### ¿El operador `?`?" -#: src/ch09-02-error-handling.md:127 +#: src/ch09-02-recoverable-errors.md:146 msgid "" "The last operator we will talk about is the `?` operator. The `?` operator is used for more idiomatic and concise error handling. When you use the `?` operator on a `Result` or " "`Option` type, it will do the following:" @@ -12640,7 +13210,7 @@ msgstr "" "El último operador del que hablaremos es el operador `?`. El operador `?` se utiliza para un manejo de errores más idiomático y conciso. Cuando usas el operador `?` en un tipo " "`Result` u `Option`, hará lo siguiente:" -#: src/ch09-02-error-handling.md:129 +#: src/ch09-02-recoverable-errors.md:148 msgid "" "- If the value is `Result::Ok(x)` or `Option::Some(x)`, it will return the inner value `x` directly.\n" "- If the value is `Result::Err(e)` or `Option::None`, it will propagate the error or `None` by immediately returning from the function." @@ -12648,15 +13218,15 @@ msgstr "" "- Si el valor es `Result::Ok(x)` u `Opción::Some(x)`, devolverá el valor interno `x` directamente.\n" "- Si el valor es `Result::Err(e)` u `Option::None`, propagará el error o `None` retornando inmediatamente de la función." -#: src/ch09-02-error-handling.md:132 +#: src/ch09-02-recoverable-errors.md:151 msgid "The `?` operator is useful when you want to handle errors implicitly and let the calling function deal with them." msgstr "El operador `?` es útil cuando se desea manejar los errores implícitamente y dejar que la función de llamada se ocupe de ellos." -#: src/ch09-02-error-handling.md:134 +#: src/ch09-02-recoverable-errors.md:153 msgid "Here is an example." msgstr "Aquí un ejemplo." -#: src/ch09-02-error-handling.md:136 +#: src/ch09-02-recoverable-errors.md:155 msgid "" "```rust\n" "fn do_something_with_parse_u8(input: felt252) -> Result {\n" @@ -12676,54 +13246,102 @@ msgstr "" "}\n" "```" -#: src/ch09-02-error-handling.md:145 +#: src/ch09-02-recoverable-errors.md:164 +msgid "Listing 9-1: Using the `?` operator" +msgstr "Listado 9-1: Utilización del operador `?`" + +#: src/ch09-02-recoverable-errors.md:166 msgid "" "`do_something_with_parse_u8` function takes a `felt252` value as input and calls `parse_u8`. The `?` operator is used to propagate the error, if any, or unwrap the successful value." msgstr "" "La función `do_something_with_parse_u8` toma un valor `felt252` como entrada y llama a `parse_u8`. El operador `?` se utiliza para propagar el error, si lo hay, o desenvolver el " "valor correcto." -#: src/ch09-02-error-handling.md:147 +#: src/ch09-02-recoverable-errors.md:168 msgid "And with a little test case:" msgstr "Y con un pequeño caso de prueba:" -#: src/ch09-02-error-handling.md:149 -msgid "" -"```rust\n" -"#[test]\n" -"fn test_function_2() {\n" -" let number: felt252 = 258_felt252;\n" -" match do_something_with_parse_u8(number) {\n" -" Result::Ok(value) => value.print(),\n" -" Result::Err(e) => e.print()\n" +#: src/ch09-02-recoverable-errors.md:170 +msgid "" +"```rust\n" +"# use traits::TryInto;\n" +"# \n" +"# fn parse_u8(s: felt252) -> Result {\n" +"# match s.try_into() {\n" +"# Option::Some(value) => Result::Ok(value),\n" +"# Option::None(_) => Result::Err('Invalid integer'),\n" +"# }\n" +"# }\n" +"# \n" +"# fn do_something_with_parse_u8(input: felt252) -> Result {\n" +"# let input_to_u8: u8 = parse_u8(input)?;\n" +"# // DO SOMETHING\n" +"# let res = input_to_u8 - 1;\n" +"# Result::Ok(res)\n" +"# }\n" +"# \n" +"# #[cfg(test)]\n" +"# mod tests {\n" +"# use super::do_something_with_parse_u8;\n" +"# use debug::PrintTrait;\n" +" #[test]\n" +" fn test_function_2() {\n" +" let number: felt252 = 258_felt252;\n" +" match do_something_with_parse_u8(number) {\n" +" Result::Ok(value) => value.print(),\n" +" Result::Err(e) => e.print()\n" +" }\n" " }\n" -"}\n" -"```" -msgstr "" -"```rust\n" -"#[test]\n" -"fn test_function_2() {\n" -" let number: felt252 = 258_felt252;\n" -" match do_something_with_parse_u8(number) {\n" -" Result::Ok(value) => value.print(),\n" -" Result::Err(e) => e.print()\n" +"# }\n" +"# \n" +"```" +msgstr "" +"```rust\n" +"# use traits::TryInto;\n" +"# \n" +"# fn parse_u8(s: felt252) -> Result {\n" +"# match s.try_into() {\n" +"# Option::Some(value) => Result::Ok(value),\n" +"# Option::None(_) => Result::Err('Invalid integer'),\n" +"# }\n" +"# }\n" +"# \n" +"# fn do_something_with_parse_u8(input: felt252) -> Result {\n" +"# let input_to_u8: u8 = parse_u8(input)?;\n" +"# // DO SOMETHING\n" +"# let res = input_to_u8 - 1;\n" +"# Result::Ok(res)\n" +"# }\n" +"# \n" +"# #[cfg(test)]\n" +"# mod tests {\n" +"# use super::do_something_with_parse_u8;\n" +"# use debug::PrintTrait;\n" +" #[test]\n" +" fn test_function_2() {\n" +" let number: felt252 = 258_felt252;\n" +" match do_something_with_parse_u8(number) {\n" +" Result::Ok(value) => value.print(),\n" +" Result::Err(e) => e.print()\n" +" }\n" " }\n" -"}\n" +"# }\n" +"# \n" "```" -#: src/ch09-02-error-handling.md:160 +#: src/ch09-02-recoverable-errors.md:203 msgid "The console will print the error \"Invalid Integer\"." msgstr "La consola mostrará el error \"Invalid Integer\"." -#: src/ch09-02-error-handling.md:162 +#: src/ch09-02-recoverable-errors.md:205 msgid "
" msgstr "
" -#: src/ch09-02-error-handling.md:164 +#: src/ch09-02-recoverable-errors.md:207 msgid "### Summary" msgstr "### Resumen" -#: src/ch09-02-error-handling.md:166 +#: src/ch09-02-recoverable-errors.md:209 msgid "" "We saw that recoverable errors can be handled in Cairo using the Result enum, which has two variants: `Ok` and `Err`. The `Result` enum is generic, with types `T` and `E` " "representing the successful and error values, respectively. The `ResultTrait` provides methods for working with `Result`, such as unwrapping values, checking if the result is " @@ -12733,7 +13351,7 @@ msgstr "" "`E` representando los valores de éxito y error, respectivamente. El `ResultTrait` proporciona métodos para trabajar con `Result`, como desenvolver valores, comprobar si el " "resultado es `Ok` o `Err`, y asustar con mensajes personalizados." -#: src/ch09-02-error-handling.md:168 +#: src/ch09-02-recoverable-errors.md:211 msgid "" "To handle recoverable errors, a function can return a `Result` type and use pattern matching to handle the success or failure of an operation. The `?` operator can be used to " "implicitly handle errors by propagating the error or unwrapping the successful value. This allows for more concise and clear error handling, where the caller is responsible for " @@ -12743,6 +13361,104 @@ msgstr "" "operador `?` puede utilizarse para gestionar errores implícitamente, propagando el error o desenvolviendo el valor correcto. Esto permite una gestión de errores más concisa y clara, " "en la que el autor de la llamada es responsable de gestionar los errores generados por la función llamada." +#: src/ch10-00-advanced-features.md:1 +msgid "# Advanced Features" +msgstr "# Funciones Avanzadas" + +#: src/ch10-01-operator-overloading.md:1 +msgid "# Operator Overloading" +msgstr "# Sobrecarga de Operadores" + +#: src/ch10-01-operator-overloading.md:3 +msgid "" +"Operator overloading is a feature in some programming languages that allows the redefinition of standard operators, such as addition (+), subtraction (-), multiplication (\\*), and " +"division (/), to work with user-defined types. This can make the syntax of the code more intuitive, by enabling operations on user-defined types to be expressed in the same way as " +"operations on primitive types." +msgstr "" +"La sobrecarga de operadores es una característica de algunos lenguajes de programación que permite redefinir operadores estándar, como la suma (+), la resta (-), la multiplicación " +"(\\*) y la división (/), para que funcionen con tipos definidos por el usuario. Esto puede hacer que la sintaxis del código sea más intuitiva, al permitir que las operaciones sobre " +"tipos definidos por el usuario se expresen del mismo modo que las operaciones sobre tipos primitivos." + +#: src/ch10-01-operator-overloading.md:5 +msgid "" +"In Cairo, operator overloading is achieved through the implementation of specific traits. Each operator has an associated trait, and overloading that operator involves providing an " +"implementation of that trait for a custom type.\n" +"However, it's essential to use operator overloading judiciously. Misuse can lead to confusion, making the code more difficult to maintain, for example when there is no semantic " +"meaning to the operator being overloaded." +msgstr "" +"En Cairo, la sobrecarga de operadores se consigue mediante la implementación de rasgos específicos. Cada operador tiene un rasgo asociado, y sobrecargar ese operador implica " +"proporcionar una implementación de ese rasgo para un tipo personalizado.\n" +"Sin embargo, es esencial utilizar la sobrecarga de operadores con criterio. Un mal uso puede llevar a confusión, haciendo el código más difícil de mantener, por ejemplo cuando no hay " +"un significado semántico para el operador que se sobrecarga." + +#: src/ch10-01-operator-overloading.md:8 +msgid "Consider an example where two `Potions` need to be combined. `Potions` have two data fields, mana and health. Combining two `Potions` should add their respective fields." +msgstr "" +"Consideremos un ejemplo en el que hay que combinar dos `Potions`. Las `Potions` tienen dos campos de datos, maná y salud. Al combinar dos `Potions` se deben añadir sus respectivos " +"campos." + +#: src/ch10-01-operator-overloading.md:10 +msgid "" +"```rust\n" +"struct Potion {\n" +" health: felt252,\n" +" mana: felt252\n" +"}\n" +"\n" +"impl PotionAdd of Add {\n" +" fn add(lhs: Potion, rhs: Potion) -> Potion {\n" +" Potion { health: lhs.health + rhs.health, mana: lhs.mana + rhs.mana, }\n" +" }\n" +"}\n" +"\n" +"fn main() {\n" +" let health_potion: Potion = Potion { health: 100, mana: 0 };\n" +" let mana_potion: Potion = Potion { health: 0, mana: 100 };\n" +" let super_potion: Potion = health_potion + mana_potion;\n" +" // Both potions were combined with the `+` operator.\n" +" assert(super_potion.health == 100, '');\n" +" assert(super_potion.mana == 100, '');\n" +"}\n" +"```" +msgstr "" +"```rust\n" +"struct Potion {\n" +" health: felt252,\n" +" mana: felt252\n" +"}\n" +"\n" +"impl PotionAdd of Add {\n" +" fn add(lhs: Potion, rhs: Potion) -> Potion {\n" +" Potion { health: lhs.health + rhs.health, mana: lhs.mana + rhs.mana, }\n" +" }\n" +"}\n" +"\n" +"fn main() {\n" +" let health_potion: Potion = Potion { health: 100, mana: 0 };\n" +" let mana_potion: Potion = Potion { health: 0, mana: 100 };\n" +" let super_potion: Potion = health_potion + mana_potion;\n" +" // Both potions were combined with the `+` operator.\n" +" assert(super_potion.health == 100, '');\n" +" assert(super_potion.mana == 100, '');\n" +"}\n" +"```" + +#: src/ch10-01-operator-overloading.md:32 +msgid "" +"In the code above, we're implementing the `Add` trait for the `Potion` type. The add function takes two arguments: `lhs` and `rhs` (left and right-hand side). The function body " +"returns a new `Potion` instance, its field values being a combination of `lhs` and `rhs`." +msgstr "" +"En el código anterior, estamos implementando el rasgo `Add` para el tipo `Potion`. La función add toma dos argumentos: `lhs` y `rhs` (izquierda y derecha). El cuerpo de la función " +"devuelve una nueva instancia de `Poción`, cuyos valores de campo son una combinación de `lhs` y `rhs`." + +#: src/ch10-01-operator-overloading.md:34 +msgid "" +"As illustrated in the example, overloading an operator requires specification of the concrete type being overloaded. The overloaded generic trait is `Add`, and we define a " +"concrete implementation for the type `Potion` with `Add`." +msgstr "" +"Como se ilustra en el ejemplo, la sobrecarga de un operador requiere la especificación del tipo concreto que se sobrecarga. El trait genérico sobrecargado es `Add`, y definimos " +"una implementación concreta para el tipo `Potion` con `Add`." + #: src/ch99-00-starknet-smart-contracts.md:1 msgid "# Starknet Smart Contracts" msgstr "# Contratos Inteligentes en Starknet" @@ -12762,8 +13478,14 @@ msgstr "" "de Starknet, pueden modificar variables en los estados de Starknet, comunicarse con otros contratos e interactuar sin problemas con la L1 subyacente." #: src/ch99-00-starknet-smart-contracts.md:7 -msgid "Starknet contracts are denoted by the `#[contract]` attribute. We'll dive deeper into this in the next sections." -msgstr "Los contratos inteligentes en Starknet se denotan por el atributo `#[contract]`. Profundizaremos más en esto en las próximas secciones." +msgid "" +"Starknet contracts are denoted by the `#[contract]` attribute. We'll dive deeper into this in the next sections.\n" +"If you want to learn more about the Starknet network itself, its architecture and the tooling available, you should read the [Starknet Book](https://book.starknet.io/). This section " +"will focus on writing smart contracts in Cairo." +msgstr "" +"Los contratos de Starknet se denotan mediante el atributo `#[contract]`. Profundizaremos en esto en las próximas secciones.\n" +"Si quieres aprender más sobre la propia red Starknet, su arquitectura y las herramientas disponibles, deberías leer el [Libro Starknet](https://book.starknet.io/). Esta sección se " +"centrará en escribir contratos inteligentes en Cairo." #: src/ch99-01-01-introduction-to-smart-contracts.md:1 msgid "# Introduction to smart-contracts" @@ -12798,8 +13520,8 @@ msgstr "" #: src/ch99-01-01-introduction-to-smart-contracts.md:10 msgid "" "The programming language used to write smart contracts varies depending on the blockchain. For example, on Ethereum and the [EVM-compatible ecosystem](https://ethereum.org/en/" -"developers/docs/evm/) ecosystem, the most commonly used language is Solidity, while on Starknet, it is Cairo. The way the code is compiled also differs based on the blockchain. On " -"Ethereum, Solidity is compiled into bytecode. On Starknet, Cairo is compiled into Sierra and then into Cairo Assembly (casm)." +"developers/docs/evm/), the most commonly used language is Solidity, while on Starknet, it is Cairo. The way the code is compiled also differs based on the blockchain. On Ethereum, " +"Solidity is compiled into bytecode. On Starknet, Cairo is compiled into Sierra and then into Cairo Assembly (casm)." msgstr "" "El lenguaje de programación utilizado para escribir contratos inteligentes varía en función de la blockchain. Por ejemplo, en Ethereum y en el ecosistema [compatible con EVM](https://" "ethereum.org/en/developers/docs/evm/), el lenguaje más utilizado es Solidity, mientras que en Starknet es Cairo. La forma de compilar el código también difiere en función del " @@ -12820,8 +13542,8 @@ msgstr "" #: src/ch99-01-01-introduction-to-smart-contracts.md:14 msgid "" -"For developers to build smart contracts that can interact with each others, it is required to know what the other contracts look like. Hence, Ethereum developers started to build " -"standards for smart contract developement, the `ERCxx`. The two most used and famous standards are the `ERC20`, used to build tokens like `USDC`, `DAI` or `STARK`, and the `ERC721`, " +"For developers to build smart contracts that can interact with each other, it is required to know what the other contracts look like. Hence, Ethereum developers started to build " +"standards for smart contract development, the `ERCxx`. The two most used and famous standards are the `ERC20`, used to build tokens like `USDC`, `DAI` or `STARK`, and the `ERC721`, " "for NFTs (Non-fungible tokens) like `CryptoPunks` or `Everai`." msgstr "" "Para que los desarrolladores puedan crear contratos inteligentes que interactúen entre sí, es necesario saber cómo son los demás contratos. Por ello, los desarrolladores de Ethereum " @@ -12950,7 +13672,7 @@ msgid "" "Remember Cairo? It is, in fact, a language developed specifically to work with STARKs and make them general-purpose. With Cairo, we can write **provable code**. In the context of " "Starknet, this allows proving the correctness of computations from one state to another. Unlike most (if not all) of Starknet's competitors that chose to use the EVM (either as-is or " "adapted) as a base layer, Starknet employs its own VM. This frees developers from the constraints of the EVM, opening up a broader range of possibilities. Coupled with decreased " -"transaction costs, the combination of Starknet and Cairo creates an exiting playground for developers. Native account abstraction enables more complex logic for accounts and " +"transaction costs, the combination of Starknet and Cairo creates an exciting playground for developers. Native account abstraction enables more complex logic for accounts and " "transaction flows. Emerging use cases include **transparent AI** and artificial intelligence and machine learning applications. Finally, **blockchain games** can be developed " "entirely **on-chain**. Starknet has been specifically designed to maximize the capabilities of STARK proofs for optimal scalability." msgstr "" @@ -13005,31 +13727,31 @@ msgstr "" msgid "" "```rust\n" "#[contract]\n" -"mod Example{\n" +"mod example {\n" " use starknet::get_caller_address;\n" " use starknet::ContractAddress;\n" "\n" -" struct Storage{\n" -" names: LegacyMap::,\n" +" struct Storage {\n" +" names: LegacyMap::, \n" " }\n" "\n" " #[event]\n" -" fn StoredName(caller: ContractAddress, name:felt252){}\n" +" fn StoredName(caller: ContractAddress, name: felt252) {}\n" "\n" " #[constructor]\n" -" fn constructor(_name: felt252, _address: ContractAddress){\n" +" fn constructor(_name: felt252, _address: ContractAddress) {\n" " names::write(_address, _name);\n" " }\n" "\n" " #[external]\n" -" fn store_name(_name: felt252){\n" +" fn store_name(_name: felt252) {\n" " let caller = get_caller_address();\n" " names::write(caller, _name);\n" -" StoredName(caller,_name);\n" +" StoredName(caller, _name);\n" " }\n" "\n" " #[view]\n" -" fn get_name(_address:ContractAddress) -> felt252{\n" +" fn get_name(_address: ContractAddress) -> felt252 {\n" " let name = names::read(_address);\n" " return name;\n" " }\n" @@ -13038,31 +13760,31 @@ msgid "" msgstr "" "```rust\n" "#[contract]\n" -"mod Example{\n" +"mod example {\n" " use starknet::get_caller_address;\n" " use starknet::ContractAddress;\n" "\n" -" struct Storage{\n" -" names: LegacyMap::,\n" +" struct Storage {\n" +" names: LegacyMap::, \n" " }\n" "\n" " #[event]\n" -" fn StoredName(caller: ContractAddress, name:felt252){}\n" +" fn StoredName(caller: ContractAddress, name: felt252) {}\n" "\n" " #[constructor]\n" -" fn constructor(_name: felt252, _address: ContractAddress){\n" +" fn constructor(_name: felt252, _address: ContractAddress) {\n" " names::write(_address, _name);\n" " }\n" "\n" " #[external]\n" -" fn store_name(_name: felt252){\n" +" fn store_name(_name: felt252) {\n" " let caller = get_caller_address();\n" " names::write(caller, _name);\n" -" StoredName(caller,_name);\n" +" StoredName(caller, _name);\n" " }\n" "\n" " #[view]\n" -" fn get_name(_address:ContractAddress) -> felt252{\n" +" fn get_name(_address: ContractAddress) -> felt252 {\n" " let name = names::read(_address);\n" " return name;\n" " }\n" @@ -13070,11 +13792,11 @@ msgstr "" "```" #: src/ch99-01-02-writing-starknet-contracts.md:49 -msgid "Listing 9-1: A simple naming service contract" +msgid "Listing 99-1: A simple naming service contract" msgstr "Listado 9-1: Un contrato simple de servicio de nombres" #: src/ch99-01-02-writing-starknet-contracts.md:51 -msgid "> NB: Starknet contracts are defined within [modules](./ch06-02-defining-modules-to-control-scope.md)." +msgid "> Note: Starknet contracts are defined within [modules](./ch06-02-defining-modules-to-control-scope.md)." msgstr "> NB: Los contratos Starknet se definen dentro de [modules](./ch06-02-defining-modules-to-control-scope.md)." #: src/ch99-01-02-writing-starknet-contracts.md:53 @@ -13090,7 +13812,7 @@ msgid "" msgstr "" #: src/ch99-01-02-writing-starknet-contracts.md:59 -msgid "Here are a list of common attributes used in Starknet contracts:" +msgid "Here is a list of common attributes used in Starknet contracts:" msgstr "He aquí una lista de atributos comunes utilizados en los contratos Starknet:" #: src/ch99-01-02-writing-starknet-contracts.md:61 @@ -13147,24 +13869,30 @@ msgstr "Las variables de almacenamiento en los contratos Starknet se almacenan e #: src/ch99-01-02-writing-starknet-contracts.md:81 msgid "" "```rust\n" -"struct Storage{\n" -" id: u8,\n" -" names: LegacyMap::,\n" -"}\n" +"# #[contract]\n" +"# mod contract {\n" +" struct Storage {\n" +" id: u8,\n" +" names: LegacyMap::,\n" +" }\n" +"# }\n" "```" msgstr "" "```rust\n" -"struct Storage{\n" -" id: u8,\n" -" names: LegacyMap::,\n" -"}\n" +"# #[contract]\n" +"# mod contract {\n" +" struct Storage {\n" +" id: u8,\n" +" names: LegacyMap::,\n" +" }\n" +"# }\n" "```" -#: src/ch99-01-02-writing-starknet-contracts.md:88 -msgid "Listing 9-2: A Storage Struct" +#: src/ch99-01-02-writing-starknet-contracts.md:91 +msgid "Listing 99-2: A Storage Struct" msgstr "Listado 9-2: Una Estructura de Almacenamiento" -#: src/ch99-01-02-writing-starknet-contracts.md:90 +#: src/ch99-01-02-writing-starknet-contracts.md:93 msgid "" "The storage struct is a [struct](./ch04-00-using-structs-to-structure-related-data.md) like any other,\n" "except that it allows you to define mappings using the `LegacyMap` type." @@ -13172,11 +13900,11 @@ msgstr "" "La estructura de almacenamiento es una [struct](./ch04-00-using-structs-to-structure-related-data.md) como cualquier otra,\n" "excepto que permite definir mapeos utilizando el tipo `LegacyMap`." -#: src/ch99-01-02-writing-starknet-contracts.md:93 +#: src/ch99-01-02-writing-starknet-contracts.md:96 msgid "### Storage Mappings" msgstr "### Storage Mappings" -#: src/ch99-01-02-writing-starknet-contracts.md:95 +#: src/ch99-01-02-writing-starknet-contracts.md:98 msgid "" "Mappings are a key-value data structure that you can use to store data within a smart contract. They are essentially hash tables that allow you to associate a unique key with a " "corresponding value. Mappings are also useful to store sets of data, as it's impossible to store arrays in storage." @@ -13184,40 +13912,40 @@ msgstr "" "Los mapeos son una estructura de datos clave-valor que puedes utilizar para almacenar datos dentro de un contrato inteligente. Son esencialmente tablas hash que te permiten asociar " "una clave única con un valor correspondiente. Los mapeos también son útiles para almacenar conjuntos de datos, ya que es imposible almacenar matrices en el almacenamiento." -#: src/ch99-01-02-writing-starknet-contracts.md:97 +#: src/ch99-01-02-writing-starknet-contracts.md:100 msgid "" "A mapping is a variable of type LegacyMap, in which the key and value types are specified within angular brackets <>.\n" "It is important to note that the `LegacyMap` type can only be used inside the `Storage` struct, and can't be used to define mappings in user-defined structs.\n" -"The syntax for declaring a mapping is as follows in Listing 9-2." +"The syntax for declaring a mapping is as follows in Listing 99-2." msgstr "" "Un mapeo es una variable de tipo LegacyMap, en la que los tipos de clave y valor se especifican entre corchetes angulares <>.\n" "Es importante tener en cuenta que el tipo `LegacyMap` sólo se puede utilizar dentro de la estructura `Storage`, y no se puede utilizar para definir mapeos en estructuras definidas " "por el usuario.\n" "La sintaxis para declarar un mapeo es la siguiente en el Listado 9-2." -#: src/ch99-01-02-writing-starknet-contracts.md:101 +#: src/ch99-01-02-writing-starknet-contracts.md:104 msgid "" -"You can also create more complex mappings than that found in Listing 9-2 like the popular `allowances` storage variable in the ERC20 Standard which maps the `owner` and `spender` to " +"You can also create more complex mappings than that found in Listing 99-2 like the popular `allowances` storage variable in the ERC20 Standard which maps the `owner` and `spender` to " "the `allowance` using tuples:" msgstr "" -"También se pueden crear asignaciones más complejas que la del Listado 9-2, como la popular variable de almacenamiento `allowances` de la Norma ERC20, que asigna el `propietario` y el " -"`gastador` a la `asignación` utilizando tuplas:" +"También se pueden crear asignaciones más complejas que la del Listado 9-2, como la popular variable de almacenamiento `allowances` de la Norma ERC20, que asigna el `owner` y el " +"`spender` a la `allowance` utilizando tuplas:" -#: src/ch99-01-02-writing-starknet-contracts.md:103 +#: src/ch99-01-02-writing-starknet-contracts.md:106 msgid "" "```rust\n" -"struct Storage{\n" -" allowances: LegacyMap::<(ContractAddress, ContractAddress), u256>\n" -"}\n" +" struct Storage {\n" +" allowances: LegacyMap::<(ContractAddress, ContractAddress), u256>\n" +" }\n" "```" msgstr "" "```rust\n" -"struct Storage{\n" -" allowances: LegacyMap::<(ContractAddress, ContractAddress), u256>\n" -"}\n" +" struct Storage {\n" +" allowances: LegacyMap::<(ContractAddress, ContractAddress), u256>\n" +" }\n" "```" -#: src/ch99-01-02-writing-starknet-contracts.md:109 +#: src/ch99-01-02-writing-starknet-contracts.md:112 msgid "" "In mappings, the address of the value at key `k_1,...,k_n` is `h(...h(h(sn_keccak(variable_name),k_1),k_2),...,k_n)` where ℎ\n" "is the Pedersen hash and the final value is taken `mod2251−256`. You can learn more about the contract storage layout in the [Starknet Documentation](https://docs.starknet.io/" @@ -13227,90 +13955,90 @@ msgstr "" "es el hash de Pedersen y el valor final se toma `mod2251-256`. Puedes obtener más información sobre el esquema de almacenamiento de contratos en la [Documentación de Starknet]" "(https://docs.starknet.io/documentation/architecture_and_concepts/Contracts/contract-storage/#storage_variables)" -#: src/ch99-01-02-writing-starknet-contracts.md:112 +#: src/ch99-01-02-writing-starknet-contracts.md:115 msgid "### Reading from Storage" msgstr "### Lectura desde Storage" -#: src/ch99-01-02-writing-starknet-contracts.md:114 +#: src/ch99-01-02-writing-starknet-contracts.md:117 msgid "To read the value of the storage variable `names`, we call the `read` function on the `names` storage variable, passing in the key `_address` as a parameter." msgstr "" "Para leer el valor de la variable de almacenamiento `names`, llamamos a la función `read` sobre la variable de almacenamiento `names`, pasando la clave `_address` como parámetro." -#: src/ch99-01-02-writing-starknet-contracts.md:116 +#: src/ch99-01-02-writing-starknet-contracts.md:119 msgid "" "```rust\n" -"let name = names::read(_address);\n" +" let name = names::read(_address);\n" "```" msgstr "" "```rust\n" -"let name = names::read(_address);\n" +" let name = names::read(_address);\n" "```" -#: src/ch99-01-02-writing-starknet-contracts.md:120 -msgid "Listing 9-3: Calling the `read` function on the `names` variable" +#: src/ch99-01-02-writing-starknet-contracts.md:123 +msgid "Listing 99-3: Calling the `read` function on the `names` variable" msgstr "Listado 9-3: Llamada a la función `read` sobre la variable `names`" -#: src/ch99-01-02-writing-starknet-contracts.md:122 +#: src/ch99-01-02-writing-starknet-contracts.md:125 msgid "> Note: When the storage variable does not store a mapping, its value is accessed without passing any parameters to the read method" msgstr "> Nota: Cuando la variable de almacenamiento no almacena una asignación, se accede a su valor sin pasar ningún parámetro al método de lectura" -#: src/ch99-01-02-writing-starknet-contracts.md:124 +#: src/ch99-01-02-writing-starknet-contracts.md:127 msgid "### Writing to Storage" msgstr "### Escritura en Storage" -#: src/ch99-01-02-writing-starknet-contracts.md:126 +#: src/ch99-01-02-writing-starknet-contracts.md:129 msgid "To write a value to the storage variable `names`, we call the `write` function on the `names` storage variable, passing in the key and values as arguments." msgstr "" "Para escribir un valor en la variable de almacenamiento `names`, llamamos a la función `write` en la variable de almacenamiento `names`, pasando la clave y los valores como " "argumentos." -#: src/ch99-01-02-writing-starknet-contracts.md:128 +#: src/ch99-01-02-writing-starknet-contracts.md:131 msgid "" "```rust\n" -"names::write(_address, _name);\n" +" names::write(caller, _name);\n" "```" msgstr "" "```rust\n" -"names::write(_address, _name);\n" +" names::write(caller, _name);\n" "```" -#: src/ch99-01-02-writing-starknet-contracts.md:132 -msgid "Listing 9-4: Writing to the `names` variable" +#: src/ch99-01-02-writing-starknet-contracts.md:135 +msgid "Listing 99-4: Writing to the `names` variable" msgstr "Listado 9-4: Escribir en la variable `names`" -#: src/ch99-01-02-writing-starknet-contracts.md:136 +#: src/ch99-01-02-writing-starknet-contracts.md:139 msgid "In this section, we are going to be looking at some popular function types you'd encounter with most contracts:" msgstr "En esta sección, vamos a ver algunos tipos de funciones populares que se encuentran en la mayoría de los contratos:" -#: src/ch99-01-02-writing-starknet-contracts.md:138 +#: src/ch99-01-02-writing-starknet-contracts.md:141 msgid "### 1. Constructors" msgstr "### 1. Constructores" -#: src/ch99-01-02-writing-starknet-contracts.md:140 +#: src/ch99-01-02-writing-starknet-contracts.md:143 msgid "Constructors are a special type of function that runs only once when deploying a contract, and can be used to initialize the state of the contract." msgstr "Los constructores son un tipo especial de función que sólo se ejecuta una vez al desplegar un contrato, y pueden utilizarse para inicializar el estado del contrato." -#: src/ch99-01-02-writing-starknet-contracts.md:142 +#: src/ch99-01-02-writing-starknet-contracts.md:145 msgid "" "```rust\n" -"#[constructor]\n" -"fn constructor(_name: felt252, _address: ContractAddress){\n" -" names::write(_address, _name);\n" -"}\n" +" #[constructor]\n" +" fn constructor(_name: felt252, _address: ContractAddress) {\n" +" names::write(_address, _name);\n" +" }\n" "```" msgstr "" "```rust\n" -"#[constructor]\n" -"fn constructor(_name: felt252, _address: ContractAddress){\n" -" names::write(_address, _name);\n" -"}\n" +" #[constructor]\n" +" fn constructor(_name: felt252, _address: ContractAddress) {\n" +" names::write(_address, _name);\n" +" }\n" "```" -#: src/ch99-01-02-writing-starknet-contracts.md:149 +#: src/ch99-01-02-writing-starknet-contracts.md:152 msgid "Some important rules to note:" msgstr "Algunas reglas importantes a tener en cuenta:" -#: src/ch99-01-02-writing-starknet-contracts.md:151 +#: src/ch99-01-02-writing-starknet-contracts.md:154 msgid "" "1. Your contract can't have more than one constructor.\n" "2. Your constructor function must be named `constructor`.\n" @@ -13320,11 +14048,11 @@ msgstr "" "2. Tu función constructora debe llamarse `constructor`.\n" "3. Por último, debe estar anotada con el atributo `#[constructor]`." -#: src/ch99-01-02-writing-starknet-contracts.md:155 +#: src/ch99-01-02-writing-starknet-contracts.md:158 msgid "### 2. External functions" msgstr "### 2. Funciones Externas" -#: src/ch99-01-02-writing-starknet-contracts.md:157 +#: src/ch99-01-02-writing-starknet-contracts.md:160 msgid "" "External functions are functions that can modify the state of a contract. They are public and can be called by any other contract or externally.\n" "You can define external functions by annotating them with the `#[external]` attribute:" @@ -13332,31 +14060,31 @@ msgstr "" "Las funciones externas son funciones que pueden modificar el estado de un contrato. Son públicas y pueden ser llamadas por cualquier otro contrato o externamente.\n" "Puedes definir funciones externas anotándolas con el atributo `#[external]`:" -#: src/ch99-01-02-writing-starknet-contracts.md:160 +#: src/ch99-01-02-writing-starknet-contracts.md:163 msgid "" "```rust\n" -"#[external]\n" -"fn store_name(_name: felt252){\n" -" let caller = get_caller_address();\n" -" names::write(caller, _name);\n" -" StoredName(caller,_name);\n" -"}\n" +" #[external]\n" +" fn store_name(_name: felt252) {\n" +" let caller = get_caller_address();\n" +" names::write(caller, _name);\n" +" StoredName(caller, _name);\n" +" }\n" "```" msgstr "" "```rust\n" -"#[external]\n" -"fn store_name(_name: felt252){\n" -" let caller = get_caller_address();\n" -" names::write(caller, _name);\n" -" StoredName(caller,_name);\n" -"}\n" +" #[external]\n" +" fn store_name(_name: felt252) {\n" +" let caller = get_caller_address();\n" +" names::write(caller, _name);\n" +" StoredName(caller, _name);\n" +" }\n" "```" -#: src/ch99-01-02-writing-starknet-contracts.md:169 +#: src/ch99-01-02-writing-starknet-contracts.md:172 msgid "### 3. View functions" msgstr "### 3. Ver funciones" -#: src/ch99-01-02-writing-starknet-contracts.md:171 +#: src/ch99-01-02-writing-starknet-contracts.md:174 msgid "" "View functions are read-only functions allowing you to access data from the contract while ensuring that the state of the contract is not modified. They can be called by other " "contracts or externally.\n" @@ -13366,46 +14094,47 @@ msgstr "" "llamadas por otros contratos o externamente.\n" "Puedes definir funciones de vista anotándolas con el atributo `#[view]`:" -#: src/ch99-01-02-writing-starknet-contracts.md:174 +#: src/ch99-01-02-writing-starknet-contracts.md:177 msgid "" "```rust\n" -"#[view]\n" -"fn get_name(_address:ContractAddress) -> felt252{\n" -" let name = names::read(_address);\n" -" return name;\n" -"}\n" +" #[view]\n" +" fn get_name(_address: ContractAddress) -> felt252 {\n" +" let name = names::read(_address);\n" +" return name;\n" +" }\n" "```" msgstr "" "```rust\n" -"#[view]\n" -"fn get_name(_address:ContractAddress) -> felt252{\n" -" let name = names::read(_address);\n" -" return name;\n" -"}\n" +" #[external]\n" +" fn store_name(_name: felt252) {\n" +" let caller = get_caller_address();\n" +" names::write(caller, _name);\n" +" StoredName(caller, _name);\n" +" }\n" "```" -#: src/ch99-01-02-writing-starknet-contracts.md:182 +#: src/ch99-01-02-writing-starknet-contracts.md:185 msgid "" -"> **NB:** It's important to note that, both external and view functions are public. To create an internal function in a contract, you simply don't annotate it with any attribute." +"> **Note:** It's important to note that, both external and view functions are public. To create an internal function in a contract, you simply don't annotate it with any attribute." msgstr "" -"> **NB:** Es importante tener en cuenta que, tanto las funciones externas como las de vista son públicas. Para crear una función interna en un contrato, simplemente no la anotes con " -"ningún atributo." +"> **Nota:** Es importante tener en cuenta que, tanto las funciones externas como las de vista son públicas. Para crear una función interna en un contrato, simplemente no la anotes " +"con ningún atributo." -#: src/ch99-01-02-writing-starknet-contracts.md:184 +#: src/ch99-01-02-writing-starknet-contracts.md:187 msgid "## Events" msgstr "## Eventos" -#: src/ch99-01-02-writing-starknet-contracts.md:186 +#: src/ch99-01-02-writing-starknet-contracts.md:189 msgid "" "Events are custom data structures that are emitted by smart contracts during execution.\n" "They provide a way for smart contracts to communicate with the external world by logging information\n" -"about specific occurences in a contract." +"about specific occurrences in a contract." msgstr "" "Los eventos son estructuras de datos personalizadas que emiten los contratos inteligentes durante su ejecución.\n" "Proporcionan una manera para que los contratos inteligentes se comuniquen con el mundo externo mediante el registro de información\n" "sobre sucesos específicos en un contrato." -#: src/ch99-01-02-writing-starknet-contracts.md:190 +#: src/ch99-01-02-writing-starknet-contracts.md:193 msgid "" "Events play a crucial role in the creation of smart contracts. Take, for instance, the Non-Fungible Tokens (NFTs) minted on Starknet. All of these are indexed and stored in a " "database, then displayed to users through the use of these events. Neglecting to include an event within your NFT contract could lead to a bad user experience. This is because users " @@ -13416,11 +14145,11 @@ msgstr "" "conducir a una mala experiencia de usuario. Esto se debe a que los usuarios pueden no ver sus NFTs aparecer en sus carteras (las carteras utilizan estos indexadores para mostrar los " "NFTs de un usuario)." -#: src/ch99-01-02-writing-starknet-contracts.md:192 +#: src/ch99-01-02-writing-starknet-contracts.md:195 msgid "### Defining events" msgstr "### Definición de eventos" -#: src/ch99-01-02-writing-starknet-contracts.md:194 +#: src/ch99-01-02-writing-starknet-contracts.md:197 msgid "" "An event is defined as an empty function annotated with the `#[event]` attribute. The parameters of this function\n" "are the data that will be emitted by the event." @@ -13428,23 +14157,23 @@ msgstr "" "Un evento se define como una función vacía anotada con el atributo `#[evento]`. Los parámetros de esta función\n" "son los datos que serán emitidos por el evento." -#: src/ch99-01-02-writing-starknet-contracts.md:197 -msgid "In Listing 9-1, `StoredName` is an event that emits information when names are stored in the contract:" +#: src/ch99-01-02-writing-starknet-contracts.md:200 +msgid "In Listing 99-1, `StoredName` is an event that emits information when names are stored in the contract:" msgstr "En el Listado 9-1, `StoredName` es un evento que emite información cuando se almacenan nombres en el contrato:" -#: src/ch99-01-02-writing-starknet-contracts.md:199 +#: src/ch99-01-02-writing-starknet-contracts.md:202 msgid "" "```rust\n" -"#[event]\n" -"fn StoredName(caller: ContractAddress, name:felt252){}\n" +" #[event]\n" +" fn StoredName(caller: ContractAddress, name: felt252) {}\n" "```" msgstr "" "```rust\n" -"#[event]\n" -"fn StoredName(caller: ContractAddress, name:felt252){}\n" +" #[event]\n" +" fn StoredName(caller: ContractAddress, name: felt252) {}\n" "```" -#: src/ch99-01-02-writing-starknet-contracts.md:204 +#: src/ch99-01-02-writing-starknet-contracts.md:207 msgid "" "We pass in the emitted data types as parameters within the parentheses. In this example, our event will emit the contract address of the caller and the name stored within the " "contract." @@ -13452,11 +14181,11 @@ msgstr "" "Pasamos los tipos de datos emitidos como parámetros dentro de los paréntesis. En este ejemplo, nuestro evento emitirá la dirección del contrato de la persona que llama y el nombre " "almacenado en el contrato." -#: src/ch99-01-02-writing-starknet-contracts.md:206 +#: src/ch99-01-02-writing-starknet-contracts.md:209 msgid "### Emitting events" msgstr "### Emisión de eventos" -#: src/ch99-01-02-writing-starknet-contracts.md:208 +#: src/ch99-01-02-writing-starknet-contracts.md:211 msgid "" "After defining events, we can emit them by simply calling the event name like we'll call functions,\n" "passing in the values to be emitted as parameters:" @@ -13464,14 +14193,14 @@ msgstr "" "Después de definir los eventos, podemos emitirlos simplemente llamando al nombre del evento como llamaremos a las funciones,\n" "pasando los valores a emitir como parámetros:" -#: src/ch99-01-02-writing-starknet-contracts.md:211 +#: src/ch99-01-02-writing-starknet-contracts.md:214 msgid "" "```rust\n" -"StoredName(caller,_name);\n" +" StoredName(caller, _name);\n" "```" msgstr "" "```rust\n" -"StoredName(caller,_name);\n" +" StoredName(caller, _name);\n" "```" #: src/ch99-02-00-abis-and-cross-contract-interactions.md:1 @@ -13613,8 +14342,8 @@ msgstr "" "```" #: src/ch99-02-01-abis-and-interfaces.md:57 -msgid "Listing 9-1: A simple ERC20 Interface" -msgstr "Listado 9-1: Una interfaz simple de ERC20" +msgid "Listing 99-4: A simple ERC20 Interface" +msgstr "Listado 9-4: Una interfaz simple de ERC20" #: src/ch99-02-01-abis-and-interfaces.md:59 msgid "## ABIs" @@ -13666,8 +14395,8 @@ msgid "In this chapter, we are going to extensively discuss how these dispatcher msgstr "En este capítulo, discutiremos en detalle cómo funcionan estos despachadores y su uso." #: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:10 -msgid "To effectively break down the concepts in this chapter, we are going to be using the IERC20 interface from the previous chapter (refer to Listing 9-1):" -msgstr "Para desglosar efectivamente los conceptos en este capítulo, utilizaremos la interfaz IERC20 del capítulo anterior (consulte la Lista 9-1):" +msgid "To effectively break down the concepts in this chapter, we are going to be using the IERC20 interface from the previous chapter (refer to Listing 99-4):" +msgstr "Para desglosar efectivamente los conceptos en este capítulo, utilizaremos la interfaz IERC20 del capítulo anterior (consulte la Lista 9-4):" #: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:12 msgid "## Contract Dispatcher" @@ -13684,69 +14413,79 @@ msgstr "" #: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:16 msgid "" +"**Note:** The expanded code for our IERC20 interface is a lot longer, but to keep this chapter concise and straight to the point, we focused on one view function `get_name`, and one " +"external function `transfer`." +msgstr "" +"**Nota:** El código expandido para nuestra interfaz IERC20 es mucho más robusto, pero para mantener este capítulo conciso y al grano, nos enfocamos en una función de vista `get_name` " +"y una función externa `transfer`." + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:18 +msgid "" "```rust\n" +"//does_not_compile\n" +"use starknet::{ContractAddress};\n" +"\n" "trait IERC20DispatcherTrait {\n" -" fn get_name(self: T) -> felt252;\n" +" fn name(self: T) -> felt252;\n" " fn transfer(self: T, recipient: ContractAddress, amount: u256);\n" "}\n" "\n" -"#[derive(Copy, Drop)]\n" +"#[derive(Copy, Drop, storage_access::StorageAccess, Serde)]\n" "struct IERC20Dispatcher {\n" -" contract_address: starknet::ContractAddress,\n" +" contract_address: starknet::ContractAddress, \n" "}\n" "\n" -"impl IERC20DispatcherImpl of IERC20DispatcherTrait:: {\n" -" fn get_name(self: IERC20Dispatcher) -> felt252 {\n" -" // starknet::call_contract_syscall is called in here\n" +"impl IERC20DispatcherImpl of IERC20DispatcherTrait {\n" +" fn name(\n" +" self: IERC20Dispatcher\n" +" ) -> felt252 { // starknet::call_contract_syscall is called in here\n" " }\n" -" fn transfer(self: IERC20Dispatcher, recipient: ContractAddress, amount: u256) {\n" -" // starknet::call_contract_syscall is called in here\n" +" fn transfer(\n" +" self: IERC20Dispatcher, recipient: ContractAddress, amount: u256\n" +" ) { // starknet::call_contract_syscall is called in here\n" " }\n" "}\n" "```" msgstr "" "```rust\n" +"//does_not_compile\n" +"use starknet::{ContractAddress};\n" +"\n" "trait IERC20DispatcherTrait {\n" -" fn get_name(self: T) -> felt252;\n" +" fn name(self: T) -> felt252;\n" " fn transfer(self: T, recipient: ContractAddress, amount: u256);\n" "}\n" "\n" -"#[derive(Copy, Drop)]\n" +"#[derive(Copy, Drop, storage_access::StorageAccess, Serde)]\n" "struct IERC20Dispatcher {\n" -" contract_address: starknet::ContractAddress,\n" +" contract_address: starknet::ContractAddress, \n" "}\n" "\n" -"impl IERC20DispatcherImpl of IERC20DispatcherTrait:: {\n" -" fn get_name(self: IERC20Dispatcher) -> felt252 {\n" -" // starknet::call_contract_syscall is called in here\n" +"impl IERC20DispatcherImpl of IERC20DispatcherTrait {\n" +" fn name(\n" +" self: IERC20Dispatcher\n" +" ) -> felt252 { // starknet::call_contract_syscall is called in here\n" " }\n" -" fn transfer(self: IERC20Dispatcher, recipient: ContractAddress, amount: u256) {\n" -" // starknet::call_contract_syscall is called in here\n" +" fn transfer(\n" +" self: IERC20Dispatcher, recipient: ContractAddress, amount: u256\n" +" ) { // starknet::call_contract_syscall is called in here\n" " }\n" "}\n" "```" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:37 -msgid "Listing 9-2: An expanded form of the IERC20 trait" -msgstr "Listado 9-2: Una forma expandida de la interfaz IERC20" - -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:39 -msgid "" -"**NB:** The expanded code for our IERC20 interface is a lot more robust, but to keep this chapter concise and straight to the point, we focused on one view function `get_name`, and " -"one external function `transfer`." -msgstr "" -"**Nota:** El código expandido para nuestra interfaz IERC20 es mucho más robusto, pero para mantener este capítulo conciso y al grano, nos enfocamos en una función de vista `get_name` " -"y una función externa `transfer`." +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:44 +msgid "Listing 99-5: An expanded form of the IERC20 trait" +msgstr "Listado 9-5: Una forma expandida del trait IERC20" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:41 -msgid "It's also worthy of note that all these is abstracted behind the scenes thanks to the power of Cairo plugins." +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:46 +msgid "It's also worthy of note that all these are abstracted behind the scenes thanks to the power of Cairo plugins." msgstr "También es digno de mención que todo esto se abstrae detrás de escena, gracias al poder de los complementos de Cairo." -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:43 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:48 msgid "### Calling Contracts using the Contract Dispatcher" msgstr "### Llamando contratos usando el Dispatcher de Contrato" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:45 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:50 msgid "" "This is an example of a contract named `Dispatcher` using the Contract interface dispatcher to call an ERC-20 contract in the ERC-20 contract's context and, in the case of " "`transfer_token`, altering the state of the ERC-20 contract:" @@ -13754,63 +14493,123 @@ msgstr "" "Este es un ejemplo de un contrato llamado `Dispatcher` que utiliza la interfaz Contract dispatcher para llamar a un contrato ERC-20 en el contexto del contrato ERC-20 y, en el caso " "de `transfer_token`, alterar el estado del contrato ERC-20:" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:47 -msgid "" -"```rust\n" +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:52 +msgid "" +"```rust\n" +"# use starknet::ContractAddress;\n" +"# \n" +"# #[abi]\n" +"# trait IERC20 {\n" +"# #[view]\n" +"# fn name() -> felt252;\n" +"# \n" +"# #[view]\n" +"# fn symbol() -> felt252;\n" +"# \n" +"# #[view]\n" +"# fn decimals() -> u8;\n" +"# \n" +"# #[view]\n" +"# fn total_supply() -> u256;\n" +"# \n" +"# #[view]\n" +"# fn balance_of(account: ContractAddress) -> u256;\n" +"# \n" +"# #[view]\n" +"# fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256;\n" +"# \n" +"# #[external]\n" +"# fn transfer(recipient: ContractAddress, amount: u256) -> bool;\n" +"# \n" +"# #[external]\n" +"# fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool;\n" +"# \n" +"# #[external]\n" +"# fn approve(spender: ContractAddress, amount: u256) -> bool;\n" +"# }\n" +"# \n" "//**** Specify interface here ****//\n" -"\n" "#[contract]\n" -"mod Dispatcher {\n" +"mod dispatcher {\n" " use super::IERC20DispatcherTrait;\n" " use super::IERC20Dispatcher;\n" " use starknet::ContractAddress;\n" "\n" " #[view]\n" -" fn token_name(\n" -" _contract_address: ContractAddress\n" -" ) -> felt252 {\n" -" IERC20Dispatcher {contract_address: _contract_address }.name()\n" +" fn token_name(_contract_address: ContractAddress) -> felt252 {\n" +" IERC20Dispatcher { contract_address: _contract_address }.name()\n" " }\n" "\n" " #[external]\n" " fn transfer_token(\n" " _contract_address: ContractAddress, recipient: ContractAddress, amount: u256\n" " ) -> bool {\n" -" IERC20Dispatcher {contract_address: _contract_address }.transfer(recipient, amount)\n" +" IERC20Dispatcher { contract_address: _contract_address }.transfer(recipient, amount)\n" " }\n" "}\n" -"```" -msgstr "" -"```rust\n" +"# \n" +"```" +msgstr "" +"```rust\n" +"# use starknet::ContractAddress;\n" +"# \n" +"# #[abi]\n" +"# trait IERC20 {\n" +"# #[view]\n" +"# fn name() -> felt252;\n" +"# \n" +"# #[view]\n" +"# fn symbol() -> felt252;\n" +"# \n" +"# #[view]\n" +"# fn decimals() -> u8;\n" +"# \n" +"# #[view]\n" +"# fn total_supply() -> u256;\n" +"# \n" +"# #[view]\n" +"# fn balance_of(account: ContractAddress) -> u256;\n" +"# \n" +"# #[view]\n" +"# fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256;\n" +"# \n" +"# #[external]\n" +"# fn transfer(recipient: ContractAddress, amount: u256) -> bool;\n" +"# \n" +"# #[external]\n" +"# fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool;\n" +"# \n" +"# #[external]\n" +"# fn approve(spender: ContractAddress, amount: u256) -> bool;\n" +"# }\n" +"# \n" "//**** Specify interface here ****//\n" -"\n" "#[contract]\n" -"mod Dispatcher {\n" +"mod dispatcher {\n" " use super::IERC20DispatcherTrait;\n" " use super::IERC20Dispatcher;\n" " use starknet::ContractAddress;\n" "\n" " #[view]\n" -" fn token_name(\n" -" _contract_address: ContractAddress\n" -" ) -> felt252 {\n" -" IERC20Dispatcher {contract_address: _contract_address }.name()\n" +" fn token_name(_contract_address: ContractAddress) -> felt252 {\n" +" IERC20Dispatcher { contract_address: _contract_address }.name()\n" " }\n" "\n" " #[external]\n" " fn transfer_token(\n" " _contract_address: ContractAddress, recipient: ContractAddress, amount: u256\n" " ) -> bool {\n" -" IERC20Dispatcher {contract_address: _contract_address }.transfer(recipient, amount)\n" +" IERC20Dispatcher { contract_address: _contract_address }.transfer(recipient, amount)\n" " }\n" "}\n" +"# \n" "```" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:72 -msgid "Listing 9-3: A sample contract which uses the Contract Dispatcher" -msgstr "Listado 9-3: Un ejemplo de contrato que utiliza el Contract Dispatcher" +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:107 +msgid "Listing 99-6: A sample contract which uses the Contract Dispatcher" +msgstr "Listado 9-6: Un ejemplo de contrato que utiliza el Contract Dispatcher" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:74 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:109 msgid "" "As you can see, we had to first import the `IERC20DispatcherTrait` and `IERC20Dispatcher` which was generated and exported on compiling our interface, then we make calls to the " "methods implemented for the `IERC20Dispatcher` struct (`name`, `transfer`, etc), passing in the `contract_address` parameter which represents the address of the contract we want to " @@ -13820,11 +14619,11 @@ msgstr "" "realizamos llamadas a los métodos implementados para la estructura `IERC20Dispatcher` (`name`, `transfer`, etc.), pasando el parámetro `contract_address` que representa la dirección " "del contrato que queremos llamar." -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:76 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:111 msgid "## Library Dispatcher" msgstr "## Dispatcher de Biblioteca" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:78 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:113 msgid "" "The key difference between the contract dispatcher and the library dispatcher is that while the contract dispatcher calls an external contract's logic in the external contract's " "context, the library dispatcher calls the target contract's classhash, whilst executing the call in the calling contract's context.\n" @@ -13835,7 +14634,7 @@ msgstr "" "Por lo tanto, a diferencia del despachador de contratos, las llamadas realizadas mediante el despachador de bibliotecas no tienen la posibilidad de alterar el estado del contrato de " "destino." -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:81 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:116 msgid "" "As stated in the previous chapter, contracts annotated with the `#[abi]` macro on compilation generates a new trait, two new structs (one for contract calls, and the other for " "library calls) and their implementation of this trait. The expanded form of the library traits looks like:" @@ -13843,109 +14642,121 @@ msgstr "" "Como se indicó en el capítulo anterior, los contratos anotados con la macro `#[abi]` en la compilación generan un nuevo trait, dos nuevas estructuras (una para llamadas a contratos y " "otra para llamadas a bibliotecas) y su implementación de este trait. La forma expandida de los traits de biblioteca se ve así:" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:83 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:118 msgid "" "```rust\n" +"//does_not_compile\n" +"use starknet::ContractAddress;\n" +"\n" "trait IERC20DispatcherTrait {\n" -" fn get_name(self: T) -> felt252;\n" +" fn name(self: T) -> felt252;\n" " fn transfer(self: T, recipient: ContractAddress, amount: u256);\n" "}\n" "\n" -"#[derive(Copy, Drop)]\n" +"#[derive(Copy, Drop, storage_access::StorageAccess, Serde)]\n" "struct IERC20LibraryDispatcher {\n" -" class_hash: starknet::ClassHash,\n" +" class_hash: starknet::ClassHash, \n" "}\n" "\n" -"impl IERC20LibraryDispatcherImpl of IERC20DispatcherTrait:: {\n" -" fn get_name(self: IERC20LibraryDispatcher) -> felt252 {\n" -" // starknet::syscalls::library_call_syscall is called in here\n" +"impl IERC20LibraryDispatcherImpl of IERC20DispatcherTrait {\n" +" fn name(\n" +" self: IERC20LibraryDispatcher\n" +" ) -> felt252 { // starknet::syscalls::library_call_syscall is called in here\n" " }\n" -" fn transfer(self: IERC20LibraryDispatcher, recipient: ContractAddress, amount: u256) {\n" -" // starknet::syscalls::library_call_syscall is called in here\n" +" fn transfer(\n" +" self: IERC20LibraryDispatcher, recipient: ContractAddress, amount: u256\n" +" ) { // starknet::syscalls::library_call_syscall is called in here\n" " }\n" "}\n" "```" msgstr "" "```rust\n" +"//does_not_compile\n" +"use starknet::ContractAddress;\n" +"\n" "trait IERC20DispatcherTrait {\n" -" fn get_name(self: T) -> felt252;\n" +" fn name(self: T) -> felt252;\n" " fn transfer(self: T, recipient: ContractAddress, amount: u256);\n" "}\n" "\n" -"#[derive(Copy, Drop)]\n" +"#[derive(Copy, Drop, storage_access::StorageAccess, Serde)]\n" "struct IERC20LibraryDispatcher {\n" -" class_hash: starknet::ClassHash,\n" +" class_hash: starknet::ClassHash, \n" "}\n" "\n" -"impl IERC20LibraryDispatcherImpl of IERC20DispatcherTrait:: {\n" -" fn get_name(self: IERC20LibraryDispatcher) -> felt252 {\n" -" // starknet::syscalls::library_call_syscall is called in here\n" +"impl IERC20LibraryDispatcherImpl of IERC20DispatcherTrait {\n" +" fn name(\n" +" self: IERC20LibraryDispatcher\n" +" ) -> felt252 { // starknet::syscalls::library_call_syscall is called in here\n" " }\n" -" fn transfer(self: IERC20LibraryDispatcher, recipient: ContractAddress, amount: u256) {\n" -" // starknet::syscalls::library_call_syscall is called in here\n" +" fn transfer(\n" +" self: IERC20LibraryDispatcher, recipient: ContractAddress, amount: u256\n" +" ) { // starknet::syscalls::library_call_syscall is called in here\n" " }\n" "}\n" "```" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:104 -msgid "Listing 9-4: An expanded form of the IERC20 trait" -msgstr "Listado 9-4: Una forma expandida del trait IERC20" +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:144 +msgid "Listing 99-7: An expanded form of the IERC20 trait" +msgstr "Listado 9-7: Una forma expandida de trait IERC20" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:106 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:146 msgid "### Calling Contracts using the Library Dispatcher" msgstr "### Llamando a Contratos usando el Dispatcher de Biblioteca" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:108 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:148 msgid "Below's a sample code on calling contracts using the Library Dispatcher:" msgstr "A continuación se muestra un código de muestra sobre cómo llamar a contratos utilizando el Dispatcher de Biblioteca:" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:110 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:150 msgid "" "```rust\n" -"//**** Specify interface here ****//\n" -"\n" -"use super::IERC20DispatcherTrait;\n" -"use super::IERC20LibraryDispatcher;\n" -"use starknet::ContractAddress;\n" +"#[contract]\n" +"mod contract {\n" +" use super::IERC20DispatcherTrait;\n" +" use super::IERC20LibraryDispatcher;\n" +" use starknet::ContractAddress;\n" "\n" -"#[view]\n" -"fn token_name() -> felt252 {\n" -" IERC20LibraryDispatcher { class_hash: starknet::class_hash_const::<0x1234>() }.name()\n" -"}\n" +" #[view]\n" +" fn token_name() -> felt252 {\n" +" IERC20LibraryDispatcher { class_hash: starknet::class_hash_const::<0x1234>() }.name()\n" +" }\n" "\n" -"#[external]\n" -"fn transfer_token(\n" -" recipient: ContractAddress, amount: u256\n" -") -> bool {\n" -" IERC20LibraryDispatcher { class_hash: starknet::class_hash_const::<0x1234>() }.transfer(recipient, amount)\n" +" #[external]\n" +" fn transfer_token(recipient: ContractAddress, amount: u256) -> bool {\n" +" IERC20LibraryDispatcher {\n" +" class_hash: starknet::class_hash_const::<0x1234>()\n" +" }.transfer(recipient, amount)\n" +" }\n" "}\n" "```" msgstr "" "```rust\n" -"//**** Specify interface here ****//\n" -"\n" -"use super::IERC20DispatcherTrait;\n" -"use super::IERC20LibraryDispatcher;\n" -"use starknet::ContractAddress;\n" +"#[contract]\n" +"mod contract {\n" +" use super::IERC20DispatcherTrait;\n" +" use super::IERC20LibraryDispatcher;\n" +" use starknet::ContractAddress;\n" "\n" -"#[view]\n" -"fn token_name() -> felt252 {\n" -" IERC20LibraryDispatcher { class_hash: starknet::class_hash_const::<0x1234>() }.name()\n" -"}\n" +" #[view]\n" +" fn token_name() -> felt252 {\n" +" IERC20LibraryDispatcher { class_hash: starknet::class_hash_const::<0x1234>() }.name()\n" +" }\n" "\n" -"#[external]\n" -"fn transfer_token(\n" -" recipient: ContractAddress, amount: u256\n" -") -> bool {\n" -" IERC20LibraryDispatcher { class_hash: starknet::class_hash_const::<0x1234>() }.transfer(recipient, amount)\n" +" #[external]\n" +" fn transfer_token(recipient: ContractAddress, amount: u256) -> bool {\n" +" IERC20LibraryDispatcher {\n" +" class_hash: starknet::class_hash_const::<0x1234>()\n" +" }.transfer(recipient, amount)\n" +" }\n" "}\n" "```" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:130 -msgid "Listing 9-4: A sample contract using the Library Dispatcher" -msgstr "Listado 9-4: Un contrato de muestra que utiliza el Dispatcher de Biblioteca" +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:171 +msgid "Listing 99-8: A sample contract using the Library Dispatcher" +msgstr "Listado 9-8: Un contrato de muestra que utiliza el Dispatcher de Biblioteca" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:132 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:173 msgid "" "As you can see, we had to first import the `IERC20DispatcherTrait` and `IERC20LibraryDispatcher` which was generated and exported on compiling our interface, then we make calls to " "the methods implemented for the `IERC20LibraryDispatcher` struct (`name`, `transfer`, etc), passing in the `class_hash` parameter which represents the class of the contract we want " @@ -13955,11 +14766,11 @@ msgstr "" "realizamos llamadas a los métodos implementados para la estructura `IERC20LibraryDispatcher` (`name`, `transfer`, etc.), pasando el parámetro `class_hash` que representa la clase del " "contrato que queremos llamar." -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:134 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:175 msgid "## Calling Contracts using low-level System calls" msgstr "## Llamando a Contratos usando llamadas de Sistema de bajo nivel" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:136 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:177 msgid "" "Another way to call other contracts is to use the `starknet::call_contract_syscall` system call. The Dispatchers we described in the previous sections are high-level syntaxes for " "this low-level system call." @@ -13967,7 +14778,7 @@ msgstr "" "Otra forma de llamar a otros contratos es mediante la llamada de sistema `starknet::call_contract_syscall`. Los Dispatchers que describimos en las secciones anteriores son sintaxis " "de alto nivel para esta llamada de sistema de bajo nivel." -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:138 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:179 msgid "" "Using the system call `starknet::call_contract_syscall` can be handy for customized error handling or possessing more control over the serialization/deserialization of the call data " "and the returned data. Here's an example demonstrating a low-level `transfer` call:" @@ -13975,31 +14786,39 @@ msgstr "" "El uso de la llamada de sistema `starknet::call_contract_syscall` puede ser útil para la personalización del manejo de errores o para tener más control sobre la serialización/" "deserialización de los datos de llamada y los datos devueltos. Aquí hay un ejemplo que demuestra una llamada de `transfer` de bajo nivel:" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:140 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:181 msgid "" "```rust\n" -"#[external]\n" -"fn transfer_token(\n" -" address: starknet::ContractAddress, selector: felt252, calldata: Array\n" -") -> Span:: {\n" -" starknet::call_contract_syscall(address, selector, calldata.span()).unwrap_syscall()\n" +"#[contract]\n" +"mod contract {\n" +" use array::ArrayTrait;\n" +" #[external]\n" +" fn transfer_token(\n" +" address: starknet::ContractAddress, selector: felt252, calldata: Array\n" +" ) -> Span:: {\n" +" starknet::call_contract_syscall(address, selector, calldata.span()).unwrap_syscall()\n" +" }\n" "}\n" "```" msgstr "" "```rust\n" -"#[external]\n" -"fn transfer_token(\n" -" address: starknet::ContractAddress, selector: felt252, calldata: Array\n" -") -> Span:: {\n" -" starknet::call_contract_syscall(address, selector, calldata.span()).unwrap_syscall()\n" +"#[contract]\n" +"mod contract {\n" +" use array::ArrayTrait;\n" +" #[external]\n" +" fn transfer_token(\n" +" address: starknet::ContractAddress, selector: felt252, calldata: Array\n" +" ) -> Span:: {\n" +" starknet::call_contract_syscall(address, selector, calldata.span()).unwrap_syscall()\n" +" }\n" "}\n" "```" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:149 -msgid "Listing 9-5: A sample contract implementing system calls" -msgstr "Listado 9-5: Un contrato de muestra que implementa llamadas de sistema" +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:194 +msgid "Listing 99-9: A sample contract implementing system calls" +msgstr "Listado 9-9 Un contrato de muestra que implementa llamadas de sistema" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:151 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:196 msgid "" "As you can see, rather than pass our function arguments directly, we passed in the contract address, function selector (which is a keccak hash of the function name), and the calldata " "(function arguments). At the end, we get returned a serialized value which we'll need to deserialize ourselves!" @@ -14007,6 +14826,371 @@ msgstr "" "Como se puede ver, en lugar de pasar nuestros argumentos de función directamente, pasamos la dirección del contrato, el selector de la función (que es un hash keccak del nombre de la " "función) y los datos de llamada (argumentos de función). Al final, ¡Se nos devuelve un valor serializado que tendremos que deserializar nosotros mismos!" +#: src/ch99-03-security-considerations.md:1 +msgid "# Security Considerations" +msgstr "# Consideraciones de Seguridad" + +#: src/ch99-03-security-considerations.md:3 +msgid "When developing software, ensuring it functions as intended is usually straightforward. However, preventing unintended usage and vulnerabilities can be more challenging." +msgstr "Cuando se desarrolla software, asegurarse de que funciona según lo previsto suele ser sencillo. Sin embargo, evitar usos no previstos y vulnerabilidades puede ser más difícil." + +#: src/ch99-03-security-considerations.md:5 +msgid "In smart contract development, security is very important. A single error can result in the loss of valuable assets or the improper functioning of certain features." +msgstr "" +"En el desarrollo de contratos inteligentes, la seguridad es muy importante. Un solo error puede provocar la pérdida de activos valiosos o el funcionamiento incorrecto de determinadas " +"características." + +#: src/ch99-03-security-considerations.md:7 +msgid "" +"Smart contracts are executed in a public environment where anyone can examine the code and interact with it. Any errors or vulnerabilities in the code can be exploited by malicious " +"actors." +msgstr "" +"Los Smart contracts se ejecutan en un entorno público en el que cualquiera puede examinar el código e interactuar con él. Cualquier error o vulnerabilidad en el código puede ser " +"explotado por actores maliciosos." + +#: src/ch99-03-security-considerations.md:9 +msgid "" +"This chapter presents general recommendations for writing secure smart contracts. By incorporating these concepts during development, you can create robust and reliable smart " +"contracts. This reduces the chances of unexpected behavior or vulnerabilities." +msgstr "" +"Este capítulo presenta recomendaciones generales para escribir contratos inteligentes seguros. Al incorporar estos conceptos durante el desarrollo, puedes crear contratos " +"inteligentes robustos y confiables. Esto reduce las posibilidades de comportamientos inesperados o vulnerabilidades." + +#: src/ch99-03-security-considerations.md:11 +msgid "## Disclaimer" +msgstr "## Descargo de responsabilidad" + +#: src/ch99-03-security-considerations.md:13 +msgid "This chapter does not provide an exhaustive list of all possible security issues, and it does not guarantee that your contracts will be completely secure." +msgstr "Este capítulo no proporciona una lista exhaustiva de todos los posibles problemas de seguridad, y no garantiza que sus contratos sean completamente seguros." + +#: src/ch99-03-security-considerations.md:15 +msgid "If you are developing smart contracts for production use, it is highly recommended to conduct external audits performed by security experts." +msgstr "Si está desarrollando contratos inteligentes para su uso en producción, es muy recomendable llevar a cabo auditorías externas realizadas por expertos en seguridad." + +#: src/ch99-03-security-considerations.md:17 +msgid "## Mindset" +msgstr "## Mentalidad" + +#: src/ch99-03-security-considerations.md:19 +msgid "" +"Cairo is a highly safe language inspired by rust. It is designed in a way that force you to cover all possible cases. Security issues on Starknet mostly arise from the way smart " +"contracts flows are designed, not much from the language itself." +msgstr "" +"Cairo es un lenguaje altamente seguro inspirado en rust. Está diseñado de forma que obliga a cubrir todos los casos posibles. Los problemas de seguridad en Starknet surgen " +"principalmente de la forma en que se diseñan los flujos de contratos inteligentes, y no tanto del propio lenguaje." + +#: src/ch99-03-security-considerations.md:21 +msgid "Adopting a security mindset is the initial step in writing secure smart contracts. Try to always consider all possible scenarios when writing code." +msgstr "" +"Adoptar una mentalidad de seguridad es el paso inicial para escribir contratos inteligentes seguros. Intenta considerar siempre todos los escenarios posibles al escribir código." + +#: src/ch99-03-security-considerations.md:23 +msgid "### Viewing smart contract as Finite State Machines" +msgstr "### Ver los smart contracts como Finite State Machines" + +#: src/ch99-03-security-considerations.md:25 +msgid "Transactions in smart contracts are atomic, meaning they either succeed or fail without making any changes." +msgstr "Las transacciones en los smart contracts son atómicas, lo que significa que tienen éxito o fracasan sin realizar ningún cambio." + +#: src/ch99-03-security-considerations.md:27 +msgid "" +"Think of smart contracts as state machines: they have a set of initial states defined by the constructor constraints, and external function represents a set of possible state " +"transitions. A transaction is nothing more than a state transition." +msgstr "" +"Piense en los smart contracts como máquinas de estados: tienen un conjunto de estados iniciales definidos por las restricciones del constructor, y la función externa representa un " +"conjunto de posibles transiciones de estado. Una transacción no es más que una transición de estado." + +#: src/ch99-03-security-considerations.md:29 +msgid "" +"The `assert` or `panic` functions can be used to validate conditions before performing specific actions. You can learn more about these on the [Unrecoverable Errors with panic](./" +"ch09-01-unrecoverable-errors-with-panic.md) page." +msgstr "" +"Las funciones `assert` o `panic` pueden utilizarse para validar condiciones antes de realizar acciones específicas. Puede obtener más información sobre ellas en la página [Errores " +"irrecuperables con pánico](./ch09-01-unrecoverable-errors-with-panic.md)." + +#: src/ch99-03-security-considerations.md:31 +msgid "These validations can include:" +msgstr "Estas validaciones pueden incluir:" + +#: src/ch99-03-security-considerations.md:33 +msgid "" +"- Inputs provided by the caller\n" +"- Execution requirements\n" +"- Invariants (conditions that must always be true)\n" +"- Return values from other function calls" +msgstr "" +"- Entradas proporcionadas por el autor de la llamada\n" +"- Requisitos de ejecución\n" +"- Invariantes (condiciones que deben cumplirse siempre)\n" +"- Valores de retorno de otras llamadas a funciones" + +#: src/ch99-03-security-considerations.md:38 +msgid "" +"For example, you could use the `assert` function to validate that a user has enough funds to perform a withdraw transaction. If the condition is not met, the transaction will fail " +"and the state of the contract will not change." +msgstr "" +"Por ejemplo, podría utilizar la función `assert` para validar que un usuario tiene fondos suficientes para realizar una transacción de retirada. Si la condición no se cumple, la " +"transacción fallará y el estado del contrato no cambiará." + +#: src/ch99-03-security-considerations.md:40 +msgid "" +"```rust\n" +" #[external]\n" +" fn withdraw(amount: u256) {\n" +" let current_balance = balance::read();\n" +"\n" +" assert(balance >= amount, 'Insufficient funds');\n" +"\n" +" balance::write(current_balance - amount);\n" +" }\n" +"```" +msgstr "" +"```rust\n" +" #[external]\n" +" fn withdraw(amount: u256) {\n" +" let current_balance = balance::read();\n" +"\n" +" assert(balance >= amount, 'Insufficient funds');\n" +"\n" +" balance::write(current_balance - amount);\n" +" }\n" +"```" + +#: src/ch99-03-security-considerations.md:51 +msgid "" +"Using these functions to check conditions adds constraints that help clearly define the boundaries of possible state transitions for each function in your smart contract. These " +"checks ensure that the behavior of the contract stays within the expected limits." +msgstr "" +"El uso de estas funciones para comprobar condiciones añade restricciones que ayudan a definir claramente los límites de las posibles transiciones de estado para cada función de tu " +"smart contract. Estas comprobaciones garantizan que el comportamiento del contrato se mantenga dentro de los límites esperados." + +#: src/ch99-03-security-considerations.md:53 +msgid "## Recommendations" +msgstr "## Recomendaciones" + +#: src/ch99-03-security-considerations.md:55 +msgid "### Checks Effects Interactions Pattern" +msgstr "### Comprueba Efectos Interacciones Patrón" + +#: src/ch99-03-security-considerations.md:57 +msgid "" +"The Checks Effects Interactions pattern is a common design pattern used to prevent reentrancy attacks on Ethereum. While reentrancy is harder to achieve in Starknet, it is still " +"recommended to use this pattern in your smart contracts." +msgstr "" +"El patrón Checks Effects Interactions es un patrón de diseño común utilizado para prevenir ataques de reentrada en Ethereum. Aunque la reentrada es más difícil de conseguir en " +"Starknet, se recomienda utilizar este patrón en los smart contracts." + +#: src/ch99-03-security-considerations.md:59 +msgid "" +msgstr "" + +#: src/ch99-03-security-considerations.md:61 +msgid "The pattern consists of following a specific order of operations in your functions:" +msgstr "El patrón consiste en seguir un orden específico de operaciones en sus funciones:" + +#: src/ch99-03-security-considerations.md:63 +msgid "" +"1. **Checks**: Validate all conditions and inputs before performing any state changes.\n" +"2. **Effects**: Perform all state changes.\n" +"3. **Interactions**: All external calls to other contracts should be made at the end of the function." +msgstr "" +"1. **Comprobaciones**: Validar todas las condiciones y entradas antes de realizar cualquier cambio de estado.\n" +"2. **Efectos**: Realizar todos los cambios de estado.\n" +"3. **Interacciones**: Todas las llamadas externas a otros contratos deben realizarse al final de la función." + +#: src/ch99-03-security-considerations.md:67 +msgid "### Access control" +msgstr "### Control de Acceso" + +#: src/ch99-03-security-considerations.md:69 +msgid "" +"Access control is the process of restricting access to certain features or resources. It is a common security mechanism used to prevent unauthorized access to sensitive information " +"or actions. In smart contracts, some functions may often be restricted to specific users or roles." +msgstr "" +"El Control de Acceso es el proceso de restringir el acceso a determinadas funciones o recursos. Es un mecanismo de seguridad común utilizado para evitar el acceso no autorizado a " +"información o acciones sensibles. En los contratos inteligentes, algunas funciones pueden a menudo estar restringidas a usuarios o roles específicos." + +#: src/ch99-03-security-considerations.md:71 +msgid "" +"You can implement the access control pattern to easily manage permissions. This pattern consists of defining a set of roles and assigning them to specific users. Each function can " +"then be restricted to specific roles." +msgstr "" +"Puede implementar el patrón de control de acceso para gestionar fácilmente los permisos. Este patrón consiste en definir un conjunto de funciones y asignarlas a usuarios específicos. " +"Cada función puede entonces restringirse a roles específicos." + +#: src/ch99-03-security-considerations.md:73 +msgid "" +"```rust\n" +"#[contract]\n" +"mod access_control_contract {\n" +" use starknet::ContractAddress;\n" +" use starknet::get_caller_address;\n" +"\n" +" #[storage]\n" +" struct Storage {\n" +" // Role 'owner': only one address\n" +" owner: ContractAddress,\n" +" // Role 'role_a': a set of addresses\n" +" role_a: LegacyMap::\n" +" }\n" +"\n" +" #[constructor]\n" +" fn constructor() {\n" +" owner::write(get_caller_address());\n" +" }\n" +"\n" +" // Guard functions to check roles\n" +"\n" +" #[inline(always)]\n" +" fn is_owner() -> bool {\n" +" owner::read() == get_caller_address()\n" +" }\n" +"\n" +" #[inline(always)]\n" +" fn is_role_a() -> bool {\n" +" role_a::read(get_caller_address())\n" +" }\n" +"\n" +" #[inline(always)]\n" +" fn only_owner() {\n" +" assert(is_owner(), 'Not owner');\n" +" }\n" +"\n" +" #[inline(always)]\n" +" fn only_role_a() {\n" +" assert(is_role_a(), 'Not role A');\n" +" }\n" +"\n" +" // You can easily combine guards to perfom complex checks\n" +" fn only_allowed() {\n" +" assert(is_owner() || is_role_a(), 'Not allowed');\n" +" }\n" +"\n" +" // Functions to manage roles\n" +"\n" +" #[external]\n" +" fn set_role_a(_target: ContractAddress, _active: bool) {\n" +" only_owner();\n" +" role_a::write(_target, _active);\n" +" }\n" +"\n" +" // You can now focus on the business logic of your contract\n" +" // and reduce the complexity of your code by using guard functions\n" +"\n" +" #[external]\n" +" fn role_a_action() {\n" +" only_role_a();\n" +" // ...\n" +" }\n" +"\n" +" #[external]\n" +" fn allowed_action() {\n" +" only_allowed();\n" +" // ...\n" +" }\n" +"}\n" +"\n" +"```" +msgstr "" +"```rust\n" +"#[contract]\n" +"mod access_control_contract {\n" +" use starknet::ContractAddress;\n" +" use starknet::get_caller_address;\n" +"\n" +" #[storage]\n" +" struct Storage {\n" +" // Role 'owner': only one address\n" +" owner: ContractAddress,\n" +" // Role 'role_a': a set of addresses\n" +" role_a: LegacyMap::\n" +" }\n" +"\n" +" #[constructor]\n" +" fn constructor() {\n" +" owner::write(get_caller_address());\n" +" }\n" +"\n" +" // Guard functions to check roles\n" +"\n" +" #[inline(always)]\n" +" fn is_owner() -> bool {\n" +" owner::read() == get_caller_address()\n" +" }\n" +"\n" +" #[inline(always)]\n" +" fn is_role_a() -> bool {\n" +" role_a::read(get_caller_address())\n" +" }\n" +"\n" +" #[inline(always)]\n" +" fn only_owner() {\n" +" assert(is_owner(), 'Not owner');\n" +" }\n" +"\n" +" #[inline(always)]\n" +" fn only_role_a() {\n" +" assert(is_role_a(), 'Not role A');\n" +" }\n" +"\n" +" // You can easily combine guards to perfom complex checks\n" +" fn only_allowed() {\n" +" assert(is_owner() || is_role_a(), 'Not allowed');\n" +" }\n" +"\n" +" // Functions to manage roles\n" +"\n" +" #[external]\n" +" fn set_role_a(_target: ContractAddress, _active: bool) {\n" +" only_owner();\n" +" role_a::write(_target, _active);\n" +" }\n" +"\n" +" // You can now focus on the business logic of your contract\n" +" // and reduce the complexity of your code by using guard functions\n" +"\n" +" #[external]\n" +" fn role_a_action() {\n" +" only_role_a();\n" +" // ...\n" +" }\n" +"\n" +" #[external]\n" +" fn allowed_action() {\n" +" only_allowed();\n" +" // ...\n" +" }\n" +"}\n" +"\n" +"```" + +#: src/ch99-03-security-considerations.md:145 +msgid "### Static analysis tool" +msgstr "### Herramienta de análisis estático" + +#: src/ch99-03-security-considerations.md:147 +msgid "" +"Static analysis refers to the process of examining code without its execution, focusing on its structure, syntax, and properties. It involves analyzing the source code to identify " +"potential issues, vulnerabilities, or violations of specified rules." +msgstr "" +"El análisis estático se refiere al proceso de examinar el código sin su ejecución, centrándose en su estructura, sintaxis y propiedades. Consiste en analizar el código fuente para " +"identificar posibles problemas, vulnerabilidades o infracciones de normas específicas." + +#: src/ch99-03-security-considerations.md:149 +msgid "By defining rules, such as coding conventions or security guidelines, developers can utilize static analysis tools to automatically check the code against these standards." +msgstr "" +"Mediante la definición de normas, como convenciones de codificación o directrices de seguridad, los desarrolladores pueden utilizar herramientas de análisis estático para comprobar " +"automáticamente el código con respecto a estas normas." + +#: src/ch99-03-security-considerations.md:151 +msgid "Reference:" +msgstr "Referencias:" + +#: src/ch99-03-security-considerations.md:153 +msgid "- [Semgrep Cairo 1.0 support](https://semgrep.dev/blog/2023/semgrep-now-supports-cairo-1-0)" +msgstr "- [Semgrep Cairo 1.0 support](https://semgrep.dev/blog/2023/semgrep-now-supports-cairo-1-0)" + #: src/appendix-00.md:1 msgid "# Appendix" msgstr "# Apéndice" @@ -14032,8 +15216,8 @@ msgstr "" "por el lenguaje Cairo." #: src/appendix-01-keywords.md:6 -msgid "There are three keyword categories:" -msgstr "Hay tres categorías de (Keyword) palabras clave:" +msgid "There are two keyword categories:" +msgstr "Hay dos categorías de (Keyword) palabras clave:" #: src/appendix-01-keywords.md:8 msgid "" @@ -14043,11 +15227,19 @@ msgstr "" "- strict\n" "- reserved" -#: src/appendix-01-keywords.md:13 +#: src/appendix-01-keywords.md:11 +msgid "" +"There is a third category, which are functions from the core library. While their names are not reserved,\n" +"they are not recommended to be used as names of any items to follow good practices." +msgstr "" +"Hay una tercera categoría, que son funciones de la biblioteca central. Aunque sus nombres no están reservados\n" +"no se recomienda utilizarlos como nombres de ningún elemento para seguir las buenas prácticas." + +#: src/appendix-01-keywords.md:16 msgid "### Strict keywords" msgstr "### Palabras Clave Estrictas" -#: src/appendix-01-keywords.md:15 +#: src/appendix-01-keywords.md:18 msgid "" "These keywords can only be used in their correct contexts.\n" "They cannot be used as names of any items." @@ -14055,7 +15247,7 @@ msgstr "" "Estas palabras clave sólo pueden utilizarse en sus contextos correctos.\n" "No pueden utilizarse como nombres de ningún elemento." -#: src/appendix-01-keywords.md:18 +#: src/appendix-01-keywords.md:21 msgid "" "- `as` - Rename import\n" "- `break` - Exit a loop immediately\n" @@ -14111,11 +15303,11 @@ msgstr "" "- `type` - Definir un alias de tipo\n" "- `use` - Introducir símbolos" -#: src/appendix-01-keywords.md:47 +#: src/appendix-01-keywords.md:50 msgid "### Reserved keywords" msgstr "### Palabras Clave Reservadas" -#: src/appendix-01-keywords.md:49 +#: src/appendix-01-keywords.md:52 msgid "" "These keywords aren't used yet, but they are reserved for future use.\n" "They have the same restrictions as strict keywords.\n" @@ -14127,9 +15319,8 @@ msgstr "" "El razonamiento detrás de esto es hacer que los programas actuales sean compatibles con futuras versiones de\n" "Cairo prohibiéndoles usar estas palabras clave." -#: src/appendix-01-keywords.md:54 +#: src/appendix-01-keywords.md:57 msgid "" -"- `assert`\n" "- `do`\n" "- `dyn`\n" "- `macro`\n" @@ -14147,7 +15338,6 @@ msgid "" "- `with`\n" "- `yield`" msgstr "" -"- `assert`\n" "- `do`\n" "- `dyn`\n" "- `macro`\n" @@ -14165,6 +15355,22 @@ msgstr "" "- `with`\n" "- `yield`" +#: src/appendix-01-keywords.md:76 +msgid "### Built-in functions" +msgstr "### Funciones incorporadas (Built-in)" + +#: src/appendix-01-keywords.md:78 +msgid "" +"The Cairo programming language provides several specific functions that serve a special purpose. We will not cover all of them in this book, but using the names of these functions as " +"names of other items is not recommended." +msgstr "" +"El lenguaje de programación Cairo proporciona varias funciones específicas que sirven a un propósito especial. No las cubriremos todas en este libro, pero no se recomienda usar los " +"nombres de estas funciones como nombres de otros elementos." + +#: src/appendix-01-keywords.md:80 +msgid "-`assert` - This function checks a boolean expression, and if it evaluates to false, it triggers the panic function. -`panic` - This function terminates the program." +msgstr "-`assert` - Esta función comprueba una expresión booleana, y si se evalúa como falsa, desencadena la función de pánico. -`panic` - Esta función termina el programa." + #: src/appendix-02-operators-and-symbols.md:1 msgid "# Appendix B: Operators and Symbols" msgstr "# Apéndice B: Operadores y Símbolos" @@ -14846,17 +16052,13 @@ msgstr "" msgid "## Appendix E - Most Common Types and Traits Required To Write Contracts" msgstr "## Apéndice E - Tipos y Traits Más Comunes Necesarios para Escribir Contratos" -#: src/appendix-05-most-common-types-and-traits.md:3 src/appendix-05-most-common-types-and-traits.md:7 +#: src/appendix-05-most-common-types-and-traits.md:3 msgid "This appendix provides a reference for common types and traits used in contract development, along with their corresponding imports, paths, and usage examples." msgstr "" "Este apéndice proporciona una referencia para los tipos y traits comunes utilizados en el desarrollo de contratos, junto con sus correspondientes importaciones, rutas y ejemplos de " "uso." #: src/appendix-05-most-common-types-and-traits.md:5 -msgid "# Contract Development Appendix" -msgstr "# Apéndice Desarrollo de Contratos" - -#: src/appendix-05-most-common-types-and-traits.md:9 msgid "" "| Import | Path | " "Usage " @@ -14908,7 +16110,7 @@ msgstr "" "| `get_contract_address` | `starknet::info::get_contract_address` | `get_contract_address()` es una función que devuelve la dirección del contrato actual. Se puede " "usar para obtener la dirección del contrato que se está ejecutando. |" -#: src/appendix-05-most-common-types-and-traits.md:21 +#: src/appendix-05-most-common-types-and-traits.md:17 msgid "" "This is not an exhaustive list, but it covers some of the commonly used types and traits in contract development. For more details, refer to the official documentation and explore " "the available libraries and frameworks." @@ -14916,5 +16118,641 @@ msgstr "" "Esta no es una lista exhaustiva, pero cubre algunos de los tipos y rasgos más utilizados en el desarrollo de contratos. Para más detalles, consulta la documentación oficial y explora " "las bibliotecas y frameworks disponibles." +#~ msgid "" +#~ "- Disable previous Cairo 0.x extension\n" +#~ "- Install the Cairo 1 extension for proper syntax highlighting and code navigation.\n" +#~ " Just follow the steps indicated [here](https://github.com/starkware-libs/cairo/blob/main/vscode-cairo/README.md)." +#~ msgstr "" +#~ "- Deshabilite la extensión anterior Cairo 0.x\n" +#~ "- Instale la extensión Cairo 1 para un correcto resaltado de sintaxis y navegación por el código.\n" +#~ " Simplemente siga los pasos indicados [aquí](https://github.com/starkware-libs/cairo/blob/main/vscode-cairo/README.md)." + +#~ msgid "As for now, Scarb needs manual installation with the following steps:" +#~ msgstr "Por ahora, Scarb necesita instalación manual con los siguientes pasos:" + +#~ msgid "" +#~ "- Download the release archive matching your operating system and CPU architecture, from [Scarb releases on GitHub](https://github.com/software-mansion/scarb/releases)\n" +#~ "- Extract it to a location where you would like to have Scarb installed, e.g. `~/scarb`\n" +#~ "- Add path to the `scarb/bin` directory to your `PATH` environment variable.\n" +#~ "\n" +#~ " This depend on what shell you are using. Let’s take the example of [zsh](https://ohmyz.sh/) and you have extracted Scarb to `~/scarb`:\n" +#~ "\n" +#~ " - Open `~/.zshrc` file in your favorite editor\n" +#~ " - Add the following line to the end of the file: `export PATH=\"$PATH:~/scarb/bin\"`\n" +#~ "\n" +#~ "- Verify installation by running the following command in new terminal session, it should print both Scarb and Cairo language versions, e.g:\n" +#~ "\n" +#~ " ```bash\n" +#~ " $ scarb --version\n" +#~ " scarb 0.1.0 (289137c24 2023-03-28)\n" +#~ " cairo: 1.0.0-alpha.6\n" +#~ " ```" +#~ msgstr "" +#~ "- Descargue el archivo de versiones correspondiente a su sistema operativo y arquitectura de CPU desde [Scarb releases on GitHub](https://github.com/software-mansion/scarb/" +#~ "releases)\n" +#~ "- Extráigalo a una ubicación en la que desee tener Scarb instalado, por ejemplo. `~/scarb`\n" +#~ "- Añada la ruta al directorio `scarb/bin` a su variable de entorno `PATH`.\n" +#~ "\n" +#~ " Esto depende del shell que esté utilizando. Tomemos el ejemplo de [zsh](https://ohmyz.sh/) y has extraido Scarb a `~/scarb`:\n" +#~ "\n" +#~ " - Abra el archivo `~/.zshrc` en su editor favorito\n" +#~ " - Añada la siguiente línea al final del archivo: `export PATH=\"$PATH:~/scarb/bin\"`\n" +#~ "\n" +#~ "- Verifique la instalación ejecutando el siguiente comando en una nueva sesión de terminal, debería imprimir las versiones en Scarb y Cairo, por ejemplo:\n" +#~ "\n" +#~ " ```bash\n" +#~ " $ scarb --version\n" +#~ " scarb 0.1.0 (289137c24 2023-03-28)\n" +#~ " cairo: 1.0.0-alpha.6\n" +#~ " ```" + +#~ msgid "" +#~ "```rust\n" +#~ "{\n" +#~ " let x = 3;\n" +#~ " x + 1\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "{\n" +#~ " let x = 3;\n" +#~ " x + 1\n" +#~ "}\n" +#~ "```" + +#~ msgid "" +#~ "```rust,ignore,does_not_compile\n" +#~ "use debug::PrintTrait;\n" +#~ "fn main() {\n" +#~ " let mut i:usize = 0;\n" +#~ " loop {\n" +#~ " if i > 10{\n" +#~ " break();\n" +#~ " }\n" +#~ " 'again!'.print();\n" +#~ " }\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust,ignore,does_not_compile\n" +#~ "use debug::PrintTrait;\n" +#~ "fn main() {\n" +#~ " let mut i:usize = 0;\n" +#~ " loop {\n" +#~ " if i > 10{\n" +#~ " break();\n" +#~ " }\n" +#~ " 'again!'.print();\n" +#~ " }\n" +#~ "}\n" +#~ "```" + +#~ msgid "" +#~ "```rust\n" +#~ " let mut a = ArrayTrait::new();\n" +#~ " a.append(10);\n" +#~ " a.append(1);\n" +#~ " a.append(2);\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ " let mut a = ArrayTrait::new();\n" +#~ " a.append(10);\n" +#~ " a.append(1);\n" +#~ " a.append(2);\n" +#~ "```" + +#~ msgid "" +#~ "```rust\n" +#~ "let span = array.span();\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "let span = array.span();\n" +#~ "```" + +#~ msgid "" +#~ "```rust\n" +#~ "let mut arr = ArrayTrait::::new();\n" +#~ "arr.append(1);\n" +#~ "arr.append(2);\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "let mut arr = ArrayTrait::::new();\n" +#~ "arr.append(1);\n" +#~ "arr.append(2);\n" +#~ "```" + +#~ msgid "" +#~ "```rust\n" +#~ "let mut arr1 = ArrayTrait::::new();\n" +#~ "let second_length = calculate_length(@arr1); // Calculate the current length of the array\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "let mut arr1 = ArrayTrait::::new();\n" +#~ "let second_length = calculate_length(@arr1); // Calculate the current length of the array\n" +#~ "```" + +#~ msgid "" +#~ "```rust,does_not_compile\n" +#~ "fn main() {\n" +#~ " let mut user1 = User {\n" +#~ " active: true,\n" +#~ " username: 'someusername123',\n" +#~ " email: 'someone@example.com',\n" +#~ " sign_in_count: 1_u64,\n" +#~ " };\n" +#~ " user1.email = 'anotheremail@example.com';\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust,does_not_compile\n" +#~ "fn main() {\n" +#~ " let mut user1 = User {\n" +#~ " active: true,\n" +#~ " username: 'someusername123',\n" +#~ " email: 'someone@example.com',\n" +#~ " sign_in_count: 1_u64,\n" +#~ " };\n" +#~ " user1.email = 'anotheremail@example.com';\n" +#~ "}\n" +#~ "```" + +#~ msgid "" +#~ "```rust\n" +#~ "fn build_user(email: felt252, username: felt252) -> User {\n" +#~ " User {\n" +#~ " active: true,\n" +#~ " username: username,\n" +#~ " email: email,\n" +#~ " sign_in_count: 1,\n" +#~ " }\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "fn build_user(email: felt252, username: felt252) -> User {\n" +#~ " User {\n" +#~ " active: true,\n" +#~ " username: username,\n" +#~ " email: email,\n" +#~ " sign_in_count: 1,\n" +#~ " }\n" +#~ "}\n" +#~ "```" + +#~ msgid "" +#~ "```rust\n" +#~ "fn build_user(email: felt252, username: felt252) -> User {\n" +#~ " User {\n" +#~ " active: true,\n" +#~ " username,\n" +#~ " email,\n" +#~ " sign_in_count: 1_u64,\n" +#~ " }\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "fn build_user(email: felt252, username: felt252) -> User {\n" +#~ " User {\n" +#~ " active: true,\n" +#~ " username,\n" +#~ " email,\n" +#~ " sign_in_count: 1_u64,\n" +#~ " }\n" +#~ "}\n" +#~ "```" + +#~ msgid "" +#~ "```rs\n" +#~ "let direction = Direction::North(());\n" +#~ "```" +#~ msgstr "" +#~ "```rs\n" +#~ "let direction = Direction::North(());\n" +#~ "```" + +#~ msgid "" +#~ "```rust\n" +#~ "let msg: Message = Message::Quit(());\n" +#~ "msg.process();\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "let msg: Message = Message::Quit(());\n" +#~ "msg.process();\n" +#~ "```" + +#~ msgid "" +#~ "```rust\n" +#~ "fn value_in_cents(coin: Coin) -> felt252 {\n" +#~ " match coin {\n" +#~ " Coin::Penny(_) => {\n" +#~ " ('Lucky penny!').print();\n" +#~ " 1\n" +#~ " },\n" +#~ " Coin::Nickel(_) => 5,\n" +#~ " Coin::Dime(_) => 10,\n" +#~ " Coin::Quarter(_)=> 25,\n" +#~ " }\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "fn value_in_cents(coin: Coin) -> felt252 {\n" +#~ " match coin {\n" +#~ " Coin::Penny(_) => {\n" +#~ " ('Lucky penny!').print();\n" +#~ " 1\n" +#~ " },\n" +#~ " Coin::Nickel(_) => 5,\n" +#~ " Coin::Dime(_) => 10,\n" +#~ " Coin::Quarter(_)=> 25,\n" +#~ " }\n" +#~ "}\n" +#~ "```" + +#~ msgid "" +#~ "```rust\n" +#~ " enum Option {\n" +#~ " Some: T,\n" +#~ " None: (),\n" +#~ " }\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ " enum Option {\n" +#~ " Some: T,\n" +#~ " None: (),\n" +#~ " }\n" +#~ "```" + +#~ msgid "" +#~ "In the next chapter, we’ll look at some collection data structures in the\n" +#~ "standard library that you can use in your neatly organized code." +#~ msgstr "" +#~ "En el próximo capítulo, veremos algunas estructuras de datos de colección en la\n" +#~ "biblioteca estándar que puedes utilizar en tu código bien organizado." + +#~ msgid "Compiling the above code would error due to the `derive` macro not working well with generics. When using generic types is best to directly write the traits you want to use:" +#~ msgstr "" +#~ "La compilación del código anterior daría un error debido a que la macro `derive` no funciona bien con tipos genéricos. Cuando se usan tipos genéricos, es mejor escribir " +#~ "directamente los traits que se quieren utilizar:" + +#~ msgid "" +#~ msgstr "" + +#~ msgid "" +#~ "```rust\n" +#~ "struct Wallet {\n" +#~ " balance: T,\n" +#~ " address: U,\n" +#~ "}\n" +#~ "\n" +#~ "impl WalletDrop, U, impl UDrop: Drop> of Drop>;\n" +#~ "\n" +#~ "fn main() {\n" +#~ " let w = Wallet { balance: 3_u128, address: 14 };\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "struct Wallet {\n" +#~ " balance: T,\n" +#~ " address: U,\n" +#~ "}\n" +#~ "\n" +#~ "impl WalletDrop, U, impl UDrop: Drop> of Drop>;\n" +#~ "\n" +#~ "fn main() {\n" +#~ " let w = Wallet { balance: 3_u128, address: 14 };\n" +#~ "}\n" +#~ "```" + +#~ msgid "" +#~ "We add to `Wallet` struct definiton a new generic type `U` and then assign this type to the new field member `address`.\n" +#~ "Then we adapt the `WalletDrop` trait to work with the new generic type `U`. Notice that when initializing the struct inside `main` it automatically infers that `T` is a `u128` and " +#~ "`U` is a `felt252` and since they are both droppable, `Wallet` is droppable as well!" +#~ msgstr "" +#~ "Agregamos a la definición de la estructura `Wallet` un nuevo tipo genérico `U` y luego asignamos este tipo al nuevo miembro del campo `address`. Luego adaptamos el trait " +#~ "`WalletDrop` para que funcione con el nuevo tipo genérico `U`. ¡Observa que al inicializar la estructura dentro de `main`, automáticamente infiere que `T` es un `u128` y `U` es un " +#~ "`felt252` y como ambos son droppable, `Wallet` también lo es!" + +#~ msgid "" +#~ "```rust\n" +#~ "enum Option {\n" +#~ " Some(T),\n" +#~ " None,\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "enum Option {\n" +#~ " Some(T),\n" +#~ " None,\n" +#~ "}\n" +#~ "```" + +#~ msgid "Listing 8-1: A test module and function" +#~ msgstr "Listado 8-1: Un módulo y función de prueba" + +#~ msgid "Listing 8-2: The output from running a test" +#~ msgstr "Listado 8-2: Resultados de la ejecución de una prueba" + +#~ msgid "" +#~ "```rust\n" +#~ "trait RectangleTrait {\n" +#~ " fn area(self: @Rectangle) -> u64;\n" +#~ " fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" +#~ "}\n" +#~ "\n" +#~ "impl RectangleImpl of RectangleTrait {\n" +#~ " fn area(self: @Rectangle) -> u64 {\n" +#~ " *self.width * *self.height\n" +#~ " }\n" +#~ " fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +#~ " *self.width > *other.width & *self.height > *other.height\n" +#~ " }\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "trait RectangleTrait {\n" +#~ " fn area(self: @Rectangle) -> u64;\n" +#~ " fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" +#~ "}\n" +#~ "\n" +#~ "impl RectangleImpl of RectangleTrait {\n" +#~ " fn area(self: @Rectangle) -> u64 {\n" +#~ " *self.width * *self.height\n" +#~ " }\n" +#~ " fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +#~ " *self.width > *other.width & *self.height > *other.height\n" +#~ " }\n" +#~ "}\n" +#~ "```" + +#~ msgid "" +#~ "```rust\n" +#~ "#[cfg(test)]\n" +#~ "mod tests {\n" +#~ " use super::Rectangle;\n" +#~ " use super::RectangleTrait;\n" +#~ "\n" +#~ " #[test]\n" +#~ " fn larger_can_hold_smaller() {\n" +#~ " let larger = Rectangle {\n" +#~ " height: 7_u64,\n" +#~ " width: 8_u64,\n" +#~ " };\n" +#~ " let smaller = Rectangle {\n" +#~ " height: 1_u64,\n" +#~ " width: 5_u64,\n" +#~ " };\n" +#~ "\n" +#~ " assert(larger.can_hold(@smaller), 'rectangle cannot hold');\n" +#~ " }\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "#[cfg(test)]\n" +#~ "mod tests {\n" +#~ " use super::Rectangle;\n" +#~ " use super::RectangleTrait;\n" +#~ "\n" +#~ " #[test]\n" +#~ " fn larger_can_hold_smaller() {\n" +#~ " let larger = Rectangle {\n" +#~ " height: 7_u64,\n" +#~ " width: 8_u64,\n" +#~ " };\n" +#~ " let smaller = Rectangle {\n" +#~ " height: 1_u64,\n" +#~ " width: 5_u64,\n" +#~ " };\n" +#~ "\n" +#~ " assert(larger.can_hold(@smaller), 'rectangle cannot hold');\n" +#~ " }\n" +#~ "}\n" +#~ "```" + +#~ msgid "" +#~ "```rust\n" +#~ "#[cfg(test)]\n" +#~ "mod tests {\n" +#~ " use super::Rectangle;\n" +#~ " use super::RectangleTrait;\n" +#~ "\n" +#~ " #[test]\n" +#~ " fn larger_can_hold_smaller() {\n" +#~ " // --snip--\n" +#~ " }\n" +#~ "\n" +#~ " #[test]\n" +#~ " fn smaller_cannot_hold_larger() {\n" +#~ " let larger = Rectangle {\n" +#~ " height: 7_u64,\n" +#~ " width: 8_u64,\n" +#~ " };\n" +#~ " let smaller = Rectangle {\n" +#~ " height: 1_u64,\n" +#~ " width: 5_u64,\n" +#~ " };\n" +#~ "\n" +#~ " assert(!smaller.can_hold(@larger), 'rectangle cannot hold');\n" +#~ " }\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "#[cfg(test)]\n" +#~ "mod tests {\n" +#~ " use super::Rectangle;\n" +#~ " use super::RectangleTrait;\n" +#~ "\n" +#~ " #[test]\n" +#~ " fn larger_can_hold_smaller() {\n" +#~ " // --snip--\n" +#~ " }\n" +#~ "\n" +#~ " #[test]\n" +#~ " fn smaller_cannot_hold_larger() {\n" +#~ " let larger = Rectangle {\n" +#~ " height: 7_u64,\n" +#~ " width: 8_u64,\n" +#~ " };\n" +#~ " let smaller = Rectangle {\n" +#~ " height: 1_u64,\n" +#~ " width: 5_u64,\n" +#~ " };\n" +#~ "\n" +#~ " assert(!smaller.can_hold(@larger), 'rectangle cannot hold');\n" +#~ " }\n" +#~ "}\n" +#~ "```" + +#~ msgid "" +#~ "```rust\n" +#~ "// --snip--\n" +#~ "impl RectangleImpl of RectangleTrait {\n" +#~ " fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +#~ " *self.width < *other.width & *self.height > *other.height\n" +#~ " }\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "// --snip--\n" +#~ "impl RectangleImpl of RectangleTrait {\n" +#~ " fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +#~ " *self.width < *other.width & *self.height > *other.height\n" +#~ " }\n" +#~ "}\n" +#~ "```" + +#~ msgid "" +#~ "```rust\n" +#~ "// --snip--\n" +#~ "impl GuessImpl of GuessTrait {\n" +#~ " fn new(value: u64) -> Guess {\n" +#~ " if value < 1_u64 {\n" +#~ " let mut data = ArrayTrait::new();\n" +#~ " data.append('Guess must be >= 1 and <= 100');\n" +#~ " panic(data);\n" +#~ " }\n" +#~ "\n" +#~ " Guess { value, }\n" +#~ " }\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "// --snip--\n" +#~ "impl GuessImpl of GuessTrait {\n" +#~ " fn new(value: u64) -> Guess {\n" +#~ " if value < 1_u64 {\n" +#~ " let mut data = ArrayTrait::new();\n" +#~ " data.append('Guess must be >= 1 and <= 100');\n" +#~ " panic(data);\n" +#~ " }\n" +#~ "\n" +#~ " Guess { value, }\n" +#~ " }\n" +#~ "}\n" +#~ "```" + +#~ msgid "" +#~ "```rust\n" +#~ "if value < 1_u64 {\n" +#~ " let mut data = ArrayTrait::new();\n" +#~ " data.append('Guess must be <= 100');\n" +#~ " panic(data);\n" +#~ "} else if value > 100_u64 {\n" +#~ " let mut data = ArrayTrait::new();\n" +#~ " data.append('Guess must be >= 1');\n" +#~ " panic(data);\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "if value < 1_u64 {\n" +#~ " let mut data = ArrayTrait::new();\n" +#~ " data.append('Guess must be <= 100');\n" +#~ " panic(data);\n" +#~ "} else if value > 100_u64 {\n" +#~ " let mut data = ArrayTrait::new();\n" +#~ " data.append('Guess must be >= 1');\n" +#~ " panic(data);\n" +#~ "}\n" +#~ "```" + +#~ msgid "" +#~ "```rust\n" +#~ "#[test]\n" +#~ "fn test_function_2() {\n" +#~ " let number: felt252 = 258_felt252;\n" +#~ " match do_something_with_parse_u8(number) {\n" +#~ " Result::Ok(value) => value.print(),\n" +#~ " Result::Err(e) => e.print()\n" +#~ " }\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "#[test]\n" +#~ "fn test_function_2() {\n" +#~ " let number: felt252 = 258_felt252;\n" +#~ " match do_something_with_parse_u8(number) {\n" +#~ " Result::Ok(value) => value.print(),\n" +#~ " Result::Err(e) => e.print()\n" +#~ " }\n" +#~ "}\n" +#~ "```" + +#~ msgid "Starknet contracts are denoted by the `#[contract]` attribute. We'll dive deeper into this in the next sections." +#~ msgstr "Los contratos inteligentes en Starknet se denotan por el atributo `#[contract]`. Profundizaremos más en esto en las próximas secciones." + +#~ msgid "" +#~ "```rust\n" +#~ "//**** Specify interface here ****//\n" +#~ "\n" +#~ "#[contract]\n" +#~ "mod dispatcher {\n" +#~ " use super::IERC20DispatcherTrait;\n" +#~ " use super::IERC20Dispatcher;\n" +#~ " use starknet::ContractAddress;\n" +#~ "\n" +#~ " #[view]\n" +#~ " fn token_name(\n" +#~ " _contract_address: ContractAddress\n" +#~ " ) -> felt252 {\n" +#~ " IERC20Dispatcher {contract_address: _contract_address }.name()\n" +#~ " }\n" +#~ "\n" +#~ " #[external]\n" +#~ " fn transfer_token(\n" +#~ " _contract_address: ContractAddress, recipient: ContractAddress, amount: u256\n" +#~ " ) -> bool {\n" +#~ " IERC20Dispatcher {contract_address: _contract_address }.transfer(recipient, amount)\n" +#~ " }\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "//**** Specify interface here ****//\n" +#~ "\n" +#~ "#[contract]\n" +#~ "mod dispatcher {\n" +#~ " use super::IERC20DispatcherTrait;\n" +#~ " use super::IERC20Dispatcher;\n" +#~ " use starknet::ContractAddress;\n" +#~ "\n" +#~ " #[view]\n" +#~ " fn token_name(\n" +#~ " _contract_address: ContractAddress\n" +#~ " ) -> felt252 {\n" +#~ " IERC20Dispatcher {contract_address: _contract_address }.name()\n" +#~ " }\n" +#~ "\n" +#~ " #[external]\n" +#~ " fn transfer_token(\n" +#~ " _contract_address: ContractAddress, recipient: ContractAddress, amount: u256\n" +#~ " ) -> bool {\n" +#~ " IERC20Dispatcher {contract_address: _contract_address }.transfer(recipient, amount)\n" +#~ " }\n" +#~ "}\n" +#~ "```" + +#~ msgid "Listing 9-4: An expanded form of the IERC20 trait" +#~ msgstr "Listado 9-4: Una forma expandida del trait IERC20" + +#~ msgid "# Contract Development Appendix" +#~ msgstr "# Apéndice Desarrollo de Contratos" + #~ msgid "## Appendix A - Useful Development Tools" #~ msgstr "## Apéndice A - Herramientas de Desarrollo Útiles" diff --git a/po/fr.po b/po/fr.po index da8dde79d..c36c061c4 100644 --- a/po/fr.po +++ b/po/fr.po @@ -307,7 +307,7 @@ msgid "" "provable, even when the computation fails." msgstr "" "Cairo est un langage de programmation conçu pour un processeur virtuel du même nom. " -"L'aspect unique de ce processeur est qu'il n'a pas été créé pour les contraintes physiques de notre monde, " +"L'aspect unique de ce processeur est qu'il n'a pas été créé pour les contraintes physiques de notre monde, " "mais pour des contraintes cryptographiques, ce qui lui permet de prouver efficacement l'exécution de n'importe quel programme s'exécutant sur celui-ci. " "Cela signifie que vous pouvez effectuer des opérations complexes sur une machine " "en laquelle vous n'avez pas confiance, et vérifier le résultat très rapidement sur une machine moins coûteuse. " @@ -1366,7 +1366,7 @@ msgid "" "version = \"0.1.0\"\n" "\n" "# See more keys and their definitions at https://docs.swmansion.com/scarb/" -"docs/reference/manifest\n" +"docs/reference/manifest.html\n" "\n" "[dependencies]\n" "# foo = { path = \"vendor/foo\" }\n" @@ -3428,7 +3428,7 @@ msgid "" " let mut i:usize = 0;\n" " loop {\n" " if i > 10{\n" -" break();\n" +" break;\n" " }\n" " 'again!'.print();\n" " }\n" @@ -3443,7 +3443,7 @@ msgid "" "until we stop the program manually, because the stop condition is never " "reached.\n" "While the compiler prevents us from writing programs without a stop " -"condition (`break()` statement),\n" +"condition (`break` statement),\n" "the stop condition might never be reached, resulting in an infinite loop.\n" "Most terminals support the keyboard shortcut ctrl-" "c to interrupt a program that is\n" @@ -3486,7 +3486,7 @@ msgstr "" #: src/ch02-05-control-flow.md:170 msgid "" -"To break out of a loop, you can place the `break()` statement within the " +"To break out of a loop, you can place the `break` statement within the " "loop to tell the program when to stop\n" "executing the loop. Let's fix the infinite loop by adding a making the stop " "condition `i > 10` reachable." @@ -3500,7 +3500,7 @@ msgid "" " let mut i: usize = 0;\n" " loop {\n" " if i > 10 {\n" -" break ();\n" +" break;\n" " }\n" " 'again'.print();\n" " i += 1;\n" @@ -6185,10 +6185,10 @@ msgid "" " if index < length {\n" " if *arr.at(index) == value {\n" " found = Option::Some(index);\n" -" break ();\n" +" break;\n" " }\n" " } else {\n" -" break ();\n" +" break;\n" " }\n" " index += 1_usize;\n" " };\n" @@ -6855,7 +6855,7 @@ msgid "" "- `Scarb.toml` is the package manifest file, which contains metadata and " "configuration options for the package, such as dependencies, package name, " "version, and authors. You can find documentation about it on the [scarb " -"reference](https://docs.swmansion.com/scarb/docs/reference/manifest)." +"reference](https://docs.swmansion.com/scarb/docs/reference/manifest.html)." msgstr "" #: src/ch06-01-packages-and-crates.md:33 @@ -7682,7 +7682,7 @@ msgstr "" msgid "" "> The dependencies system is still a work in progress. You can check the " "official [documentation](https://docs.swmansion.com/scarb/docs/guides/" -"dependencies)." +"dependencies.html)." msgstr "" #: src/ch06-05-separating-modules-into-different-files.md:1 @@ -10437,7 +10437,7 @@ msgid "" "//**** Specify interface here ****//\n" "\n" "#[contract]\n" -"mod Dispatcher {\n" +"mod dispatcher {\n" " use super::IERC20DispatcherTrait;\n" " use super::IERC20Dispatcher;\n" " use starknet::ContractAddress;\n" diff --git a/po/messages.pot b/po/messages.pot index 94ffe9c6b..8f7d9e5a0 100644 --- a/po/messages.pot +++ b/po/messages.pot @@ -168,50 +168,66 @@ msgstr "" msgid "Recoverable Errors with Result" msgstr "" -#: src/SUMMARY.md:77 +#: src/SUMMARY.md:75 +msgid "Advanced Features" +msgstr "" + +#: src/SUMMARY.md:78 +msgid "Operator Overloading" +msgstr "" + +#: src/SUMMARY.md:82 msgid "Starknet Smart Contracts" msgstr "" -#: src/SUMMARY.md:79 +#: src/SUMMARY.md:84 msgid "Introduction to smart-contracts" msgstr "" -#: src/SUMMARY.md:80 +#: src/SUMMARY.md:85 msgid "Writing Starknet Contracts" msgstr "" -#: src/SUMMARY.md:81 +#: src/SUMMARY.md:86 msgid "ABIs and Cross-contract Interactions" msgstr "" -#: src/SUMMARY.md:82 +#: src/SUMMARY.md:87 msgid "ABIs and Interfaces" msgstr "" -#: src/SUMMARY.md:83 +#: src/SUMMARY.md:88 msgid "Contract Dispatchers, Library Dispachers and system calls" msgstr "" -#: src/SUMMARY.md:85 +#: src/SUMMARY.md:89 +msgid "Security Considerations" +msgstr "" + +#: src/SUMMARY.md:91 msgid "Appendix" msgstr "" -#: src/SUMMARY.md:86 +#: src/SUMMARY.md:92 msgid "A - Keywords" msgstr "" -#: src/SUMMARY.md:87 +#: src/SUMMARY.md:93 msgid "B - Operators and Symbols" msgstr "" -#: src/SUMMARY.md:88 +#: src/SUMMARY.md:94 msgid "C - Derivable Traits" msgstr "" -#: src/SUMMARY.md:89 +#: src/SUMMARY.md:95 msgid "D - Useful Development Tools" msgstr "" +#: src/SUMMARY.md:96 +msgid "E - Cairo Most Common Types and Traits" +msgstr "" + #: src/title-page.md:1 msgid "# The Cairo Programming Language" msgstr "" @@ -227,9 +243,8 @@ msgstr "" #: src/title-page.md:5 msgid "" -"This version of the text assumes you’re using Cairo v1.0.0 (released " -"2023-05-15). See the “Installation” section of Chapter 1 to install or " -"update Cairo." +"This version of the text assumes you’re using Cairo v1.1.0. See the " +"“Installation” section of Chapter 1 to install or update Cairo." msgstr "" #: src/ch00-01-foreword.md:1 @@ -323,12 +338,12 @@ msgid "" "applications where every single interaction between a user and a d-app is " "verified by all the participants. Starknet is a Layer 2 built on top of " "Ethereum. Instead of having all the participants of the network to verify " -"all user interactions, only one node, called the prover, execute the " -"programs and generate proofs that the computations were done correctly.These " -"proofs are then verified by an Ethereum smart contract, requiring " +"all user interactions, only one node, called the prover, executes the " +"programs and generates proofs that the computations were done correctly. " +"These proofs are then verified by an Ethereum smart contract, requiring " "significantly less computational power compared to executing the " "interactions themselves. This approach allows for increased throughput and " -"reduced transaction costs but preserving Ethereum security." +"reduced transaction costs while preserving Ethereum security." msgstr "" #: src/ch00-00-introduction.md:12 @@ -358,7 +373,7 @@ msgid "" "algorithm for verifying than for computing. Currently, writing custom " "non-deterministic code is not supported for the developers, but the standard " "library leverages non-determinism for improved performance. For example " -"sorting an array in Cairo costs the same price than copying it. Because the " +"sorting an array in Cairo costs the same price as copying it. Because the " "verifier doesn't sort the array, it just checks that it is sorted, which is " "cheaper." msgstr "" @@ -432,7 +447,7 @@ msgstr "" msgid "" "If you wish to install a specific release of Cairo rather than the latest " "head, set the `CAIRO_GIT_TAG` environment variable (e.g. `export " -"CAIRO_GIT_TAG=v1.0.0`)." +"CAIRO_GIT_TAG=v1.1.0`)." msgstr "" #: src/ch01-01-installation.md:22 @@ -656,7 +671,7 @@ msgid "" "# View tags (you can also do this in the cairo compiler repository)\n" "git describe --tags `git rev-list --tags`\n" "# Checkout the version you want\n" -"git checkout tags/v1.0.0\n" +"git checkout tags/v1.1.0\n" "\n" "# Generate release binaries\n" "cargo build --all --release\n" @@ -712,35 +727,40 @@ msgstr "" #: src/ch01-01-installation.md:188 msgid "" -"- Disable previous Cairo 0.x extension\n" +"- If you have the previous Cairo 0 extension installed, you can " +"disable/uninstall it.\n" "- Install the Cairo 1 extension for proper syntax highlighting and code " -"navigation.\n" -" Just follow the steps indicated " -"[here](https://github.com/starkware-libs/cairo/blob/main/vscode-cairo/README.md)." +"navigation. You can find the link to the extension " +"[here](https://marketplace.visualstudio.com/items?itemName=starkware.cairo1&ssr=false), " +"or just search for \"Cairo 1.0\" in the VS Code marketplace.\n" +"- The extension will work out of the box once you will have " +"[Scarb](./ch01-03-hello-scarb.md) installed." msgstr "" #: src/ch01-01-installation.md:192 -msgid "#### Cairo Language Server" +msgid "#### Cairo Language Server without Scarb" msgstr "" #: src/ch01-01-installation.md:194 msgid "" -"From [Step 1](#step-1-install-cairo-10-guide-by-abdel), the " +"If you don't want to depend on Scarb, you can still use the Cairo Language " +"Server with the compiler binary.\n" +"From [Step 1](#installing-cairo-with-a-script-installer-by-fran), the " "`cairo-language-server` binary should be built and executing this command " "will copy its path into your clipboard." msgstr "" -#: src/ch01-01-installation.md:196 +#: src/ch01-01-installation.md:197 msgid "" "```bash\n" "which cairo-language-server | pbcopy\n" "```" msgstr "" -#: src/ch01-01-installation.md:200 +#: src/ch01-01-installation.md:201 msgid "" -"Update the `languageServerPath` of the Cairo 1.0 extension by pasting the " -"path." +"Update the `cairo1.languageServerPath` of the Cairo 1.0 extension by pasting " +"the path." msgstr "" #: src/ch01-02-hello-world.md:1 @@ -768,7 +788,7 @@ msgid "" "developed\n" "> a VSCode extension for the Cairo language that you can use to get the " "features from\n" -"> the language server and code highlighting. See [Appendix B][devtools]\n" +"> the language server and code highlighting. See [Appendix D][devtools]\n" "> for more details." msgstr "" @@ -908,7 +928,7 @@ msgstr "" #: src/ch01-02-hello-world.md:83 msgid "" -"```rust\n" +"```rust,ignore_format\n" "fn main() {\n" "\n" "}\n" @@ -942,7 +962,7 @@ msgid "" "> use the automatic formatter tool called `cairo-format` to format your code " "in a\n" "> particular style (more on `cairo-format` in\n" -"> [Appendix B][devtools]). The Cairo team has included this tool\n" +"> [Appendix D][devtools]). The Cairo team has included this tool\n" "> with the standard Cairo distribution, as `cairo-run` is, so it should " "already be\n" "> installed on your computer!" @@ -1029,7 +1049,8 @@ msgstr "" msgid "" "Scarb handles a lot of tasks for you, such as building your code (either " "pure Cairo or Starknet contracts), downloading the libraries your code " -"depends on, and building those libraries." +"depends on, building those libraries, and provides LSP support for the " +"VSCode Cairo 1 extension." msgstr "" #: src/ch01-03-hello-scarb.md:7 @@ -1064,96 +1085,93 @@ msgid "### Installation" msgstr "" #: src/ch01-03-hello-scarb.md:19 -msgid "As for now, Scarb needs manual installation with the following steps:" +msgid "" +"To install Scarb, please refer to the [installation " +"instructions](https://docs.swmansion.com/scarb/download.html).\n" +"You can simply run the following command in your terminal, then follow the " +"onscreen instructions. This will install the latest stable release." msgstr "" -#: src/ch01-03-hello-scarb.md:21 +#: src/ch01-03-hello-scarb.md:22 +msgid "" +"```bash\n" +"curl --proto '=https' --tlsv1.2 -sSf " +"https://docs.swmansion.com/scarb/install.sh | sh\n" +"```" +msgstr "" + +#: src/ch01-03-hello-scarb.md:26 msgid "" -"- Download the release archive matching your operating system and CPU " -"architecture, from [Scarb releases on " -"GitHub](https://github.com/software-mansion/scarb/releases)\n" -"- Extract it to a location where you would like to have Scarb installed, " -"e.g. `~/scarb`\n" -"- Add path to the `scarb/bin` directory to your `PATH` environment " -"variable.\n" -"\n" -" This depend on what shell you are using. Let’s take the example of " -"[zsh](https://ohmyz.sh/) and you have extracted Scarb to `~/scarb`:\n" -"\n" -" - Open `~/.zshrc` file in your favorite editor\n" -" - Add the following line to the end of the file: `export " -"PATH=\"$PATH:~/scarb/bin\"`\n" -"\n" "- Verify installation by running the following command in new terminal " "session, it should print both Scarb and Cairo language versions, e.g:\n" "\n" " ```bash\n" " $ scarb --version\n" -" scarb 0.1.0 (289137c24 2023-03-28)\n" -" cairo: 1.0.0-alpha.6\n" +" scarb 0.4.0 (f813517bf 2023-06-06)\n" +" cairo: 1.1.0 (43b83560d)\n" " ```" msgstr "" -#: src/ch01-03-hello-scarb.md:38 +#: src/ch01-03-hello-scarb.md:34 msgid "### Creating a Project with Scarb" msgstr "" -#: src/ch01-03-hello-scarb.md:40 +#: src/ch01-03-hello-scarb.md:36 msgid "" "Let’s create a new project using Scarb and look at how it differs from our " "original “Hello, world!” project." msgstr "" -#: src/ch01-03-hello-scarb.md:42 +#: src/ch01-03-hello-scarb.md:38 msgid "" "Navigate back to your projects directory (or wherever you decided to store " "your code). Then run the following:" msgstr "" -#: src/ch01-03-hello-scarb.md:44 +#: src/ch01-03-hello-scarb.md:40 msgid "" "```bash\n" "$ scarb new hello_scarb\n" "```" msgstr "" -#: src/ch01-03-hello-scarb.md:48 +#: src/ch01-03-hello-scarb.md:44 msgid "" "It creates a new directory and project called hello_scarb. We’ve named our " "project hello_scarb, and Scarb creates its files in a directory of the same " "name." msgstr "" -#: src/ch01-03-hello-scarb.md:50 +#: src/ch01-03-hello-scarb.md:46 msgid "" "Go into the hello_scarb directory with the command `cd hello_scarb`. You’ll " "see that Scarb has generated two files and one directory for us: a " "`Scarb.toml` file and a src directory with a `lib.cairo` file inside." msgstr "" -#: src/ch01-03-hello-scarb.md:52 +#: src/ch01-03-hello-scarb.md:48 msgid "" "It has also initialized a new Git repository along with a `.gitignore` file" msgstr "" -#: src/ch01-03-hello-scarb.md:54 +#: src/ch01-03-hello-scarb.md:50 msgid "" "> Note: Git is a common version control system. You can stop using version " "control system by using the `--vcs` flag.\n" "> Run `scarb new -help` to see the available options." msgstr "" -#: src/ch01-03-hello-scarb.md:57 +#: src/ch01-03-hello-scarb.md:53 msgid "" "Open _Scarb.toml_ in your text editor of choice. It should look similar to " "the code in Listing 1-2." msgstr "" -#: src/ch01-03-hello-scarb.md:59 +#: src/ch01-03-hello-scarb.md:55 msgid "Filename: Scarb.toml" msgstr "" -#: src/ch01-03-hello-scarb.md:61 +#: src/ch01-03-hello-scarb.md:57 msgid "" "```toml\n" "[package]\n" @@ -1161,69 +1179,76 @@ msgid "" "version = \"0.1.0\"\n" "\n" "# See more keys and their definitions at " -"https://docs.swmansion.com/scarb/docs/reference/manifest\n" +"https://docs.swmansion.com/scarb/docs/reference/manifest.html\n" "\n" "[dependencies]\n" "# foo = { path = \"vendor/foo\" }\n" "```" msgstr "" -#: src/ch01-03-hello-scarb.md:72 +#: src/ch01-03-hello-scarb.md:68 msgid "" "Listing 1-2: Contents of Scarb.toml generated by " "`scarb new`" msgstr "" -#: src/ch01-03-hello-scarb.md:74 +#: src/ch01-03-hello-scarb.md:70 msgid "" "This file is in the [TOML](https://toml.io/) (Tom’s Obvious, Minimal " "Language) format, which is Scarb’s configuration format." msgstr "" -#: src/ch01-03-hello-scarb.md:76 +#: src/ch01-03-hello-scarb.md:72 msgid "" "The first line, `[package]`, is a section heading that indicates that the " "following statements are configuring a package. As we add more information " "to this file, we’ll add other sections." msgstr "" -#: src/ch01-03-hello-scarb.md:78 +#: src/ch01-03-hello-scarb.md:74 msgid "" "The next two lines set the configuration information Scarb needs to compile " "your program: the name and the version of Scarb to use." msgstr "" -#: src/ch01-03-hello-scarb.md:80 +#: src/ch01-03-hello-scarb.md:76 msgid "" "The last line, `[dependencies]`, is the start of a section for you to list " "any of your project’s dependencies. In Cairo, packages of code are referred " "to as crates. We won’t need any other crates for this project." msgstr "" -#: src/ch01-03-hello-scarb.md:82 +#: src/ch01-03-hello-scarb.md:78 +msgid "" +"> Note: If you're building contracts for Starknet, you will need to add the " +"`starknet` dependency as mentioned in the [Scarb " +"documentation](https://docs.swmansion.com/scarb/docs/starknet/starknet-package.html)." +msgstr "" + +#: src/ch01-03-hello-scarb.md:80 msgid "" "The other file created by Scarb is `src/lib.cairo`, let's delete all the " "content and put in the following content, we will explain the reason later." msgstr "" -#: src/ch01-03-hello-scarb.md:84 +#: src/ch01-03-hello-scarb.md:82 msgid "" "```rust\n" "mod hello_scarb;\n" "```" msgstr "" -#: src/ch01-03-hello-scarb.md:88 +#: src/ch01-03-hello-scarb.md:86 msgid "" "Then create a new file called `src/hello_scarb.cairo` and put the following " "code in it:" msgstr "" -#: src/ch01-03-hello-scarb.md:90 +#: src/ch01-03-hello-scarb.md:88 msgid "Filename: src/hello_scarb.cairo" msgstr "" -#: src/ch01-03-hello-scarb.md:92 +#: src/ch01-03-hello-scarb.md:90 msgid "" "```rust,file=hello_scarb.cairo\n" "use debug::PrintTrait;\n" @@ -1233,19 +1258,19 @@ msgid "" "```" msgstr "" -#: src/ch01-03-hello-scarb.md:99 +#: src/ch01-03-hello-scarb.md:97 msgid "" "We have just created a file called `lib.cairo`, which contains a module " "declaration referencing another module named \"hello_scarb\", as well as the " -"file `hello_scarb.cairo`,containing the implementation details of the " +"file `hello_scarb.cairo`, containing the implementation details of the " "\"hello_scarb\" module." msgstr "" -#: src/ch01-03-hello-scarb.md:101 +#: src/ch01-03-hello-scarb.md:99 msgid "Scarb requires your source files to be located within the src directory." msgstr "" -#: src/ch01-03-hello-scarb.md:103 +#: src/ch01-03-hello-scarb.md:101 msgid "" "The top-level project directory is reserved for README files, license " "information, configuration files, and any other non-code-related content.\n" @@ -1253,7 +1278,7 @@ msgid "" "a structured organization." msgstr "" -#: src/ch01-03-hello-scarb.md:106 +#: src/ch01-03-hello-scarb.md:104 msgid "" "If you started a project that doesn’t use Scarb, as we did with the “Hello, " "world!” project, you can convert it to a project that does use Scarb. Move " @@ -1261,17 +1286,17 @@ msgid "" "`Scarb.toml` file." msgstr "" -#: src/ch01-03-hello-scarb.md:108 +#: src/ch01-03-hello-scarb.md:106 msgid "### Building a Scarb Project" msgstr "" -#: src/ch01-03-hello-scarb.md:110 +#: src/ch01-03-hello-scarb.md:108 msgid "" "From your hello_scarb directory, build your project by entering the " "following command:" msgstr "" -#: src/ch01-03-hello-scarb.md:112 +#: src/ch01-03-hello-scarb.md:110 msgid "" "```bash\n" "$ scarb build\n" @@ -1280,19 +1305,19 @@ msgid "" "```" msgstr "" -#: src/ch01-03-hello-scarb.md:118 +#: src/ch01-03-hello-scarb.md:116 msgid "" "This command creates a `sierra` file in `target/release`, let's ignore the " "`sierra` file for now." msgstr "" -#: src/ch01-03-hello-scarb.md:120 +#: src/ch01-03-hello-scarb.md:118 msgid "" "If you have installed Cairo correctly, you should be able to run and see the " "following output:" msgstr "" -#: src/ch01-03-hello-scarb.md:122 +#: src/ch01-03-hello-scarb.md:120 msgid "" "```bash\n" "$ cairo-run src/lib.cairo\n" @@ -1303,7 +1328,7 @@ msgid "" "```" msgstr "" -#: src/ch01-03-hello-scarb.md:129 +#: src/ch01-03-hello-scarb.md:127 msgid "" "> Note: You will notice here that we didn't use a Scarb command, but rather " "a command from the Cairo binaries directly.\n" @@ -1313,18 +1338,18 @@ msgid "" "Scarb commands to initialize projects." msgstr "" -#: src/ch01-03-hello-scarb.md:133 +#: src/ch01-03-hello-scarb.md:131 msgid "### Defining Custom Scripts" msgstr "" -#: src/ch01-03-hello-scarb.md:135 +#: src/ch01-03-hello-scarb.md:133 msgid "" "We can define Scarb scripts in `Scarb.toml` file, which can be used to " "execute custom shell scripts.\n" "Add the following line to your `Scarb.toml` file:" msgstr "" -#: src/ch01-03-hello-scarb.md:138 +#: src/ch01-03-hello-scarb.md:136 msgid "" "```toml\n" "[scripts]\n" @@ -1332,11 +1357,11 @@ msgid "" "```" msgstr "" -#: src/ch01-03-hello-scarb.md:143 +#: src/ch01-03-hello-scarb.md:141 msgid "Now you can run the following command to run the project:" msgstr "" -#: src/ch01-03-hello-scarb.md:145 +#: src/ch01-03-hello-scarb.md:143 msgid "" "```bash\n" "$ scarb run run-lib\n" @@ -1347,17 +1372,17 @@ msgid "" "```" msgstr "" -#: src/ch01-03-hello-scarb.md:152 +#: src/ch01-03-hello-scarb.md:150 msgid "" "Using `scarb run` is a convenient way to run custom shell scripts that can " "be useful to run files and test your project." msgstr "" -#: src/ch01-03-hello-scarb.md:154 +#: src/ch01-03-hello-scarb.md:152 msgid "Let’s recap what we’ve learned so far about Scarb:" msgstr "" -#: src/ch01-03-hello-scarb.md:156 +#: src/ch01-03-hello-scarb.md:154 msgid "" "- We can create a project using `scarb new`.\n" "- We can build a project using `scarb build` to generate the compiled Sierra " @@ -1366,31 +1391,31 @@ msgid "" "run` command." msgstr "" -#: src/ch01-03-hello-scarb.md:160 +#: src/ch01-03-hello-scarb.md:158 msgid "" "An additional advantage of using Scarb is that the commands are the same no " "matter which operating system you’re working on. So, at this point, we’ll no " "longer provide specific instructions for Linux and macOS versus Windows." msgstr "" -#: src/ch01-03-hello-scarb.md:162 +#: src/ch01-03-hello-scarb.md:160 msgid "# Summary" msgstr "" -#: src/ch01-03-hello-scarb.md:164 +#: src/ch01-03-hello-scarb.md:162 msgid "" "You’re already off to a great start on your Cairo journey! In this chapter, " "you’ve learned how to:" msgstr "" -#: src/ch01-03-hello-scarb.md:166 +#: src/ch01-03-hello-scarb.md:164 msgid "" "- Install the latest stable version of Cairo\n" "- Write and run a “Hello, world!” program using `cairo-run` directly\n" "- Create and run a new project using the conventions of Scarb" msgstr "" -#: src/ch01-03-hello-scarb.md:170 +#: src/ch01-03-hello-scarb.md:168 msgid "" "This is a great time to build a more substantial program to get used to " "reading and writing Cairo code." @@ -1451,33 +1476,33 @@ msgid "" msgstr "" #: src/ch02-01-variables-and-mutability.md:17 -#: src/ch02-01-variables-and-mutability.md:76 -#: src/ch02-01-variables-and-mutability.md:154 +#: src/ch02-01-variables-and-mutability.md:77 +#: src/ch02-01-variables-and-mutability.md:155 #: src/ch02-05-control-flow.md:130 #: src/ch03-02-references-and-snapshots.md:23 -#: src/ch03-02-references-and-snapshots.md:111 +#: src/ch03-02-references-and-snapshots.md:130 #: src/ch04-02-an-example-program-using-structs.md:7 #: src/ch04-02-an-example-program-using-structs.md:48 #: src/ch04-02-an-example-program-using-structs.md:74 -#: src/ch04-02-an-example-program-using-structs.md:106 -#: src/ch04-02-an-example-program-using-structs.md:142 +#: src/ch04-02-an-example-program-using-structs.md:103 +#: src/ch04-02-an-example-program-using-structs.md:136 #: src/ch04-03-method-syntax.md:18 #: src/ch04-03-method-syntax.md:93 #: src/ch04-03-method-syntax.md:135 #: src/ch04-03-method-syntax.md:192 #: src/ch04-03-method-syntax.md:231 #: src/ch06-02-defining-modules-to-control-scope.md:90 -#: src/ch06-02-defining-modules-to-control-scope.md:144 +#: src/ch06-02-defining-modules-to-control-scope.md:143 #: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:15 #: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:62 #: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:10 -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:35 -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:74 -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:131 -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:156 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:36 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:76 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:132 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:206 #: src/ch06-05-separating-modules-into-different-files.md:18 -#: src/ch08-01-how-to-write-tests.md:426 -#: src/ch08-01-how-to-write-tests.md:464 +#: src/ch08-01-how-to-write-tests.md:512 +#: src/ch08-01-how-to-write-tests.md:550 msgid "Filename: src/lib.cairo" msgstr "" @@ -1491,17 +1516,18 @@ msgid "" " x = 6;\n" " x.print();\n" "}\n" +"\n" "```" msgstr "" -#: src/ch02-01-variables-and-mutability.md:29 +#: src/ch02-01-variables-and-mutability.md:30 msgid "" "Save and run the program using `cairo-run src/lib.cairo`. You should receive " "an error message\n" "regarding an immutability error, as shown in this output:" msgstr "" -#: src/ch02-01-variables-and-mutability.md:32 +#: src/ch02-01-variables-and-mutability.md:33 msgid "" "```console\n" "error: Cannot assign to an immutable variable.\n" @@ -1513,7 +1539,7 @@ msgid "" "```" msgstr "" -#: src/ch02-01-variables-and-mutability.md:41 +#: src/ch02-01-variables-and-mutability.md:42 msgid "" "This example shows how the compiler helps you find errors in your programs.\n" "Compiler errors can be frustrating, but really they only mean your program\n" @@ -1522,13 +1548,13 @@ msgid "" "not a good programmer! Experienced Caironautes still get compiler errors." msgstr "" -#: src/ch02-01-variables-and-mutability.md:46 +#: src/ch02-01-variables-and-mutability.md:47 msgid "" "You received the error message `Cannot assign to an immutable variable.`\n" "because you tried to assign a second value to the immutable `x` variable." msgstr "" -#: src/ch02-01-variables-and-mutability.md:49 +#: src/ch02-01-variables-and-mutability.md:50 msgid "" "It’s important that we get compile-time errors when we attempt to change a\n" "value that’s designated as immutable because this specific situation can " @@ -1547,7 +1573,7 @@ msgid "" "easier to reason through." msgstr "" -#: src/ch02-01-variables-and-mutability.md:60 +#: src/ch02-01-variables-and-mutability.md:61 msgid "" "But mutability can be very useful, and can make code more convenient to " "write.\n" @@ -1558,7 +1584,7 @@ msgid "" "will be changing this variable’s value." msgstr "" -#: src/ch02-01-variables-and-mutability.md:66 +#: src/ch02-01-variables-and-mutability.md:67 msgid "" "However, you might be wondering at this point what exactly happens when a " "variable\n" @@ -1575,11 +1601,11 @@ msgid "" "level, the variable is not redeclared so its type cannot change." msgstr "" -#: src/ch02-01-variables-and-mutability.md:74 +#: src/ch02-01-variables-and-mutability.md:75 msgid "For example, let’s change _src/lib.cairo_ to the following:" msgstr "" -#: src/ch02-01-variables-and-mutability.md:78 +#: src/ch02-01-variables-and-mutability.md:79 msgid "" "```rust\n" "use debug::PrintTrait;\n" @@ -1592,11 +1618,11 @@ msgid "" "```" msgstr "" -#: src/ch02-01-variables-and-mutability.md:88 +#: src/ch02-01-variables-and-mutability.md:89 msgid "When we run the program now, we get this:" msgstr "" -#: src/ch02-01-variables-and-mutability.md:90 +#: src/ch02-01-variables-and-mutability.md:91 msgid "" "```console\n" "❯ cairo-run src/lib.cairo\n" @@ -1608,7 +1634,7 @@ msgid "" "```" msgstr "" -#: src/ch02-01-variables-and-mutability.md:99 +#: src/ch02-01-variables-and-mutability.md:100 msgid "" "We’re allowed to change the value bound to `x` from `5` to `6` when `mut` " "is\n" @@ -1617,11 +1643,11 @@ msgid "" "depends on what you think is clearest in that particular situation." msgstr "" -#: src/ch02-01-variables-and-mutability.md:103 +#: src/ch02-01-variables-and-mutability.md:104 msgid "### Constants" msgstr "" -#: src/ch02-01-variables-and-mutability.md:105 +#: src/ch02-01-variables-and-mutability.md:106 msgid "" "Like immutable variables, _constants_ are values that are bound to a name " "and\n" @@ -1630,7 +1656,7 @@ msgid "" "and variables." msgstr "" -#: src/ch02-01-variables-and-mutability.md:109 +#: src/ch02-01-variables-and-mutability.md:110 msgid "" "First, you aren’t allowed to use `mut` with constants. Constants aren’t " "just\n" @@ -1643,13 +1669,13 @@ msgid "" "right now. Just know that you must always annotate the type." msgstr "" -#: src/ch02-01-variables-and-mutability.md:116 +#: src/ch02-01-variables-and-mutability.md:117 msgid "" "Constants can only be declared in the global scope, which makes\n" "them useful for values that many parts of code need to know about." msgstr "" -#: src/ch02-01-variables-and-mutability.md:119 +#: src/ch02-01-variables-and-mutability.md:120 msgid "" "The last difference is that constants may be set only to a constant " "expression,\n" @@ -1658,24 +1684,24 @@ msgid "" "are currently supported." msgstr "" -#: src/ch02-01-variables-and-mutability.md:123 +#: src/ch02-01-variables-and-mutability.md:124 msgid "Here’s an example of a constant declaration:" msgstr "" -#: src/ch02-01-variables-and-mutability.md:125 +#: src/ch02-01-variables-and-mutability.md:126 msgid "" "```rust\n" -"const ONE_HOUR_IN_SECONDS: u32 = 3600_u32;\n" +"const ONE_HOUR_IN_SECONDS: u32 = 3600;\n" "```" msgstr "" -#: src/ch02-01-variables-and-mutability.md:129 +#: src/ch02-01-variables-and-mutability.md:130 msgid "" "Cairo's naming convention for constants is to use all uppercase with\n" "underscores between words." msgstr "" -#: src/ch02-01-variables-and-mutability.md:132 +#: src/ch02-01-variables-and-mutability.md:133 msgid "" "Constants are valid for the entire time a program runs, within the scope in\n" "which they were declared. This property makes constants useful for values " @@ -1687,7 +1713,7 @@ msgid "" "earn, or the speed of light." msgstr "" -#: src/ch02-01-variables-and-mutability.md:138 +#: src/ch02-01-variables-and-mutability.md:139 msgid "" "Naming hardcoded values used throughout your program as constants is useful " "in\n" @@ -1697,11 +1723,11 @@ msgid "" "hardcoded value needed to be updated in the future." msgstr "" -#: src/ch02-01-variables-and-mutability.md:143 +#: src/ch02-01-variables-and-mutability.md:144 msgid "### Shadowing" msgstr "" -#: src/ch02-01-variables-and-mutability.md:145 +#: src/ch02-01-variables-and-mutability.md:146 msgid "" "Variable shadowing refers to the declaration of a\n" "new variable with the same name as a previous variable. Caironautes say that " @@ -1718,9 +1744,9 @@ msgid "" "use of the `let` keyword as follows:" msgstr "" -#: src/ch02-01-variables-and-mutability.md:156 +#: src/ch02-01-variables-and-mutability.md:157 msgid "" -"```swift\n" +"```rust\n" "use debug::PrintTrait;\n" "fn main() {\n" " let x = 5;\n" @@ -1736,7 +1762,7 @@ msgid "" "```" msgstr "" -#: src/ch02-01-variables-and-mutability.md:171 +#: src/ch02-01-variables-and-mutability.md:172 msgid "" "This program first binds `x` to a value of `5`. Then it creates a new " "variable\n" @@ -1751,7 +1777,7 @@ msgid "" "When we run this program, it will output the following:" msgstr "" -#: src/ch02-01-variables-and-mutability.md:179 +#: src/ch02-01-variables-and-mutability.md:180 msgid "" "```console\n" "cairo-run src/lib.cairo\n" @@ -1770,7 +1796,7 @@ msgid "" "```" msgstr "" -#: src/ch02-01-variables-and-mutability.md:193 +#: src/ch02-01-variables-and-mutability.md:194 msgid "" "Shadowing is different from marking a variable as `mut` because we’ll get a\n" "compile-time error if we accidentally try to reassign to this variable " @@ -1782,7 +1808,7 @@ msgid "" "been completed." msgstr "" -#: src/ch02-01-variables-and-mutability.md:199 +#: src/ch02-01-variables-and-mutability.md:200 msgid "" "Another distinction between `mut` and shadowing is that when we use the " "`let` keyword again,\n" @@ -1792,19 +1818,19 @@ msgid "" "and mutable variables\n" "are equivalent at the lower level.\n" "The only difference is that by shadowing a variable, the compiler will not " -"complain \n" +"complain\n" "if you change its type. For example, say our program performs a type " "conversion between the\n" "`u64` and `felt252` types." msgstr "" -#: src/ch02-01-variables-and-mutability.md:207 +#: src/ch02-01-variables-and-mutability.md:208 msgid "" "```rust\n" "use debug::PrintTrait;\n" "use traits::Into;\n" "fn main() {\n" -" let x = 2_u64;\n" +" let x = 2;\n" " x.print();\n" " let x: felt252 = x.into(); // converts x to a felt, type annotation is " "required.\n" @@ -1813,7 +1839,7 @@ msgid "" "```" msgstr "" -#: src/ch02-01-variables-and-mutability.md:218 +#: src/ch02-01-variables-and-mutability.md:219 msgid "" "The first `x` variable has a `u64` type while the second `x` variable has a " "`felt252` type.\n" @@ -1824,13 +1850,13 @@ msgid "" "`mut` for this, as shown here, we’ll get a compile-time error:" msgstr "" -#: src/ch02-01-variables-and-mutability.md:223 +#: src/ch02-01-variables-and-mutability.md:224 msgid "" "```rust,does_not_compile\n" "use debug::PrintTrait;\n" "use traits::Into;\n" "fn main() {\n" -" let mut x = 2_u64;\n" +" let mut x = 2;\n" " x.print();\n" " x = x.into();\n" " x.print()\n" @@ -1838,13 +1864,13 @@ msgid "" "```" msgstr "" -#: src/ch02-01-variables-and-mutability.md:234 +#: src/ch02-01-variables-and-mutability.md:235 msgid "" -"The error says we’re were expecting a `u64` (the original type) but we got a " +"The error says we were expecting a `u64` (the original type) but we got a " "different type:" msgstr "" -#: src/ch02-01-variables-and-mutability.md:236 +#: src/ch02-01-variables-and-mutability.md:237 msgid "" "```console\n" "❯ cairo-run src/lib.cairo\n" @@ -1858,7 +1884,7 @@ msgid "" "```" msgstr "" -#: src/ch02-01-variables-and-mutability.md:246 +#: src/ch02-01-variables-and-mutability.md:247 msgid "" "Now that we’ve explored how variables work, let’s look at more data types " "they\n" @@ -1889,12 +1915,12 @@ msgstr "" #: src/ch02-02-data-types.md:10 msgid "" -"```Rust\n" +"```rust\n" "use traits::TryInto;\n" "use option::OptionTrait;\n" -"fn main(){\n" +"fn main() {\n" " let x: felt252 = 3;\n" -" let y:u32 = x.try_into().unwrap();\n" +" let y: u32 = x.try_into().unwrap();\n" "}\n" "```" msgstr "" @@ -2066,7 +2092,7 @@ msgstr "" msgid "" "```rust\n" "fn main() {\n" -" // addition\n" +" // addition\n" " let sum = 5_u128 + 10_u128;\n" "\n" " // subtraction\n" @@ -2094,16 +2120,15 @@ msgstr "" #: src/ch02-02-data-types.md:120 msgid "" -"\n" -"" +"[Appendix B][appendix_b] contains a list of all operators that Cairo " +"provides." msgstr "" -#: src/ch02-02-data-types.md:123 +#: src/ch02-02-data-types.md:122 msgid "#### The Boolean Type" msgstr "" -#: src/ch02-02-data-types.md:125 +#: src/ch02-02-data-types.md:124 msgid "" "As in most other programming languages, a Boolean type in Cairo has two " "possible\n" @@ -2112,7 +2137,7 @@ msgid "" "Cairo is specified using `bool`. For example:" msgstr "" -#: src/ch02-02-data-types.md:129 +#: src/ch02-02-data-types.md:128 msgid "" "```rust\n" "fn main() {\n" @@ -2123,18 +2148,18 @@ msgid "" "```" msgstr "" -#: src/ch02-02-data-types.md:139 +#: src/ch02-02-data-types.md:136 msgid "" "The main way to use Boolean values is through conditionals, such as an `if`\n" "expression. We’ll cover how `if` expressions work in Cairo in the [“Control\n" "Flow”][control-flow] section." msgstr "" -#: src/ch02-02-data-types.md:143 +#: src/ch02-02-data-types.md:140 msgid "#### The Short String Type" msgstr "" -#: src/ch02-02-data-types.md:145 +#: src/ch02-02-data-types.md:142 msgid "" "Cairo doesn't have a native type for strings, but you can store characters " "forming what we call a \"short string\" inside `felt252`s. A short string " @@ -2144,82 +2169,85 @@ msgid "" "quotes:" msgstr "" -#: src/ch02-02-data-types.md:148 +#: src/ch02-02-data-types.md:145 msgid "" "```rust\n" -"let my_first_char = 'C';\n" -"let my_first_string = 'Hello world';\n" +"# fn main() {\n" +" let my_first_char = 'C';\n" +" let my_first_string = 'Hello world';\n" +"# }\n" "```" msgstr "" -#: src/ch02-02-data-types.md:153 +#: src/ch02-02-data-types.md:152 msgid "### Type casting" msgstr "" -#: src/ch02-02-data-types.md:155 +#: src/ch02-02-data-types.md:154 msgid "" -"In Cairo, you can convert values between common scalar types and `felt252` " +"In Cairo, you can convert types scalar types from one type to another by " "using the `try_into` and `into` methods provided by the `TryInto` and `Into` " "traits, respectively." msgstr "" -#: src/ch02-02-data-types.md:157 +#: src/ch02-02-data-types.md:156 msgid "" "The `try_into` method allows for safe type casting when the target type " "might not fit the source value. Keep in mind that `try_into` returns an " "`Option` type, which you'll need to unwrap to access the new value." msgstr "" -#: src/ch02-02-data-types.md:159 +#: src/ch02-02-data-types.md:158 msgid "" "On the other hand, the `into` method can be used for type casting when " "success is guaranteed, such as when the source type is smaller than the " "destination type." msgstr "" -#: src/ch02-02-data-types.md:161 +#: src/ch02-02-data-types.md:160 msgid "" "To perform the conversion, call `var.into()` or `var.try_into()` on the " "source value to cast it to another type. The new variable's type must be " "explicitly defined, as demonstrated in the example below." msgstr "" -#: src/ch02-02-data-types.md:163 +#: src/ch02-02-data-types.md:162 msgid "" "```rust\n" "use traits::TryInto;\n" "use traits::Into;\n" "use option::OptionTrait;\n" "\n" -"fn main(){\n" -" let my_felt = 10;\n" -" let my_u8: u8 = my_felt.try_into().unwrap(); // Since a felt252 might " -"not fit in a u8, we need to unwrap the Option type\n" -" let my_u16: u16 = my_felt.try_into().unwrap();\n" -" let my_u32: u32 = my_felt.try_into().unwrap();\n" -" let my_u64: u64 = my_felt.try_into().unwrap();\n" -" let my_u128: u128 = my_felt.try_into().unwrap();\n" -" let my_u256: u256 = my_felt.into(); // As a felt252 is smaller than a " -"u256, we can use the into() method\n" -" let my_usize: usize = my_felt.try_into().unwrap();\n" -" let my_felt2: felt252 = my_u8.into();\n" -" let my_felt3: felt252 = my_u16.into();\n" +"fn main() {\n" +" let my_felt252 = 10;\n" +" // Since a felt252 might not fit in a u8, we need to unwrap the " +"Option type\n" +" let my_u8: u8 = my_felt252.try_into().unwrap();\n" +" let my_u16: u16 = my_u8.into();\n" +" let my_u32: u32 = my_u16.into();\n" +" let my_u64: u64 = my_u32.into();\n" +" let my_u128: u128 = my_u64.into();\n" +" // As a felt252 is smaller than a u256, we can use the into() method\n" +" let my_u256: u256 = my_felt252.into();\n" +" let my_usize: usize = my_felt252.try_into().unwrap();\n" +" let my_other_felt252: felt252 = my_u8.into();\n" +" let my_third_felt252: felt252 = my_u16.into();\n" "}\n" "```" msgstr "" -#: src/ch02-02-data-types.md:182 +#: src/ch02-02-data-types.md:183 msgid "### The Tuple Type" msgstr "" -#: src/ch02-02-data-types.md:184 +#: src/ch02-02-data-types.md:185 msgid "" "A _tuple_ is a general way of grouping together a number of values with a\n" "variety of types into one compound type. Tuples have a fixed length: once\n" "declared, they cannot grow or shrink in size." msgstr "" -#: src/ch02-02-data-types.md:188 +#: src/ch02-02-data-types.md:189 msgid "" "We create a tuple by writing a comma-separated list of values inside\n" "parentheses. Each position in the tuple has a type, and the types of the\n" @@ -2228,16 +2256,16 @@ msgid "" "type annotations in this example:" msgstr "" -#: src/ch02-02-data-types.md:193 +#: src/ch02-02-data-types.md:194 msgid "" "```rust\n" "fn main() {\n" -" let tup: (u32,u64,bool) = (10,20,true);\n" +" let tup: (u32, u64, bool) = (10, 20, true);\n" "}\n" "```" msgstr "" -#: src/ch02-02-data-types.md:199 +#: src/ch02-02-data-types.md:200 msgid "" "The variable `tup` binds to the entire tuple because a tuple is considered " "a\n" @@ -2246,7 +2274,7 @@ msgid "" "use pattern matching to destructure a tuple value, like this:" msgstr "" -#: src/ch02-02-data-types.md:203 +#: src/ch02-02-data-types.md:204 msgid "" "```rust\n" "use debug::PrintTrait;\n" @@ -2262,7 +2290,7 @@ msgid "" "```" msgstr "" -#: src/ch02-02-data-types.md:216 +#: src/ch02-02-data-types.md:217 msgid "" "This program first creates a tuple and binds it to the variable `tup`. It " "then\n" @@ -2274,13 +2302,13 @@ msgid "" "`y` is `6`." msgstr "" -#: src/ch02-02-data-types.md:222 +#: src/ch02-02-data-types.md:223 msgid "" -"We can also declare the tuple with value and name at the same time.\n" +"We can also declare the tuple with value and types at the same time.\n" "For example:" msgstr "" -#: src/ch02-02-data-types.md:225 +#: src/ch02-02-data-types.md:226 msgid "" "```rust\n" "fn main() {\n" @@ -2289,11 +2317,11 @@ msgid "" "```" msgstr "" -#: src/ch02-02-data-types.md:231 +#: src/ch02-02-data-types.md:232 msgid "### The unit type ()" msgstr "" -#: src/ch02-02-data-types.md:233 +#: src/ch02-02-data-types.md:234 msgid "" "A _unit type_ is a type which has only one value `()`.\n" "It is represented by a tuple with no elements.\n" @@ -2302,7 +2330,7 @@ msgid "" msgstr "" #: src/ch02-03-functions.md:1 -#: src/ch99-01-02-writing-starknet-contracts.md:134 +#: src/ch99-01-02-writing-starknet-contracts.md:137 msgid "## Functions" msgstr "" @@ -2318,13 +2346,13 @@ msgstr "" #: src/ch02-03-functions.md:8 msgid "" -"Cairo code uses *snake case* as the conventional style for function and " +"Cairo code uses _snake case_ as the conventional style for function and " "variable\n" "names, in which all letters are lowercase and underscores separate words.\n" "Here’s a program that contains an example function definition:" msgstr "" -#: src/ch02-03-functions.md:13 +#: src/ch02-03-functions.md:12 msgid "" "```rust\n" "use debug::PrintTrait;\n" @@ -2340,7 +2368,7 @@ msgid "" "```" msgstr "" -#: src/ch02-03-functions.md:26 +#: src/ch02-03-functions.md:25 msgid "" "We define a function in Cairo by entering `fn` followed by a function name " "and a\n" @@ -2348,7 +2376,7 @@ msgid "" "body begins and ends." msgstr "" -#: src/ch02-03-functions.md:30 +#: src/ch02-03-functions.md:29 msgid "" "We can call any function we’ve defined by entering its name followed by a " "set\n" @@ -2356,22 +2384,22 @@ msgid "" "be\n" "called from inside the `main` function. Note that we defined " "`another_function`\n" -"*before* the `main` function in the source code; we could have defined it " +"_before_ the `main` function in the source code; we could have defined it " "after\n" "as well. Cairo doesn’t care where you define your functions, only that " "they’re\n" "defined somewhere in a scope that can be seen by the caller." msgstr "" -#: src/ch02-03-functions.md:37 +#: src/ch02-03-functions.md:36 msgid "" -"Let’s start a new project with Scarb named *functions* to explore functions\n" -"further. Place the `another_function` example in *src/lib.cairo* and run it. " +"Let’s start a new project with Scarb named _functions_ to explore functions\n" +"further. Place the `another_function` example in _src/lib.cairo_ and run it. " "You\n" "should see the following output:" msgstr "" -#: src/ch02-03-functions.md:41 +#: src/ch02-03-functions.md:40 msgid "" "```console\n" "$ cairo-run src/lib.cairo\n" @@ -2381,7 +2409,7 @@ msgid "" "```" msgstr "" -#: src/ch02-03-functions.md:47 +#: src/ch02-03-functions.md:46 msgid "" "The lines execute in the order in which they appear in the `main` function.\n" "First the “Hello, world!” message prints, and then `another_function` is " @@ -2389,30 +2417,30 @@ msgid "" "and its message is printed." msgstr "" -#: src/ch02-03-functions.md:51 +#: src/ch02-03-functions.md:50 msgid "### Parameters" msgstr "" -#: src/ch02-03-functions.md:53 +#: src/ch02-03-functions.md:52 msgid "" -"We can define functions to have *parameters*, which are special variables " +"We can define functions to have _parameters_, which are special variables " "that\n" "are part of a function’s signature. When a function has parameters, you can\n" "provide it with concrete values for those parameters. Technically, the " "concrete\n" -"values are called *arguments*, but in casual conversation, people tend to " +"values are called _arguments_, but in casual conversation, people tend to " "use\n" -"the words *parameter* and *argument* interchangeably for either the " +"the words _parameter_ and _argument_ interchangeably for either the " "variables\n" "in a function’s definition or the concrete values passed in when you call a\n" "function." msgstr "" -#: src/ch02-03-functions.md:61 +#: src/ch02-03-functions.md:60 msgid "In this version of `another_function` we add a parameter:" msgstr "" -#: src/ch02-03-functions.md:63 +#: src/ch02-03-functions.md:62 msgid "" "```rust\n" "use debug::PrintTrait;\n" @@ -2427,12 +2455,12 @@ msgid "" "```" msgstr "" -#: src/ch02-03-functions.md:75 +#: src/ch02-03-functions.md:74 msgid "Try running this program; you should get the following output:" msgstr "" -#: src/ch02-03-functions.md:77 -#: src/ch02-03-functions.md:250 +#: src/ch02-03-functions.md:76 +#: src/ch02-03-functions.md:276 msgid "" "```console\n" "$ cairo-run src/lib.cairo\n" @@ -2440,7 +2468,7 @@ msgid "" "```" msgstr "" -#: src/ch02-03-functions.md:82 +#: src/ch02-03-functions.md:81 msgid "" "The declaration of `another_function` has one parameter named `x`. The type " "of\n" @@ -2449,9 +2477,9 @@ msgid "" "`.print()` function outputs `5` in the console." msgstr "" -#: src/ch02-03-functions.md:86 +#: src/ch02-03-functions.md:85 msgid "" -"In function signatures, you *must* declare the type of each parameter. This " +"In function signatures, you _must_ declare the type of each parameter. This " "is\n" "a deliberate decision in Cairo’s design: requiring type annotations in " "function\n" @@ -2462,29 +2490,29 @@ msgid "" "more helpful error messages if it knows what types the function expects." msgstr "" -#: src/ch02-03-functions.md:92 +#: src/ch02-03-functions.md:91 msgid "" "When defining multiple parameters, separate the parameter declarations with\n" "commas, like this:" msgstr "" -#: src/ch02-03-functions.md:95 +#: src/ch02-03-functions.md:94 msgid "" "```rust\n" "use debug::PrintTrait;\n" "\n" "fn main() {\n" -" another_function(5,6);\n" +" another_function(5, 6);\n" "}\n" "\n" -"fn another_function(x: felt252, y:felt252) {\n" +"fn another_function(x: felt252, y: felt252) {\n" " x.print();\n" " y.print();\n" "}\n" "```" msgstr "" -#: src/ch02-03-functions.md:108 +#: src/ch02-03-functions.md:107 msgid "" "This example creates a function named `another_function` with two\n" "parameters. The first parameter is named `x` and is an `felt252`. The second " @@ -2493,15 +2521,15 @@ msgid "" "the felt `x` and then the content of the felt `y`." msgstr "" -#: src/ch02-03-functions.md:112 +#: src/ch02-03-functions.md:111 msgid "" "Let’s try running this code. Replace the program currently in your " -"*functions*\n" -"project’s *src/lib.cairo* file with the preceding example and run it using " +"_functions_\n" +"project’s _src/lib.cairo_ file with the preceding example and run it using " "`cairo-run src/lib.cairo`:" msgstr "" -#: src/ch02-03-functions.md:115 +#: src/ch02-03-functions.md:114 msgid "" "```console\n" "$ cairo-run src/lib.cairo\n" @@ -2510,17 +2538,53 @@ msgid "" "```" msgstr "" -#: src/ch02-03-functions.md:121 +#: src/ch02-03-functions.md:120 msgid "" "Because we called the function with `5` as the value for `x` and `6` as\n" "the value for `y`, the program output contains those values." msgstr "" -#: src/ch02-03-functions.md:124 +#: src/ch02-03-functions.md:123 +msgid "#### Named parameters" +msgstr "" + +#: src/ch02-03-functions.md:125 +msgid "" +"In Cairo, named parameters allow you to specify the names of arguments when " +"you call a function. This makes the function calls more readable and " +"self-descriptive.\n" +"If you want to use named parameters, you need to specify the name of the " +"parameter and the value you want to pass to it. The syntax is " +"`parameter_name: value`. If you pass a variable that has the same name as " +"the parameter, you can simply write `:parameter_name` instead of " +"`parameter_name: variable_name`." +msgstr "" + +#: src/ch02-03-functions.md:128 +msgid "Here is an example:" +msgstr "" + +#: src/ch02-03-functions.md:130 +msgid "" +"```rust\n" +"fn foo(x: u8, y: u8) {}\n" +"\n" +"fn main() {\n" +" let first_arg = 3;\n" +" let second_arg = 4;\n" +" foo(x: first_arg, y: second_arg);\n" +" let x = 1;\n" +" let y = 2;\n" +" foo(:x, :y)\n" +"}\n" +"```" +msgstr "" + +#: src/ch02-03-functions.md:143 msgid "### Statements and Expressions" msgstr "" -#: src/ch02-03-functions.md:126 +#: src/ch02-03-functions.md:145 msgid "" "Function bodies are made up of a series of statements optionally ending in " "an\n" @@ -2534,24 +2598,24 @@ msgid "" "of functions." msgstr "" -#: src/ch02-03-functions.md:134 +#: src/ch02-03-functions.md:153 msgid "" -"* **Statements** are instructions that perform some action and do not " +"- **Statements** are instructions that perform some action and do not " "return\n" " a value.\n" -"* **Expressions** evaluate to a resultant value. Let’s look at some examples." +"- **Expressions** evaluate to a resultant value. Let’s look at some examples." msgstr "" -#: src/ch02-03-functions.md:138 +#: src/ch02-03-functions.md:157 msgid "" "We’ve actually already used statements and expressions. Creating a variable " "and\n" "assigning a value to it with the `let` keyword is a statement. In Listing " -"3-1,\n" +"2-1,\n" "`let y = 6;` is a statement." msgstr "" -#: src/ch02-03-functions.md:142 +#: src/ch02-03-functions.md:161 msgid "" "```rust\n" "fn main() {\n" @@ -2560,39 +2624,39 @@ msgid "" "```" msgstr "" -#: src/ch02-03-functions.md:148 +#: src/ch02-03-functions.md:167 msgid "" -"Listing 3-1: A `main` function declaration " +"Listing 2-1: A `main` function declaration " "containing one statement" msgstr "" -#: src/ch02-03-functions.md:150 +#: src/ch02-03-functions.md:169 msgid "" "Function definitions are also statements; the entire preceding example is a\n" "statement in itself." msgstr "" -#: src/ch02-03-functions.md:153 +#: src/ch02-03-functions.md:172 msgid "" "Statements do not return values. Therefore, you can’t assign a `let` " "statement\n" "to another variable, as the following code tries to do; you’ll get an error:" msgstr "" -#: src/ch02-03-functions.md:156 +#: src/ch02-03-functions.md:175 msgid "" -"```rust,does_not_compile\n" +"```rust,does_not_compile,ignore_format\n" "fn main() {\n" " let x = (let y = 6);\n" "}\n" "```" msgstr "" -#: src/ch02-03-functions.md:161 +#: src/ch02-03-functions.md:181 msgid "When you run this program, the error you’ll get looks like this:" msgstr "" -#: src/ch02-03-functions.md:162 +#: src/ch02-03-functions.md:183 msgid "" "```console\n" "$ cairo-run src/lib.cairo\n" @@ -2617,7 +2681,7 @@ msgid "" "```" msgstr "" -#: src/ch02-03-functions.md:184 +#: src/ch02-03-functions.md:205 msgid "" "The `let y = 6` statement does not return a value, so there isn’t anything " "for\n" @@ -2630,20 +2694,20 @@ msgid "" "`6`; that is not the case in Cairo." msgstr "" -#: src/ch02-03-functions.md:190 +#: src/ch02-03-functions.md:211 msgid "" "Expressions evaluate to a value and make up most of the rest of the code " "that\n" "you’ll write in Cairo. Consider a math operation, such as `5 + 6`, which is " "an\n" "expression that evaluates to the value `11`. Expressions can be part of\n" -"statements: in Listing 3-1, the `6` in the statement `let y = 6;` is an\n" +"statements: in Listing 2-1, the `6` in the statement `let y = 6;` is an\n" "expression that evaluates to the value `6`. Calling a function is an\n" "expression. A new scope block created with\n" "curly brackets is an expression, for example:" msgstr "" -#: src/ch02-03-functions.md:199 +#: src/ch02-03-functions.md:219 msgid "" "```rust\n" "use debug::PrintTrait;\n" @@ -2658,21 +2722,21 @@ msgid "" "```" msgstr "" -#: src/ch02-03-functions.md:211 +#: src/ch02-03-functions.md:231 msgid "This expression:" msgstr "" -#: src/ch02-03-functions.md:212 +#: src/ch02-03-functions.md:233 msgid "" -"```rust\n" +"```rust, does_not_compile, ignore_format\n" "{\n" -" let x = 3;\n" -" x + 1\n" +" let x = 3;\n" +" x + 1\n" "}\n" "```" msgstr "" -#: src/ch02-03-functions.md:218 +#: src/ch02-03-functions.md:240 msgid "" "is a block that, in this case, evaluates to `4`. That value gets bound to " "`y`\n" @@ -2687,11 +2751,11 @@ msgid "" "next." msgstr "" -#: src/ch02-03-functions.md:225 +#: src/ch02-03-functions.md:248 msgid "### Functions with Return Values" msgstr "" -#: src/ch02-03-functions.md:226 +#: src/ch02-03-functions.md:250 msgid "" "Functions can return values to the code that calls them. We don’t name " "return\n" @@ -2704,13 +2768,13 @@ msgid "" "function that returns a value:" msgstr "" -#: src/ch02-03-functions.md:234 +#: src/ch02-03-functions.md:258 msgid "" "```rust\n" "use debug::PrintTrait;\n" "\n" "fn five() -> u32 {\n" -" 5_u32\n" +" 5\n" "}\n" "\n" "fn main() {\n" @@ -2720,7 +2784,7 @@ msgid "" "```" msgstr "" -#: src/ch02-03-functions.md:246 +#: src/ch02-03-functions.md:271 msgid "" "There are no function calls, or even `let` statements in the `five`\n" "function—just the number `5` by itself. That’s a perfectly valid function " @@ -2730,7 +2794,7 @@ msgid "" "running this code; the output should look like this:" msgstr "" -#: src/ch02-03-functions.md:254 +#: src/ch02-03-functions.md:281 msgid "" "The `5` in `five` is the function’s return value, which is why the return " "type\n" @@ -2742,14 +2806,14 @@ msgid "" "that line is the same as the following:" msgstr "" -#: src/ch02-03-functions.md:259 +#: src/ch02-03-functions.md:287 msgid "" -"```rust\n" +"```rust, does_not_compile\n" "let x = 5;\n" "```" msgstr "" -#: src/ch02-03-functions.md:262 +#: src/ch02-03-functions.md:291 msgid "" "Second, the `five` function has no parameters and defines the type of the\n" "return value, but the body of the function is a lonely `5` with no " @@ -2758,24 +2822,24 @@ msgid "" "Let’s look at another example:" msgstr "" -#: src/ch02-03-functions.md:267 +#: src/ch02-03-functions.md:296 msgid "" "```rust\n" "use debug::PrintTrait;\n" "\n" "fn main() {\n" -" let x = plus_one(5_u32);\n" +" let x = plus_one(5);\n" "\n" " x.print();\n" "}\n" "\n" "fn plus_one(x: u32) -> u32 {\n" -" x + 1_u32\n" +" x + 1\n" "}\n" "```" msgstr "" -#: src/ch02-03-functions.md:280 +#: src/ch02-03-functions.md:310 msgid "" "Running this code will print `[DEBUG] (raw: 6)`. But if " "we place a\n" @@ -2783,28 +2847,28 @@ msgid "" "expression to a statement, we’ll get an error:" msgstr "" -#: src/ch02-03-functions.md:284 +#: src/ch02-03-functions.md:314 msgid "" "```rust,does_not_compile\n" "use debug::PrintTrait;\n" "\n" "fn main() {\n" -" let x = plus_one(5_u32);\n" +" let x = plus_one(5);\n" "\n" " x.print();\n" "}\n" "\n" "fn plus_one(x: u32) -> u32 {\n" -" x + 1_u32;\n" +" x + 1;\n" "}\n" "```" msgstr "" -#: src/ch02-03-functions.md:298 +#: src/ch02-03-functions.md:328 msgid "Compiling this code produces an error, as follows:" msgstr "" -#: src/ch02-03-functions.md:299 +#: src/ch02-03-functions.md:330 msgid "" "```console\n" "error: Unexpected return type. Expected: \"core::integer::u32\", found: " @@ -2812,7 +2876,7 @@ msgid "" "```" msgstr "" -#: src/ch02-03-functions.md:302 +#: src/ch02-03-functions.md:334 msgid "" "The main error message, `Unexpected return type`, reveals the core issue " "with this\n" @@ -2922,7 +2986,7 @@ msgstr "" #: src/ch02-05-control-flow.md:38 msgid "" -"```rust\n" +"```rust, does_not_compile\n" " let number = 5;\n" "```" msgstr "" @@ -3090,13 +3154,13 @@ msgstr "" #: src/ch02-05-control-flow.md:132 msgid "" -"```rust,ignore,does_not_compile\n" +"```rust\n" "use debug::PrintTrait;\n" "fn main() {\n" -" let mut i:usize = 0;\n" +" let mut i: usize = 0;\n" " loop {\n" -" if i > 10{\n" -" break();\n" +" if i > 10 {\n" +" break ();\n" " }\n" " 'again!'.print();\n" " }\n" @@ -3111,7 +3175,7 @@ msgid "" "until we stop the program manually, because the stop condition is never " "reached.\n" "While the compiler prevents us from writing programs without a stop " -"condition (`break()` statement),\n" +"condition (`break` statement),\n" "the stop condition might never be reached, resulting in an infinite loop.\n" "Most terminals support the keyboard shortcut ctrl-c to interrupt a program that is\n" @@ -3154,8 +3218,8 @@ msgstr "" #: src/ch02-05-control-flow.md:170 msgid "" -"To break out of a loop, you can place the `break()` statement within the " -"loop to tell the program when to stop\n" +"To break out of a loop, you can place the `break` statement within the loop " +"to tell the program when to stop\n" "executing the loop. Let's fix the infinite loop by adding a making the stop " "condition `i > 10` reachable." msgstr "" @@ -3178,11 +3242,46 @@ msgid "" msgstr "" #: src/ch02-05-control-flow.md:187 -msgid "#### Returning Values from Loops" +msgid "" +"The `continue` keyword tells the program to go to the next iteration of the " +"loop and to skip the rest of the code in this iteration. Let's add a " +"`continue` statement to our loop to skip the `print` statement when `i` is " +"equal to `5`." msgstr "" #: src/ch02-05-control-flow.md:189 msgid "" +"```rust\n" +"use debug::PrintTrait;\n" +"fn main() {\n" +" let mut i: usize = 0;\n" +" loop {\n" +" if i > 10 {\n" +" break ();\n" +" }\n" +" if i == 5 {\n" +" i += 1;\n" +" continue;\n" +" }\n" +" i.print();\n" +" i += 1;\n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src/ch02-05-control-flow.md:207 +msgid "" +"Executing this program will not print the value of `i` when it is equal to " +"`5`." +msgstr "" + +#: src/ch02-05-control-flow.md:209 +msgid "#### Returning Values from Loops" +msgstr "" + +#: src/ch02-05-control-flow.md:211 +msgid "" "One of the uses of a `loop` is to retry an operation you know might fail, " "such\n" "as checking whether an operation has succeeded. You might also need to pass\n" @@ -3195,7 +3294,7 @@ msgid "" "use it, as shown here:" msgstr "" -#: src/ch02-05-control-flow.md:196 +#: src/ch02-05-control-flow.md:218 msgid "" "```rust\n" "use debug::PrintTrait;\n" @@ -3215,7 +3314,7 @@ msgid "" "```" msgstr "" -#: src/ch02-05-control-flow.md:213 +#: src/ch02-05-control-flow.md:235 msgid "" "Before the loop, we declare a variable named `counter` and initialize it to\n" "`0`. Then we declare a variable named `result` to hold the value returned " @@ -3267,7 +3366,7 @@ msgstr "" #: src/ch02-06-common-collections.md:14 msgid "" "Creating an Array is done with the `ArrayTrait::new()` call. Here is an " -"example of creation of an array with 3 elements:" +"example of the creation of an array to which we append 3 elements:" msgstr "" #: src/ch02-06-common-collections.md:16 @@ -3292,7 +3391,7 @@ msgstr "" #: src/ch02-06-common-collections.md:29 msgid "" -"```rust,\n" +"```rust, does_not_compile\n" "let mut arr = ArrayTrait::::new();\n" "```" msgstr "" @@ -3313,26 +3412,30 @@ msgstr "" #: src/ch02-06-common-collections.md:39 msgid "" "```rust\n" -" let mut a = ArrayTrait::new();\n" -" a.append(10);\n" -" a.append(1);\n" -" a.append(2);\n" +"# use array::ArrayTrait;\n" +"# \n" +"# fn main() {\n" +"# let mut a = ArrayTrait::new();\n" +" a.append(0);\n" +"# a.append(1);\n" +"# a.append(2);\n" +"# }\n" "```" msgstr "" -#: src/ch02-06-common-collections.md:46 +#: src/ch02-06-common-collections.md:50 msgid "##### Removing Elements" msgstr "" -#: src/ch02-06-common-collections.md:48 +#: src/ch02-06-common-collections.md:52 msgid "" -"To remove an element from the front of an array, you can use the " +"You can only remove elements from the front of an array by using the " "`pop_front()` method.\n" "This method returns an `Option` containing the removed element, or " "`Option::None` if the array is empty." msgstr "" -#: src/ch02-06-common-collections.md:51 +#: src/ch02-06-common-collections.md:55 msgid "" "```rust\n" "use option::OptionTrait;\n" @@ -3351,12 +3454,12 @@ msgid "" "```" msgstr "" -#: src/ch02-06-common-collections.md:67 +#: src/ch02-06-common-collections.md:71 msgid "" "The above code will print `10` as we remove the first element that was added." msgstr "" -#: src/ch02-06-common-collections.md:69 +#: src/ch02-06-common-collections.md:73 msgid "" "In Cairo, memory is immutable, which means that it is not possible to modify " "the elements of an array once they've been added. You can only add elements " @@ -3365,18 +3468,18 @@ msgid "" "rather than directly modifying the memory cells." msgstr "" -#: src/ch02-06-common-collections.md:71 +#: src/ch02-06-common-collections.md:75 msgid "#### Reading Elements from an Array" msgstr "" -#: src/ch02-06-common-collections.md:73 +#: src/ch02-06-common-collections.md:77 msgid "" "To access array elements, you can use `get()` or `at()` array methods that " "return different types. Using `arr.at(index)` is equivalent to using the " "subscripting operator `arr[index]`." msgstr "" -#: src/ch02-06-common-collections.md:75 +#: src/ch02-06-common-collections.md:79 msgid "" "The `get` function returns an `Option>`, which means it returns an " "option to a Box type (Cairo's smart-pointer type) containing a snapshot to " @@ -3388,7 +3491,7 @@ msgid "" "Snapshots](ch03-02-references-and-snapshots.md) chapter." msgstr "" -#: src/ch02-06-common-collections.md:77 +#: src/ch02-06-common-collections.md:81 msgid "" "The `at` function, on the other hand, directly returns a snapshot to the " "element at the specified index using the `unbox()` operator to extract the " @@ -3397,14 +3500,14 @@ msgid "" "index is out of the array's bounds, which can prevent unexpected behavior." msgstr "" -#: src/ch02-06-common-collections.md:79 +#: src/ch02-06-common-collections.md:83 msgid "" "In summary, use `at` when you want to panic on out-of-bounds access " "attempts, and use `get` when you prefer to handle such cases gracefully " "without panicking." msgstr "" -#: src/ch02-06-common-collections.md:81 +#: src/ch02-06-common-collections.md:85 msgid "" "```rust\n" "use array::ArrayTrait;\n" @@ -3413,13 +3516,13 @@ msgid "" " a.append(0);\n" " a.append(1);\n" "\n" -" let first = *a.at(0_usize);\n" -" let second = *a.at(1_usize);\n" +" let first = *a.at(0);\n" +" let second = *a.at(1);\n" "}\n" "```" msgstr "" -#: src/ch02-06-common-collections.md:93 +#: src/ch02-06-common-collections.md:97 msgid "" "In this example, the variable named `first` will get the value `0` because " "that\n" @@ -3428,27 +3531,28 @@ msgid "" "the value `1` from index `1` in the array." msgstr "" -#: src/ch02-06-common-collections.md:97 +#: src/ch02-06-common-collections.md:101 msgid "Here is an example with the `get()` method:" msgstr "" -#: src/ch02-06-common-collections.md:99 +#: src/ch02-06-common-collections.md:103 msgid "" -"```rust\n" +"```rust,ignore_format\n" "use array::ArrayTrait;\n" "use box::BoxTrait;\n" "fn main() -> u128 {\n" " let mut arr = ArrayTrait::::new();\n" -" arr.append(100_u128);\n" +" arr.append(100);\n" " let index_to_access =\n" -" 1_usize; // Change this value to see different results, what " -"would happen if the index doesn't exist ?\n" +" 1; // Change this value to see different results, what would happen " +"if the index doesn't exist?\n" " match arr.get(index_to_access) {\n" " Option::Some(x) => {\n" -" *x.unbox() // Don't worry about * for now, if you are curious " -"see Chapter 3.2 #desnap operator\n" -" // It basically means \"transform what get(idx) " -"returned into a real value\"\n" +" *x.unbox()\n" +" // Don't worry about * for now, if you are curious see Chapter 3.2 " +"#desnap operator\n" +" // It basically means \"transform what get(idx) returned into a real " +"value\"\n" " },\n" " Option::None(_) => {\n" " let mut data = ArrayTrait::new();\n" @@ -3460,34 +3564,34 @@ msgid "" "```" msgstr "" -#: src/ch02-06-common-collections.md:121 +#: src/ch02-06-common-collections.md:126 msgid "#### Size related methods" msgstr "" -#: src/ch02-06-common-collections.md:123 +#: src/ch02-06-common-collections.md:128 msgid "" "To determine the number of elements in an array, use the `len()` method. The " "return is of type `usize`." msgstr "" -#: src/ch02-06-common-collections.md:125 +#: src/ch02-06-common-collections.md:130 msgid "" "If you want to check if an array is empty or not, you can use the " "`is_empty()` method, which returns `true` if the array is empty and `false` " "otherwise." msgstr "" -#: src/ch02-06-common-collections.md:127 +#: src/ch02-06-common-collections.md:132 msgid "#### Storing multiple types with Enums" msgstr "" -#: src/ch02-06-common-collections.md:129 +#: src/ch02-06-common-collections.md:134 msgid "" "If you want to store elements of different types in an array, you can use an " "`Enum` to define a custom data type that can hold multiple types." msgstr "" -#: src/ch02-06-common-collections.md:131 +#: src/ch02-06-common-collections.md:136 msgid "" "```rust\n" "use array::ArrayTrait;\n" @@ -3502,18 +3606,18 @@ msgid "" "\n" "fn main() {\n" " let mut messages: Array = ArrayTrait::new();\n" -" messages.append(Data::Integer(100_u128));\n" +" messages.append(Data::Integer(100));\n" " messages.append(Data::Felt('hello world'));\n" -" messages.append(Data::Tuple((10_u32, 30_u32)));\n" +" messages.append(Data::Tuple((10, 30)));\n" "}\n" "```" msgstr "" -#: src/ch02-06-common-collections.md:150 +#: src/ch02-06-common-collections.md:155 msgid "#### Span" msgstr "" -#: src/ch02-06-common-collections.md:152 +#: src/ch02-06-common-collections.md:157 msgid "" "`Span` is a struct that represents a snapshot of an `Array`. It is designed " "to provide safe and controlled access to the elements of an array without " @@ -3523,34 +3627,39 @@ msgid "" "Snapshots](ch03-02-references-and-snapshots.md))" msgstr "" -#: src/ch02-06-common-collections.md:154 +#: src/ch02-06-common-collections.md:159 msgid "" "All methods provided by `Array` can also be used with `Span`, with the " "exception of the `append()` method." msgstr "" -#: src/ch02-06-common-collections.md:156 +#: src/ch02-06-common-collections.md:161 msgid "##### Turning an Array into span" msgstr "" -#: src/ch02-06-common-collections.md:158 +#: src/ch02-06-common-collections.md:163 msgid "To create a `Span` of an `Array`, call the `span()` method:" msgstr "" -#: src/ch02-06-common-collections.md:160 +#: src/ch02-06-common-collections.md:165 msgid "" "```rust\n" -"let span = array.span();\n" +"# use array::ArrayTrait;\n" +"# \n" +"# fn main() {\n" +"# let mut array = ArrayTrait::new();\n" +" array.span()\n" +"# }\n" "```" msgstr "" -#: src/ch02-06-common-collections.md:164 +#: src/ch02-06-common-collections.md:174 #: src/ch04-03-method-syntax.md:286 -#: src/ch06-05-separating-modules-into-different-files.md:98 +#: src/ch06-05-separating-modules-into-different-files.md:99 msgid "## Summary" msgstr "" -#: src/ch02-06-common-collections.md:166 +#: src/ch02-06-common-collections.md:176 msgid "" "You made it! This was a sizable chapter: you learned about variables, data " "types, functions, comments,\n" @@ -3559,13 +3668,13 @@ msgid "" "try building programs to do the following:" msgstr "" -#: src/ch02-06-common-collections.md:170 +#: src/ch02-06-common-collections.md:180 msgid "" "- Generate the _n_-th Fibonacci number.\n" "- Compute the factorial of a number _n_." msgstr "" -#: src/ch02-06-common-collections.md:173 +#: src/ch02-06-common-collections.md:183 msgid "" "When you’re ready to move on, we’ll talk about a concept that Cairo shares " "with Rust and that _doesn’t_\n" @@ -3669,33 +3778,35 @@ msgstr "" #: src/ch03-01-what-is-ownership.md:39 msgid "" "```rust\n" +"# fn main() {\n" " { // s is not valid here, it’s not yet declared\n" " let s = 'hello'; // s is valid from this point forward\n" "\n" " // do stuff with s\n" " } // this scope is now over, and s is no longer " "valid\n" +"# }\n" "```" msgstr "" -#: src/ch03-01-what-is-ownership.md:47 +#: src/ch03-01-what-is-ownership.md:49 msgid "" "Listing 3-1: A variable and the scope in which it " "is\n" "valid" msgstr "" -#: src/ch03-01-what-is-ownership.md:50 +#: src/ch03-01-what-is-ownership.md:52 msgid "In other words, there are two important points in time here:" msgstr "" -#: src/ch03-01-what-is-ownership.md:52 +#: src/ch03-01-what-is-ownership.md:54 msgid "" "- When `s` comes _into_ scope, it is valid.\n" "- It remains valid until it goes _out of_ scope." msgstr "" -#: src/ch03-01-what-is-ownership.md:55 +#: src/ch03-01-what-is-ownership.md:57 msgid "" "At this point, the relationship between scopes and when variables are valid " "is\n" @@ -3705,11 +3816,11 @@ msgid "" "chapter](ch02-06-common-collections.md)." msgstr "" -#: src/ch03-01-what-is-ownership.md:59 +#: src/ch03-01-what-is-ownership.md:61 msgid "### Ownership with the `Array` Type" msgstr "" -#: src/ch03-01-what-is-ownership.md:61 +#: src/ch03-01-what-is-ownership.md:63 msgid "" "To illustrate the rules of ownership, we need a data type that is more " "complex.\n" @@ -3720,23 +3831,26 @@ msgid "" "easily\n" "be dropped when they're no longer used. But what is the behavior with the " "`Array` type whose size\n" -"is unknown at compile time and which can't be trivially copied ?" +"is unknown at compile time and which can't be trivially copied?" msgstr "" -#: src/ch03-01-what-is-ownership.md:69 +#: src/ch03-01-what-is-ownership.md:71 msgid "Here is a short reminder of what an array looks like:" msgstr "" -#: src/ch03-01-what-is-ownership.md:71 +#: src/ch03-01-what-is-ownership.md:73 msgid "" "```rust\n" -"let mut arr = ArrayTrait::::new();\n" -"arr.append(1);\n" -"arr.append(2);\n" +"# use array::ArrayTrait;\n" +"# fn main() {\n" +" let mut arr = ArrayTrait::::new();\n" +" arr.append(1);\n" +" arr.append(2);\n" +"# }\n" "```" msgstr "" -#: src/ch03-01-what-is-ownership.md:77 +#: src/ch03-01-what-is-ownership.md:82 msgid "" "So, how does the ownership system ensure that each cell is never written to " "more than once?\n" @@ -3745,15 +3859,13 @@ msgid "" "function calls:" msgstr "" -#: src/ch03-01-what-is-ownership.md:81 +#: src/ch03-01-what-is-ownership.md:86 msgid "" "```rust,does_not_compile\n" "use array::ArrayTrait;\n" -"fn foo(arr: Array) {\n" -"}\n" +"fn foo(arr: Array) {}\n" "\n" -"fn bar(arr:Array){\n" -"}\n" +"fn bar(arr: Array) {}\n" "\n" "fn main() {\n" " let mut arr = ArrayTrait::::new();\n" @@ -3763,7 +3875,7 @@ msgid "" "```" msgstr "" -#: src/ch03-01-what-is-ownership.md:96 +#: src/ch03-01-what-is-ownership.md:99 msgid "" "In this case, we try to pass the same array instance `arr` by value to the " "functions `foo` and `bar`, which means\n" @@ -3780,11 +3892,11 @@ msgid "" "system thus prevents us from using the same instance of `arr` in `foo`." msgstr "" -#: src/ch03-01-what-is-ownership.md:104 +#: src/ch03-01-what-is-ownership.md:107 msgid "Running the code above will result in a compile-time error:" msgstr "" -#: src/ch03-01-what-is-ownership.md:106 +#: src/ch03-01-what-is-ownership.md:109 msgid "" "```console\n" "error: Variable was previously moved. Trait has no implementation in " @@ -3795,11 +3907,11 @@ msgid "" "```" msgstr "" -#: src/ch03-01-what-is-ownership.md:113 +#: src/ch03-01-what-is-ownership.md:116 msgid "### The `Copy` Trait" msgstr "" -#: src/ch03-01-what-is-ownership.md:115 +#: src/ch03-01-what-is-ownership.md:118 msgid "" "If a type implements the `Copy` trait, passing it to a function will not " "move the ownership of the value to the function called, but will instead " @@ -3812,9 +3924,9 @@ msgid "" "contain either of them can be." msgstr "" -#: src/ch03-01-what-is-ownership.md:119 +#: src/ch03-01-what-is-ownership.md:122 msgid "" -"```rust\n" +"```rust,ignore_format\n" "#[derive(Copy, Drop)]\n" "struct Point {\n" " x: u128,\n" @@ -3833,7 +3945,7 @@ msgid "" "```" msgstr "" -#: src/ch03-01-what-is-ownership.md:137 +#: src/ch03-01-what-is-ownership.md:140 msgid "" "In this example, we can pass `p1` twice to the foo function because the " "`Point` type implements the `Copy` trait. This means that when we pass `p1` " @@ -3843,17 +3955,17 @@ msgid "" "get a compile-time error when trying to compile the code." msgstr "" -#: src/ch03-01-what-is-ownership.md:140 +#: src/ch03-01-what-is-ownership.md:143 msgid "" "_Don't worry about the `Struct` keyword. We will introduce this in [Chapter " "4](ch04-00-using-structs-to-structure-related-data.md)._" msgstr "" -#: src/ch03-01-what-is-ownership.md:142 +#: src/ch03-01-what-is-ownership.md:145 msgid "### The `Drop` Trait" msgstr "" -#: src/ch03-01-what-is-ownership.md:144 +#: src/ch03-01-what-is-ownership.md:147 msgid "" "You may have noticed that the `Point` type in the previous example also " "implements the `Drop` trait. In Cairo, a value cannot go out of scope unless " @@ -3862,7 +3974,7 @@ msgid "" "not moved before it goes out of scope:" msgstr "" -#: src/ch03-01-what-is-ownership.md:147 +#: src/ch03-01-what-is-ownership.md:150 msgid "" "```rust,does_not_compile\n" "struct A {}\n" @@ -3873,7 +3985,7 @@ msgid "" "```" msgstr "" -#: src/ch03-01-what-is-ownership.md:155 +#: src/ch03-01-what-is-ownership.md:158 msgid "" "This is to ensure the soundness of Cairo programs. Soundness refers to the " "fact that if a\n" @@ -3883,15 +3995,15 @@ msgid "" "consistency of\n" "consecutive dictionary key updates during program execution, which is only " "checked when\n" -"the dictionaries are`squashed` - which moves the ownership of the dictionary " -"to the\n" +"the dictionaries are `squashed` - which moves the ownership of the " +"dictionary to the\n" "`squash` method, thus allowing the dictionary to go out of scope. Unsquashed " "dictionaries\n" "are dangerous, as a malicious prover could prove the correctness of " "inconsistent updates." msgstr "" -#: src/ch03-01-what-is-ownership.md:163 +#: src/ch03-01-what-is-ownership.md:166 msgid "" "However, types that implement the `Drop` trait are allowed to go out of " "scope without being explicitly moved. When a value of a type that implements " @@ -3903,15 +4015,15 @@ msgid "" "go out of scope." msgstr "" -#: src/ch03-01-what-is-ownership.md:166 +#: src/ch03-01-what-is-ownership.md:169 msgid "" "The `Drop` implementation can be derived for all types, allowing them to be " -"dropped when goint out of scope, except for dictionaries (`Felt252Dict`) and " +"dropped when going out of scope, except for dictionaries (`Felt252Dict`) and " "types containing dictionaries.\n" "For example, the following code compiles:" msgstr "" -#: src/ch03-01-what-is-ownership.md:169 +#: src/ch03-01-what-is-ownership.md:172 msgid "" "```rust\n" "#[derive(Drop)]\n" @@ -3923,11 +4035,11 @@ msgid "" "```" msgstr "" -#: src/ch03-01-what-is-ownership.md:178 +#: src/ch03-01-what-is-ownership.md:181 msgid "### The `Destruct` Trait" msgstr "" -#: src/ch03-01-what-is-ownership.md:180 +#: src/ch03-01-what-is-ownership.md:183 msgid "" "Manually calling the `squash` method on a dictionary is not very convenient, " "and it is easy to forget to do so. To make it easier to use dictionaries, " @@ -3939,13 +4051,13 @@ msgid "" "`squash` method." msgstr "" -#: src/ch03-01-what-is-ownership.md:182 +#: src/ch03-01-what-is-ownership.md:185 msgid "" "Consider the following example, in which we define a custom type that " "contains a dictionary:" msgstr "" -#: src/ch03-01-what-is-ownership.md:184 +#: src/ch03-01-what-is-ownership.md:187 msgid "" "```rust,does_not_compile\n" "use dict::Felt252DictTrait;\n" @@ -3955,18 +4067,16 @@ msgid "" "}\n" "\n" "fn main() {\n" -" A {\n" -" dict: Felt252DictTrait::new()\n" -" };\n" +" A { dict: Felt252DictTrait::new() };\n" "}\n" "```" msgstr "" -#: src/ch03-01-what-is-ownership.md:198 +#: src/ch03-01-what-is-ownership.md:199 msgid "If you try to run this code, you will get a compile-time error:" msgstr "" -#: src/ch03-01-what-is-ownership.md:200 +#: src/ch03-01-what-is-ownership.md:201 msgid "" "```console\n" "error: Variable not dropped. Trait has no implementation in context: " @@ -3978,7 +4088,7 @@ msgid "" "```" msgstr "" -#: src/ch03-01-what-is-ownership.md:207 +#: src/ch03-01-what-is-ownership.md:208 msgid "" "When A goes out of scope, it can't be dropped as it implements neither the " "`Drop` (as it contains a dictionary and can't `derive(Drop)`) nor the " @@ -3986,7 +4096,7 @@ msgid "" "implementation for the `A` type:" msgstr "" -#: src/ch03-01-what-is-ownership.md:209 +#: src/ch03-01-what-is-ownership.md:210 msgid "" "```rust\n" "use dict::Felt252DictTrait;\n" @@ -3997,24 +4107,22 @@ msgid "" "}\n" "\n" "fn main() {\n" -" A {\n" -" dict: Felt252DictTrait::new()\n" -" }; // No error here\n" +" A { dict: Felt252DictTrait::new() }; // No error here\n" "}\n" "```" msgstr "" -#: src/ch03-01-what-is-ownership.md:224 +#: src/ch03-01-what-is-ownership.md:223 msgid "" "Now, when `A` goes out of scope, its dictionary will be automatically " "`squashed`, and the program will compile." msgstr "" -#: src/ch03-01-what-is-ownership.md:226 +#: src/ch03-01-what-is-ownership.md:225 msgid "### Copy Array data with Clone" msgstr "" -#: src/ch03-01-what-is-ownership.md:228 +#: src/ch03-01-what-is-ownership.md:227 msgid "" "If we _do_ want to deeply copy the data of an `Array`, we can use a common " "method called `clone`. We’ll discuss method syntax in Chapter 5, but because " @@ -4022,38 +4130,38 @@ msgid "" "programming languages, you’ve probably seen them before." msgstr "" -#: src/ch03-01-what-is-ownership.md:231 +#: src/ch03-01-what-is-ownership.md:230 msgid "Here’s an example of the `clone` method in action." msgstr "" -#: src/ch03-01-what-is-ownership.md:233 +#: src/ch03-01-what-is-ownership.md:232 msgid "" "> Note: in the following example, we need to import the `Clone` trait from " "the corelib `clone` module, and its implementation for the array type from " "the `array` module." msgstr "" -#: src/ch03-01-what-is-ownership.md:235 +#: src/ch03-01-what-is-ownership.md:234 msgid "" "```rust\n" "use array::ArrayTrait;\n" "use clone::Clone;\n" "use array::ArrayTCloneImpl;\n" -"...\n" -"let arr1 = ArrayTrait::::new();\n" -"let arr2 = arr1.clone();\n" -"\n" +"fn main() {\n" +" let arr1 = ArrayTrait::::new();\n" +" let arr2 = arr1.clone();\n" +"}\n" "```" msgstr "" -#: src/ch03-01-what-is-ownership.md:245 +#: src/ch03-01-what-is-ownership.md:244 msgid "" "> Note: you will need to run `cairo-run` with the `--available-gas=2000000` " "option to run this example, because it uses a loop and must be ran with a " "gas limit." msgstr "" -#: src/ch03-01-what-is-ownership.md:247 +#: src/ch03-01-what-is-ownership.md:246 msgid "" "When you see a call to `clone`, you know that some arbitrary code is being\n" "executed and that code may be expensive. It’s a visual indicator that " @@ -4061,32 +4169,32 @@ msgid "" "different is going on." msgstr "" -#: src/ch03-01-what-is-ownership.md:251 +#: src/ch03-01-what-is-ownership.md:250 msgid "### Ownership and Functions" msgstr "" -#: src/ch03-01-what-is-ownership.md:253 +#: src/ch03-01-what-is-ownership.md:252 msgid "" "Passing a variable to a function will either move it or copy it. As seen in " "the Array section, passing an `Array` as a function parameter transfers its " "ownership; let's see what happens with other types." msgstr "" -#: src/ch03-01-what-is-ownership.md:255 +#: src/ch03-01-what-is-ownership.md:254 msgid "" "Listing 3-3 has an example with some annotations\n" "showing where variables go into and out of scope." msgstr "" -#: src/ch03-01-what-is-ownership.md:258 -#: src/ch03-01-what-is-ownership.md:300 -#: src/ch03-01-what-is-ownership.md:353 +#: src/ch03-01-what-is-ownership.md:257 +#: src/ch03-01-what-is-ownership.md:299 +#: src/ch03-01-what-is-ownership.md:352 msgid "Filename: src/main.cairo" msgstr "" -#: src/ch03-01-what-is-ownership.md:260 +#: src/ch03-01-what-is-ownership.md:259 msgid "" -"```rust\n" +"```rust,ignore_format\n" "#[derive(Drop)]\n" "struct MyStruct{}\n" "\n" @@ -4097,7 +4205,7 @@ msgid "" "function...\n" " // ... and so is no longer valid here\n" "\n" -" let x = 5_u128; // x comes into scope\n" +" let x = 5; // x comes into scope\n" "\n" " makes_copy(x); // x would move into the function,\n" " // but u128 implements Copy, so it is " @@ -4116,13 +4224,13 @@ msgid "" "```" msgstr "" -#: src/ch03-01-what-is-ownership.md:286 +#: src/ch03-01-what-is-ownership.md:285 msgid "" "Listing 3-3: Functions with ownership and scope\n" "annotated" msgstr "" -#: src/ch03-01-what-is-ownership.md:289 +#: src/ch03-01-what-is-ownership.md:288 msgid "" "If we tried to use `my_struct` after the call to `takes_ownership`, Cairo " "would throw a\n" @@ -4133,11 +4241,11 @@ msgid "" "the ownership rules prevent you from doing so." msgstr "" -#: src/ch03-01-what-is-ownership.md:294 +#: src/ch03-01-what-is-ownership.md:293 msgid "### Return Values and Scope" msgstr "" -#: src/ch03-01-what-is-ownership.md:296 +#: src/ch03-01-what-is-ownership.md:295 msgid "" "Returning values can also transfer ownership. Listing 3-4 shows an example " "of a\n" @@ -4146,18 +4254,18 @@ msgid "" "4-3." msgstr "" -#: src/ch03-01-what-is-ownership.md:302 +#: src/ch03-01-what-is-ownership.md:301 msgid "" -"```rust\n" +"```rust,ignore_format\n" "#[derive(Drop)]\n" -"struct A{}\n" +"struct A {}\n" "\n" "fn main() {\n" " let a1 = gives_ownership(); // gives_ownership moves its " "return\n" " // value into a1\n" "\n" -" let a2 = A{}; // a2 comes into scope\n" +" let a2 = A {}; // a2 comes into scope\n" "\n" " let a3 = takes_and_gives_back(a2); // a2 is moved into\n" " // takes_and_gives_back, which " @@ -4171,7 +4279,7 @@ msgid "" " // return value into the function\n" " // that calls it\n" "\n" -" let some_a = A{}; // some_a comes into scope\n" +" let some_a = A {}; // some_a comes into scope\n" "\n" " some_a // some_a is returned and\n" " // moves ownership to the calling\n" @@ -4189,19 +4297,19 @@ msgid "" "```" msgstr "" -#: src/ch03-01-what-is-ownership.md:340 +#: src/ch03-01-what-is-ownership.md:339 msgid "" "Listing 3-4: Transferring ownership of return\n" "values" msgstr "" -#: src/ch03-01-what-is-ownership.md:343 +#: src/ch03-01-what-is-ownership.md:342 msgid "" "When a variable goes out of scope, its value is dropped, unless ownership of " "the value has been moved to another variable." msgstr "" -#: src/ch03-01-what-is-ownership.md:345 +#: src/ch03-01-what-is-ownership.md:344 msgid "" "While this works, taking ownership and then returning ownership with every\n" "function is a bit tedious. What if we want to let a function use a value " @@ -4213,13 +4321,13 @@ msgid "" "from the body of the function that we might want to return as well." msgstr "" -#: src/ch03-01-what-is-ownership.md:351 +#: src/ch03-01-what-is-ownership.md:350 msgid "" "Cairo does let us return multiple values using a tuple, as shown in Listing " "3-5." msgstr "" -#: src/ch03-01-what-is-ownership.md:355 +#: src/ch03-01-what-is-ownership.md:354 msgid "" "```rust\n" "use array::ArrayTrait;\n" @@ -4237,12 +4345,12 @@ msgid "" "```" msgstr "" -#: src/ch03-01-what-is-ownership.md:370 +#: src/ch03-01-what-is-ownership.md:369 msgid "" "Listing 3-5: Returning ownership of parameters" msgstr "" -#: src/ch03-01-what-is-ownership.md:372 +#: src/ch03-01-what-is-ownership.md:371 msgid "" "But this is too much ceremony and a lot of work for a concept that should " "be\n" @@ -4297,7 +4405,7 @@ msgstr "" #: src/ch03-02-references-and-snapshots.md:25 msgid "" -"```rust\n" +"```rust,ignore_format\n" "use array::ArrayTrait;\n" "use debug::PrintTrait;\n" "\n" @@ -4305,9 +4413,10 @@ msgid "" " let mut arr1 = ArrayTrait::::new();\n" " let first_snapshot = @arr1; // Take a snapshot of `arr1` at this point " "in time\n" -" arr1.append(1_u128); // Mutate `arr1` by appending a value\n" -" let first_length = calculate_length(first_snapshot); // Calculate the " -"length of the array when the snapshot was taken\n" +" arr1.append(1); // Mutate `arr1` by appending a value\n" +" let first_length = calculate_length(\n" +" first_snapshot\n" +" ); // Calculate the length of the array when the snapshot was taken\n" " let second_length = calculate_length(@arr1); // Calculate the current " "length of the array\n" " first_length.print();\n" @@ -4320,7 +4429,7 @@ msgid "" "```" msgstr "" -#: src/ch03-02-references-and-snapshots.md:44 +#: src/ch03-02-references-and-snapshots.md:46 msgid "" "> Note: It is only possible to call the `len()` method on an array snapshot " "because it is defined as such in the `ArrayTrait` trait. If you try to call " @@ -4329,11 +4438,11 @@ msgid "" "non-snapshot types." msgstr "" -#: src/ch03-02-references-and-snapshots.md:46 +#: src/ch03-02-references-and-snapshots.md:48 msgid "The output of this program is:" msgstr "" -#: src/ch03-02-references-and-snapshots.md:48 +#: src/ch03-02-references-and-snapshots.md:50 msgid "" "```console\n" "[DEBUG]\t \t(raw: 0)\n" @@ -4344,7 +4453,7 @@ msgid "" "```" msgstr "" -#: src/ch03-02-references-and-snapshots.md:56 +#: src/ch03-02-references-and-snapshots.md:58 msgid "" "First, notice that all the tuple code in the variable declaration and the " "function return value is gone. Second, note\n" @@ -4352,20 +4461,37 @@ msgid "" "`@Array` rather than `Array`." msgstr "" -#: src/ch03-02-references-and-snapshots.md:59 +#: src/ch03-02-references-and-snapshots.md:61 msgid "Let’s take a closer look at the function call here:" msgstr "" -#: src/ch03-02-references-and-snapshots.md:61 +#: src/ch03-02-references-and-snapshots.md:63 msgid "" "```rust\n" -"let mut arr1 = ArrayTrait::::new();\n" -"let second_length = calculate_length(@arr1); // Calculate the current length " -"of the array\n" +"# use array::ArrayTrait;\n" +"# use debug::PrintTrait;\n" +"# \n" +"# fn main() {\n" +"# let mut arr1 = ArrayTrait::::new();\n" +"# let first_snapshot = @arr1; // Take a snapshot of `arr1` at this point " +"in time\n" +"# arr1.append(1); // Mutate `arr1` by appending a value\n" +"# let first_length = calculate_length(\n" +"# first_snapshot\n" +"# ); // Calculate the length of the array when the snapshot was taken\n" +" let second_length = calculate_length(@arr1); // Calculate the current " +"length of the array\n" +"# first_length.print();\n" +"# second_length.print();\n" +"# }\n" +"# \n" +"# fn calculate_length(arr: @Array) -> usize {\n" +"# arr.len()\n" +"# }\n" "```" msgstr "" -#: src/ch03-02-references-and-snapshots.md:66 +#: src/ch03-02-references-and-snapshots.md:84 msgid "" "The `@arr1` syntax lets us create a snapshot of the value in `arr1`. Because " "a snapshot is an immutable view of a value, the value it points to cannot be " @@ -4373,17 +4499,18 @@ msgid "" "dropped once the snapshot stops being used." msgstr "" -#: src/ch03-02-references-and-snapshots.md:68 +#: src/ch03-02-references-and-snapshots.md:86 msgid "" "Similarly, the signature of the function uses `@` to indicate that the type " "of the parameter `arr` is a snapshot. Let’s add some explanatory annotations:" msgstr "" -#: src/ch03-02-references-and-snapshots.md:70 +#: src/ch03-02-references-and-snapshots.md:88 msgid "" "```rust\n" -"fn calculate_length(array_snapshot: @Array) -> usize { // " -"array_snapshot is a snapshot of an Array\n" +"fn calculate_length(\n" +" array_snapshot: @Array\n" +") -> usize { // array_snapshot is a snapshot of an Array\n" " array_snapshot.len()\n" "} // Here, array_snapshot goes out of scope and is dropped.\n" "// However, because it is only a view of what the original array `arr` " @@ -4391,7 +4518,7 @@ msgid "" "```" msgstr "" -#: src/ch03-02-references-and-snapshots.md:77 +#: src/ch03-02-references-and-snapshots.md:97 msgid "" "The scope in which the variable `array_snapshot` is valid is the same as any " "function parameter’s scope, but the underlying value of the snapshot is not " @@ -4401,7 +4528,7 @@ msgid "" "because we never had it." msgstr "" -#: src/ch03-02-references-and-snapshots.md:79 +#: src/ch03-02-references-and-snapshots.md:99 msgid "" "Snapshots can be converted back into regular values using the `desnap` " "operator `*`, as long as the value type is copyable (which is not the case " @@ -4414,28 +4541,27 @@ msgid "" "values using the `desnap` operator `*`." msgstr "" -#: src/ch03-02-references-and-snapshots.md:81 +#: src/ch03-02-references-and-snapshots.md:101 msgid "" "The snapshot type is always copyable and droppable, so that you can use it " "multiple times without worrying about ownership transfers." msgstr "" -#: src/ch03-02-references-and-snapshots.md:83 +#: src/ch03-02-references-and-snapshots.md:103 msgid "" "```rust\n" "use debug::PrintTrait;\n" "\n" -"#[derive(Copy,Drop)]\n" +"#[derive(Copy, Drop)]\n" "struct Rectangle {\n" " height: u64,\n" " width: u64,\n" "}\n" "\n" -"fn main(){\n" -" let rec = Rectangle{height:3_u64, width:10_u64};\n" +"fn main() {\n" +" let rec = Rectangle { height: 3, width: 10 };\n" " let area = calculate_area(@rec);\n" " area.print();\n" -"\n" "}\n" "\n" "fn calculate_area(rec: @Rectangle) -> u64 {\n" @@ -4452,24 +4578,25 @@ msgid "" "```" msgstr "" -#: src/ch03-02-references-and-snapshots.md:108 +#: src/ch03-02-references-and-snapshots.md:127 msgid "" "But, what happens if we try to modify something we’re passing as snapshot? " "Try the code in\n" "Listing 3-6. Spoiler alert: it doesn’t work!" msgstr "" -#: src/ch03-02-references-and-snapshots.md:113 +#: src/ch03-02-references-and-snapshots.md:132 msgid "" "```rust,does_not_compile\n" -"#[derive(Copy,Drop)]\n" +"// does_not_compile\n" +"#[derive(Copy, Drop)]\n" "struct Rectangle {\n" " height: u64,\n" " width: u64,\n" "}\n" "\n" -"fn main(){\n" -" let rec = Rectangle{height:3_u64, width:10_u64};\n" +"fn main() {\n" +" let rec = Rectangle { height: 3, width: 10 };\n" " flip(@rec);\n" "}\n" "\n" @@ -4481,17 +4608,17 @@ msgid "" "```" msgstr "" -#: src/ch03-02-references-and-snapshots.md:132 +#: src/ch03-02-references-and-snapshots.md:152 msgid "" "Listing 3-6: Attempting to modify a snapshot " "value" msgstr "" -#: src/ch03-02-references-and-snapshots.md:134 +#: src/ch03-02-references-and-snapshots.md:154 msgid "Here’s the error:" msgstr "" -#: src/ch03-02-references-and-snapshots.md:136 +#: src/ch03-02-references-and-snapshots.md:156 msgid "" "```console\n" "error: Invalid left-hand side of assignment.\n" @@ -4501,15 +4628,15 @@ msgid "" "```" msgstr "" -#: src/ch03-02-references-and-snapshots.md:143 +#: src/ch03-02-references-and-snapshots.md:163 msgid "The compiler prevents us from modifying values associated to snapshots." msgstr "" -#: src/ch03-02-references-and-snapshots.md:145 +#: src/ch03-02-references-and-snapshots.md:165 msgid "### Mutable References" msgstr "" -#: src/ch03-02-references-and-snapshots.md:147 +#: src/ch03-02-references-and-snapshots.md:167 msgid "" "We can achieve the behavior we want in Listing 3-6 by using a _mutable " "reference_ instead of a snapshot. Mutable references are actually mutable " @@ -4521,20 +4648,20 @@ msgid "" "modifier." msgstr "" -#: src/ch03-02-references-and-snapshots.md:150 +#: src/ch03-02-references-and-snapshots.md:170 msgid "" "> **Note**: In Cairo, a parameter can only be passed as _mutable reference_ " "using the `ref` modifier if the variable is declared as mutable with `mut`." msgstr "" -#: src/ch03-02-references-and-snapshots.md:152 +#: src/ch03-02-references-and-snapshots.md:172 msgid "" "In Listing 3-7, we use a mutable reference to modify the value of the " "`height` and `width` fields of the `Rectangle` instance in the `flip` " "function." msgstr "" -#: src/ch03-02-references-and-snapshots.md:154 +#: src/ch03-02-references-and-snapshots.md:174 msgid "" "```rust\n" "use debug::PrintTrait;\n" @@ -4545,7 +4672,7 @@ msgid "" "}\n" "\n" "fn main() {\n" -" let mut rec = Rectangle { height: 3_u64, width: 10_u64 };\n" +" let mut rec = Rectangle { height: 3, width: 10 };\n" " flip(ref rec);\n" " rec.height.print();\n" " rec.width.print();\n" @@ -4559,13 +4686,13 @@ msgid "" "```" msgstr "" -#: src/ch03-02-references-and-snapshots.md:176 +#: src/ch03-02-references-and-snapshots.md:196 msgid "" "Listing 3-7: Use of a mutable reference to modify a " "value" msgstr "" -#: src/ch03-02-references-and-snapshots.md:178 +#: src/ch03-02-references-and-snapshots.md:198 msgid "" "First, we change `rec` to be `mut`. Then we pass a mutable reference of " "`rec` into `flip` with `ref rec`, and update the function signature to " @@ -4574,11 +4701,11 @@ msgid "" "instance passed as parameter." msgstr "" -#: src/ch03-02-references-and-snapshots.md:180 +#: src/ch03-02-references-and-snapshots.md:200 msgid "The output of the program is:" msgstr "" -#: src/ch03-02-references-and-snapshots.md:182 +#: src/ch03-02-references-and-snapshots.md:202 msgid "" "```console\n" "[DEBUG]\n" @@ -4588,22 +4715,22 @@ msgid "" "```" msgstr "" -#: src/ch03-02-references-and-snapshots.md:189 +#: src/ch03-02-references-and-snapshots.md:209 msgid "" "As expected, the `height` and `width` fields of the `rec` variable have been " "swapped." msgstr "" -#: src/ch03-02-references-and-snapshots.md:191 +#: src/ch03-02-references-and-snapshots.md:211 msgid "### Small recap" msgstr "" -#: src/ch03-02-references-and-snapshots.md:193 +#: src/ch03-02-references-and-snapshots.md:213 msgid "" "Let’s recap what we’ve discussed about ownership, snapshots, and references:" msgstr "" -#: src/ch03-02-references-and-snapshots.md:195 +#: src/ch03-02-references-and-snapshots.md:215 msgid "" "- At any given time, a variable can only have one owner.\n" "- You can pass a variable by-value, by-snapshot, or by-reference to a " @@ -4666,9 +4793,9 @@ msgstr "" #: src/ch04-01-defining-and-instantiating-structs.md:7 #: src/ch04-01-defining-and-instantiating-structs.md:26 -#: src/ch04-01-defining-and-instantiating-structs.md:50 -#: src/ch04-01-defining-and-instantiating-structs.md:72 -#: src/ch04-01-defining-and-instantiating-structs.md:93 +#: src/ch04-01-defining-and-instantiating-structs.md:48 +#: src/ch04-01-defining-and-instantiating-structs.md:83 +#: src/ch04-01-defining-and-instantiating-structs.md:118 msgid "Filename: structs.cairo" msgstr "" @@ -4718,22 +4845,21 @@ msgid "" "}\n" "fn main() {\n" " let user1 = User {\n" -" active: true,\n" -" username: 'someusername123',\n" -" email: 'someone@example.com',\n" -" sign_in_count: 1_u64,\n" +" active: true, username: 'someusername123', email: " +"'someone@example.com', sign_in_count: 1\n" " };\n" "}\n" +"\n" "```" msgstr "" -#: src/ch04-01-defining-and-instantiating-structs.md:46 +#: src/ch04-01-defining-and-instantiating-structs.md:44 msgid "" "Listing 4-2: Creating an instance of the `User` " "struct" msgstr "" -#: src/ch04-01-defining-and-instantiating-structs.md:48 +#: src/ch04-01-defining-and-instantiating-structs.md:46 msgid "" "To get a specific value from a struct, we use dot notation. For example, to " "access this user’s email address, we use `user1.email`. If the instance is " @@ -4742,67 +4868,98 @@ msgid "" "field of a mutable `User` instance." msgstr "" -#: src/ch04-01-defining-and-instantiating-structs.md:52 +#: src/ch04-01-defining-and-instantiating-structs.md:50 msgid "" -"```rust,does_not_compile\n" +"```rust\n" +"# #[derive(Copy, Drop)]\n" +"# struct User {\n" +"# active: bool,\n" +"# username: felt252,\n" +"# email: felt252,\n" +"# sign_in_count: u64,\n" +"# }\n" "fn main() {\n" " let mut user1 = User {\n" -" active: true,\n" -" username: 'someusername123',\n" -" email: 'someone@example.com',\n" -" sign_in_count: 1_u64,\n" +" active: true, username: 'someusername123', email: " +"'someone@example.com', sign_in_count: 1\n" " };\n" " user1.email = 'anotheremail@example.com';\n" "}\n" +"# \n" +"# fn build_user(email: felt252, username: felt252) -> User {\n" +"# User { active: true, username: username, email: email, sign_in_count: " +"1, }\n" +"# }\n" +"# \n" +"# fn build_user_short(email: felt252, username: felt252) -> User {\n" +"# User { active: true, username, email, sign_in_count: 1, }\n" +"# }\n" +"# \n" "```" msgstr "" -#: src/ch04-01-defining-and-instantiating-structs.md:64 +#: src/ch04-01-defining-and-instantiating-structs.md:75 msgid "" "Listing 4-3: Changing the value in the email field " "of a `User` instance" msgstr "" -#: src/ch04-01-defining-and-instantiating-structs.md:66 +#: src/ch04-01-defining-and-instantiating-structs.md:77 msgid "" "Note that the entire instance must be mutable; Cairo doesn’t allow us to " "mark only certain fields as mutable." msgstr "" -#: src/ch04-01-defining-and-instantiating-structs.md:68 +#: src/ch04-01-defining-and-instantiating-structs.md:79 msgid "" "As with any expression, we can construct a new instance of the struct as the " "last expression in the function body to implicitly return that new instance." msgstr "" -#: src/ch04-01-defining-and-instantiating-structs.md:70 +#: src/ch04-01-defining-and-instantiating-structs.md:81 msgid "" "Listing 4-4 shows a `build_user` function that returns a `User` instance " "with the given email and username. The `active` field gets the value of " "`true`, and the `sign_in_count` gets a value of `1`." msgstr "" -#: src/ch04-01-defining-and-instantiating-structs.md:74 +#: src/ch04-01-defining-and-instantiating-structs.md:85 msgid "" "```rust\n" +"# #[derive(Copy, Drop)]\n" +"# struct User {\n" +"# active: bool,\n" +"# username: felt252,\n" +"# email: felt252,\n" +"# sign_in_count: u64,\n" +"# }\n" +"# fn main() {\n" +"# let mut user1 = User {\n" +"# active: true, username: 'someusername123', email: " +"'someone@example.com', sign_in_count: 1\n" +"# };\n" +"# user1.email = 'anotheremail@example.com';\n" +"# }\n" +"# \n" "fn build_user(email: felt252, username: felt252) -> User {\n" -" User {\n" -" active: true,\n" -" username: username,\n" -" email: email,\n" -" sign_in_count: 1,\n" -" }\n" +" User { active: true, username: username, email: email, sign_in_count: 1, " +" }\n" "}\n" +"# \n" +"# fn build_user_short(email: felt252, username: felt252) -> User {\n" +"# User { active: true, username, email, sign_in_count: 1, }\n" +"# }\n" +"# \n" "```" msgstr "" -#: src/ch04-01-defining-and-instantiating-structs.md:85 +#: src/ch04-01-defining-and-instantiating-structs.md:110 msgid "" "Listing 4-4: A `build_user` function that takes an " "email and username and returns a `User` instance" msgstr "" -#: src/ch04-01-defining-and-instantiating-structs.md:87 +#: src/ch04-01-defining-and-instantiating-structs.md:112 msgid "" "It makes sense to name the function parameters with the same name as the " "struct fields, but having to repeat the `email` and `username` field names " @@ -4811,11 +4968,11 @@ msgid "" "shorthand!" msgstr "" -#: src/ch04-01-defining-and-instantiating-structs.md:89 +#: src/ch04-01-defining-and-instantiating-structs.md:114 msgid "## Using the Field Init Shorthand" msgstr "" -#: src/ch04-01-defining-and-instantiating-structs.md:91 +#: src/ch04-01-defining-and-instantiating-structs.md:116 msgid "" "Because the parameter names and the struct field names are exactly the same " "in Listing 4-4, we can use the field init shorthand syntax to rewrite " @@ -4823,28 +4980,44 @@ msgid "" "of `username` and `email`, as shown in Listing 4-5." msgstr "" -#: src/ch04-01-defining-and-instantiating-structs.md:95 +#: src/ch04-01-defining-and-instantiating-structs.md:120 msgid "" "```rust\n" -"fn build_user(email: felt252, username: felt252) -> User {\n" -" User {\n" -" active: true,\n" -" username,\n" -" email,\n" -" sign_in_count: 1_u64,\n" -" }\n" +"# #[derive(Copy, Drop)]\n" +"# struct User {\n" +"# active: bool,\n" +"# username: felt252,\n" +"# email: felt252,\n" +"# sign_in_count: u64,\n" +"# }\n" +"# fn main() {\n" +"# let mut user1 = User {\n" +"# active: true, username: 'someusername123', email: " +"'someone@example.com', sign_in_count: 1\n" +"# };\n" +"# user1.email = 'anotheremail@example.com';\n" +"# }\n" +"# \n" +"# fn build_user(email: felt252, username: felt252) -> User {\n" +"# User { active: true, username: username, email: email, sign_in_count: " +"1, }\n" +"# }\n" +"# \n" +"fn build_user_short(email: felt252, username: felt252) -> User {\n" +" User { active: true, username, email, sign_in_count: 1, }\n" "}\n" +"# \n" "```" msgstr "" -#: src/ch04-01-defining-and-instantiating-structs.md:106 +#: src/ch04-01-defining-and-instantiating-structs.md:145 msgid "" "Listing 4-5: A `build_user` function that uses field " "init shorthand because the `username` and `email` parameters have the same " "name as struct fields" msgstr "" -#: src/ch04-01-defining-and-instantiating-structs.md:108 +#: src/ch04-01-defining-and-instantiating-structs.md:147 msgid "" "Here, we’re creating a new instance of the `User` struct, which has a field " "named `email`. We want to set the `email` field’s value to the value in the " @@ -4877,8 +5050,8 @@ msgid "" "```rust\n" "use debug::PrintTrait;\n" "fn main() {\n" -" let width1 = 30_u64;\n" -" let height1 = 10_u64;\n" +" let width1 = 30;\n" +" let height1 = 10;\n" " let area = area(width1, height1);\n" " area.print();\n" "}\n" @@ -4950,13 +5123,13 @@ msgid "" "```rust\n" "use debug::PrintTrait;\n" "fn main() {\n" -" let rectangle = (30_u64, 10_u64);\n" +" let rectangle = (30, 10);\n" " let area = area(rectangle);\n" " area.print(); // print out the area\n" "}\n" "\n" "fn area(dimension: (u64, u64)) -> u64 {\n" -" let (x,y) = dimension;\n" +" let (x, y) = dimension;\n" " x * y\n" "}\n" "```" @@ -4999,7 +5172,7 @@ msgstr "" #: src/ch04-02-an-example-program-using-structs.md:76 msgid "" -"```rust\n" +"```rust,ignore_format\n" "use debug::PrintTrait;\n" "\n" "struct Rectangle {\n" @@ -5008,10 +5181,7 @@ msgid "" "}\n" "\n" "fn main() {\n" -" let rectangle = Rectangle {\n" -" width: 30_u64,\n" -" height: 10_u64,\n" -" };\n" +" let rectangle = Rectangle { width: 30, height: 10, };\n" " let area = area(rectangle);\n" " area.print(); // print out the area\n" "}\n" @@ -5022,11 +5192,11 @@ msgid "" "```" msgstr "" -#: src/ch04-02-an-example-program-using-structs.md:98 +#: src/ch04-02-an-example-program-using-structs.md:95 msgid "Listing 4-8: Defining a `Rectangle` struct" msgstr "" -#: src/ch04-02-an-example-program-using-structs.md:100 +#: src/ch04-02-an-example-program-using-structs.md:97 msgid "" "Here we’ve defined a struct and named it `Rectangle`. Inside the curly " "brackets, we defined the fields as `width` and `height`, both of which have " @@ -5038,11 +5208,11 @@ msgid "" "tuple index values of `0` and `1`." msgstr "" -#: src/ch04-02-an-example-program-using-structs.md:102 +#: src/ch04-02-an-example-program-using-structs.md:99 msgid "## Adding Useful Functionality with Trait" msgstr "" -#: src/ch04-02-an-example-program-using-structs.md:104 +#: src/ch04-02-an-example-program-using-structs.md:101 msgid "" "It’d be useful to be able to print an instance of `Rectangle` while we’re " "debugging our program and see the values for all its fields. Listing 4-9 " @@ -5050,9 +5220,9 @@ msgid "" "work." msgstr "" -#: src/ch04-02-an-example-program-using-structs.md:108 +#: src/ch04-02-an-example-program-using-structs.md:105 msgid "" -"```rust,does_not_compile\n" +"```rust\n" "use debug::PrintTrait;\n" "\n" "struct Rectangle {\n" @@ -5061,26 +5231,23 @@ msgid "" "}\n" "\n" "fn main() {\n" -" let rectangle = Rectangle {\n" -" width: 30_u64,\n" -" height: 10_u64,\n" -" };\n" +" let rectangle = Rectangle { width: 30, height: 10, };\n" " rectangle.print();\n" "}\n" "```" msgstr "" -#: src/ch04-02-an-example-program-using-structs.md:125 +#: src/ch04-02-an-example-program-using-structs.md:119 msgid "" "Listing 4-9: Attempting to print a `Rectangle` " "instance" msgstr "" -#: src/ch04-02-an-example-program-using-structs.md:127 +#: src/ch04-02-an-example-program-using-structs.md:121 msgid "When we compile this code, we get an error with this message:" msgstr "" -#: src/ch04-02-an-example-program-using-structs.md:129 +#: src/ch04-02-an-example-program-using-structs.md:123 msgid "" "```bash\n" "$ cairo-compile src/lib.cairo\n" @@ -5094,7 +5261,7 @@ msgid "" "```" msgstr "" -#: src/ch04-02-an-example-program-using-structs.md:139 +#: src/ch04-02-an-example-program-using-structs.md:133 msgid "" "The `print` trait is implemented for many data types, but not for the " "`Rectangle` struct. We can fix this by implementing the `PrintTrait` trait " @@ -5103,9 +5270,9 @@ msgid "" "Cairo](ch07-02-traits-in-cairo.md)." msgstr "" -#: src/ch04-02-an-example-program-using-structs.md:144 +#: src/ch04-02-an-example-program-using-structs.md:138 msgid "" -"```rust\n" +"```rust,ignore_format\n" "use debug::PrintTrait;\n" "\n" "struct Rectangle {\n" @@ -5114,10 +5281,7 @@ msgid "" "}\n" "\n" "fn main() {\n" -" let rectangle = Rectangle {\n" -" width: 30_u64,\n" -" height: 10_u64,\n" -" };\n" +" let rectangle = Rectangle { width: 30, height: 10, };\n" " rectangle.print();\n" "}\n" "\n" @@ -5130,13 +5294,13 @@ msgid "" "```" msgstr "" -#: src/ch04-02-an-example-program-using-structs.md:168 +#: src/ch04-02-an-example-program-using-structs.md:159 msgid "" "Listing 4-10: Implementing the `PrintTrait` trait on " "`Rectangle`" msgstr "" -#: src/ch04-02-an-example-program-using-structs.md:170 +#: src/ch04-02-an-example-program-using-structs.md:161 msgid "" "Nice! It’s not the prettiest output, but it shows the values of all the " "fields for this instance, which would definitely help during debugging." @@ -5175,7 +5339,7 @@ msgid "" "parameter\n" "and instead make an `area` method defined on the `RectangleTrait` trait, as " "shown\n" -"in Listing 5-13." +"in Listing 4-13." msgstr "" #: src/ch04-03-method-syntax.md:20 @@ -5199,7 +5363,7 @@ msgid "" "}\n" "\n" "fn main() {\n" -" let rect1 = Rectangle { width: 30_u64, height: 50_u64, };\n" +" let rect1 = Rectangle { width: 30, height: 50, };\n" "\n" " rect1.area().print();\n" "}\n" @@ -5216,7 +5380,7 @@ msgstr "" #: src/ch04-03-method-syntax.md:48 msgid "" "To define the function within the context of `Rectangle`, we start by " -"definining a `trait`\n" +"defining a `trait`\n" "block with the signature of the method that we want to implement. Traits are " "not linked to\n" "a specific type; only the `self` parameter of the method defines which type " @@ -5323,12 +5487,12 @@ msgid "" "\n" "impl RectangleImpl of RectangleTrait {\n" " fn width(self: @Rectangle) -> bool {\n" -" (*self.width) > 0_u64\n" +" (*self.width) > 0\n" " }\n" "}\n" "\n" "fn main() {\n" -" let rect1 = Rectangle { width: 30_u64, height: 50_u64, };\n" +" let rect1 = Rectangle { width: 30, height: 50, };\n" " rect1.width().print();\n" "}\n" "```" @@ -5364,7 +5528,7 @@ msgid "" "within `self` (the first `Rectangle`); otherwise, it should return `false`.\n" "That is, once we’ve defined the `can_hold` method, we want to be able to " "write\n" -"the program shown in Listing 5-14." +"the program shown in Listing 4-14." msgstr "" #: src/ch04-03-method-syntax.md:137 @@ -5378,9 +5542,9 @@ msgid "" "}\n" "\n" "fn main() {\n" -" let rect1 = Rectangle { width: 30_u64, height: 50_u64, };\n" -" let rect2 = Rectangle { width: 10_u64, height: 40_u64, };\n" -" let rect3 = Rectangle { width: 60_u64, height: 45_u64, };\n" +" let rect1 = Rectangle { width: 30, height: 50, };\n" +" let rect2 = Rectangle { width: 10, height: 40, };\n" +" let rect3 = Rectangle { width: 60, height: 45, };\n" "\n" " 'Can rect1 hold rect2?'.print();\n" " rect1.can_hold(@rect2).print();\n" @@ -5393,7 +5557,7 @@ msgstr "" #: src/ch04-03-method-syntax.md:158 msgid "" -"Listing 5-14: Using the as-yet-unwritten `can_hold`\n" +"Listing 4-14: Using the as-yet-unwritten `can_hold`\n" "method" msgstr "" @@ -5443,10 +5607,11 @@ msgid "" "`self` are greater than the width and height of the other `Rectangle`,\n" "respectively. Let’s add the new `can_hold` method to the `trait` and `impl` " "blocks from\n" -"Listing 5-13, shown in Listing 5-15." +"Listing 4-13, shown in Listing 4-15." msgstr "" #: src/ch04-03-method-syntax.md:194 +#: src/ch08-01-how-to-write-tests.md:134 msgid "" "```rust\n" "trait RectangleTrait {\n" @@ -5468,13 +5633,13 @@ msgstr "" #: src/ch04-03-method-syntax.md:211 msgid "" -"Listing 5-15: Implementing the `can_hold` method on\n" +"Listing 4-15: Implementing the `can_hold` method on\n" "`Rectangle` that takes another `Rectangle` instance as a parameter" msgstr "" #: src/ch04-03-method-syntax.md:214 msgid "" -"When we run this code with the `main` function in Listing 5-14, we’ll get " +"When we run this code with the `main` function in Listing 4-14, we’ll get " "our\n" "desired output. Methods can take multiple parameters that we add to the\n" "signature after the `self` parameter, and those parameters work just like\n" @@ -5522,8 +5687,8 @@ msgstr "" #: src/ch04-03-method-syntax.md:245 msgid "" "To call this function, we use the `::` syntax with the implementation name;\n" -"`let square = RectangleImpl::square(10_u64);` is an example. This function " -"is namespaced by\n" +"`let square = RectangleImpl::square(10);` is an example. This function is " +"namespaced by\n" "the implementation; the `::` syntax is used for both trait functions and\n" "namespaces created by modules. We’ll discuss modules in [Chapter " "7][modules]." @@ -5532,7 +5697,7 @@ msgstr "" #: src/ch04-03-method-syntax.md:250 msgid "" "> Note: It is also possible to call this function using the trait name, with " -"`RectangleTrait::square(10_u64)`." +"`RectangleTrait::square(10)`." msgstr "" #: src/ch04-03-method-syntax.md:252 @@ -5543,7 +5708,7 @@ msgstr "" msgid "" "Each struct is allowed to have multiple `trait` and `impl` blocks. For " "example, Listing\n" -"5-15 is equivalent to the code shown in Listing 5-16, which has each method " +"5-15 is equivalent to the code shown in Listing 4-16, which has each method " "in\n" "its own `trait` and `impl` blocks." msgstr "" @@ -5574,7 +5739,7 @@ msgstr "" #: src/ch04-03-method-syntax.md:279 msgid "" -"Listing 5-16: Rewriting Listing 5-15 using multiple " +"Listing 4-16: Rewriting Listing 4-15 using multiple " "`impl`\n" "blocks" msgstr "" @@ -5632,7 +5797,7 @@ msgstr "" #: src/ch05-01-enums.md:9 msgid "" -"```rs\n" +"```rust\n" "#[derive(Drop)]\n" "enum Direction {\n" " North: (),\n" @@ -5640,11 +5805,10 @@ msgid "" " South: (),\n" " West: (),\n" "}\n" -"\n" "```" msgstr "" -#: src/ch05-01-enums.md:20 +#: src/ch05-01-enums.md:19 msgid "" "Unlike other languages like Rust, every variant has a type. In this example, " "we've defined an enum called `Direction` with four variants: `North`, " @@ -5654,67 +5818,79 @@ msgid "" "instantiated using this syntax:" msgstr "" -#: src/ch05-01-enums.md:22 +#: src/ch05-01-enums.md:21 msgid "" -"```rs\n" -"let direction = Direction::North(());\n" +"```rust\n" +"# #[derive(Drop)]\n" +"# enum Direction {\n" +"# North: (),\n" +"# East: (),\n" +"# South: (),\n" +"# West: (),\n" +"# }\n" +"# \n" +"# fn main() {\n" +" let direction = Direction::North(());\n" +"# }\n" +"# \n" +"# \n" "```" msgstr "" -#: src/ch05-01-enums.md:26 +#: src/ch05-01-enums.md:37 msgid "" "It's easy to write code that acts differently depending on the variant of an " "enum instance, in this example to run specific code according to a " -"Direction. You can learn more about it on the [The Match Control Flow " -"Construct page](ch05-02-the-match-control-flow-construct.md)." +"Direction. You can learn more about it on [The Match Control Flow Construct " +"page](ch05-02-the-match-control-flow-construct.md)." msgstr "" -#: src/ch05-01-enums.md:28 +#: src/ch05-01-enums.md:39 msgid "## Enums Combined with Custom Types" msgstr "" -#: src/ch05-01-enums.md:30 +#: src/ch05-01-enums.md:41 msgid "" "Enums can also be used to store more interesting data associated with each " "variant. For example:" msgstr "" -#: src/ch05-01-enums.md:32 +#: src/ch05-01-enums.md:43 msgid "" -"```rs\n" +"```rust\n" "#[derive(Drop)]\n" "enum Message {\n" -" Quit : (),\n" -" Echo : felt252,\n" -" Move : (u128, u128),\n" +" Quit: (),\n" +" Echo: felt252,\n" +" Move: (u128, u128),\n" "}\n" "```" msgstr "" -#: src/ch05-01-enums.md:41 +#: src/ch05-01-enums.md:52 msgid "" "In this example, the `Message` enum has three variants: `Quit`, `Echo` and " "`Move`, all with different types:" msgstr "" -#: src/ch05-01-enums.md:43 +#: src/ch05-01-enums.md:54 msgid "" "- `Quit` is the unit type - it has no data associated with it at all.\n" "- `Echo` is a single felt.\n" "- `Move` is a tuple of two u128 values." msgstr "" -#: src/ch05-01-enums.md:47 +#: src/ch05-01-enums.md:58 msgid "" "You could even use a Struct or another Enum you defined inside one of your " "Enum variants." msgstr "" -#: src/ch05-01-enums.md:49 +#: src/ch05-01-enums.md:60 msgid "## Trait Implementations for Enums" msgstr "" -#: src/ch05-01-enums.md:51 +#: src/ch05-01-enums.md:62 msgid "" "In Cairo, you can define traits and implement them for your custom enums. " "This allows you to define methods and behaviors associated with the enum. " @@ -5722,7 +5898,7 @@ msgid "" "`Message` enum:" msgstr "" -#: src/ch05-01-enums.md:53 +#: src/ch05-01-enums.md:64 msgid "" "```rs\n" "trait Processing {\n" @@ -5747,29 +5923,60 @@ msgid "" "```" msgstr "" -#: src/ch05-01-enums.md:75 +#: src/ch05-01-enums.md:86 msgid "" "In this example, we implemented the `Processing` trait for `Message`. Here " "is how it could be used to process a Quit message:" msgstr "" -#: src/ch05-01-enums.md:77 +#: src/ch05-01-enums.md:88 msgid "" "```rust\n" -"let msg: Message = Message::Quit(());\n" -"msg.process();\n" -"```" -msgstr "" - -#: src/ch05-01-enums.md:82 +"# use debug::PrintTrait;\n" +"# #[derive(Drop)]\n" +"# enum Message {\n" +"# Quit: (),\n" +"# Echo: felt252,\n" +"# Move: (u128, u128),\n" +"# }\n" +"# \n" +"# trait Processing {\n" +"# fn process(self: Message);\n" +"# }\n" +"# \n" +"# impl ProcessingImpl of Processing {\n" +"# fn process(self: Message) {\n" +"# match self {\n" +"# Message::Quit(()) => {\n" +"# 'quitting'.print();\n" +"# },\n" +"# Message::Echo(value) => {\n" +"# value.print();\n" +"# },\n" +"# Message::Move((x, y)) => {\n" +"# 'moving'.print();\n" +"# },\n" +"# }\n" +"# }\n" +"# }\n" +"# fn main() {\n" +" let msg: Message = Message::Quit(());\n" +" msg.process();\n" +"# }\n" +"# \n" +"# \n" +"```" +msgstr "" + +#: src/ch05-01-enums.md:124 msgid "Running this code would print `quitting`." msgstr "" -#: src/ch05-01-enums.md:84 +#: src/ch05-01-enums.md:126 msgid "## The Option Enum and Its Advantages" msgstr "" -#: src/ch05-01-enums.md:86 +#: src/ch05-01-enums.md:128 msgid "" "The Option enum is a standard Cairo enum that represents the concept of an " "optional value. It has two variants: `Some: T` and `None: ()`. `Some: T ` " @@ -5777,9 +5984,11 @@ msgid "" "absence of a value." msgstr "" -#: src/ch05-01-enums.md:88 +#: src/ch05-01-enums.md:130 +#: src/ch05-02-the-match-control-flow-construct.md:136 +#: src/ch07-01-generic-data-types.md:174 msgid "" -"```rs\n" +"```rust\n" "enum Option {\n" " Some: T,\n" " None: (),\n" @@ -5787,7 +5996,7 @@ msgid "" "```" msgstr "" -#: src/ch05-01-enums.md:95 +#: src/ch05-01-enums.md:137 msgid "" "The `Option` enum is helpful because it allows you to explicitly represent " "the possibility of a value being absent, making your code more expressive " @@ -5795,45 +6004,37 @@ msgid "" "by using uninitialized or unexpected `null` values." msgstr "" -#: src/ch05-01-enums.md:97 +#: src/ch05-01-enums.md:139 msgid "" "To give you an example, here is a function which returns the index of the " "first element of an array with a given value, or None if the element is not " "present." msgstr "" -#: src/ch05-01-enums.md:99 +#: src/ch05-01-enums.md:141 msgid "We are demonstrating two approaches for the above function:" msgstr "" -#: src/ch05-01-enums.md:101 +#: src/ch05-01-enums.md:143 msgid "" "- Recursive Approach `find_value_recursive`\n" "- Iterative Approach `find_value_iterative`" msgstr "" -#: src/ch05-01-enums.md:104 +#: src/ch05-01-enums.md:146 msgid "" "> Note: in the future it would be nice to replace this example by something " "simpler using a loop and without gas related code." msgstr "" -#: src/ch05-01-enums.md:106 +#: src/ch05-01-enums.md:148 msgid "" "```rust\n" "use array::ArrayTrait;\n" "use debug::PrintTrait;\n" +"use option::OptionTrait;\n" "fn find_value_recursive(arr: @Array, value: felt252, index: usize) " "-> Option {\n" -" match gas::withdraw_gas() {\n" -" Option::Some(_) => {},\n" -" Option::None(_) => {\n" -" let mut data = ArrayTrait::new();\n" -" data.append('OOG');\n" -" panic(data);\n" -" },\n" -" }\n" -"\n" " if index >= arr.len() {\n" " return Option::None(());\n" " }\n" @@ -5842,13 +6043,13 @@ msgid "" " return Option::Some(index);\n" " }\n" "\n" -" find_value_recursive(arr, value, index + 1_usize)\n" +" find_value_recursive(arr, value, index + 1)\n" "}\n" "\n" "fn find_value_iterative(arr: @Array, value: felt252) -> " "Option {\n" " let length = arr.len();\n" -" let mut index = 0_usize;\n" +" let mut index = 0;\n" " let mut found: Option = Option::None(());\n" " loop {\n" " if index < length {\n" @@ -5859,7 +6060,7 @@ msgid "" " } else {\n" " break ();\n" " }\n" -" index += 1_usize;\n" +" index += 1;\n" " };\n" " return found;\n" "}\n" @@ -5874,13 +6075,12 @@ msgid "" " my_array.append(5);\n" "\n" " let value_to_find = 7;\n" -" let result = find_value_recursive(@my_array, value_to_find, 0_usize);\n" +" let result = find_value_recursive(@my_array, value_to_find, 0);\n" " let result_i = find_value_iterative(@my_array, value_to_find);\n" "\n" -"\n" " match result {\n" " Option::Some(index) => {\n" -" if index == 1_usize {\n" +" if index == 1 {\n" " 'it worked'.print();\n" " }\n" " },\n" @@ -5890,7 +6090,7 @@ msgid "" " }\n" " match result_i {\n" " Option::Some(index) => {\n" -" if index == 1_usize {\n" +" if index == 1 {\n" " 'it worked'.print();\n" " }\n" " },\n" @@ -5903,7 +6103,7 @@ msgid "" "```" msgstr "" -#: src/ch05-01-enums.md:186 +#: src/ch05-01-enums.md:219 msgid "Running this code would print `it worked`." msgstr "" @@ -6025,32 +6225,22 @@ msgstr "" #: src/ch05-02-the-match-control-flow-construct.md:43 msgid "" "```rust\n" -"fn value_in_cents(coin: Coin) -> felt252 {\n" -" match coin {\n" -" Coin::Penny(_) => {\n" -" ('Lucky penny!').print();\n" -" 1\n" -" },\n" -" Coin::Nickel(_) => 5,\n" -" Coin::Dime(_) => 10,\n" -" Coin::Quarter(_)=> 25,\n" -" }\n" -"}\n" +"\n" "```" msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:57 +#: src/ch05-02-the-match-control-flow-construct.md:47 msgid "## Patterns That Bind to Values" msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:59 +#: src/ch05-02-the-match-control-flow-construct.md:49 msgid "" "Another useful feature of match arms is that they can bind to the parts of " "the values that match the pattern. This is how we can extract values out of " "enum variants." msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:61 +#: src/ch05-02-the-match-control-flow-construct.md:51 msgid "" "As an example, let’s change one of our enum variants to hold data inside it. " "From 1999 through 2008, the United States minted quarters with different " @@ -6060,7 +6250,7 @@ msgid "" "stored inside it, which we’ve done in Listing 5-4." msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:63 +#: src/ch05-02-the-match-control-flow-construct.md:53 msgid "" "```rust\n" "#[derive(Drop)]\n" @@ -6074,18 +6264,18 @@ msgid "" " Penny: (),\n" " Nickel: (),\n" " Dime: (),\n" -" Quarter: (UsState),\n" +" Quarter: (UsState, ),\n" "}\n" "```" msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:79 +#: src/ch05-02-the-match-control-flow-construct.md:69 msgid "" "Listing 5-4: A `Coin` enum in which the `Quarter` variant also holds a " "`UsState` value" msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:81 +#: src/ch05-02-the-match-control-flow-construct.md:71 msgid "" "Let’s imagine that a friend is trying to collect all 50 state quarters. " "While we sort our loose change by coin type, we’ll also call out the name of " @@ -6093,7 +6283,7 @@ msgid "" "doesn’t have, they can add it to their collection." msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:83 +#: src/ch05-02-the-match-control-flow-construct.md:73 msgid "" "In the match expression for this code, we add a variable called `state` to " "the pattern that matches values of the variant `Coin::Quarter`. When a " @@ -6101,7 +6291,7 @@ msgid "" "quarter’s state. Then we can use `state` in the code for that arm, like so:" msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:85 +#: src/ch05-02-the-match-control-flow-construct.md:75 msgid "" "```rust\n" "fn value_in_cents(coin: Coin) -> felt252 {\n" @@ -6109,7 +6299,7 @@ msgid "" " Coin::Penny(_) => 1,\n" " Coin::Nickel(_) => 5,\n" " Coin::Dime(_) => 10,\n" -" Coin::Quarter(state)=> {\n" +" Coin::Quarter(state) => {\n" " state.print();\n" " 25\n" " },\n" @@ -6118,16 +6308,16 @@ msgid "" "```" msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:99 +#: src/ch05-02-the-match-control-flow-construct.md:89 msgid "" "To print the value of a variant of an enum in Cairo, we need to add an " "implementation for the `print` function for the `debug::PrintTrait`:" msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:101 +#: src/ch05-02-the-match-control-flow-construct.md:91 msgid "" "```rust\n" -"impl UsStatePrintImpl of PrintTrait:: {\n" +"impl UsStatePrintImpl of PrintTrait {\n" " fn print(self: UsState) {\n" " match self {\n" " UsState::Alabama(_) => ('Alabama').print(),\n" @@ -6138,7 +6328,7 @@ msgid "" "```" msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:112 +#: src/ch05-02-the-match-control-flow-construct.md:102 msgid "" "If we were to call `value_in_cents(Coin::Quarter(UsState::Alaska(())))`, " "`coin` would be `Coin::Quarter(UsState::Alaska())`. When we compare that " @@ -6149,11 +6339,11 @@ msgid "" "`Quarter`." msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:114 +#: src/ch05-02-the-match-control-flow-construct.md:104 msgid "## Matching with Options" msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:116 +#: src/ch05-02-the-match-control-flow-construct.md:106 msgid "" "In the previous section, we wanted to get the inner `T` value out of the " "`Some` case when using `Option`; we can also handle `Option` using " @@ -6163,21 +6353,21 @@ msgid "" "`option::OptionTrait` trait." msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:118 +#: src/ch05-02-the-match-control-flow-construct.md:108 msgid "" "Let’s say we want to write a function that takes an `Option` and, if " -"there’s a value inside, adds `1_u8` to that value. If there isn’t a value " +"there’s a value inside, adds `1` to that value. If there isn’t a value " "inside, the function should return the `None` value and not attempt to " "perform any operations." msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:120 +#: src/ch05-02-the-match-control-flow-construct.md:110 msgid "" "This function is very easy to write, thanks to match, and will look like " "Listing 5-5." msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:122 +#: src/ch05-02-the-match-control-flow-construct.md:112 msgid "" "```rust\n" "use option::OptionTrait;\n" @@ -6185,13 +6375,13 @@ msgid "" "\n" "fn plus_one(x: Option) -> Option {\n" " match x {\n" -" Option::Some(val) => Option::Some(val + 1_u8),\n" +" Option::Some(val) => Option::Some(val + 1),\n" " Option::None(_) => Option::None(()),\n" " }\n" "}\n" "\n" "fn main() {\n" -" let five: Option = Option::Some(5_u8);\n" +" let five: Option = Option::Some(5);\n" " let six: Option = plus_one(five);\n" " six.unwrap().print();\n" " let none = plus_one(Option::None(()));\n" @@ -6200,77 +6390,67 @@ msgid "" "```" msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:142 +#: src/ch05-02-the-match-control-flow-construct.md:132 msgid "Listing 5-5: A function that uses a match expression on an `Option`" msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:144 +#: src/ch05-02-the-match-control-flow-construct.md:134 msgid "" "Note that your arms must respect the same order as the enum defined in the " "`OptionTrait` of the core Cairo lib." msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:146 -msgid "" -"```rust\n" -" enum Option {\n" -" Some: T,\n" -" None: (),\n" -" }\n" -"```" -msgstr "" - -#: src/ch05-02-the-match-control-flow-construct.md:153 +#: src/ch05-02-the-match-control-flow-construct.md:143 msgid "" "Let’s examine the first execution of `plus_one` in more detail. When we call " "`plus_one(five)`, the variable `x` in the body of `plus_one` will have the " -"value `Some(5_u8)`. We then compare that against each match arm:" +"value `Some(5)`. We then compare that against each match arm:" msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:155 -#: src/ch05-02-the-match-control-flow-construct.md:163 +#: src/ch05-02-the-match-control-flow-construct.md:145 +#: src/ch05-02-the-match-control-flow-construct.md:153 msgid "" "```rust\n" -" Option::Some(val) => Option::Some(val + 1_u8),\n" +" Option::Some(val) => Option::Some(val + 1),\n" "```" msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:159 +#: src/ch05-02-the-match-control-flow-construct.md:149 msgid "" -"Does `Option::Some(5_u8)` value match the pattern `Option::Some(val)`? It " -"does! We have the same variant. The `val` binds to the value contained in " -"`Option::Some`, so `val` takes the value `5_u8`. The code in the match arm " -"is then executed, so we add `1_u8` to the value of `val` and create a new " -"`Option::Some` value with our total `6_u8` inside. Because the first arm " +"Does `Option::Some(5)` value match the pattern `Option::Some(val)`? It does! " +"We have the same variant. The `val` binds to the value contained in " +"`Option::Some`, so `val` takes the value `5`. The code in the match arm is " +"then executed, so we add `1` to the value of `val` and create a new " +"`Option::Some` value with our total `6` inside. Because the first arm " "matched, no other arms are compared." msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:161 +#: src/ch05-02-the-match-control-flow-construct.md:151 msgid "" "Now let’s consider the second call of `plus_one` in our main function, where " "`x` is `Option::None(())`. We enter the match and compare to the first arm:" msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:167 +#: src/ch05-02-the-match-control-flow-construct.md:157 msgid "" "The `Option::Some(val)` value doesn’t match the pattern `Option::None`, so " "we continue to the next arm:" msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:169 +#: src/ch05-02-the-match-control-flow-construct.md:159 msgid "" "```rust\n" -" Option::None(_) => Option::None(()),\n" +" Option::None(_) => Option::None(()),\n" "```" msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:173 +#: src/ch05-02-the-match-control-flow-construct.md:163 msgid "" "It matches! There’s no value to add to, so the program stops and returns the " "`Option::None(())` value on the right side of `=>`." msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:175 +#: src/ch05-02-the-match-control-flow-construct.md:165 msgid "" "Combining `match` and enums is useful in many situations. You’ll see this " "pattern a lot in Cairo code: `match` against an enum, bind a variable to the " @@ -6279,18 +6459,29 @@ msgid "" "consistently a user favorite." msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:177 +#: src/ch05-02-the-match-control-flow-construct.md:167 msgid "## Matches Are Exhaustive" msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:179 +#: src/ch05-02-the-match-control-flow-construct.md:169 msgid "" "There’s one other aspect of match we need to discuss: the arms’ patterns " "must cover all possibilities. Consider this version of our `plus_one` " "function, which has a bug and won’t compile:" msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:181 +#: src/ch05-02-the-match-control-flow-construct.md:171 +msgid "" +"```rust\n" +"fn plus_one(x: Option) -> Option {\n" +" match x {\n" +" Option::Some(val) => Option::Some(val + 1), \n" +" }\n" +"}\n" +"```" +msgstr "" + +#: src/ch05-02-the-match-control-flow-construct.md:179 msgid "" "```bash\n" "$ cairo-run src/test.cairo\n" @@ -6304,7 +6495,7 @@ msgid "" "```" msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:191 +#: src/ch05-02-the-match-control-flow-construct.md:189 msgid "" "Cairo knows that we didn’t cover every possible case, and even knows which " "pattern we forgot! Matches in Cairo are exhaustive: we must exhaust every " @@ -6315,26 +6506,26 @@ msgid "" "impossible." msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:193 +#: src/ch05-02-the-match-control-flow-construct.md:191 msgid "## Match 0 and the \\_ Placeholder" msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:195 +#: src/ch05-02-the-match-control-flow-construct.md:193 msgid "" "Using enums, we can also take special actions for a few particular values, " "but for all other values take one default action. Currently only `0` and the " "`_`operator are supported." msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:197 +#: src/ch05-02-the-match-control-flow-construct.md:195 msgid "" "Imagine we’re implementing a game where, you get a random number between 0 " -"and 7. If you have 0, you win. For all other values you loose. Here's a " -"match that implements that logic, with the number hardcoded rather than a " -"random value." +"and 7. If you have 0, you win. For all other values you lose. Here's a match " +"that implements that logic, with the number hardcoded rather than a random " +"value." msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:199 +#: src/ch05-02-the-match-control-flow-construct.md:197 msgid "" "```rust\n" "fn did_i_win(nb: felt252) {\n" @@ -6346,7 +6537,7 @@ msgid "" "```" msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:208 +#: src/ch05-02-the-match-control-flow-construct.md:206 msgid "" "The first arm, the pattern is the literal values 0. For the last arm that " "covers every other possible value, the pattern is the character `_`. This " @@ -6359,7 +6550,7 @@ msgid "" "arms after a catch-all!" msgstr "" -#: src/ch05-02-the-match-control-flow-construct.md:210 +#: src/ch05-02-the-match-control-flow-construct.md:208 msgid "" "" @@ -6525,7 +6716,7 @@ msgid "" "- `Scarb.toml` is the package manifest file, which contains metadata and " "configuration options for the package, such as dependencies, package name, " "version, and authors. You can find documentation about it on the [scarb " -"reference](https://docs.swmansion.com/scarb/docs/reference/manifest)." +"reference](https://docs.swmansion.com/scarb/docs/reference/manifest.html)." msgstr "" #: src/ch06-01-packages-and-crates.md:33 @@ -6686,67 +6877,66 @@ msgstr "" #: src/ch06-02-defining-modules-to-control-scope.md:92 msgid "" -"```rust,does_not_compile\n" +"```rust\n" +"// does_not_compile\n" "use garden::vegetables::Asparagus;\n" "\n" "mod garden;\n" "\n" -"fn main(){\n" -" let Asparagus = Asparagus{};\n" +"fn main() {\n" +" let Asparagus = Asparagus {};\n" "}\n" -"\n" -"\n" "```" msgstr "" -#: src/ch06-02-defining-modules-to-control-scope.md:104 +#: src/ch06-02-defining-modules-to-control-scope.md:103 msgid "" "The `mod garden;` line tells the compiler to include the code it finds in " "_src/garden.cairo_, which is:" msgstr "" -#: src/ch06-02-defining-modules-to-control-scope.md:106 +#: src/ch06-02-defining-modules-to-control-scope.md:105 msgid "Filename: src/garden.cairo" msgstr "" -#: src/ch06-02-defining-modules-to-control-scope.md:108 +#: src/ch06-02-defining-modules-to-control-scope.md:107 msgid "" "```rust\n" "mod vegetables;\n" "```" msgstr "" -#: src/ch06-02-defining-modules-to-control-scope.md:112 +#: src/ch06-02-defining-modules-to-control-scope.md:111 msgid "" "Here, `mod vegetables;` means the code in _src/garden/vegetables.cairo_ is\n" "included too. That code is:" msgstr "" -#: src/ch06-02-defining-modules-to-control-scope.md:115 +#: src/ch06-02-defining-modules-to-control-scope.md:114 msgid "" "```rust\n" -"#[derive(Copy,Drop)]\n" -"struct Asparagus{}\n" +"#[derive(Copy, Drop)]\n" +"struct Asparagus {}\n" "```" msgstr "" -#: src/ch06-02-defining-modules-to-control-scope.md:120 +#: src/ch06-02-defining-modules-to-control-scope.md:119 msgid "" "The line `use garden::vegetables::Asparagus;` lets us use bring the " "`Asparagus` type into scope,\n" "so we can use it in the `main` function." msgstr "" -#: src/ch06-02-defining-modules-to-control-scope.md:123 +#: src/ch06-02-defining-modules-to-control-scope.md:122 msgid "" "Now let’s get into the details of these rules and demonstrate them in action!" msgstr "" -#: src/ch06-02-defining-modules-to-control-scope.md:125 +#: src/ch06-02-defining-modules-to-control-scope.md:124 msgid "### Grouping Related Code in Modules" msgstr "" -#: src/ch06-02-defining-modules-to-control-scope.md:127 +#: src/ch06-02-defining-modules-to-control-scope.md:126 msgid "" "_Modules_ let us organize code within a crate for readability and easy " "reuse.\n" @@ -6757,7 +6947,7 @@ msgid "" "implementation of a restaurant." msgstr "" -#: src/ch06-02-defining-modules-to-control-scope.md:133 +#: src/ch06-02-defining-modules-to-control-scope.md:132 msgid "" "In the restaurant industry, some parts of a restaurant are referred to as\n" "_front of house_ and others as _back of house_. Front of house is where\n" @@ -6768,7 +6958,7 @@ msgid "" "administrative work." msgstr "" -#: src/ch06-02-defining-modules-to-control-scope.md:140 +#: src/ch06-02-defining-modules-to-control-scope.md:139 msgid "" "To structure our crate in this way, we can organize its functions into " "nested\n" @@ -6778,7 +6968,7 @@ msgid "" "section:" msgstr "" -#: src/ch06-02-defining-modules-to-control-scope.md:146 +#: src/ch06-02-defining-modules-to-control-scope.md:145 msgid "" "```rust\n" "mod front_of_house {\n" @@ -6799,14 +6989,14 @@ msgid "" "```" msgstr "" -#: src/ch06-02-defining-modules-to-control-scope.md:164 +#: src/ch06-02-defining-modules-to-control-scope.md:163 msgid "" "Listing 6-1: A `front_of_house` module containing " "other\n" "modules that then contain functions" msgstr "" -#: src/ch06-02-defining-modules-to-control-scope.md:167 +#: src/ch06-02-defining-modules-to-control-scope.md:166 msgid "" "We define a module with the `mod` keyword followed by the name of the " "module\n" @@ -6820,7 +7010,7 @@ msgid "" "6-1—functions." msgstr "" -#: src/ch06-02-defining-modules-to-control-scope.md:174 +#: src/ch06-02-defining-modules-to-control-scope.md:173 msgid "" "By using modules, we can group related definitions together and name why\n" "they’re related. Programmers using this code can navigate the code based on " @@ -6833,7 +7023,7 @@ msgid "" "organized." msgstr "" -#: src/ch06-02-defining-modules-to-control-scope.md:180 +#: src/ch06-02-defining-modules-to-control-scope.md:179 msgid "" "Earlier, we mentioned that _src/lib.cairo_ is called the crate\n" "root. The reason for this name is that the content of this file form a " @@ -6842,11 +7032,11 @@ msgid "" "known as the _module tree_." msgstr "" -#: src/ch06-02-defining-modules-to-control-scope.md:184 +#: src/ch06-02-defining-modules-to-control-scope.md:183 msgid "Listing 6-2 shows the module tree for the structure in Listing 6-1." msgstr "" -#: src/ch06-02-defining-modules-to-control-scope.md:186 +#: src/ch06-02-defining-modules-to-control-scope.md:185 msgid "" "```text\n" "restaurant\n" @@ -6861,14 +7051,14 @@ msgid "" "```" msgstr "" -#: src/ch06-02-defining-modules-to-control-scope.md:198 +#: src/ch06-02-defining-modules-to-control-scope.md:197 msgid "" "Listing 6-2: The module tree for the code in " "Listing\n" "6-1" msgstr "" -#: src/ch06-02-defining-modules-to-control-scope.md:201 +#: src/ch06-02-defining-modules-to-control-scope.md:200 msgid "" "This tree shows how some of the modules nest inside one another; for " "example,\n" @@ -6884,7 +7074,7 @@ msgid "" "tree is rooted under the explicit name of the crate `restaurant`." msgstr "" -#: src/ch06-02-defining-modules-to-control-scope.md:209 +#: src/ch06-02-defining-modules-to-control-scope.md:208 msgid "" "The module tree might remind you of the filesystem’s directory tree on your\n" "computer; this is a very apt comparison! Just like directories in a " @@ -6950,7 +7140,7 @@ msgid "" "}\n" "\n" "\n" -"pub fn eat_at_restaurant() {\n" +"fn eat_at_restaurant() {\n" " // Absolute path\n" " restaurant::front_of_house::hosting::add_to_waitlist(); // ✅ Compiles\n" "\n" @@ -7052,6 +7242,7 @@ msgstr "" #: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:12 msgid "" "```rust\n" +"// does_not_compile\n" "mod front_of_house {\n" " mod hosting {\n" " fn add_to_waitlist() {}\n" @@ -7066,13 +7257,13 @@ msgid "" "```" msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:26 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:27 msgid "" "Listing 6-5: Bringing a module into scope with\n" "`use`" msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:29 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:30 msgid "" "Adding use and a path in a scope is similar to creating a symbolic link in " "the filesystem. By adding `use restaurant::front_of_house::hosting` in the " @@ -7080,7 +7271,7 @@ msgid "" "`hosting` module had been defined in the crate root." msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:31 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:32 msgid "" "Note that `use` only creates the shortcut for the particular scope in which " "the `use` occurs. Listing 6-6 moves the `eat_at_restaurant` function into a " @@ -7090,9 +7281,10 @@ msgid "" "statement, so the function body won’t compile:" msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:37 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:38 msgid "" "```rust\n" +"// does_not_compile\n" "mod front_of_house {\n" " mod hosting {\n" " fn add_to_waitlist() {}\n" @@ -7109,20 +7301,20 @@ msgid "" "```" msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:53 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:55 msgid "" "Listing 6-6: A `use` statement only applies in the " "scope\n" "it’s in" msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:56 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:58 msgid "" "The compiler error shows that the shortcut no longer applies within the\n" "`customer` module:" msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:59 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:61 msgid "" "```console\n" "❯ scarb build\n" @@ -7133,11 +7325,11 @@ msgid "" "```" msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:67 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:69 msgid "## Creating Idiomatic `use` Paths" msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:69 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:71 msgid "" "In Listing 6-5, you might have wondered why we specified `use\n" "restaurant::front_of_house::hosting` and then called " @@ -7147,32 +7339,31 @@ msgid "" "the `add_to_waitlist` function to achieve the same result, as in Listing 6-7." msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:76 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:78 msgid "" "```rust\n" "mod front_of_house {\n" -" pub mod hosting {\n" -" pub fn add_to_waitlist() {}\n" +" mod hosting {\n" +" fn add_to_waitlist() {}\n" " }\n" "}\n" "\n" "use restaurant::front_of_house::hosting::add_to_waitlist;\n" "\n" -"pub fn eat_at_restaurant() {\n" +"fn eat_at_restaurant() {\n" " add_to_waitlist();\n" "}\n" -"\n" "```" msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:91 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:92 msgid "" "Listing 6-7: Bringing the `add_to_waitlist` " "function\n" "into scope with `use`, which is unidiomatic" msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:94 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:95 msgid "" "Although both Listing 6-5 and 6-7 accomplish the same task, Listing 6-5 is\n" "the idiomatic way to bring a function into scope with `use`. Bringing the\n" @@ -7184,7 +7375,7 @@ msgid "" "unclear as to where `add_to_waitlist` is defined." msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:102 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:103 msgid "" "On the other hand, when bringing in structs, enums, traits, and other items " "with `use`,\n" @@ -7193,7 +7384,7 @@ msgid "" "to bring the core library’s `ArrayTrait` trait into the scope." msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:106 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:107 msgid "" "```rust\n" "use array::ArrayTrait;\n" @@ -7205,13 +7396,13 @@ msgid "" "```" msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:115 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:116 msgid "" "Listing 6-8: Bringing `ArrayTrait` into scope in an\n" "idiomatic way" msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:118 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:119 msgid "" "There’s no strong reason behind this idiom: it’s just the convention that " "has\n" @@ -7220,18 +7411,18 @@ msgid "" "As Cairo shares many idioms with Rust, we follow this convention as well." msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:122 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:123 msgid "" "The exception to this idiom is if we’re bringing two items with the same " "name\n" "into scope with `use` statements, because Cairo doesn’t allow that." msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:125 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:126 msgid "### Providing New Names with the `as` Keyword" msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:127 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:128 msgid "" "There’s another solution to the problem of bringing two types of the same " "name\n" @@ -7241,36 +7432,107 @@ msgid "" "an import with `as`:" msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:133 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:134 msgid "" "```rust\n" "use array::ArrayTrait as Arr;\n" "\n" -"fn main(){\n" +"fn main() {\n" " let mut arr = Arr::new(); // ArrayTrait was renamed to Arr\n" " arr.append(1);\n" "}\n" "```" msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:142 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:143 msgid "" "Listing 6-9: Renaming a trait when it’s brought " "into\n" "scope with the `as` keyword" msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:145 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:146 msgid "" "Here, we brought `ArrayTrait` into scope with the alias `Arr`. We can now " "access the trait's methods with the `Arr` identifier." msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:147 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:148 +msgid "### Importing multiple items from the same module" +msgstr "" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:150 +msgid "" +"When you want to import multiple items (like functions, structs or enums)\n" +"from the same module in Cairo, you can use curly braces `{}` to list all of\n" +"the items that you want to import. This helps to keep your code clean and " +"easy\n" +"to read by avoiding a long list of individual use statements." +msgstr "" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:155 +msgid "The general syntax for importing multiple items from the same module is:" +msgstr "" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:157 +msgid "" +"```rust\n" +"use module::{item1, item2, item3};\n" +"```" +msgstr "" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:161 +msgid "Here is an example where we import three structures from the same module:" +msgstr "" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:163 +msgid "" +"```rust\n" +"// Assuming we have a module called `shapes` with the structures `Square`, " +"`Circle`, and `Triangle`.\n" +"mod shapes {\n" +" #[derive(Drop)]\n" +" struct Square {\n" +" side: u32\n" +" }\n" +"\n" +" #[derive(Drop)]\n" +" struct Circle {\n" +" radius: u32\n" +" }\n" +"\n" +" #[derive(Drop)]\n" +" struct Triangle {\n" +" base: u32,\n" +" height: u32,\n" +" }\n" +"}\n" +"\n" +"// We can import the structures `Square`, `Circle`, and `Triangle` from the " +"`shapes` module like this:\n" +"use shapes::{Square, Circle, Triangle};\n" +"\n" +"// Now we can directly use `Square`, `Circle`, and `Triangle` in our code.\n" +"fn main() {\n" +" let sq = Square { side: 5 };\n" +" let cr = Circle { radius: 3 };\n" +" let tr = Triangle { base: 5, height: 2 };\n" +"// ...\n" +"}\n" +"```" +msgstr "" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:195 +msgid "" +"Listing 6-10: Importing multiple items from the same " +"module" +msgstr "" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:197 msgid "## Re-exporting Names in Module Files" msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:149 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:199 msgid "" "When we bring a name into scope with the `use` keyword, the name available " "in\n" @@ -7281,15 +7543,16 @@ msgid "" "but also making that item available for others to bring into their scope." msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:154 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:204 msgid "" "For example, let's re-export the `add_to_waitlist` function in the " "restaurant example:" msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:158 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:208 msgid "" -"```rs\n" +"```rust\n" +"// does_not_compile\n" "mod front_of_house {\n" " mod hosting {\n" " fn add_to_waitlist() {}\n" @@ -7304,14 +7567,14 @@ msgid "" "```" msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:172 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:223 msgid "" -"Listing 6-10: Making a name available for any code " +"Listing 6-11: Making a name available for any code " "to use\n" "from a new scope with `pub use`" msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:175 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:226 msgid "" "Before this change, external code would have to call the `add_to_waitlist`\n" "function by using the path\n" @@ -7321,7 +7584,7 @@ msgid "" "can now use the path `restaurant::hosting::add_to_waitlist()` instead." msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:181 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:232 msgid "" "Re-exporting is useful when the internal structure of your code is " "different\n" @@ -7337,22 +7600,22 @@ msgid "" "the library and programmers calling the library." msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:190 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:241 msgid "## Using External Packages in Cairo with Scarb" msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:192 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:243 msgid "" "You might need to use external packages to leverage the functionality " "provided by the community. To use an external package in your project with " "Scarb, follow these steps:" msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:194 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:245 msgid "" "> The dependencies system is still a work in progress. You can check the " "official " -"[documentation](https://docs.swmansion.com/scarb/docs/guides/dependencies)." +"[documentation](https://docs.swmansion.com/scarb/docs/guides/dependencies.html)." msgstr "" #: src/ch06-05-separating-modules-into-different-files.md:1 @@ -7370,7 +7633,7 @@ msgstr "" #: src/ch06-05-separating-modules-into-different-files.md:7 msgid "" -"For example, let’s start from the code in Listing 6-10 that had multiple\n" +"For example, let’s start from the code in Listing 6-11 that had multiple\n" "restaurant modules. We’ll extract modules into files instead of having all " "the\n" "modules defined in the crate root file. In this case, the crate root file " @@ -7386,46 +7649,47 @@ msgid "" "only\n" "the `mod front_of_house;` declaration, so that _src/lib.cairo_ contains the " "code\n" -"shown in Listing 6-11. Note that this won’t compile until we create the\n" -"_src/front_of_house.cairo_ file in Listing 6-12." +"shown in Listing 6-12. Note that this won’t compile until we create the\n" +"_src/front_of_house.cairo_ file in Listing 6-13." msgstr "" #: src/ch06-05-separating-modules-into-different-files.md:20 msgid "" "```rust\n" +"// does_not_compile\n" "mod front_of_house;\n" "\n" "use restaurant::front_of_house::hosting;\n" "\n" -"pub fn eat_at_restaurant() {\n" +"fn eat_at_restaurant() {\n" " hosting::add_to_waitlist();\n" "}\n" "```" msgstr "" -#: src/ch06-05-separating-modules-into-different-files.md:30 +#: src/ch06-05-separating-modules-into-different-files.md:31 msgid "" -"Listing 6-11: Declaring the `front_of_house` module " +"Listing 6-12: Declaring the `front_of_house` module " "whose\n" "body will be in _src/front_of_house.cairo_" msgstr "" -#: src/ch06-05-separating-modules-into-different-files.md:33 +#: src/ch06-05-separating-modules-into-different-files.md:34 msgid "" "Next, place the code that was in the curly brackets into a new file named\n" -"_src/front_of_house.cairo_, as shown in Listing 6-12. The compiler knows to " +"_src/front_of_house.cairo_, as shown in Listing 6-13. The compiler knows to " "look\n" "in this file because it came across the module declaration in the crate " "root\n" "with the name `front_of_house`." msgstr "" -#: src/ch06-05-separating-modules-into-different-files.md:38 -#: src/ch06-05-separating-modules-into-different-files.md:66 +#: src/ch06-05-separating-modules-into-different-files.md:39 +#: src/ch06-05-separating-modules-into-different-files.md:67 msgid "Filename: src/front_of_house.cairo" msgstr "" -#: src/ch06-05-separating-modules-into-different-files.md:40 +#: src/ch06-05-separating-modules-into-different-files.md:41 msgid "" "```rust,\n" "mod hosting {\n" @@ -7434,14 +7698,14 @@ msgid "" "```" msgstr "" -#: src/ch06-05-separating-modules-into-different-files.md:46 +#: src/ch06-05-separating-modules-into-different-files.md:47 msgid "" -"Listing 6-12: Definitions inside the " +"Listing 6-13: Definitions inside the " "`front_of_house`\n" "module in _src/front_of_house.cairo_" msgstr "" -#: src/ch06-05-separating-modules-into-different-files.md:49 +#: src/ch06-05-separating-modules-into-different-files.md:50 msgid "" "Note that you only need to load a file using a `mod` declaration _once_ in " "your\n" @@ -7459,7 +7723,7 @@ msgid "" "programming languages." msgstr "" -#: src/ch06-05-separating-modules-into-different-files.md:58 +#: src/ch06-05-separating-modules-into-different-files.md:59 msgid "" "Next, we’ll extract the `hosting` module to its own file. The process is a " "bit\n" @@ -7471,40 +7735,40 @@ msgid "" "_src/front_of_house/_." msgstr "" -#: src/ch06-05-separating-modules-into-different-files.md:63 +#: src/ch06-05-separating-modules-into-different-files.md:64 msgid "" "To start moving `hosting`, we change _src/front_of_house.cairo_ to contain " "only the\n" "declaration of the `hosting` module:" msgstr "" -#: src/ch06-05-separating-modules-into-different-files.md:68 +#: src/ch06-05-separating-modules-into-different-files.md:69 msgid "" "```rust\n" "mod hosting;\n" "```" msgstr "" -#: src/ch06-05-separating-modules-into-different-files.md:72 +#: src/ch06-05-separating-modules-into-different-files.md:73 msgid "" "Then we create a _src/front_of_house_ directory and a file _hosting.cairo_ " "to\n" "contain the definitions made in the `hosting` module:" msgstr "" -#: src/ch06-05-separating-modules-into-different-files.md:75 +#: src/ch06-05-separating-modules-into-different-files.md:76 msgid "" "Filename: src/front_of_house/hosting.cairo" msgstr "" -#: src/ch06-05-separating-modules-into-different-files.md:77 +#: src/ch06-05-separating-modules-into-different-files.md:78 msgid "" "```rust\n" -"pub fn add_to_waitlist() {}\n" +"fn add_to_waitlist() {}\n" "```" msgstr "" -#: src/ch06-05-separating-modules-into-different-files.md:81 +#: src/ch06-05-separating-modules-into-different-files.md:82 msgid "" "If we instead put _hosting.cairo_ in the _src_ directory, the compiler " "would\n" @@ -7515,7 +7779,7 @@ msgid "" "directories and files more closely match the module tree." msgstr "" -#: src/ch06-05-separating-modules-into-different-files.md:87 +#: src/ch06-05-separating-modules-into-different-files.md:88 msgid "" "We’ve moved each module’s code to a separate file, and the module tree " "remains\n" @@ -7524,7 +7788,7 @@ msgid "" "technique lets you move modules to new files as they grow in size." msgstr "" -#: src/ch06-05-separating-modules-into-different-files.md:92 +#: src/ch06-05-separating-modules-into-different-files.md:93 msgid "" "Note that the `use restaurant::front_of_house::hosting` statement in\n" "_src/lib.cairo_ also hasn’t changed, nor does `use` have any impact on what " @@ -7536,7 +7800,7 @@ msgid "" "that module." msgstr "" -#: src/ch06-05-separating-modules-into-different-files.md:100 +#: src/ch06-05-separating-modules-into-different-files.md:101 msgid "" "Cairo lets you split a package into multiple crates and a crate into " "modules\n" @@ -7549,12 +7813,6 @@ msgid "" "the item in that scope. Module code is public by default." msgstr "" -#: src/ch06-05-separating-modules-into-different-files.md:106 -msgid "" -"In the next chapter, we’ll look at some collection data structures in the\n" -"standard library that you can use in your neatly organized code." -msgstr "" - #: src/ch07-00-generic-types-and-traits.md:1 msgid "# Generic Types and Traits" msgstr "" @@ -7608,7 +7866,7 @@ msgid "" "and functions, which we can then use with many different concrete data " "types. In Cairo we can use generics when defining functions, structs, enums, " "traits, implementations and methods! In this chapter we are going to take a " -"look on how to effectively use generic types with all of them." +"look at how to effectively use generic types with all of them." msgstr "" #: src/ch07-01-generic-data-types.md:5 @@ -7621,15 +7879,15 @@ msgid "" "function signature, where we would usually specify the data types of the " "parameter and return value. For example, imagine we want to create a " "function which given two `Array` of items, will return the largest one. If " -"we need to perform this operations for lists of different types, then we " +"we need to perform this operation for lists of different types, then we " "would have to redefine the function each time. Luckily we can implement the " "function once using generics and move on to other tasks." msgstr "" #: src/ch07-01-generic-data-types.md:9 msgid "" -"```rust,does_not_compile\n" -"// This code does not compile!\n" +"```rust\n" +"// does_not_compile\n" "\n" "use array::ArrayTrait;\n" "\n" @@ -7665,17 +7923,18 @@ msgid "" "The `largest_list` function compares two lists of the same type and returns " "the one with more elements and drops the other. If you compile the previous " "code, you will notice that it will fail with an error saying that there are " -"no traits defined for droping an array of a generic type. This happens " +"no traits defined for dropping an array of a generic type. This happens " "because the compiler has no way to guarantee that an `Array` is droppable " "when executing the `main` function. In order to drop an array of `T`, the " -"compiler must first know how to drop `T`. This can be fixed by specifiying " -"in the function signature of `largest_list` that `T` must implement the drop " +"compiler must first know how to drop `T`. This can be fixed by specifying in " +"the function signature of `largest_list` that `T` must implement the drop " "trait. The correct function definition of `largest_list` is as follows:" msgstr "" #: src/ch07-01-generic-data-types.md:42 msgid "" "```rust\n" +"use array::ArrayTrait;\n" "fn largest_list>(l1: Array, l2: Array) -> " "Array {\n" " if l1.len() > l2.len() {\n" @@ -7687,7 +7946,7 @@ msgid "" "```" msgstr "" -#: src/ch07-01-generic-data-types.md:52 +#: src/ch07-01-generic-data-types.md:53 msgid "" "The new `largest_list` function includes in its definition the requirement " "that whatever generic type is placed there, it must be droppable. The `main` " @@ -7695,11 +7954,11 @@ msgid "" "concrete type is being used and if it implements the `Drop` trait." msgstr "" -#: src/ch07-01-generic-data-types.md:54 +#: src/ch07-01-generic-data-types.md:55 msgid "### Constraints for Generic Types" msgstr "" -#: src/ch07-01-generic-data-types.md:56 +#: src/ch07-01-generic-data-types.md:57 msgid "" "When defining generic types, it is useful to have information about them. " "Knowing which traits a generic type implements allow us to use them more " @@ -7711,7 +7970,7 @@ msgid "" "logic." msgstr "" -#: src/ch07-01-generic-data-types.md:58 +#: src/ch07-01-generic-data-types.md:59 msgid "" "Imagine that we want, given a list of elements of some generic type `T`, " "find the smallest element among them. Initially, we know that for an element " @@ -7719,11 +7978,11 @@ msgid "" "resulting function would be:" msgstr "" -#: src/ch07-01-generic-data-types.md:60 +#: src/ch07-01-generic-data-types.md:61 msgid "" -"```rust,does_not_compile\n" -"// This code does not compile!\n" -"use array:ArrayTrait;\n" +"```rust\n" +"// does_not_compile\n" +"use array::ArrayTrait;\n" "\n" "// Given a list of T get the smallest one.\n" "// The PartialOrd trait implements comparison operations for T\n" @@ -7731,14 +7990,14 @@ msgid "" "T {\n" " // This represents the smallest element through the iteration\n" " // Notice that we use the desnap (*) operator\n" -" let mut smallest = *list[0_usize];\n" +" let mut smallest = *list[0];\n" "\n" " // The index we will use to move through the list\n" -" let mut index = 1_usize;\n" +" let mut index = 1;\n" "\n" " // Iterate through the whole list storing the smallest\n" " loop {\n" -" if index >= list.len(){\n" +" if index >= list.len() {\n" " break smallest;\n" " }\n" " if *list[index] < smallest {\n" @@ -7748,17 +8007,16 @@ msgid "" " }\n" "}\n" "\n" -"fn main() {\n" -" let mut list = ArrayTrait::new();\n" -" list.append(5_u8);\n" -" list.append(3_u8);\n" -" list.append(10_u8);\n" +"fn main() {\n" +" let mut list: Array = ArrayTrait::new();\n" +" list.append(5);\n" +" list.append(3);\n" +" list.append(10);\n" "\n" " // We need to specify that we are passing a snapshot of `list` as an " "argument\n" " let s = smallest_element(@list);\n" -" assert(s == 3_u8, 0);\n" -"\n" +" assert(s == 3, 0);\n" "}\n" "```" msgstr "" @@ -7766,7 +8024,7 @@ msgstr "" #: src/ch07-01-generic-data-types.md:99 msgid "" "The `smallest_element` function uses a generic type `T` that implements the " -"`PartialOrd` trait, takes an snapshot of an `Array` as a parameter and " +"`PartialOrd` trait, takes a snapshot of an `Array` as a parameter and " "returns a copy of the smallest element. Because the parameter is of type " "`@Array`, we no longer need to drop it at the end of the execution and so " "we don't require to implement the `Drop` trait for `T` as well. Why it does " @@ -7789,12 +8047,15 @@ msgstr "" #: src/ch07-01-generic-data-types.md:103 msgid "" "```rs\n" +"use array::ArrayTrait;\n" "fn smallest_element, impl TCopy: Copy, " -"impl TDrop: Drop>(list: @Array) -> T {\n" -" let mut smallest = *list[0_usize];\n" -" let mut index = 1_usize;\n" +"impl TDrop: Drop>(\n" +" list: @Array\n" +") -> T {\n" +" let mut smallest = *list[0];\n" +" let mut index = 1;\n" " loop {\n" -" if index >= list.len(){\n" +" if index >= list.len() {\n" " break smallest;\n" " }\n" " if *list[index] < smallest {\n" @@ -7806,11 +8067,11 @@ msgid "" "```" msgstr "" -#: src/ch07-01-generic-data-types.md:119 +#: src/ch07-01-generic-data-types.md:122 msgid "## Structs" msgstr "" -#: src/ch07-01-generic-data-types.md:121 +#: src/ch07-01-generic-data-types.md:124 msgid "" "We can also define structs to use a generic type parameter for one or more " "fields using the `<>` syntax, similar to function definitions. First we " @@ -7821,52 +8082,43 @@ msgid "" "type `T`." msgstr "" -#: src/ch07-01-generic-data-types.md:123 +#: src/ch07-01-generic-data-types.md:126 msgid "" -"```rust,does_not_compile\n" -"// This code does not compile!\n" -"\n" +"```rust\n" "#[derive(Drop)]\n" "struct Wallet {\n" -" balance: T,\n" +" balance: T\n" "}\n" "\n" "\n" "fn main() {\n" -" let w = Wallet{ balance: 3_u128};\n" +" let w = Wallet { balance: 3 };\n" "}\n" "```" msgstr "" -#: src/ch07-01-generic-data-types.md:137 -msgid "" -"Compiling the above code would error due to the `derive` macro not working " -"well with generics. When using generic types is best to directly write the " -"traits you want to use:" -msgstr "" - -#: src/ch07-01-generic-data-types.md:139 +#: src/ch07-01-generic-data-types.md:138 msgid "" -"" +"The above code derives the `Drop` trait for the `Wallet` type automatically. " +"It is equivalent to writing the following code:" msgstr "" -#: src/ch07-01-generic-data-types.md:141 +#: src/ch07-01-generic-data-types.md:140 msgid "" "```rust\n" "struct Wallet {\n" -" balance: T,\n" +" balance: T\n" "}\n" "\n" "impl WalletDrop> of Drop>;\n" "\n" "fn main() {\n" -" let w = Wallet { balance: 3_u128 };\n" +" let w = Wallet { balance: 3 };\n" "}\n" "```" msgstr "" -#: src/ch07-01-generic-data-types.md:153 +#: src/ch07-01-generic-data-types.md:152 msgid "" "We avoid using the `derive` macro for `Drop` implementation of `Wallet` and " "instead define our own `WalletDrop` implementation. Notice that we must " @@ -7875,62 +8127,47 @@ msgid "" "that the struct `Wallet` is droppable as long as `T` is also droppable." msgstr "" -#: src/ch07-01-generic-data-types.md:155 +#: src/ch07-01-generic-data-types.md:154 msgid "" -"Finally, if we want to add a field to `Wallet` representing its Cairo " -"address and we want that field to be different than `T` but generic as well, " -"we can simply add another generic type between the `<>`:" +"Finally, if we want to add a field to `Wallet` representing its address and " +"we want that field to be different than `T` but generic as well, we can " +"simply add another generic type between the `<>`:" msgstr "" -#: src/ch07-01-generic-data-types.md:157 +#: src/ch07-01-generic-data-types.md:156 msgid "" "```rust\n" +"#[derive(Drop)]\n" "struct Wallet {\n" " balance: T,\n" " address: U,\n" "}\n" "\n" -"impl WalletDrop, U, impl UDrop: Drop> of " -"Drop>;\n" -"\n" "fn main() {\n" -" let w = Wallet { balance: 3_u128, address: 14 };\n" +" let w = Wallet { balance: 3, address: 14 };\n" "}\n" "```" msgstr "" -#: src/ch07-01-generic-data-types.md:170 +#: src/ch07-01-generic-data-types.md:168 msgid "" -"We add to `Wallet` struct definiton a new generic type `U` and then assign " -"this type to the new field member `address`.\n" -"Then we adapt the `WalletDrop` trait to work with the new generic type `U`. " -"Notice that when initializing the struct inside `main` it automatically " -"infers that `T` is a `u128` and `U` is a `felt252` and since they are both " -"droppable, `Wallet` is droppable as well!" +"We add to `Wallet` struct definition a new generic type `U` and then assign " +"this type to the new field member `address`. Notice that the derive " +"attribute for the `Drop` trait works for `U` as well." msgstr "" -#: src/ch07-01-generic-data-types.md:173 +#: src/ch07-01-generic-data-types.md:170 msgid "## Enums" msgstr "" -#: src/ch07-01-generic-data-types.md:175 +#: src/ch07-01-generic-data-types.md:172 msgid "" "As we did with structs, we can define enums to hold generic data types in " "their variants. For example the `Option` enum provided by the Cairo core " "library:" msgstr "" -#: src/ch07-01-generic-data-types.md:177 -msgid "" -"```rust\n" -"enum Option {\n" -" Some(T),\n" -" None,\n" -"}\n" -"```" -msgstr "" - -#: src/ch07-01-generic-data-types.md:184 +#: src/ch07-01-generic-data-types.md:181 msgid "" "The `Option` enum is generic over a type `T` and has two variants: " "`Some`, which holds one value of type `T` and `None` that doesn't hold any " @@ -7939,25 +8176,25 @@ msgid "" "type `T` we can use this abstraction with any type." msgstr "" -#: src/ch07-01-generic-data-types.md:186 +#: src/ch07-01-generic-data-types.md:183 msgid "" "Enums can use multiple generic types as well, like definition of the " "`Result` enum that the core library provides:" msgstr "" -#: src/ch07-01-generic-data-types.md:188 -#: src/ch09-02-error-handling.md:11 +#: src/ch07-01-generic-data-types.md:185 +#: src/ch09-02-recoverable-errors.md:11 msgid "" "```rust\n" "enum Result {\n" -" Ok(T),\n" -" Err(E),\n" +" Ok: T,\n" +" Err: E,\n" "}\n" "```" msgstr "" -#: src/ch07-01-generic-data-types.md:195 -#: src/ch09-02-error-handling.md:18 +#: src/ch07-01-generic-data-types.md:192 +#: src/ch09-02-recoverable-errors.md:18 msgid "" "The `Result` enum has two generic types, `T` and `E`, and two " "variants: `Ok` which holds the value of type `T` and `Err` which holds the " @@ -7966,27 +8203,25 @@ msgid "" "of type `T`) or fail (by returning a value of type `E`)." msgstr "" -#: src/ch07-01-generic-data-types.md:197 +#: src/ch07-01-generic-data-types.md:194 msgid "## Generic Methods" msgstr "" -#: src/ch07-01-generic-data-types.md:199 +#: src/ch07-01-generic-data-types.md:196 msgid "" "We can implement methods on structs and enums, and use the generic types in " "their definition, too. Using our previous definition of `Wallet` struct, " "we define a `balance` method for it:" msgstr "" -#: src/ch07-01-generic-data-types.md:201 +#: src/ch07-01-generic-data-types.md:198 msgid "" "```rust\n" +"#[derive(Copy, Drop)]\n" "struct Wallet {\n" -" balance: T,\n" +" balance: T\n" "}\n" "\n" -"impl WalletDrop> of Drop>;\n" -"impl WalletCopy> of Copy>;\n" -"\n" "trait WalletTrait {\n" " fn balance(self: @Wallet) -> T;\n" "}\n" @@ -8004,7 +8239,7 @@ msgid "" "```" msgstr "" -#: src/ch07-01-generic-data-types.md:225 +#: src/ch07-01-generic-data-types.md:220 msgid "" "We first define `WalletTrait` trait using a generic type `T` which " "defines a method that returns a snapshot of the field `address` from " @@ -8013,7 +8248,7 @@ msgid "" "trait and the implementation." msgstr "" -#: src/ch07-01-generic-data-types.md:227 +#: src/ch07-01-generic-data-types.md:222 msgid "" "We can also specify constraints on generic types when defining methods on " "the type. We could, for example, implement methods only for `Wallet` " @@ -8022,14 +8257,14 @@ msgid "" "`balance` field." msgstr "" -#: src/ch07-01-generic-data-types.md:229 +#: src/ch07-01-generic-data-types.md:224 msgid "" "```rust\n" +"#[derive(Copy, Drop)]\n" "struct Wallet {\n" -" balance: T,\n" +" balance: T\n" "}\n" -"impl WalletDrop> of Drop>;\n" -"impl WalletCopy> of Copy>;\n" +"\n" "/// Generic trait for wallets\n" "trait WalletTrait {\n" " fn balance(self: @Wallet) -> T;\n" @@ -8053,16 +8288,16 @@ msgid "" "}\n" "\n" "fn main() {\n" -" let mut w = Wallet { balance: 50_u128 };\n" -" assert(w.balance() == 50_u128, 0);\n" +" let mut w = Wallet { balance: 50 };\n" +" assert(w.balance() == 50, 0);\n" "\n" -" w.receive(100_u128);\n" -" assert(w.balance() == 150_u128, 0);\n" +" w.receive(100);\n" +" assert(w.balance() == 150, 0);\n" "}\n" "```" msgstr "" -#: src/ch07-01-generic-data-types.md:266 +#: src/ch07-01-generic-data-types.md:261 msgid "" "The new method `receive` increments the size of the balance of any instance " "of a `Wallet`. Notice that we changed the `main` function making `w` a " @@ -8071,31 +8306,32 @@ msgid "" "the previous code wouldn't compile." msgstr "" -#: src/ch07-01-generic-data-types.md:268 +#: src/ch07-01-generic-data-types.md:263 msgid "" "Cairo allows us to define generic methods inside generic traits as well. " "Using the past implementation from `Wallet` we are going to define a " "trait that picks two wallets of different generic types and create a new one " -"with a generic type of each. First, lets rewrite the struct definiton:" +"with a generic type of each. First, let's rewrite the struct definition:" msgstr "" -#: src/ch07-01-generic-data-types.md:270 +#: src/ch07-01-generic-data-types.md:265 msgid "" "```rust\n" +"// does_not_compile\n" "struct Wallet {\n" " balance: T,\n" " address: U,\n" -"}\n" "```" msgstr "" -#: src/ch07-01-generic-data-types.md:277 +#: src/ch07-01-generic-data-types.md:272 msgid "Next we are going to naively define the mixup trait and implementation:" msgstr "" -#: src/ch07-01-generic-data-types.md:279 +#: src/ch07-01-generic-data-types.md:274 msgid "" "```rust\n" +"\n" "// This does not compile!\n" "trait WalletMixTrait {\n" " fn mixup(self: Wallet, other: Wallet) -> " @@ -8107,11 +8343,11 @@ msgid "" "Wallet {\n" " Wallet { balance: self.balance, address: other.address }\n" " }\n" -"}\n" +"\n" "```" msgstr "" -#: src/ch07-01-generic-data-types.md:292 +#: src/ch07-01-generic-data-types.md:288 msgid "" "We are creating a trait `WalletMixTrait` with the `mixup` " "methods which given an instance of `Wallet` and `Wallet` " @@ -8119,12 +8355,12 @@ msgid "" "and `other` are getting dropped at the end of the function, which is the " "reason for this code not to compile. If you have been following from the " "start until now you would know that we must add a requirement for all the " -"generic types specifiying that they will implement the `Drop` trait in order " +"generic types specifying that they will implement the `Drop` trait in order " "for the compiler to know how to drop instances of `Wallet`. The " "updated implementation is as follow:" msgstr "" -#: src/ch07-01-generic-data-types.md:294 +#: src/ch07-01-generic-data-types.md:290 msgid "" "```rust\n" "trait WalletMixTrait {\n" @@ -8144,29 +8380,29 @@ msgid "" "```" msgstr "" -#: src/ch07-01-generic-data-types.md:310 +#: src/ch07-01-generic-data-types.md:306 msgid "" "We add the requirements for `T1` and `U1` to be droppable on `WalletMixImpl` " "declaration. Then we do the same for `T2` and `U2`, this time as part of " "`mixup` signature. We can now try the `mixup` function:" msgstr "" -#: src/ch07-01-generic-data-types.md:312 +#: src/ch07-01-generic-data-types.md:308 msgid "" -"```rs, does_not_compile\n" +"```rust\n" "fn main() {\n" -" let w1 = Wallet { balance: true, address: 10_u128 };\n" -" let w2 = Wallet { balance: 32, address: 100_u8 };\n" +" let w1 = Wallet { balance: true, address: 10 };\n" +" let w2 = Wallet { balance: 32, address: 100 };\n" "\n" " let w3 = w1.mixup(w2);\n" "\n" " assert(w3.balance == true, 0);\n" -" assert(w3.address == 100_u8, 0);\n" +" assert(w3.address == 100, 0);\n" "}\n" "```" msgstr "" -#: src/ch07-01-generic-data-types.md:324 +#: src/ch07-01-generic-data-types.md:320 msgid "" "We first create two instances: one of `Wallet` and the other of " "`Wallet`. Then, we call `mixup` and create a new `Wallet u64 {\n" -" 2_u64 * (self.height + self.width)\n" +" 2 * (self.height + self.width)\n" " }\n" "\tfn area(self: Rectangle) -> u64 {\n" "\t\tself.height * self.width\n" @@ -8315,18 +8551,18 @@ msgid "" "```rust\n" "use debug::PrintTrait;\n" "\n" -"#[derive(Copy,Drop)]\n" -"struct Rectangle{\n" +"#[derive(Copy, Drop)]\n" +"struct Rectangle {\n" " height: u64,\n" " width: u64,\n" "}\n" "\n" -"#[derive(Copy,Drop)]\n" -"struct Circle{\n" -" radius: u64,\n" +"#[derive(Copy, Drop)]\n" +"struct Circle {\n" +" radius: u64\n" "}\n" "\n" -"// Here T is an alias type which will be provided buring implementation\n" +"// Here T is an alias type which will be provided during implementation\n" "trait ShapeGeometry {\n" " fn boundary(self: T) -> u64;\n" " fn area(self: T) -> u64;\n" @@ -8336,7 +8572,7 @@ msgid "" "// to implement the trait for that type\n" "impl RectangleGeometry of ShapeGeometry {\n" " fn boundary(self: Rectangle) -> u64 {\n" -" 2_u64 * (self.height + self.width)\n" +" 2 * (self.height + self.width)\n" " }\n" " fn area(self: Rectangle) -> u64 {\n" " self.height * self.width\n" @@ -8347,19 +8583,19 @@ msgid "" "// which can use the same trait spec\n" "impl CircleGeometry of ShapeGeometry {\n" " fn boundary(self: Circle) -> u64 {\n" -" (2_u64 * 314_u64 * self.radius) / 100_u64\n" +" (2 * 314 * self.radius) / 100\n" " }\n" " fn area(self: Circle) -> u64 {\n" -" (314_u64 * self.radius * self.radius) / 100_u64\n" +" (314 * self.radius * self.radius) / 100\n" " }\n" "}\n" "\n" "fn main() {\n" -" let rect = Rectangle { height: 5_u64, width: 7_u64 };\n" +" let rect = Rectangle { height: 5, width: 7 };\n" " rect.area().print(); // 35\n" " rect.boundary().print(); // 24\n" "\n" -" let circ = Circle { radius: 5_u64 };\n" +" let circ = Circle { radius: 5 };\n" " circ.area().print(); // 78\n" " circ.boundary().print(); // 31\n" "}\n" @@ -8393,7 +8629,7 @@ msgstr "" #: src/ch07-02-traits-in-cairo.md:125 msgid "" -"```rust, does_not_compile\n" +"```rust,does_not_compile,ignore_format\n" "use debug::PrintTrait;\n" "\n" "// struct Circle { ... } and struct Rectangle { ... }\n" @@ -8413,14 +8649,14 @@ msgid "" "mod circle {\n" " use super::geometry::ShapeGeometry;\n" " use super::Circle;\n" -" impl CircleGeometry of ShapeGeometry:: {\n" +" impl CircleGeometry of ShapeGeometry {\n" " // ...\n" " }\n" "}\n" "\n" "fn main() {\n" -" let rect = Rectangle { height: 5_u64, width: 7_u64 };\n" -" let circ = Circle { radius: 5_u64 };\n" +" let rect = Rectangle { height: 5, width: 7 };\n" +" let circ = Circle { radius: 5 };\n" " // Fails with this error\n" " // Method `area` not found on... Did you import the correct trait and " "impl?\n" @@ -8482,7 +8718,7 @@ msgstr "" msgid "" "Let’s look at the features Cairo provides specifically for writing tests " "that take these actions, which include the `test` attribute, the `assert` " -"function, and and the `should_panic` attribute." +"function, and the `should_panic` attribute." msgstr "" #: src/ch08-01-how-to-write-tests.md:13 @@ -8546,37 +8782,33 @@ msgid "In _lib.cairo_, let's add a first test, as shown in Listing 8-1." msgstr "" #: src/ch08-01-how-to-write-tests.md:43 -#: src/ch08-01-how-to-write-tests.md:79 -#: src/ch08-01-how-to-write-tests.md:140 -#: src/ch08-01-how-to-write-tests.md:162 -#: src/ch08-01-how-to-write-tests.md:201 -#: src/ch08-01-how-to-write-tests.md:274 -#: src/ch08-01-how-to-write-tests.md:355 +#: src/ch08-01-how-to-write-tests.md:76 +#: src/ch08-01-how-to-write-tests.md:132 +#: src/ch08-01-how-to-write-tests.md:155 +#: src/ch08-01-how-to-write-tests.md:221 +#: src/ch08-01-how-to-write-tests.md:319 +#: src/ch08-01-how-to-write-tests.md:411 #: src/ch08-02-test-organization.md:19 #: src/ch09-01-unrecoverable-errors-with-panic.md:9 msgid "Filename: lib.cairo" msgstr "" #: src/ch08-01-how-to-write-tests.md:45 -#: src/ch08-02-test-organization.md:21 msgid "" "```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" " #[test]\n" " fn it_works() {\n" " let result = 2 + 2;\n" " assert(result == 4, 'result is not 4');\n" " }\n" -"}\n" "```" msgstr "" -#: src/ch08-01-how-to-write-tests.md:56 -msgid "Listing 8-1: A test module and function" +#: src/ch08-01-how-to-write-tests.md:53 +msgid "Listing 8-1: A test module and function" msgstr "" -#: src/ch08-01-how-to-write-tests.md:58 +#: src/ch08-01-how-to-write-tests.md:55 msgid "" "For now, let’s ignore the top two lines and focus on the function. Note the " "`#[test]` annotation: this attribute indicates this is a test function, so " @@ -8586,20 +8818,20 @@ msgid "" "tests." msgstr "" -#: src/ch08-01-how-to-write-tests.md:60 +#: src/ch08-01-how-to-write-tests.md:57 msgid "" "The example function body uses the `assert` function, which contains the " "result of adding 2 and 2, equals 4. This assertion serves as an example of " "the format for a typical test. Let’s run it to see that this test passes." msgstr "" -#: src/ch08-01-how-to-write-tests.md:62 +#: src/ch08-01-how-to-write-tests.md:59 msgid "" "The `cairo-test .` command runs all tests in our project, as shown in " "Listing 8-2." msgstr "" -#: src/ch08-01-how-to-write-tests.md:64 +#: src/ch08-01-how-to-write-tests.md:61 msgid "" "```shell\n" "$ cairo-test .\n" @@ -8609,11 +8841,12 @@ msgid "" "```" msgstr "" -#: src/ch08-01-how-to-write-tests.md:71 -msgid "Listing 8-2: The output from running a test" +#: src/ch08-01-how-to-write-tests.md:68 +msgid "" +"Listing 8-2: The output from running a test" msgstr "" -#: src/ch08-01-how-to-write-tests.md:73 +#: src/ch08-01-how-to-write-tests.md:70 msgid "" "`cairo-test` compiled and ran the test. We see the line `running 1 tests`. " "The next line shows the name of the generated test function, called " @@ -8623,7 +8856,7 @@ msgid "" "failed." msgstr "" -#: src/ch08-01-how-to-write-tests.md:75 +#: src/ch08-01-how-to-write-tests.md:72 msgid "" "It’s possible to mark a test as ignored so it doesn’t run in a particular " "instance; we’ll cover that in the [Ignoring Some Tests Unless Specifically " @@ -8636,33 +8869,30 @@ msgid "" "`0 filtered out`." msgstr "" -#: src/ch08-01-how-to-write-tests.md:77 +#: src/ch08-01-how-to-write-tests.md:74 msgid "" "Let’s start to customize the test to our own needs. First change the name of " "the `it_works` function to a different name, such as `exploration`, like so:" msgstr "" -#: src/ch08-01-how-to-write-tests.md:81 +#: src/ch08-01-how-to-write-tests.md:78 msgid "" "```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" " #[test]\n" " fn exploration() {\n" " let result = 2 + 2;\n" " assert(result == 4, 'result is not 4');\n" " }\n" -"}\n" "```" msgstr "" -#: src/ch08-01-how-to-write-tests.md:92 +#: src/ch08-01-how-to-write-tests.md:86 msgid "" "Then run `cairo-test -- --path src` again. The output now shows " "`exploration` instead of `it_works`:" msgstr "" -#: src/ch08-01-how-to-write-tests.md:94 +#: src/ch08-01-how-to-write-tests.md:88 msgid "" "```shell\n" "$ cairo-test .\n" @@ -8672,7 +8902,7 @@ msgid "" "```" msgstr "" -#: src/ch08-01-how-to-write-tests.md:101 +#: src/ch08-01-how-to-write-tests.md:95 msgid "" "Now we’ll add another test, but this time we’ll make a test that fails! " "Tests fail when something in the test function panics. Each test is run in a " @@ -8681,25 +8911,25 @@ msgid "" "so your _src/lib.cairo_ file looks like Listing 8-3." msgstr "" -#: src/ch08-01-how-to-write-tests.md:103 +#: src/ch08-01-how-to-write-tests.md:97 msgid "" "```rust\n" -"#[cfg(test)]\n" -"mod tests{\n" " #[test]\n" " fn another() {\n" " let result = 2 + 2;\n" " assert(result == 6, 'Make this test fail');\n" " }\n" -"}\n" +"\n" "```" msgstr "" -#: src/ch08-01-how-to-write-tests.md:114 -msgid "Listing 8-3: Adding a second test that will fail" +#: src/ch08-01-how-to-write-tests.md:106 +msgid "" +"Listing 8-3: Adding a second test that will " +"fail" msgstr "" -#: src/ch08-01-how-to-write-tests.md:116 +#: src/ch08-01-how-to-write-tests.md:108 msgid "" "```shell\n" "$ cairo-test .\n" @@ -8713,11 +8943,13 @@ msgid "" "```" msgstr "" -#: src/ch08-01-how-to-write-tests.md:126 -msgid "Listing 8-4: Test results when one test passes and one test fails" +#: src/ch08-01-how-to-write-tests.md:118 +msgid "" +"Listing 8-4: Test results when one test passes and " +"one test fails" msgstr "" -#: src/ch08-01-how-to-write-tests.md:128 +#: src/ch08-01-how-to-write-tests.md:120 msgid "" "Instead of `ok`, the line `adder::lib::tests::another` shows `fail`. A new " "section appears between the individual results and the summary. It displays " @@ -8727,23 +8959,23 @@ msgid "" "in the _src/lib.cairo_ file." msgstr "" -#: src/ch08-01-how-to-write-tests.md:130 +#: src/ch08-01-how-to-write-tests.md:122 msgid "" "The summary line displays at the end: overall, our test result is `FAILED`. " "We had one test pass and one test fail." msgstr "" -#: src/ch08-01-how-to-write-tests.md:132 +#: src/ch08-01-how-to-write-tests.md:124 msgid "" "Now that you’ve seen what the test results look like in different scenarios, " "let’s look at some functions that are useful in tests." msgstr "" -#: src/ch08-01-how-to-write-tests.md:134 +#: src/ch08-01-how-to-write-tests.md:126 msgid "## Checking Results with the assert function" msgstr "" -#: src/ch08-01-how-to-write-tests.md:136 +#: src/ch08-01-how-to-write-tests.md:128 msgid "" "The `assert` function, provided by Cairo, is useful when you want to ensure " "that some condition in a test evaluates to `true`. We give the `assert` " @@ -8754,7 +8986,7 @@ msgid "" "function helps us check that our code is functioning in the way we intend." msgstr "" -#: src/ch08-01-how-to-write-tests.md:138 +#: src/ch08-01-how-to-write-tests.md:130 msgid "" "In [Chapter 4, Listing 5-15](ch04-03-method-syntax.md#multiple-impl-blocks), " "we used a `Rectangle` struct and a `can_hold` method, which are repeated " @@ -8762,72 +8994,80 @@ msgid "" "write some tests for it using the `assert` function." msgstr "" -#: src/ch08-01-how-to-write-tests.md:142 -msgid "" -"```rust\n" -"trait RectangleTrait {\n" -" fn area(self: @Rectangle) -> u64;\n" -" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" -"}\n" -"\n" -"impl RectangleImpl of RectangleTrait {\n" -" fn area(self: @Rectangle) -> u64 {\n" -" *self.width * *self.height\n" -" }\n" -" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" -" *self.width > *other.width & *self.height > *other.height\n" -" }\n" -"}\n" -"```" -msgstr "" - -#: src/ch08-01-how-to-write-tests.md:158 -msgid "" -"Listing 8-5: Using the `Rectangle` struct and its `can_hold` method from " -"Chapter 5" -msgstr "" - -#: src/ch08-01-how-to-write-tests.md:160 -msgid "" -"The `can_hold` method returns a `Boolean`, which means it’s a perfect use " -"case for the assert function. In Listing 8-6, we write a test that exercises " -"the `can_hold` method by creating a `Rectangle` instance that has a width of " -"`8_u64` and a height of `7_u64` and asserting that it can hold another " -"`Rectangle` instance that has a width of `5_u64` and a height of `1_u64`." -msgstr "" - -#: src/ch08-01-how-to-write-tests.md:164 -msgid "" -"```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" -" use super::Rectangle;\n" -" use super::RectangleTrait;\n" -"\n" +#: src/ch08-01-how-to-write-tests.md:151 +msgid "" +"Listing 8-5: Using the `Rectangle` struct and its " +"`can_hold` method from Chapter 5" +msgstr "" + +#: src/ch08-01-how-to-write-tests.md:153 +msgid "" +"The `can_hold` method returns a `bool`, which means it’s a perfect use case " +"for the assert function. In Listing 8-6, we write a test that exercises the " +"`can_hold` method by creating a `Rectangle` instance that has a width of `8` " +"and a height of `7` and asserting that it can hold another `Rectangle` " +"instance that has a width of `5` and a height of `1`." +msgstr "" + +#: src/ch08-01-how-to-write-tests.md:157 +msgid "" +"```rust\n" +"# use debug::PrintTrait;\n" +"# #[derive(Copy, Drop)]\n" +"# struct Rectangle {\n" +"# width: u64,\n" +"# height: u64,\n" +"# }\n" +"# \n" +"# trait RectangleTrait {\n" +"# fn area(self: @Rectangle) -> u64;\n" +"# fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" +"# }\n" +"# \n" +"# impl RectangleImpl of RectangleTrait {\n" +"# fn area(self: @Rectangle) -> u64 {\n" +"# *self.width * *self.height\n" +"# }\n" +"# \n" +"# fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +"# *self.width > *other.width & *self.height > *other.height\n" +"# }\n" +"# }\n" +"# \n" +"# #[cfg(test)]\n" +"# mod tests {\n" +"# use super::Rectangle;\n" +"# use super::RectangleTrait;\n" +"# \n" +"# \n" " #[test]\n" " fn larger_can_hold_smaller() {\n" -" let larger = Rectangle {\n" -" height: 7_u64,\n" -" width: 8_u64,\n" -" };\n" -" let smaller = Rectangle {\n" -" height: 1_u64,\n" -" width: 5_u64,\n" -" };\n" +" let larger = Rectangle { height: 7, width: 8, };\n" +" let smaller = Rectangle { height: 1, width: 5, };\n" "\n" " assert(larger.can_hold(@smaller), 'rectangle cannot hold');\n" " }\n" -"}\n" +"# \n" +"# #[test]\n" +"# fn smaller_cannot_hold_larger() {\n" +"# let larger = Rectangle { height: 7, width: 8, };\n" +"# let smaller = Rectangle { height: 1, width: 5, };\n" +"# \n" +"# assert(!smaller.can_hold(@larger), 'rectangle cannot hold');\n" +"# }\n" +"# }\n" +"# \n" +"# \n" "```" msgstr "" -#: src/ch08-01-how-to-write-tests.md:186 +#: src/ch08-01-how-to-write-tests.md:206 msgid "" -"Listing 8-6: A test for `can_hold` that checks whether a larger rectangle " -"can indeed hold a smaller rectangle" +"Listing 8-6: A test for `can_hold` that checks " +"whether a larger rectangle can indeed hold a smaller rectangle" msgstr "" -#: src/ch08-01-how-to-write-tests.md:188 +#: src/ch08-01-how-to-write-tests.md:208 msgid "" "Note that we’ve added two new lines inside the tests module: `use " "super::Rectangle;` and `use super::RectangleTrait;`. The tests module is a " @@ -8836,7 +9076,7 @@ msgid "" "module into the scope of the inner module." msgstr "" -#: src/ch08-01-how-to-write-tests.md:190 +#: src/ch08-01-how-to-write-tests.md:210 msgid "" "We’ve named our test `larger_can_hold_smaller`, and we’ve created the two " "`Rectangle` instances that we need. Then we called the assert function and " @@ -8844,7 +9084,7 @@ msgid "" "is supposed to return `true`, so our test should pass. Let’s find out!" msgstr "" -#: src/ch08-01-how-to-write-tests.md:192 +#: src/ch08-01-how-to-write-tests.md:212 msgid "" "```shell\n" "$ cairo-test .\n" @@ -8854,50 +9094,72 @@ msgid "" "```" msgstr "" -#: src/ch08-01-how-to-write-tests.md:199 +#: src/ch08-01-how-to-write-tests.md:219 msgid "" "It does pass! Let’s add another test, this time asserting that a smaller " "rectangle cannot hold a larger rectangle:" msgstr "" -#: src/ch08-01-how-to-write-tests.md:203 -msgid "" -"```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" -" use super::Rectangle;\n" -" use super::RectangleTrait;\n" -"\n" -" #[test]\n" -" fn larger_can_hold_smaller() {\n" -" // --snip--\n" -" }\n" -"\n" +#: src/ch08-01-how-to-write-tests.md:223 +msgid "" +"```rust\n" +"# use debug::PrintTrait;\n" +"# #[derive(Copy, Drop)]\n" +"# struct Rectangle {\n" +"# width: u64,\n" +"# height: u64,\n" +"# }\n" +"# \n" +"# trait RectangleTrait {\n" +"# fn area(self: @Rectangle) -> u64;\n" +"# fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" +"# }\n" +"# \n" +"# impl RectangleImpl of RectangleTrait {\n" +"# fn area(self: @Rectangle) -> u64 {\n" +"# *self.width * *self.height\n" +"# }\n" +"# \n" +"# fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +"# *self.width > *other.width & *self.height > *other.height\n" +"# }\n" +"# }\n" +"# \n" +"# #[cfg(test)]\n" +"# mod tests {\n" +"# use super::Rectangle;\n" +"# use super::RectangleTrait;\n" +"# \n" +"# \n" +"# #[test]\n" +"# fn larger_can_hold_smaller() {\n" +"# let larger = Rectangle { height: 7, width: 8, };\n" +"# let smaller = Rectangle { height: 1, width: 5, };\n" +"# \n" +"# assert(larger.can_hold(@smaller), 'rectangle cannot hold');\n" +"# }\n" +"# \n" " #[test]\n" " fn smaller_cannot_hold_larger() {\n" -" let larger = Rectangle {\n" -" height: 7_u64,\n" -" width: 8_u64,\n" -" };\n" -" let smaller = Rectangle {\n" -" height: 1_u64,\n" -" width: 5_u64,\n" -" };\n" +" let larger = Rectangle { height: 7, width: 8, };\n" +" let smaller = Rectangle { height: 1, width: 5, };\n" "\n" " assert(!smaller.can_hold(@larger), 'rectangle cannot hold');\n" " }\n" -"}\n" +"# }\n" +"# \n" +"# \n" "```" msgstr "" -#: src/ch08-01-how-to-write-tests.md:230 +#: src/ch08-01-how-to-write-tests.md:272 msgid "" "Because the correct result of the `can_hold` function in this case is " "`false`, we need to negate that result before we pass it to the assert " "function. As a result, our test will pass if `can_hold` returns false:" msgstr "" -#: src/ch08-01-how-to-write-tests.md:232 +#: src/ch08-01-how-to-write-tests.md:274 msgid "" "```shell\n" "$ cairo-test .\n" @@ -8908,7 +9170,7 @@ msgid "" "```" msgstr "" -#: src/ch08-01-how-to-write-tests.md:240 +#: src/ch08-01-how-to-write-tests.md:282 msgid "" "Two tests that pass! Now let’s see what happens to our test results when we " "introduce a bug in our code. We’ll change the implementation of the " @@ -8916,11 +9178,14 @@ msgid "" "when it compares the widths:" msgstr "" -#: src/ch08-01-how-to-write-tests.md:242 +#: src/ch08-01-how-to-write-tests.md:284 msgid "" "```rust\n" -"// --snip--\n" "impl RectangleImpl of RectangleTrait {\n" +" fn area(self: @Rectangle) -> u64 {\n" +" *self.width * *self.height\n" +" }\n" +"\n" " fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" " *self.width < *other.width & *self.height > *other.height\n" " }\n" @@ -8928,11 +9193,11 @@ msgid "" "```" msgstr "" -#: src/ch08-01-how-to-write-tests.md:251 +#: src/ch08-01-how-to-write-tests.md:296 msgid "Running the tests now produces the following:" msgstr "" -#: src/ch08-01-how-to-write-tests.md:253 +#: src/ch08-01-how-to-write-tests.md:298 msgid "" "```shell\n" "$ cairo-test .\n" @@ -8948,48 +9213,48 @@ msgid "" "```" msgstr "" -#: src/ch08-01-how-to-write-tests.md:264 +#: src/ch08-01-how-to-write-tests.md:309 msgid "" -"Our tests caught the bug! Because `larger.width` is `8_u64` and " -"`smaller.width` is `5_u64`, the comparison of the widths in `can_hold` now " -"returns `false`: `8_u64` is not less than `5_u64`." +"Our tests caught the bug! Because `larger.width` is `8` and `smaller.width` " +"is `5`, the comparison of the widths in `can_hold` now returns `false`: `8` " +"is not less than `5`." msgstr "" -#: src/ch08-01-how-to-write-tests.md:266 +#: src/ch08-01-how-to-write-tests.md:311 msgid "## Checking for Panics with `should_panic`" msgstr "" -#: src/ch08-01-how-to-write-tests.md:268 +#: src/ch08-01-how-to-write-tests.md:313 msgid "" "In addition to checking return values, it’s important to check that our code " "handles error conditions as we expect. For example, consider the Guess type " "in Listing 8-8. Other code that uses `Guess` depends on the guarantee that " -"`Guess` instances will contain only values between `1_u64` and `100_u64`. We " -"can write a test that ensures that attempting to create a `Guess` instance " -"with a value outside that range panics." +"`Guess` instances will contain only values between `1` and `100`. We can " +"write a test that ensures that attempting to create a `Guess` instance with " +"a value outside that range panics." msgstr "" -#: src/ch08-01-how-to-write-tests.md:270 +#: src/ch08-01-how-to-write-tests.md:315 msgid "" "We do this by adding the attribute `should_panic` to our test function. The " "test passes if the code inside the function panics; the test fails if the " "code inside the function doesn’t panic." msgstr "" -#: src/ch08-01-how-to-write-tests.md:272 +#: src/ch08-01-how-to-write-tests.md:317 msgid "" "Listing 8-8 shows a test that checks that the error conditions of " "`GuessTrait::new` happen when we expect them to." msgstr "" -#: src/ch08-01-how-to-write-tests.md:276 +#: src/ch08-01-how-to-write-tests.md:321 msgid "" "```rust\n" "use array::ArrayTrait;\n" "\n" "#[derive(Copy, Drop)]\n" "struct Guess {\n" -" value: u64,\n" +" value: u64, \n" "}\n" "\n" "trait GuessTrait {\n" @@ -8998,7 +9263,7 @@ msgid "" "\n" "impl GuessImpl of GuessTrait {\n" " fn new(value: u64) -> Guess {\n" -" if value < 1_u64 | value > 100 {\n" +" if value < 1 | value > 100 {\n" " let mut data = ArrayTrait::new();\n" " data.append('Guess must be >= 1 and <= 100');\n" " panic(data);\n" @@ -9015,24 +9280,26 @@ msgid "" " #[test]\n" " #[should_panic]\n" " fn greater_than_100() {\n" -" GuessTrait::new(200_u64);\n" +" GuessTrait::new(200);\n" " }\n" "}\n" "```" msgstr "" -#: src/ch08-01-how-to-write-tests.md:312 -msgid "Listing 8-8: Testing that a condition will cause a panic" +#: src/ch08-01-how-to-write-tests.md:357 +msgid "" +"Listing 8-8: Testing that a condition will cause a " +"panic" msgstr "" -#: src/ch08-01-how-to-write-tests.md:314 +#: src/ch08-01-how-to-write-tests.md:359 msgid "" "We place the `#[should_panic]` attribute after the `#[test]` attribute and " "before the test function it applies to. Let’s look at the result when this " "test passes:" msgstr "" -#: src/ch08-01-how-to-write-tests.md:316 +#: src/ch08-01-how-to-write-tests.md:361 msgid "" "```shell\n" "$ cairo-test .\n" @@ -9042,35 +9309,46 @@ msgid "" "```" msgstr "" -#: src/ch08-01-how-to-write-tests.md:323 +#: src/ch08-01-how-to-write-tests.md:368 msgid "" "Looks good! Now let’s introduce a bug in our code by removing the condition " -"that the new function will panic if the value is greater than `100_u64`:" +"that the new function will panic if the value is greater than `100`:" msgstr "" -#: src/ch08-01-how-to-write-tests.md:325 +#: src/ch08-01-how-to-write-tests.md:370 msgid "" "```rust\n" -"// --snip--\n" +"# use array::ArrayTrait;\n" +"# \n" +"# #[derive(Copy, Drop)]\n" +"# struct Guess {\n" +"# value: u64, \n" +"# }\n" +"# \n" +"# trait GuessTrait {\n" +"# fn new(value: u64) -> Guess;\n" +"# }\n" +"# \n" "impl GuessImpl of GuessTrait {\n" " fn new(value: u64) -> Guess {\n" -" if value < 1_u64 {\n" +" if value < 1 {\n" " let mut data = ArrayTrait::new();\n" " data.append('Guess must be >= 1 and <= 100');\n" " panic(data);\n" " }\n" "\n" -" Guess { value, }\n" +" Guess { value, }\n" " }\n" "}\n" +"# \n" "```" msgstr "" -#: src/ch08-01-how-to-write-tests.md:340 +#: src/ch08-01-how-to-write-tests.md:396 msgid "When we run the test in Listing 8-8, it will fail:" msgstr "" -#: src/ch08-01-how-to-write-tests.md:342 +#: src/ch08-01-how-to-write-tests.md:398 msgid "" "```shell\n" "$ cairo-test .\n" @@ -9083,7 +9361,7 @@ msgid "" "```" msgstr "" -#: src/ch08-01-how-to-write-tests.md:351 +#: src/ch08-01-how-to-write-tests.md:407 msgid "" "We don’t get a very helpful message in this case, but when we look at the " "test function, we see that it’s annotated with `#[should_panic]`. The " @@ -9091,7 +9369,7 @@ msgid "" "panic." msgstr "" -#: src/ch08-01-how-to-write-tests.md:353 +#: src/ch08-01-how-to-write-tests.md:409 msgid "" "Tests that use `should_panic` can be imprecise. A `should_panic` test would " "pass even if the test panics for a different reason from the one we were " @@ -9103,47 +9381,59 @@ msgid "" "or too large." msgstr "" -#: src/ch08-01-how-to-write-tests.md:357 -msgid "" -"```rust\n" -"// --snip--\n" -"impl GuessImpl of GuessTrait {\n" -" fn new(value: u64) -> Guess {\n" -" if value < 1_u64 {\n" -" let mut data = ArrayTrait::new();\n" -" data.append('Guess must be >= 1');\n" -" panic(data);\n" -" } else if value > 100_u64 {\n" -" let mut data = ArrayTrait::new();\n" -" data.append('Guess must be <= 100');\n" -" panic(data);\n" -" }\n" -"\n" -" Guess { value, }\n" -" }\n" -"}\n" -"\n" -"#[cfg(test)]\n" -"mod tests {\n" -" use super::Guess;\n" -" use super::GuessTrait;\n" -"\n" +#: src/ch08-01-how-to-write-tests.md:413 +msgid "" +"```rust\n" +"# use array::ArrayTrait;\n" +"# \n" +"# #[derive(Copy, Drop)]\n" +"# struct Guess {\n" +"# value: u64, \n" +"# }\n" +"# \n" +"# trait GuessTrait {\n" +"# fn new(value: u64) -> Guess;\n" +"# }\n" +"# \n" +"# impl GuessImpl of GuessTrait {\n" +"# fn new(value: u64) -> Guess {\n" +"# if value < 1 {\n" +"# let mut data = ArrayTrait::new();\n" +"# data.append('Guess must be <= 100');\n" +"# panic(data);\n" +"# } else if value > 100 {\n" +"# let mut data = ArrayTrait::new();\n" +"# data.append('Guess must be >= 1');\n" +"# panic(data);\n" +"# }\n" +"# \n" +"# Guess { value, }\n" +"# }\n" +"# }\n" +"# \n" +"# #[cfg(test)]\n" +"# mod tests {\n" +"# use super::Guess;\n" +"# use super::GuessTrait;\n" +"# \n" " #[test]\n" " #[should_panic(expected: ('Guess must be <= 100', ))]\n" " fn greater_than_100() {\n" -" GuessTrait::new(200_u64);\n" +" GuessTrait::new(200);\n" " }\n" -"}\n" +"# }\n" +"# \n" +"# \n" "```" msgstr "" -#: src/ch08-01-how-to-write-tests.md:388 +#: src/ch08-01-how-to-write-tests.md:456 msgid "" -"Listing 8-9: Testing for a panic with a panic message containing the error " -"message string" +"Listing 8-9: Testing for a panic with a panic " +"message containing the error message string" msgstr "" -#: src/ch08-01-how-to-write-tests.md:390 +#: src/ch08-01-how-to-write-tests.md:458 msgid "" "This test will pass because the value we put in the `should_panic` " "attribute’s expected parameter is the array of string of the message that " @@ -9151,33 +9441,51 @@ msgid "" "message that we expect." msgstr "" -#: src/ch08-01-how-to-write-tests.md:392 +#: src/ch08-01-how-to-write-tests.md:460 msgid "" "To see what happens when a `should_panic` test with an expected message " "fails, let’s again introduce a bug into our code by swapping the bodies of " -"the if `value < 1_u64` and the else if `value > 100_u64` blocks:" +"the if `value < 1` and the else if `value > 100` blocks:" msgstr "" -#: src/ch08-01-how-to-write-tests.md:394 +#: src/ch08-01-how-to-write-tests.md:462 msgid "" "```rust\n" -"if value < 1_u64 {\n" -" let mut data = ArrayTrait::new();\n" -" data.append('Guess must be <= 100');\n" -" panic(data);\n" -"} else if value > 100_u64 {\n" -" let mut data = ArrayTrait::new();\n" -" data.append('Guess must be >= 1');\n" -" panic(data);\n" +"impl GuessImpl of GuessTrait {\n" +" fn new(value: u64) -> Guess {\n" +" if value < 1 {\n" +" let mut data = ArrayTrait::new();\n" +" data.append('Guess must be >= 1');\n" +" panic(data);\n" +" } else if value > 100 {\n" +" let mut data = ArrayTrait::new();\n" +" data.append('Guess must be <= 100');\n" +" panic(data);\n" +" }\n" +"\n" +" Guess { value, }\n" +" }\n" +"}\n" +"\n" +"#[cfg(test)]\n" +"mod tests {\n" +" use super::Guess;\n" +" use super::GuessTrait;\n" +"\n" +" #[test]\n" +" #[should_panic(expected: ('Guess must be <= 100', ))]\n" +" fn greater_than_100() {\n" +" GuessTrait::new(200);\n" +" }\n" "}\n" "```" msgstr "" -#: src/ch08-01-how-to-write-tests.md:406 +#: src/ch08-01-how-to-write-tests.md:492 msgid "This time when we run the `should_panic` test, it will fail:" msgstr "" -#: src/ch08-01-how-to-write-tests.md:408 +#: src/ch08-01-how-to-write-tests.md:494 msgid "" "```shell\n" "$ cairo-test .\n" @@ -9191,7 +9499,7 @@ msgid "" "```" msgstr "" -#: src/ch08-01-how-to-write-tests.md:418 +#: src/ch08-01-how-to-write-tests.md:504 msgid "" "The failure message indicates that this test did indeed panic as we " "expected, but the panic message did not include the expected string. The " @@ -9199,11 +9507,11 @@ msgid "" "can start figuring out where our bug is!" msgstr "" -#: src/ch08-01-how-to-write-tests.md:420 +#: src/ch08-01-how-to-write-tests.md:506 msgid "## Running Single Tests" msgstr "" -#: src/ch08-01-how-to-write-tests.md:422 +#: src/ch08-01-how-to-write-tests.md:508 msgid "" "Sometimes, running a full test suite can take a long time. If you’re working " "on code in a particular area, you might want to run only the tests " @@ -9211,13 +9519,13 @@ msgid "" "`cairo-test` the name of the test you want to run as an argument." msgstr "" -#: src/ch08-01-how-to-write-tests.md:424 +#: src/ch08-01-how-to-write-tests.md:510 msgid "" "To demonstrate how to run a single test, we’ll first create two tests " "functions, as shown in Listing 8-10, and choose which ones to run." msgstr "" -#: src/ch08-01-how-to-write-tests.md:428 +#: src/ch08-01-how-to-write-tests.md:514 msgid "" "```rust\n" "#[cfg(test)]\n" @@ -9237,17 +9545,19 @@ msgid "" "```" msgstr "" -#: src/ch08-01-how-to-write-tests.md:445 -msgid "Listing 8-10: Two tests with two different names" +#: src/ch08-01-how-to-write-tests.md:531 +msgid "" +"Listing 8-10: Two tests with two different " +"names" msgstr "" -#: src/ch08-01-how-to-write-tests.md:447 +#: src/ch08-01-how-to-write-tests.md:533 msgid "" "We can pass the name of any test function to `cairo-test` to run only that " "test using the `-f` flag:" msgstr "" -#: src/ch08-01-how-to-write-tests.md:449 +#: src/ch08-01-how-to-write-tests.md:535 msgid "" "```shell\n" "$ cairo-test . -f add_two_and_two\n" @@ -9257,24 +9567,24 @@ msgid "" "```" msgstr "" -#: src/ch08-01-how-to-write-tests.md:456 +#: src/ch08-01-how-to-write-tests.md:542 msgid "" "Only the test with the name `add_two_and_two` ran; the other test didn’t " "match that name. The test output lets us know we had one more test that " "didn’t run by displaying 1 filtered out at the end." msgstr "" -#: src/ch08-01-how-to-write-tests.md:458 +#: src/ch08-01-how-to-write-tests.md:544 msgid "" "We can also specify part of a test name, and any test whose name contains " "that value will be run." msgstr "" -#: src/ch08-01-how-to-write-tests.md:460 +#: src/ch08-01-how-to-write-tests.md:546 msgid "## Ignoring Some Tests Unless Specifically Requested" msgstr "" -#: src/ch08-01-how-to-write-tests.md:462 +#: src/ch08-01-how-to-write-tests.md:548 msgid "" "Sometimes a few specific tests can be very time-consuming to execute, so you " "might want to exclude them during most runs of `cairo-test`. Rather than " @@ -9283,7 +9593,7 @@ msgid "" "shown here:" msgstr "" -#: src/ch08-01-how-to-write-tests.md:466 +#: src/ch08-01-how-to-write-tests.md:552 msgid "" "```rust\n" "#[cfg(test)]\n" @@ -9296,20 +9606,19 @@ msgid "" "\n" " #[test]\n" " #[ignore]\n" -" fn expensive_test() {\n" -" // code that takes an hour to run\n" +" fn expensive_test() {// code that takes an hour to run\n" " }\n" "}\n" "```" msgstr "" -#: src/ch08-01-how-to-write-tests.md:483 +#: src/ch08-01-how-to-write-tests.md:568 msgid "" "After `#[test]` we add the `#[ignore]` line to the test we want to exclude. " "Now when we run our tests, `it_works` runs, but `expensive_test` doesn’t:" msgstr "" -#: src/ch08-01-how-to-write-tests.md:485 +#: src/ch08-01-how-to-write-tests.md:570 msgid "" "```shell\n" "$ cairo-test .\n" @@ -9320,11 +9629,11 @@ msgid "" "```" msgstr "" -#: src/ch08-01-how-to-write-tests.md:493 +#: src/ch08-01-how-to-write-tests.md:578 msgid "The `expensive_test` function is listed as ignored." msgstr "" -#: src/ch08-01-how-to-write-tests.md:495 +#: src/ch08-01-how-to-write-tests.md:580 msgid "" "When you’re at a point where it makes sense to check the results of the " "ignored tests and you have time to wait for the results, you can run " @@ -9391,6 +9700,20 @@ msgid "" "this chapter, we wrote this first test:" msgstr "" +#: src/ch08-02-test-organization.md:21 +msgid "" +"```rust\n" +"#[cfg(test)]\n" +"mod tests {\n" +" #[test]\n" +" fn it_works() {\n" +" let result = 2 + 2;\n" +" assert(result == 4, 'result is not 4');\n" +" }\n" +"}\n" +"```" +msgstr "" + #: src/ch08-02-test-organization.md:32 msgid "" "The attribute `cfg` stands for configuration and tells Cairo that the " @@ -9467,7 +9790,7 @@ msgstr "" #: src/ch08-02-test-organization.md:70 msgid "" -"Enter the code in Listing 11-13 into the _tests/integration_test.cairo_ file:" +"Enter the code in Listing 8-11 into the _tests/integration_test.cairo_ file:" msgstr "" #: src/ch08-02-test-organization.md:72 @@ -9477,16 +9800,19 @@ msgstr "" #: src/ch08-02-test-organization.md:74 msgid "" "```rust\n" -"use adder::main;\n" -"\n" "#[test]\n" "fn internal() {\n" -" assert(main::internal_adder(2_u32, 2_u32) == 4_u32, 'internal_adder " -"failed');\n" +" assert(main::internal_adder(2, 2) == 4, 'internal_adder failed');\n" "}\n" "```" msgstr "" +#: src/ch08-02-test-organization.md:81 +msgid "" +"Listing 8-11: Testing functions from other " +"modules" +msgstr "" + #: src/ch08-02-test-organization.md:83 msgid "" "Each file in the tests directory is a separate crate, so we need to bring " @@ -9546,7 +9872,7 @@ msgstr "" #: src/ch09-01-unrecoverable-errors-with-panic.md:5 msgid "" "When a panic occurs, it leads to an abrupt termination of the program. The " -"`panic` function take an array as argument, which can be used to provide an " +"`panic` function takes an array as argument, which can be used to provide an " "error message and performs an unwind process where all variables are dropped " "and dictionaries squashed to ensure the soundness of the program to safely " "terminate the execution." @@ -9560,38 +9886,40 @@ msgstr "" #: src/ch09-01-unrecoverable-errors-with-panic.md:11 msgid "" -"```rust,does_not_compile\n" +"```rust\n" "use array::ArrayTrait;\n" "use debug::PrintTrait;\n" "\n" "fn main() {\n" " let mut data = ArrayTrait::new();\n" " data.append(2);\n" -" panic(data);\n" -" 'This line isn't reached'.print();\n" +" if true == true {\n" +" panic(data);\n" +" }\n" +" 'This line isn\\'t reached'.print();\n" "}\n" "```" msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:23 +#: src/ch09-01-unrecoverable-errors-with-panic.md:25 msgid "Running the program will produce the following output:" msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:25 +#: src/ch09-01-unrecoverable-errors-with-panic.md:27 msgid "" "```console\n" "$ cairo-run test.cairo\n" -"Run panicked with err values: [2]\n" +"Run panicked with [2 (''), ].\n" "```" msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:30 +#: src/ch09-01-unrecoverable-errors-with-panic.md:32 msgid "" "As you can notice in the output, the print statement is never reached, as " "the program terminates after encountering the `panic` statement." msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:32 +#: src/ch09-01-unrecoverable-errors-with-panic.md:34 msgid "" "An alternative and more idiomatic approach to panic in Cairo would be to use " "the `panic_with_felt252` function. This function serves as an abstraction of " @@ -9601,11 +9929,11 @@ msgid "" "making the code more readable and maintainable." msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:34 +#: src/ch09-01-unrecoverable-errors-with-panic.md:36 msgid "Let's consider an example:" msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:36 +#: src/ch09-01-unrecoverable-errors-with-panic.md:38 msgid "" "```rust\n" "fn main() {\n" @@ -9614,26 +9942,26 @@ msgid "" "```" msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:42 +#: src/ch09-01-unrecoverable-errors-with-panic.md:44 msgid "" "Executing this program will yield the same error message as before. In that " "case, if there is no need for an array and multiple values to be returned " "within the error, so `panic_with_felt252` is a more succinct alternative." msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:44 +#: src/ch09-01-unrecoverable-errors-with-panic.md:46 msgid "## nopanic notation" msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:46 +#: src/ch09-01-unrecoverable-errors-with-panic.md:48 msgid "" "You can use the `nopanic` notation to indicate that a function will never " "panic. Only `nopanic` functions can be called in a function annotated as " "`nopanic`." msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:48 -#: src/ch09-01-unrecoverable-errors-with-panic.md:83 +#: src/ch09-01-unrecoverable-errors-with-panic.md:50 +#: src/ch09-01-unrecoverable-errors-with-panic.md:86 #: src/appendix-03-derivable-traits.md:17 #: src/appendix-03-derivable-traits.md:42 #: src/appendix-03-derivable-traits.md:63 @@ -9642,7 +9970,7 @@ msgstr "" msgid "Example:" msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:50 +#: src/ch09-01-unrecoverable-errors-with-panic.md:52 msgid "" "```rust\n" "fn function_never_panic() -> felt252 nopanic {\n" @@ -9651,28 +9979,29 @@ msgid "" "```" msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:56 +#: src/ch09-01-unrecoverable-errors-with-panic.md:58 msgid "Wrong example:" msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:58 +#: src/ch09-01-unrecoverable-errors-with-panic.md:60 msgid "" "```rust\n" +"// does_not_compile\n" "fn function_never_panic() nopanic {\n" " assert(1 == 1, 'what');\n" "}\n" "```" msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:64 +#: src/ch09-01-unrecoverable-errors-with-panic.md:67 msgid "" "If you write the following function that includes a function that may panic " "you will get the following error:" msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:66 +#: src/ch09-01-unrecoverable-errors-with-panic.md:69 msgid "" -"```bash\n" +"```console\n" "error: Function is declared as nopanic but calls a function that may panic.\n" " --> test.cairo:2:12\n" " assert(1 == 1, 'what');\n" @@ -9684,16 +10013,16 @@ msgid "" "```" msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:77 +#: src/ch09-01-unrecoverable-errors-with-panic.md:80 msgid "" "Note that there are two functions that may panic here, assert and equality." msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:79 +#: src/ch09-01-unrecoverable-errors-with-panic.md:82 msgid "## panic_with macro" msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:81 +#: src/ch09-01-unrecoverable-errors-with-panic.md:84 msgid "" "You can use the `panic_with` macro to mark a function that returns an " "`Option` or `Result`. This macro takes two arguments, which are the data " @@ -9703,7 +10032,7 @@ msgid "" "called with the given data." msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:85 +#: src/ch09-01-unrecoverable-errors-with-panic.md:88 msgid "" "```rust\n" "use option::OptionTrait;\n" @@ -9724,11 +10053,11 @@ msgid "" "```" msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:103 +#: src/ch09-01-unrecoverable-errors-with-panic.md:106 msgid "## Using assert" msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:105 +#: src/ch09-01-unrecoverable-errors-with-panic.md:108 msgid "" "The assert function from the Cairo core library is actually a utility " "function based on panics. It asserts that a boolean expression is true at " @@ -9738,11 +10067,11 @@ msgid "" "string passed must be able to fit inside a felt252." msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:107 +#: src/ch09-01-unrecoverable-errors-with-panic.md:110 msgid "Here is an example of its usage:" msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:109 +#: src/ch09-01-unrecoverable-errors-with-panic.md:112 msgid "" "```rust\n" "fn main() {\n" @@ -9755,7 +10084,7 @@ msgid "" "```" msgstr "" -#: src/ch09-01-unrecoverable-errors-with-panic.md:119 +#: src/ch09-01-unrecoverable-errors-with-panic.md:122 msgid "" "We are asserting in main that `my_number` is not zero to ensure that we're " "not performing a division by 0.\n" @@ -9765,16 +10094,16 @@ msgid "" "reached." msgstr "" -#: src/ch09-02-error-handling.md:1 +#: src/ch09-02-recoverable-errors.md:1 msgid "# Recoverable Errors with `Result`" msgstr "" -#: src/ch09-02-error-handling.md:3 -#: src/ch09-02-error-handling.md:56 +#: src/ch09-02-recoverable-errors.md:3 +#: src/ch09-02-recoverable-errors.md:56 msgid "
" msgstr "" -#: src/ch09-02-error-handling.md:5 +#: src/ch09-02-recoverable-errors.md:5 msgid "" "Most errors aren’t serious enough to require the program to stop entirely. " "Sometimes, when a function fails, it’s for a reason that you can easily " @@ -9784,22 +10113,22 @@ msgid "" "instead of causing undefined behavior or terminating the process." msgstr "" -#: src/ch09-02-error-handling.md:7 +#: src/ch09-02-recoverable-errors.md:7 msgid "## The `Result` enum" msgstr "" -#: src/ch09-02-error-handling.md:9 +#: src/ch09-02-recoverable-errors.md:9 msgid "" "Recall from [“Generic data types”](ch07-01-generic-data-types.md#enums) in " "Chapter 7 that the `Result` enum is defined as having two variants, `Ok` and " "`Err`, as follows:" msgstr "" -#: src/ch09-02-error-handling.md:20 +#: src/ch09-02-recoverable-errors.md:20 msgid "## The `ResultTrait`" msgstr "" -#: src/ch09-02-error-handling.md:22 +#: src/ch09-02-recoverable-errors.md:22 msgid "" "The `ResultTrait` trait provides methods for working with the `Result` " "enum, such as unwrapping values, checking whether the `Result` is `Ok` or " @@ -9807,7 +10136,7 @@ msgid "" "implementation defines the logic of these methods." msgstr "" -#: src/ch09-02-error-handling.md:24 +#: src/ch09-02-recoverable-errors.md:24 msgid "" "```rust\n" "trait ResultTrait {\n" @@ -9827,7 +10156,7 @@ msgid "" "```" msgstr "" -#: src/ch09-02-error-handling.md:40 +#: src/ch09-02-recoverable-errors.md:40 msgid "" "The `expect` and `unwrap` methods are similar in that they both attempt to " "extract the value of type `T` from a `Result` when it is in the `Ok` " @@ -9840,7 +10169,7 @@ msgid "" "less information about the cause of the panic." msgstr "" -#: src/ch09-02-error-handling.md:42 +#: src/ch09-02-recoverable-errors.md:42 msgid "" "The `expect_err` and `unwrap_err` have the exact opposite behavior. If the " "`Result` is `Err(x)`, both methods return the value `x`. However, the key " @@ -9852,7 +10181,7 @@ msgid "" "cause of the panic." msgstr "" -#: src/ch09-02-error-handling.md:44 +#: src/ch09-02-recoverable-errors.md:44 msgid "" "A careful reader may have noticed the `>` and `>` in the first four methods signatures. This syntax " @@ -9861,27 +10190,27 @@ msgid "" "`Drop` trait for the generic types `T` and `E`, respectively." msgstr "" -#: src/ch09-02-error-handling.md:46 +#: src/ch09-02-recoverable-errors.md:46 msgid "" "Finally, the `is_ok` and `is_err` methods are utility functions provided by " "the `ResultTrait` trait to check the variant of a `Result` enum value." msgstr "" -#: src/ch09-02-error-handling.md:48 +#: src/ch09-02-recoverable-errors.md:48 msgid "" "`is_ok` takes a snapshot of a `Result` value and returns `true` if the " "`Result` is the `Ok` variant, meaning the operation was successful. If the " "`Result` is the `Err` variant, it returns `false`." msgstr "" -#: src/ch09-02-error-handling.md:50 +#: src/ch09-02-recoverable-errors.md:50 msgid "" "`is_err` takes a reference to a `Result` value and returns `true` if " "the `Result` is the `Err` variant, meaning the operation encountered an " "error. If the `Result` is the `Ok` variant, it returns `false`." msgstr "" -#: src/ch09-02-error-handling.md:52 +#: src/ch09-02-recoverable-errors.md:52 msgid "" "These methods are helpful when you want to check the success or failure of " "an operation without consuming the Result value, allowing you to perform " @@ -9889,39 +10218,39 @@ msgid "" "unwrapping it." msgstr "" -#: src/ch09-02-error-handling.md:54 +#: src/ch09-02-recoverable-errors.md:54 msgid "" "You can find the implementation ot the `ResultTrait` " "[here](https://github.com/starkware-libs/cairo/blob/main/corelib/src/result.cairo#L20)." msgstr "" -#: src/ch09-02-error-handling.md:58 +#: src/ch09-02-recoverable-errors.md:58 msgid "It is always easier to understand with examples." msgstr "" -#: src/ch09-02-error-handling.md:60 +#: src/ch09-02-recoverable-errors.md:60 msgid "Have a look at this function signature:" msgstr "" -#: src/ch09-02-error-handling.md:62 +#: src/ch09-02-recoverable-errors.md:62 msgid "" "```rust\n" "fn u128_overflowing_add(a: u128, b: u128) -> Result;\n" "```" msgstr "" -#: src/ch09-02-error-handling.md:66 +#: src/ch09-02-recoverable-errors.md:66 msgid "" "It takes two u128 integers, a and b, and returns a `Result` " "where the `Ok` variant holds the sum if the addition does not overflow, and " "the `Err` variant holds the overflowed value if the addition does overflow." msgstr "" -#: src/ch09-02-error-handling.md:68 +#: src/ch09-02-recoverable-errors.md:68 msgid "Now, we can use this function elsewhere. For instance:" msgstr "" -#: src/ch09-02-error-handling.md:70 +#: src/ch09-02-recoverable-errors.md:70 msgid "" "```rust\n" "fn u128_checked_add(a: u128, b: u128) -> Option {\n" @@ -9933,7 +10262,7 @@ msgid "" "```" msgstr "" -#: src/ch09-02-error-handling.md:79 +#: src/ch09-02-recoverable-errors.md:79 msgid "" "Here, it accepts two u128 integers, a and b, and returns an `Option`. " "It uses the `Result` returned by `u128_overflowing_add` to determine the " @@ -9944,13 +10273,13 @@ msgid "" "overflow. The function does not panic in case of an overflow." msgstr "" -#: src/ch09-02-error-handling.md:81 +#: src/ch09-02-recoverable-errors.md:81 msgid "" "Let's take another example demonstrating the use of `unwrap`.\n" "First we import the necessary modules:" msgstr "" -#: src/ch09-02-error-handling.md:84 +#: src/ch09-02-recoverable-errors.md:84 msgid "" "```rust\n" "use core::traits::Into;\n" @@ -9961,7 +10290,7 @@ msgid "" "```" msgstr "" -#: src/ch09-02-error-handling.md:92 +#: src/ch09-02-recoverable-errors.md:92 msgid "" "In this example, the `parse_u8` function takes a `felt252` integer and tries " "to convert it into a `u8` integer using the `try_into` method. If " @@ -9969,7 +10298,7 @@ msgid "" "`Result::Err('Invalid integer')`." msgstr "" -#: src/ch09-02-error-handling.md:94 +#: src/ch09-02-recoverable-errors.md:94 msgid "" "```rust\n" "fn parse_u8(s: felt252) -> Result {\n" @@ -9981,30 +10310,51 @@ msgid "" "```" msgstr "" -#: src/ch09-02-error-handling.md:103 +#: src/ch09-02-recoverable-errors.md:103 +msgid "Listing 9-1: Using the Result type" +msgstr "" + +#: src/ch09-02-recoverable-errors.md:105 msgid "Our two test cases are:" msgstr "" -#: src/ch09-02-error-handling.md:105 +#: src/ch09-02-recoverable-errors.md:107 msgid "" "```rust\n" -"#[test]\n" -"fn test_felt252_to_u8() {\n" -" let number: felt252 = 5_felt252;\n" -" // should not panic\n" -" let res = parse_u8(number).unwrap();\n" -"}\n" +"# use traits::TryInto;\n" +"# \n" +"# fn parse_u8(s: felt252) -> Result {\n" +"# match s.try_into() {\n" +"# Option::Some(value) => Result::Ok(value),\n" +"# Option::None(_) => Result::Err('Invalid integer'),\n" +"# }\n" +"# }\n" +"# \n" +"#[cfg(test)]\n" +"mod tests {\n" +" use super::parse_u8;\n" +" use result::ResultTrait;\n" +" #[test]\n" +" fn test_felt252_to_u8() {\n" +" let number: felt252 = 5_felt252;\n" +" // should not panic\n" +" let res = parse_u8(number).unwrap();\n" +" }\n" "\n" -"#[test]\n" -"fn test_felt252_to_u8_panic() {\n" -" let number: felt252 = 256_felt252;\n" -" // should panic\n" -" let res = parse_u8(number).unwrap();\n" +" #[test]\n" +" #[should_panic]\n" +" fn test_felt252_to_u8_panic() {\n" +" let number: felt252 = 256_felt252;\n" +" // should panic\n" +" let res = parse_u8(number).unwrap();\n" +" }\n" "}\n" +"# \n" +"# \n" "```" msgstr "" -#: src/ch09-02-error-handling.md:121 +#: src/ch09-02-recoverable-errors.md:140 msgid "" "The first one tests a valid conversion from `felt252` to `u8`, expecting the " "`unwrap` method not to panic. The second test function attempts to convert a " @@ -10012,22 +10362,22 @@ msgid "" "with the error message 'Invalid integer'." msgstr "" -#: src/ch09-02-error-handling.md:123 +#: src/ch09-02-recoverable-errors.md:142 msgid "> We could have also used the #[should_panic] attribute here." msgstr "" -#: src/ch09-02-error-handling.md:125 +#: src/ch09-02-recoverable-errors.md:144 msgid "### The `?` operator ?" msgstr "" -#: src/ch09-02-error-handling.md:127 +#: src/ch09-02-recoverable-errors.md:146 msgid "" "The last operator we will talk about is the `?` operator. The `?` operator " "is used for more idiomatic and concise error handling. When you use the `?` " "operator on a `Result` or `Option` type, it will do the following:" msgstr "" -#: src/ch09-02-error-handling.md:129 +#: src/ch09-02-recoverable-errors.md:148 msgid "" "- If the value is `Result::Ok(x)` or `Option::Some(x)`, it will return the " "inner value `x` directly.\n" @@ -10035,17 +10385,17 @@ msgid "" "error or `None` by immediately returning from the function." msgstr "" -#: src/ch09-02-error-handling.md:132 +#: src/ch09-02-recoverable-errors.md:151 msgid "" "The `?` operator is useful when you want to handle errors implicitly and let " "the calling function deal with them." msgstr "" -#: src/ch09-02-error-handling.md:134 +#: src/ch09-02-recoverable-errors.md:153 msgid "Here is an example." msgstr "" -#: src/ch09-02-error-handling.md:136 +#: src/ch09-02-recoverable-errors.md:155 msgid "" "```rust\n" "fn do_something_with_parse_u8(input: felt252) -> Result {\n" @@ -10057,44 +10407,70 @@ msgid "" "```" msgstr "" -#: src/ch09-02-error-handling.md:145 +#: src/ch09-02-recoverable-errors.md:164 +msgid "Listing 9-1: Using the `?` operator" +msgstr "" + +#: src/ch09-02-recoverable-errors.md:166 msgid "" "`do_something_with_parse_u8` function takes a `felt252` value as input and " "calls `parse_u8`. The `?` operator is used to propagate the error, if any, " "or unwrap the successful value." msgstr "" -#: src/ch09-02-error-handling.md:147 +#: src/ch09-02-recoverable-errors.md:168 msgid "And with a little test case:" msgstr "" -#: src/ch09-02-error-handling.md:149 -msgid "" -"```rust\n" -"#[test]\n" -"fn test_function_2() {\n" -" let number: felt252 = 258_felt252;\n" -" match do_something_with_parse_u8(number) {\n" -" Result::Ok(value) => value.print(),\n" -" Result::Err(e) => e.print()\n" +#: src/ch09-02-recoverable-errors.md:170 +msgid "" +"```rust\n" +"# use traits::TryInto;\n" +"# \n" +"# fn parse_u8(s: felt252) -> Result {\n" +"# match s.try_into() {\n" +"# Option::Some(value) => Result::Ok(value),\n" +"# Option::None(_) => Result::Err('Invalid integer'),\n" +"# }\n" +"# }\n" +"# \n" +"# fn do_something_with_parse_u8(input: felt252) -> Result {\n" +"# let input_to_u8: u8 = parse_u8(input)?;\n" +"# // DO SOMETHING\n" +"# let res = input_to_u8 - 1;\n" +"# Result::Ok(res)\n" +"# }\n" +"# \n" +"# #[cfg(test)]\n" +"# mod tests {\n" +"# use super::do_something_with_parse_u8;\n" +"# use debug::PrintTrait;\n" +" #[test]\n" +" fn test_function_2() {\n" +" let number: felt252 = 258_felt252;\n" +" match do_something_with_parse_u8(number) {\n" +" Result::Ok(value) => value.print(),\n" +" Result::Err(e) => e.print()\n" +" }\n" " }\n" -"}\n" +"# }\n" +"# \n" "```" msgstr "" -#: src/ch09-02-error-handling.md:160 +#: src/ch09-02-recoverable-errors.md:203 msgid "The console will print the error \"Invalid Integer\"." msgstr "" -#: src/ch09-02-error-handling.md:162 +#: src/ch09-02-recoverable-errors.md:205 msgid "
" msgstr "" -#: src/ch09-02-error-handling.md:164 +#: src/ch09-02-recoverable-errors.md:207 msgid "### Summary" msgstr "" -#: src/ch09-02-error-handling.md:166 +#: src/ch09-02-recoverable-errors.md:209 msgid "" "We saw that recoverable errors can be handled in Cairo using the Result " "enum, which has two variants: `Ok` and `Err`. The `Result` enum is " @@ -10104,7 +10480,7 @@ msgid "" "`Err`, and panicking with custom messages." msgstr "" -#: src/ch09-02-error-handling.md:168 +#: src/ch09-02-recoverable-errors.md:211 msgid "" "To handle recoverable errors, a function can return a `Result` type and use " "pattern matching to handle the success or failure of an operation. The `?` " @@ -10114,6 +10490,84 @@ msgid "" "by the called function." msgstr "" +#: src/ch10-00-advanced-features.md:1 +msgid "# Advanced Features" +msgstr "" + +#: src/ch10-01-operator-overloading.md:1 +msgid "# Operator Overloading" +msgstr "" + +#: src/ch10-01-operator-overloading.md:3 +msgid "" +"Operator overloading is a feature in some programming languages that allows " +"the redefinition of standard operators, such as addition (+), subtraction " +"(-), multiplication (\\*), and division (/), to work with user-defined " +"types. This can make the syntax of the code more intuitive, by enabling " +"operations on user-defined types to be expressed in the same way as " +"operations on primitive types." +msgstr "" + +#: src/ch10-01-operator-overloading.md:5 +msgid "" +"In Cairo, operator overloading is achieved through the implementation of " +"specific traits. Each operator has an associated trait, and overloading that " +"operator involves providing an implementation of that trait for a custom " +"type.\n" +"However, it's essential to use operator overloading judiciously. Misuse can " +"lead to confusion, making the code more difficult to maintain, for example " +"when there is no semantic meaning to the operator being overloaded." +msgstr "" + +#: src/ch10-01-operator-overloading.md:8 +msgid "" +"Consider an example where two `Potions` need to be combined. `Potions` have " +"two data fields, mana and health. Combining two `Potions` should add their " +"respective fields." +msgstr "" + +#: src/ch10-01-operator-overloading.md:10 +msgid "" +"```rust\n" +"struct Potion {\n" +" health: felt252,\n" +" mana: felt252\n" +"}\n" +"\n" +"impl PotionAdd of Add {\n" +" fn add(lhs: Potion, rhs: Potion) -> Potion {\n" +" Potion { health: lhs.health + rhs.health, mana: lhs.mana + rhs.mana, " +" }\n" +" }\n" +"}\n" +"\n" +"fn main() {\n" +" let health_potion: Potion = Potion { health: 100, mana: 0 };\n" +" let mana_potion: Potion = Potion { health: 0, mana: 100 };\n" +" let super_potion: Potion = health_potion + mana_potion;\n" +" // Both potions were combined with the `+` operator.\n" +" assert(super_potion.health == 100, '');\n" +" assert(super_potion.mana == 100, '');\n" +"}\n" +"```" +msgstr "" + +#: src/ch10-01-operator-overloading.md:32 +msgid "" +"In the code above, we're implementing the `Add` trait for the `Potion` type. " +"The add function takes two arguments: `lhs` and `rhs` (left and right-hand " +"side). The function body returns a new `Potion` instance, its field values " +"being a combination of `lhs` and `rhs`." +msgstr "" + +#: src/ch10-01-operator-overloading.md:34 +msgid "" +"As illustrated in the example, overloading an operator requires " +"specification of the concrete type being overloaded. The overloaded generic " +"trait is `Add`, and we define a concrete implementation for the type " +"`Potion` with `Add`." +msgstr "" + #: src/ch99-00-starknet-smart-contracts.md:1 msgid "# Starknet Smart Contracts" msgstr "" @@ -10137,7 +10591,11 @@ msgstr "" #: src/ch99-00-starknet-smart-contracts.md:7 msgid "" "Starknet contracts are denoted by the `#[contract]` attribute. We'll dive " -"deeper into this in the next sections." +"deeper into this in the next sections.\n" +"If you want to learn more about the Starknet network itself, its " +"architecture and the tooling available, you should read the [Starknet " +"Book](https://book.starknet.io/). This section will focus on writing smart " +"contracts in Cairo." msgstr "" #: src/ch99-01-01-introduction-to-smart-contracts.md:1 @@ -10176,11 +10634,11 @@ msgstr "" msgid "" "The programming language used to write smart contracts varies depending on " "the blockchain. For example, on Ethereum and the [EVM-compatible " -"ecosystem](https://ethereum.org/en/developers/docs/evm/) ecosystem, the most " -"commonly used language is Solidity, while on Starknet, it is Cairo. The way " -"the code is compiled also differs based on the blockchain. On Ethereum, " -"Solidity is compiled into bytecode. On Starknet, Cairo is compiled into " -"Sierra and then into Cairo Assembly (casm)." +"ecosystem](https://ethereum.org/en/developers/docs/evm/), the most commonly " +"used language is Solidity, while on Starknet, it is Cairo. The way the code " +"is compiled also differs based on the blockchain. On Ethereum, Solidity is " +"compiled into bytecode. On Starknet, Cairo is compiled into Sierra and then " +"into Cairo Assembly (casm)." msgstr "" #: src/ch99-01-01-introduction-to-smart-contracts.md:12 @@ -10199,9 +10657,9 @@ msgstr "" #: src/ch99-01-01-introduction-to-smart-contracts.md:14 msgid "" -"For developers to build smart contracts that can interact with each others, " +"For developers to build smart contracts that can interact with each other, " "it is required to know what the other contracts look like. Hence, Ethereum " -"developers started to build standards for smart contract developement, the " +"developers started to build standards for smart contract development, the " "`ERCxx`. The two most used and famous standards are the `ERC20`, used to " "build tokens like `USDC`, `DAI` or `STARK`, and the `ERC721`, for NFTs " "(Non-fungible tokens) like `CryptoPunks` or `Everai`." @@ -10335,7 +10793,7 @@ msgid "" "adapted) as a base layer, Starknet employs its own VM. This frees developers " "from the constraints of the EVM, opening up a broader range of " "possibilities. Coupled with decreased transaction costs, the combination of " -"Starknet and Cairo creates an exiting playground for developers. Native " +"Starknet and Cairo creates an exciting playground for developers. Native " "account abstraction enables more complex logic for accounts and transaction " "flows. Emerging use cases include **transparent AI** and artificial " "intelligence and machine learning applications. Finally, **blockchain " @@ -10386,31 +10844,31 @@ msgstr "" msgid "" "```rust\n" "#[contract]\n" -"mod Example{\n" +"mod example {\n" " use starknet::get_caller_address;\n" " use starknet::ContractAddress;\n" "\n" -" struct Storage{\n" -" names: LegacyMap::,\n" +" struct Storage {\n" +" names: LegacyMap::, \n" " }\n" "\n" " #[event]\n" -" fn StoredName(caller: ContractAddress, name:felt252){}\n" +" fn StoredName(caller: ContractAddress, name: felt252) {}\n" "\n" " #[constructor]\n" -" fn constructor(_name: felt252, _address: ContractAddress){\n" +" fn constructor(_name: felt252, _address: ContractAddress) {\n" " names::write(_address, _name);\n" " }\n" "\n" " #[external]\n" -" fn store_name(_name: felt252){\n" +" fn store_name(_name: felt252) {\n" " let caller = get_caller_address();\n" " names::write(caller, _name);\n" -" StoredName(caller,_name);\n" +" StoredName(caller, _name);\n" " }\n" "\n" " #[view]\n" -" fn get_name(_address:ContractAddress) -> felt252{\n" +" fn get_name(_address: ContractAddress) -> felt252 {\n" " let name = names::read(_address);\n" " return name;\n" " }\n" @@ -10420,12 +10878,12 @@ msgstr "" #: src/ch99-01-02-writing-starknet-contracts.md:49 msgid "" -"Listing 9-1: A simple naming service contract" +"Listing 99-1: A simple naming service contract" msgstr "" #: src/ch99-01-02-writing-starknet-contracts.md:51 msgid "" -"> NB: Starknet contracts are defined within " +"> Note: Starknet contracts are defined within " "[modules](./ch06-02-defining-modules-to-control-scope.md)." msgstr "" @@ -10445,7 +10903,7 @@ msgid "" msgstr "" #: src/ch99-01-02-writing-starknet-contracts.md:59 -msgid "Here are a list of common attributes used in Starknet contracts:" +msgid "Here is a list of common attributes used in Starknet contracts:" msgstr "" #: src/ch99-01-02-writing-starknet-contracts.md:61 @@ -10496,18 +10954,21 @@ msgstr "" #: src/ch99-01-02-writing-starknet-contracts.md:81 msgid "" "```rust\n" -"struct Storage{\n" -" id: u8,\n" -" names: LegacyMap::,\n" -"}\n" +"# #[contract]\n" +"# mod contract {\n" +" struct Storage {\n" +" id: u8,\n" +" names: LegacyMap::,\n" +" }\n" +"# }\n" "```" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:88 -msgid "Listing 9-2: A Storage Struct" +#: src/ch99-01-02-writing-starknet-contracts.md:91 +msgid "Listing 99-2: A Storage Struct" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:90 +#: src/ch99-01-02-writing-starknet-contracts.md:93 msgid "" "The storage struct is a " "[struct](./ch04-00-using-structs-to-structure-related-data.md) like any " @@ -10515,11 +10976,11 @@ msgid "" "except that it allows you to define mappings using the `LegacyMap` type." msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:93 +#: src/ch99-01-02-writing-starknet-contracts.md:96 msgid "### Storage Mappings" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:95 +#: src/ch99-01-02-writing-starknet-contracts.md:98 msgid "" "Mappings are a key-value data structure that you can use to store data " "within a smart contract. They are essentially hash tables that allow you to " @@ -10527,33 +10988,33 @@ msgid "" "to store sets of data, as it's impossible to store arrays in storage." msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:97 +#: src/ch99-01-02-writing-starknet-contracts.md:100 msgid "" "A mapping is a variable of type LegacyMap, in which the key and value types " "are specified within angular brackets <>.\n" "It is important to note that the `LegacyMap` type can only be used inside " "the `Storage` struct, and can't be used to define mappings in user-defined " "structs.\n" -"The syntax for declaring a mapping is as follows in Listing 9-2." +"The syntax for declaring a mapping is as follows in Listing 99-2." msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:101 +#: src/ch99-01-02-writing-starknet-contracts.md:104 msgid "" -"You can also create more complex mappings than that found in Listing 9-2 " +"You can also create more complex mappings than that found in Listing 99-2 " "like the popular `allowances` storage variable in the ERC20 Standard which " "maps the `owner` and `spender` to the `allowance` using tuples:" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:103 +#: src/ch99-01-02-writing-starknet-contracts.md:106 msgid "" "```rust\n" -"struct Storage{\n" -" allowances: LegacyMap::<(ContractAddress, ContractAddress), u256>\n" -"}\n" +" struct Storage {\n" +" allowances: LegacyMap::<(ContractAddress, ContractAddress), u256>\n" +" }\n" "```" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:109 +#: src/ch99-01-02-writing-starknet-contracts.md:112 msgid "" "In mappings, the address of the value at key `k_1,...,k_n` is " "`h(...h(h(sn_keccak(variable_name),k_1),k_2),...,k_n)` where ℎ\n" @@ -10562,102 +11023,102 @@ msgid "" "Documentation](https://docs.starknet.io/documentation/architecture_and_concepts/Contracts/contract-storage/#storage_variables)" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:112 +#: src/ch99-01-02-writing-starknet-contracts.md:115 msgid "### Reading from Storage" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:114 +#: src/ch99-01-02-writing-starknet-contracts.md:117 msgid "" "To read the value of the storage variable `names`, we call the `read` " "function on the `names` storage variable, passing in the key `_address` as a " "parameter." msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:116 +#: src/ch99-01-02-writing-starknet-contracts.md:119 msgid "" "```rust\n" -"let name = names::read(_address);\n" +" let name = names::read(_address);\n" "```" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:120 +#: src/ch99-01-02-writing-starknet-contracts.md:123 msgid "" -"Listing 9-3: Calling the `read` function on the " +"Listing 99-3: Calling the `read` function on the " "`names` variable" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:122 +#: src/ch99-01-02-writing-starknet-contracts.md:125 msgid "" "> Note: When the storage variable does not store a mapping, its value is " "accessed without passing any parameters to the read method" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:124 +#: src/ch99-01-02-writing-starknet-contracts.md:127 msgid "### Writing to Storage" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:126 +#: src/ch99-01-02-writing-starknet-contracts.md:129 msgid "" "To write a value to the storage variable `names`, we call the `write` " "function on the `names` storage variable, passing in the key and values as " "arguments." msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:128 +#: src/ch99-01-02-writing-starknet-contracts.md:131 msgid "" "```rust\n" -"names::write(_address, _name);\n" +" names::write(caller, _name);\n" "```" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:132 +#: src/ch99-01-02-writing-starknet-contracts.md:135 msgid "" -"Listing 9-4: Writing to the `names` variable" +"Listing 99-4: Writing to the `names` variable" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:136 +#: src/ch99-01-02-writing-starknet-contracts.md:139 msgid "" "In this section, we are going to be looking at some popular function types " "you'd encounter with most contracts:" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:138 +#: src/ch99-01-02-writing-starknet-contracts.md:141 msgid "### 1. Constructors" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:140 +#: src/ch99-01-02-writing-starknet-contracts.md:143 msgid "" "Constructors are a special type of function that runs only once when " "deploying a contract, and can be used to initialize the state of the " "contract." msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:142 +#: src/ch99-01-02-writing-starknet-contracts.md:145 msgid "" "```rust\n" -"#[constructor]\n" -"fn constructor(_name: felt252, _address: ContractAddress){\n" -" names::write(_address, _name);\n" -"}\n" +" #[constructor]\n" +" fn constructor(_name: felt252, _address: ContractAddress) {\n" +" names::write(_address, _name);\n" +" }\n" "```" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:149 +#: src/ch99-01-02-writing-starknet-contracts.md:152 msgid "Some important rules to note:" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:151 +#: src/ch99-01-02-writing-starknet-contracts.md:154 msgid "" "1. Your contract can't have more than one constructor.\n" "2. Your constructor function must be named `constructor`.\n" "3. Lastly, it must be annotated with the `#[constructor]` attribute." msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:155 +#: src/ch99-01-02-writing-starknet-contracts.md:158 msgid "### 2. External functions" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:157 +#: src/ch99-01-02-writing-starknet-contracts.md:160 msgid "" "External functions are functions that can modify the state of a contract. " "They are public and can be called by any other contract or externally.\n" @@ -10665,23 +11126,23 @@ msgid "" "attribute:" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:160 +#: src/ch99-01-02-writing-starknet-contracts.md:163 msgid "" "```rust\n" -"#[external]\n" -"fn store_name(_name: felt252){\n" -" let caller = get_caller_address();\n" -" names::write(caller, _name);\n" -" StoredName(caller,_name);\n" -"}\n" +" #[external]\n" +" fn store_name(_name: felt252) {\n" +" let caller = get_caller_address();\n" +" names::write(caller, _name);\n" +" StoredName(caller, _name);\n" +" }\n" "```" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:169 +#: src/ch99-01-02-writing-starknet-contracts.md:172 msgid "### 3. View functions" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:171 +#: src/ch99-01-02-writing-starknet-contracts.md:174 msgid "" "View functions are read-only functions allowing you to access data from the " "contract while ensuring that the state of the contract is not modified. They " @@ -10690,38 +11151,38 @@ msgid "" "attribute:" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:174 +#: src/ch99-01-02-writing-starknet-contracts.md:177 msgid "" "```rust\n" -"#[view]\n" -"fn get_name(_address:ContractAddress) -> felt252{\n" -" let name = names::read(_address);\n" -" return name;\n" -"}\n" +" #[view]\n" +" fn get_name(_address: ContractAddress) -> felt252 {\n" +" let name = names::read(_address);\n" +" return name;\n" +" }\n" "```" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:182 +#: src/ch99-01-02-writing-starknet-contracts.md:185 msgid "" -"> **NB:** It's important to note that, both external and view functions are " -"public. To create an internal function in a contract, you simply don't " +"> **Note:** It's important to note that, both external and view functions " +"are public. To create an internal function in a contract, you simply don't " "annotate it with any attribute." msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:184 +#: src/ch99-01-02-writing-starknet-contracts.md:187 msgid "## Events" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:186 +#: src/ch99-01-02-writing-starknet-contracts.md:189 msgid "" "Events are custom data structures that are emitted by smart contracts during " "execution.\n" "They provide a way for smart contracts to communicate with the external " "world by logging information\n" -"about specific occurences in a contract." +"about specific occurrences in a contract." msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:190 +#: src/ch99-01-02-writing-starknet-contracts.md:193 msgid "" "Events play a crucial role in the creation of smart contracts. Take, for " "instance, the Non-Fungible Tokens (NFTs) minted on Starknet. All of these " @@ -10732,53 +11193,53 @@ msgid "" "NFTs)." msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:192 +#: src/ch99-01-02-writing-starknet-contracts.md:195 msgid "### Defining events" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:194 +#: src/ch99-01-02-writing-starknet-contracts.md:197 msgid "" "An event is defined as an empty function annotated with the `#[event]` " "attribute. The parameters of this function\n" "are the data that will be emitted by the event." msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:197 +#: src/ch99-01-02-writing-starknet-contracts.md:200 msgid "" -"In Listing 9-1, `StoredName` is an event that emits information when names " +"In Listing 99-1, `StoredName` is an event that emits information when names " "are stored in the contract:" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:199 +#: src/ch99-01-02-writing-starknet-contracts.md:202 msgid "" "```rust\n" -"#[event]\n" -"fn StoredName(caller: ContractAddress, name:felt252){}\n" +" #[event]\n" +" fn StoredName(caller: ContractAddress, name: felt252) {}\n" "```" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:204 +#: src/ch99-01-02-writing-starknet-contracts.md:207 msgid "" "We pass in the emitted data types as parameters within the parentheses. In " "this example, our event will emit the contract address of the caller and the " "name stored within the contract." msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:206 +#: src/ch99-01-02-writing-starknet-contracts.md:209 msgid "### Emitting events" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:208 +#: src/ch99-01-02-writing-starknet-contracts.md:211 msgid "" "After defining events, we can emit them by simply calling the event name " "like we'll call functions,\n" "passing in the values to be emitted as parameters:" msgstr "" -#: src/ch99-01-02-writing-starknet-contracts.md:211 +#: src/ch99-01-02-writing-starknet-contracts.md:214 msgid "" "```rust\n" -"StoredName(caller,_name);\n" +" StoredName(caller, _name);\n" "```" msgstr "" @@ -10892,7 +11353,7 @@ msgid "" msgstr "" #: src/ch99-02-01-abis-and-interfaces.md:57 -msgid "Listing 9-1: A simple ERC20 Interface" +msgid "Listing 99-4: A simple ERC20 Interface" msgstr "" #: src/ch99-02-01-abis-and-interfaces.md:59 @@ -10952,7 +11413,7 @@ msgstr "" #: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:10 msgid "" "To effectively break down the concepts in this chapter, we are going to be " -"using the IERC20 interface from the previous chapter (refer to Listing 9-1):" +"using the IERC20 interface from the previous chapter (refer to Listing 99-4):" msgstr "" #: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:12 @@ -10970,53 +11431,57 @@ msgstr "" #: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:16 msgid "" +"**Note:** The expanded code for our IERC20 interface is a lot longer, but to " +"keep this chapter concise and straight to the point, we focused on one view " +"function `get_name`, and one external function `transfer`." +msgstr "" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:18 +msgid "" "```rust\n" +"//does_not_compile\n" +"use starknet::{ContractAddress};\n" +"\n" "trait IERC20DispatcherTrait {\n" -" fn get_name(self: T) -> felt252;\n" +" fn name(self: T) -> felt252;\n" " fn transfer(self: T, recipient: ContractAddress, amount: u256);\n" "}\n" "\n" -"#[derive(Copy, Drop)]\n" +"#[derive(Copy, Drop, storage_access::StorageAccess, Serde)]\n" "struct IERC20Dispatcher {\n" -" contract_address: starknet::ContractAddress,\n" +" contract_address: starknet::ContractAddress, \n" "}\n" "\n" -"impl IERC20DispatcherImpl of IERC20DispatcherTrait:: {\n" -" fn get_name(self: IERC20Dispatcher) -> felt252 {\n" -" // starknet::call_contract_syscall is called in here\n" +"impl IERC20DispatcherImpl of IERC20DispatcherTrait {\n" +" fn name(\n" +" self: IERC20Dispatcher\n" +" ) -> felt252 { // starknet::call_contract_syscall is called in here\n" " }\n" -" fn transfer(self: IERC20Dispatcher, recipient: ContractAddress, amount: " -"u256) {\n" -" // starknet::call_contract_syscall is called in here\n" +" fn transfer(\n" +" self: IERC20Dispatcher, recipient: ContractAddress, amount: u256\n" +" ) { // starknet::call_contract_syscall is called in here\n" " }\n" "}\n" "```" msgstr "" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:37 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:44 msgid "" -"Listing 9-2: An expanded form of the IERC20 " +"Listing 99-5: An expanded form of the IERC20 " "trait" msgstr "" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:39 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:46 msgid "" -"**NB:** The expanded code for our IERC20 interface is a lot more robust, but " -"to keep this chapter concise and straight to the point, we focused on one " -"view function `get_name`, and one external function `transfer`." -msgstr "" - -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:41 -msgid "" -"It's also worthy of note that all these is abstracted behind the scenes " +"It's also worthy of note that all these are abstracted behind the scenes " "thanks to the power of Cairo plugins." msgstr "" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:43 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:48 msgid "### Calling Contracts using the Contract Dispatcher" msgstr "" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:45 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:50 msgid "" "This is an example of a contract named `Dispatcher` using the Contract " "interface dispatcher to call an ERC-20 contract in the ERC-20 contract's " @@ -11024,22 +11489,53 @@ msgid "" "ERC-20 contract:" msgstr "" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:47 -msgid "" -"```rust\n" +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:52 +msgid "" +"```rust\n" +"# use starknet::ContractAddress;\n" +"# \n" +"# #[abi]\n" +"# trait IERC20 {\n" +"# #[view]\n" +"# fn name() -> felt252;\n" +"# \n" +"# #[view]\n" +"# fn symbol() -> felt252;\n" +"# \n" +"# #[view]\n" +"# fn decimals() -> u8;\n" +"# \n" +"# #[view]\n" +"# fn total_supply() -> u256;\n" +"# \n" +"# #[view]\n" +"# fn balance_of(account: ContractAddress) -> u256;\n" +"# \n" +"# #[view]\n" +"# fn allowance(owner: ContractAddress, spender: ContractAddress) -> " +"u256;\n" +"# \n" +"# #[external]\n" +"# fn transfer(recipient: ContractAddress, amount: u256) -> bool;\n" +"# \n" +"# #[external]\n" +"# fn transfer_from(sender: ContractAddress, recipient: ContractAddress, " +"amount: u256) -> bool;\n" +"# \n" +"# #[external]\n" +"# fn approve(spender: ContractAddress, amount: u256) -> bool;\n" +"# }\n" +"# \n" "//**** Specify interface here ****//\n" -"\n" "#[contract]\n" -"mod Dispatcher {\n" +"mod dispatcher {\n" " use super::IERC20DispatcherTrait;\n" " use super::IERC20Dispatcher;\n" " use starknet::ContractAddress;\n" "\n" " #[view]\n" -" fn token_name(\n" -" _contract_address: ContractAddress\n" -" ) -> felt252 {\n" -" IERC20Dispatcher {contract_address: _contract_address }.name()\n" +" fn token_name(_contract_address: ContractAddress) -> felt252 {\n" +" IERC20Dispatcher { contract_address: _contract_address }.name()\n" " }\n" "\n" " #[external]\n" @@ -11047,20 +11543,21 @@ msgid "" " _contract_address: ContractAddress, recipient: ContractAddress, " "amount: u256\n" " ) -> bool {\n" -" IERC20Dispatcher {contract_address: _contract_address " +" IERC20Dispatcher { contract_address: _contract_address " "}.transfer(recipient, amount)\n" " }\n" "}\n" +"# \n" "```" msgstr "" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:72 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:107 msgid "" -"Listing 9-3: A sample contract which uses the " +"Listing 99-6: A sample contract which uses the " "Contract Dispatcher" msgstr "" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:74 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:109 msgid "" "As you can see, we had to first import the `IERC20DispatcherTrait` and " "`IERC20Dispatcher` which was generated and exported on compiling our " @@ -11070,11 +11567,11 @@ msgid "" "want to call." msgstr "" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:76 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:111 msgid "## Library Dispatcher" msgstr "" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:78 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:113 msgid "" "The key difference between the contract dispatcher and the library " "dispatcher is that while the contract dispatcher calls an external " @@ -11085,7 +11582,7 @@ msgid "" "have no possibility of tampering with the target contract's state." msgstr "" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:81 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:116 msgid "" "As stated in the previous chapter, contracts annotated with the `#[abi]` " "macro on compilation generates a new trait, two new structs (one for " @@ -11093,78 +11590,84 @@ msgid "" "this trait. The expanded form of the library traits looks like:" msgstr "" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:83 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:118 msgid "" "```rust\n" +"//does_not_compile\n" +"use starknet::ContractAddress;\n" +"\n" "trait IERC20DispatcherTrait {\n" -" fn get_name(self: T) -> felt252;\n" +" fn name(self: T) -> felt252;\n" " fn transfer(self: T, recipient: ContractAddress, amount: u256);\n" "}\n" "\n" -"#[derive(Copy, Drop)]\n" +"#[derive(Copy, Drop, storage_access::StorageAccess, Serde)]\n" "struct IERC20LibraryDispatcher {\n" -" class_hash: starknet::ClassHash,\n" +" class_hash: starknet::ClassHash, \n" "}\n" "\n" "impl IERC20LibraryDispatcherImpl of " -"IERC20DispatcherTrait:: {\n" -" fn get_name(self: IERC20LibraryDispatcher) -> felt252 {\n" -" // starknet::syscalls::library_call_syscall is called in here\n" +"IERC20DispatcherTrait {\n" +" fn name(\n" +" self: IERC20LibraryDispatcher\n" +" ) -> felt252 { // starknet::syscalls::library_call_syscall is called in " +"here\n" " }\n" -" fn transfer(self: IERC20LibraryDispatcher, recipient: ContractAddress, " -"amount: u256) {\n" -" // starknet::syscalls::library_call_syscall is called in here\n" +" fn transfer(\n" +" self: IERC20LibraryDispatcher, recipient: ContractAddress, amount: " +"u256\n" +" ) { // starknet::syscalls::library_call_syscall is called in here\n" " }\n" "}\n" "```" msgstr "" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:104 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:144 msgid "" -"Listing 9-4: An expanded form of the IERC20 " +"Listing 99-7: An expanded form of the IERC20 " "trait" msgstr "" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:106 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:146 msgid "### Calling Contracts using the Library Dispatcher" msgstr "" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:108 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:148 msgid "Below's a sample code on calling contracts using the Library Dispatcher:" msgstr "" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:110 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:150 msgid "" "```rust\n" -"//**** Specify interface here ****//\n" -"\n" -"use super::IERC20DispatcherTrait;\n" -"use super::IERC20LibraryDispatcher;\n" -"use starknet::ContractAddress;\n" +"#[contract]\n" +"mod contract {\n" +" use super::IERC20DispatcherTrait;\n" +" use super::IERC20LibraryDispatcher;\n" +" use starknet::ContractAddress;\n" "\n" -"#[view]\n" -"fn token_name() -> felt252 {\n" -" IERC20LibraryDispatcher { class_hash: " +" #[view]\n" +" fn token_name() -> felt252 {\n" +" IERC20LibraryDispatcher { class_hash: " "starknet::class_hash_const::<0x1234>() }.name()\n" -"}\n" +" }\n" "\n" -"#[external]\n" -"fn transfer_token(\n" -" recipient: ContractAddress, amount: u256\n" -") -> bool {\n" -" IERC20LibraryDispatcher { class_hash: " -"starknet::class_hash_const::<0x1234>() }.transfer(recipient, amount)\n" +" #[external]\n" +" fn transfer_token(recipient: ContractAddress, amount: u256) -> bool {\n" +" IERC20LibraryDispatcher {\n" +" class_hash: starknet::class_hash_const::<0x1234>()\n" +" }.transfer(recipient, amount)\n" +" }\n" "}\n" "```" msgstr "" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:130 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:171 msgid "" -"Listing 9-4: A sample contract using the Library " +"Listing 99-8: A sample contract using the Library " "Dispatcher" msgstr "" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:132 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:173 msgid "" "As you can see, we had to first import the `IERC20DispatcherTrait` and " "`IERC20LibraryDispatcher` which was generated and exported on compiling our " @@ -11174,11 +11677,11 @@ msgid "" "call." msgstr "" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:134 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:175 msgid "## Calling Contracts using low-level System calls" msgstr "" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:136 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:177 msgid "" "Another way to call other contracts is to use the " "`starknet::call_contract_syscall` system call. The Dispatchers we described " @@ -11186,7 +11689,7 @@ msgid "" "call." msgstr "" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:138 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:179 msgid "" "Using the system call `starknet::call_contract_syscall` can be handy for " "customized error handling or possessing more control over the " @@ -11194,27 +11697,31 @@ msgid "" "an example demonstrating a low-level `transfer` call:" msgstr "" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:140 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:181 msgid "" "```rust\n" -"#[external]\n" -"fn transfer_token(\n" -" address: starknet::ContractAddress, selector: felt252, calldata: " +"#[contract]\n" +"mod contract {\n" +" use array::ArrayTrait;\n" +" #[external]\n" +" fn transfer_token(\n" +" address: starknet::ContractAddress, selector: felt252, calldata: " "Array\n" -") -> Span:: {\n" -" starknet::call_contract_syscall(address, selector, " +" ) -> Span:: {\n" +" starknet::call_contract_syscall(address, selector, " "calldata.span()).unwrap_syscall()\n" +" }\n" "}\n" "```" msgstr "" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:149 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:194 msgid "" -"Listing 9-5: A sample contract implementing system " +"Listing 99-9: A sample contract implementing system " "calls" msgstr "" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:151 +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:196 msgid "" "As you can see, rather than pass our function arguments directly, we passed " "in the contract address, function selector (which is a keccak hash of the " @@ -11222,6 +11729,299 @@ msgid "" "returned a serialized value which we'll need to deserialize ourselves!" msgstr "" +#: src/ch99-03-security-considerations.md:1 +msgid "# Security Considerations" +msgstr "" + +#: src/ch99-03-security-considerations.md:3 +msgid "" +"When developing software, ensuring it functions as intended is usually " +"straightforward. However, preventing unintended usage and vulnerabilities " +"can be more challenging." +msgstr "" + +#: src/ch99-03-security-considerations.md:5 +msgid "" +"In smart contract development, security is very important. A single error " +"can result in the loss of valuable assets or the improper functioning of " +"certain features." +msgstr "" + +#: src/ch99-03-security-considerations.md:7 +msgid "" +"Smart contracts are executed in a public environment where anyone can " +"examine the code and interact with it. Any errors or vulnerabilities in the " +"code can be exploited by malicious actors." +msgstr "" + +#: src/ch99-03-security-considerations.md:9 +msgid "" +"This chapter presents general recommendations for writing secure smart " +"contracts. By incorporating these concepts during development, you can " +"create robust and reliable smart contracts. This reduces the chances of " +"unexpected behavior or vulnerabilities." +msgstr "" + +#: src/ch99-03-security-considerations.md:11 +msgid "## Disclaimer" +msgstr "" + +#: src/ch99-03-security-considerations.md:13 +msgid "" +"This chapter does not provide an exhaustive list of all possible security " +"issues, and it does not guarantee that your contracts will be completely " +"secure." +msgstr "" + +#: src/ch99-03-security-considerations.md:15 +msgid "" +"If you are developing smart contracts for production use, it is highly " +"recommended to conduct external audits performed by security experts." +msgstr "" + +#: src/ch99-03-security-considerations.md:17 +msgid "## Mindset" +msgstr "" + +#: src/ch99-03-security-considerations.md:19 +msgid "" +"Cairo is a highly safe language inspired by rust. It is designed in a way " +"that force you to cover all possible cases. Security issues on Starknet " +"mostly arise from the way smart contracts flows are designed, not much from " +"the language itself." +msgstr "" + +#: src/ch99-03-security-considerations.md:21 +msgid "" +"Adopting a security mindset is the initial step in writing secure smart " +"contracts. Try to always consider all possible scenarios when writing code." +msgstr "" + +#: src/ch99-03-security-considerations.md:23 +msgid "### Viewing smart contract as Finite State Machines" +msgstr "" + +#: src/ch99-03-security-considerations.md:25 +msgid "" +"Transactions in smart contracts are atomic, meaning they either succeed or " +"fail without making any changes." +msgstr "" + +#: src/ch99-03-security-considerations.md:27 +msgid "" +"Think of smart contracts as state machines: they have a set of initial " +"states defined by the constructor constraints, and external function " +"represents a set of possible state transitions. A transaction is nothing " +"more than a state transition." +msgstr "" + +#: src/ch99-03-security-considerations.md:29 +msgid "" +"The `assert` or `panic` functions can be used to validate conditions before " +"performing specific actions. You can learn more about these on the " +"[Unrecoverable Errors with " +"panic](./ch09-01-unrecoverable-errors-with-panic.md) page." +msgstr "" + +#: src/ch99-03-security-considerations.md:31 +msgid "These validations can include:" +msgstr "" + +#: src/ch99-03-security-considerations.md:33 +msgid "" +"- Inputs provided by the caller\n" +"- Execution requirements\n" +"- Invariants (conditions that must always be true)\n" +"- Return values from other function calls" +msgstr "" + +#: src/ch99-03-security-considerations.md:38 +msgid "" +"For example, you could use the `assert` function to validate that a user has " +"enough funds to perform a withdraw transaction. If the condition is not met, " +"the transaction will fail and the state of the contract will not change." +msgstr "" + +#: src/ch99-03-security-considerations.md:40 +msgid "" +"```rust\n" +" #[external]\n" +" fn withdraw(amount: u256) {\n" +" let current_balance = balance::read();\n" +"\n" +" assert(balance >= amount, 'Insufficient funds');\n" +"\n" +" balance::write(current_balance - amount);\n" +" }\n" +"```" +msgstr "" + +#: src/ch99-03-security-considerations.md:51 +msgid "" +"Using these functions to check conditions adds constraints that help clearly " +"define the boundaries of possible state transitions for each function in " +"your smart contract. These checks ensure that the behavior of the contract " +"stays within the expected limits." +msgstr "" + +#: src/ch99-03-security-considerations.md:53 +msgid "## Recommendations" +msgstr "" + +#: src/ch99-03-security-considerations.md:55 +msgid "### Checks Effects Interactions Pattern" +msgstr "" + +#: src/ch99-03-security-considerations.md:57 +msgid "" +"The Checks Effects Interactions pattern is a common design pattern used to " +"prevent reentrancy attacks on Ethereum. While reentrancy is harder to " +"achieve in Starknet, it is still recommended to use this pattern in your " +"smart contracts." +msgstr "" + +#: src/ch99-03-security-considerations.md:59 +msgid "" +msgstr "" + +#: src/ch99-03-security-considerations.md:61 +msgid "" +"The pattern consists of following a specific order of operations in your " +"functions:" +msgstr "" + +#: src/ch99-03-security-considerations.md:63 +msgid "" +"1. **Checks**: Validate all conditions and inputs before performing any " +"state changes.\n" +"2. **Effects**: Perform all state changes.\n" +"3. **Interactions**: All external calls to other contracts should be made at " +"the end of the function." +msgstr "" + +#: src/ch99-03-security-considerations.md:67 +msgid "### Access control" +msgstr "" + +#: src/ch99-03-security-considerations.md:69 +msgid "" +"Access control is the process of restricting access to certain features or " +"resources. It is a common security mechanism used to prevent unauthorized " +"access to sensitive information or actions. In smart contracts, some " +"functions may often be restricted to specific users or roles." +msgstr "" + +#: src/ch99-03-security-considerations.md:71 +msgid "" +"You can implement the access control pattern to easily manage permissions. " +"This pattern consists of defining a set of roles and assigning them to " +"specific users. Each function can then be restricted to specific roles." +msgstr "" + +#: src/ch99-03-security-considerations.md:73 +msgid "" +"```rust\n" +"#[contract]\n" +"mod access_control_contract {\n" +" use starknet::ContractAddress;\n" +" use starknet::get_caller_address;\n" +"\n" +" #[storage]\n" +" struct Storage {\n" +" // Role 'owner': only one address\n" +" owner: ContractAddress,\n" +" // Role 'role_a': a set of addresses\n" +" role_a: LegacyMap::\n" +" }\n" +"\n" +" #[constructor]\n" +" fn constructor() {\n" +" owner::write(get_caller_address());\n" +" }\n" +"\n" +" // Guard functions to check roles\n" +"\n" +" #[inline(always)]\n" +" fn is_owner() -> bool {\n" +" owner::read() == get_caller_address()\n" +" }\n" +"\n" +" #[inline(always)]\n" +" fn is_role_a() -> bool {\n" +" role_a::read(get_caller_address())\n" +" }\n" +"\n" +" #[inline(always)]\n" +" fn only_owner() {\n" +" assert(is_owner(), 'Not owner');\n" +" }\n" +"\n" +" #[inline(always)]\n" +" fn only_role_a() {\n" +" assert(is_role_a(), 'Not role A');\n" +" }\n" +"\n" +" // You can easily combine guards to perfom complex checks\n" +" fn only_allowed() {\n" +" assert(is_owner() || is_role_a(), 'Not allowed');\n" +" }\n" +"\n" +" // Functions to manage roles\n" +"\n" +" #[external]\n" +" fn set_role_a(_target: ContractAddress, _active: bool) {\n" +" only_owner();\n" +" role_a::write(_target, _active);\n" +" }\n" +"\n" +" // You can now focus on the business logic of your contract\n" +" // and reduce the complexity of your code by using guard functions\n" +"\n" +" #[external]\n" +" fn role_a_action() {\n" +" only_role_a();\n" +" // ...\n" +" }\n" +"\n" +" #[external]\n" +" fn allowed_action() {\n" +" only_allowed();\n" +" // ...\n" +" }\n" +"}\n" +"\n" +"```" +msgstr "" + +#: src/ch99-03-security-considerations.md:145 +msgid "### Static analysis tool" +msgstr "" + +#: src/ch99-03-security-considerations.md:147 +msgid "" +"Static analysis refers to the process of examining code without its " +"execution, focusing on its structure, syntax, and properties. It involves " +"analyzing the source code to identify potential issues, vulnerabilities, or " +"violations of specified rules." +msgstr "" + +#: src/ch99-03-security-considerations.md:149 +msgid "" +"By defining rules, such as coding conventions or security guidelines, " +"developers can utilize static analysis tools to automatically check the code " +"against these standards." +msgstr "" + +#: src/ch99-03-security-considerations.md:151 +msgid "Reference:" +msgstr "" + +#: src/ch99-03-security-considerations.md:153 +msgid "" +"- [Semgrep Cairo 1.0 " +"support](https://semgrep.dev/blog/2023/semgrep-now-supports-cairo-1-0)" +msgstr "" + #: src/appendix-00.md:1 msgid "# Appendix" msgstr "" @@ -11245,24 +12045,32 @@ msgid "" msgstr "" #: src/appendix-01-keywords.md:6 -msgid "There are three keyword categories:" +msgid "There are two keyword categories:" msgstr "" #: src/appendix-01-keywords.md:8 msgid "- strict\n- reserved" msgstr "" -#: src/appendix-01-keywords.md:13 +#: src/appendix-01-keywords.md:11 +msgid "" +"There is a third category, which are functions from the core library. While " +"their names are not reserved,\n" +"they are not recommended to be used as names of any items to follow good " +"practices." +msgstr "" + +#: src/appendix-01-keywords.md:16 msgid "### Strict keywords" msgstr "" -#: src/appendix-01-keywords.md:15 +#: src/appendix-01-keywords.md:18 msgid "" "These keywords can only be used in their correct contexts.\n" "They cannot be used as names of any items." msgstr "" -#: src/appendix-01-keywords.md:18 +#: src/appendix-01-keywords.md:21 msgid "" "- `as` - Rename import\n" "- `break` - Exit a loop immediately\n" @@ -11295,11 +12103,11 @@ msgid "" "- `use` - Bring symbols into scope" msgstr "" -#: src/appendix-01-keywords.md:47 +#: src/appendix-01-keywords.md:50 msgid "### Reserved keywords" msgstr "" -#: src/appendix-01-keywords.md:49 +#: src/appendix-01-keywords.md:52 msgid "" "These keywords aren't used yet, but they are reserved for future use.\n" "They have the same restrictions as strict keywords.\n" @@ -11308,9 +12116,8 @@ msgid "" "Cairo by forbidding them to use these keywords." msgstr "" -#: src/appendix-01-keywords.md:54 +#: src/appendix-01-keywords.md:57 msgid "" -"- `assert`\n" "- `do`\n" "- `dyn`\n" "- `macro`\n" @@ -11329,6 +12136,25 @@ msgid "" "- `yield`" msgstr "" +#: src/appendix-01-keywords.md:76 +msgid "### Built-in functions" +msgstr "" + +#: src/appendix-01-keywords.md:78 +msgid "" +"The Cairo programming language provides several specific functions that " +"serve a special purpose. We will not cover all of them in this book, but " +"using the names of these functions as names of other items is not " +"recommended." +msgstr "" + +#: src/appendix-01-keywords.md:80 +msgid "" +"-`assert` - This function checks a boolean expression, and if it evaluates " +"to false, it triggers the panic function. -`panic` - This function " +"terminates the program." +msgstr "" + #: src/appendix-02-operators-and-symbols.md:1 msgid "# Appendix B: Operators and Symbols" msgstr "" @@ -11860,3 +12686,69 @@ msgid "" "definition, and inline errors." msgstr "" +#: src/appendix-05-most-common-types-and-traits.md:1 +msgid "## Appendix E - Most Common Types and Traits Required To Write Contracts" +msgstr "" + +#: src/appendix-05-most-common-types-and-traits.md:3 +msgid "" +"This appendix provides a reference for common types and traits used in " +"contract development, along with their corresponding imports, paths, and " +"usage examples." +msgstr "" + +#: src/appendix-05-most-common-types-and-traits.md:5 +msgid "" +"| Import | Path " +" | Usage " +" " +" |\n" +"| ------------------------- | " +"----------------------------------------------------- | " +"-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- " +"|\n" +"| `OptionTrait` | `std::option::OptionTrait` " +" | `OptionTrait` defines a set of methods required to manipulate " +"optional value. " +" |\n" +"| `ResultTrait` | `std::result::ResultTrait` " +" | `ResultTrait` Type for Starknet contract address, a value in " +"the range [0, 2 \\*\\* 251). " +" |\n" +"| `ContractAddress` | `starknet::ContractAddress` " +" | `ContractAddress` is a type to represent the smart contract address " +" " +" |\n" +"| `ContractAddressZeroable` | " +"`starknet::contract_address::ContractAddressZeroable` | " +"`ContractAddressZeroable` is the implementation of the trait `Zeroable` for " +"the `ContractAddress` type. It is required to check whether a value of " +"`t:ContractAddress` is zero or not. |\n" +"| `contract_address_const` | `starknet::contract_address_const` " +" | The `contract_address_const!` it's a function that allows " +"instantiating constant contract address values. " +" |\n" +"| `Into` | `traits::Into;` " +" | `Into` is a trait used for conversion between types. If there is " +"an implementation of Into for the types T and S, you can convert T into " +"S. |\n" +"| `TryInto` | `traits::TryInto;` " +" | `TryInto` is a trait used for conversion between types.If there " +"is an implementation of TryInto for the types T and S, you can convert " +"T into S. |\n" +"| `get_caller_address` | `starknet::get_caller_address` " +" | `get_caller_address()` is a function that returns the address of " +"the caller of the contract. It can be used to identify the caller of a " +"contract function. |\n" +"| `get_contract_address` | `starknet::info::get_contract_address` " +" | `get_contract_address()` is a function that returns the address of " +"the current contract. It can be used to obtain the address of the contract " +"being executed. |" +msgstr "" + +#: src/appendix-05-most-common-types-and-traits.md:17 +msgid "" +"This is not an exhaustive list, but it covers some of the commonly used " +"types and traits in contract development. For more details, refer to the " +"official documentation and explore the available libraries and frameworks." +msgstr "" diff --git a/po/zh-cn.po b/po/zh-cn.po index 95a73cb16..1e9257aa1 100644 --- a/po/zh-cn.po +++ b/po/zh-cn.po @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: The Cairo Programming Language\n" "POT-Creation-Date: \n" -"PO-Revision-Date: 2023-06-11 23:48+0900\n" +"PO-Revision-Date: 2023-09-18 13:05+0900\n" "Last-Translator: cryptonerdcn \n" "Language-Team: Language zh-cn\n" "Language: zh_CN\n" @@ -10,7 +10,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Poedit 3.3.1\n" +"X-Generator: Poedit 3.3.2\n" #: src/SUMMARY.md:1 msgid "The Cairo Programming Language" @@ -36,31 +36,27 @@ msgstr "安装" msgid "Hello, World!" msgstr "Hello,world!" -#: src/SUMMARY.md:13 -msgid "Hello, Scarb!" -msgstr "Hello,Scarb!" - -#: src/SUMMARY.md:15 +#: src/SUMMARY.md:14 msgid "Common Programming Concepts" msgstr "常见的编程概念" -#: src/SUMMARY.md:18 +#: src/SUMMARY.md:17 msgid "Variables and Mutability" msgstr "变量与可变性" -#: src/SUMMARY.md:19 +#: src/SUMMARY.md:18 msgid "Data Types" msgstr "数据类型" -#: src/SUMMARY.md:20 +#: src/SUMMARY.md:19 msgid "Functions" msgstr "函数" -#: src/SUMMARY.md:21 +#: src/SUMMARY.md:20 msgid "Comments" msgstr "注释" -#: src/SUMMARY.md:22 +#: src/SUMMARY.md:21 msgid "Control Flow" msgstr "控制流" @@ -68,162 +64,218 @@ msgstr "控制流" msgid "Common Collections" msgstr "常见集合" -#: src/SUMMARY.md:25 +#: src/SUMMARY.md:26 +msgid "Arrays" +msgstr "数组" + +#: src/SUMMARY.md:27 +msgid "Dictionaries" +msgstr "字典" + +#: src/SUMMARY.md:29 msgid "Understanding Ownership" msgstr "认识所有权" -#: src/SUMMARY.md:28 +#: src/SUMMARY.md:32 msgid "What is Ownership?" msgstr "什么是所有权?" -#: src/SUMMARY.md:29 +#: src/SUMMARY.md:33 msgid "References and Snapshots" msgstr "引用和快照" -#: src/SUMMARY.md:31 +#: src/SUMMARY.md:35 msgid "Using Structs to Structure Related Data" msgstr "使用结构体组织相关联的数据" -#: src/SUMMARY.md:34 +#: src/SUMMARY.md:38 msgid "Defining and Instantiating Structs" msgstr "结构体的定义和实例化" -#: src/SUMMARY.md:35 +#: src/SUMMARY.md:39 msgid "An Example Program Using Structs" msgstr "结构体实例程序" -#: src/SUMMARY.md:36 +#: src/SUMMARY.md:40 msgid "Method Syntax" msgstr "方法语法" -#: src/SUMMARY.md:38 +#: src/SUMMARY.md:42 msgid "Enums and Pattern Matching" msgstr "枚举和模式匹配" -#: src/SUMMARY.md:38 +#: src/SUMMARY.md:42 msgid "Enums" msgstr "枚举的定义" -#: src/SUMMARY.md:42 +#: src/SUMMARY.md:46 msgid "The Match Control Flow Construct" msgstr "Match控制流结构" -#: src/SUMMARY.md:44 +#: src/SUMMARY.md:48 msgid "Managing Cairo Projects with Packages, Crates and Modules" msgstr "使用包、Crate 和模块管理Cairo项目" -#: src/SUMMARY.md:48 +#: src/SUMMARY.md:52 msgid "Packages and Crates" msgstr "包和 Crate" -#: src/SUMMARY.md:50 +#: src/SUMMARY.md:54 msgid "Defining Modules to Control Scope" msgstr "定义模块以控制作用域" -#: src/SUMMARY.md:51 +#: src/SUMMARY.md:55 msgid "Paths for Referring to an Item in the Module Tree" msgstr "引用模块项目的路径" -#: src/SUMMARY.md:52 +#: src/SUMMARY.md:56 msgid "Bringing Paths into Scope with the 'use' Keyword" msgstr "使用 ‘use’ 关键字将路径引入作用域" -#: src/SUMMARY.md:53 +#: src/SUMMARY.md:57 msgid "Separating Modules into Different Files" msgstr "将模块拆分成多个文件" -#: src/SUMMARY.md:57 +#: src/SUMMARY.md:61 msgid "Generic Types" msgstr "泛型" -#: src/SUMMARY.md:59 +#: src/SUMMARY.md:63 msgid "Generic Functions" msgstr "在函数定义中使用泛型" -#: src/SUMMARY.md:60 +#: src/SUMMARY.md:64 msgid "Traits in Cairo" msgstr "Cairo中的Trait" -#: src/SUMMARY.md:62 +#: src/SUMMARY.md:66 msgid "Testing Cairo Programs" msgstr "测试Cairo 程序" -#: src/SUMMARY.md:66 +#: src/SUMMARY.md:70 msgid "How To Write Tests" msgstr "如何编写测试" -#: src/SUMMARY.md:67 +#: src/SUMMARY.md:71 msgid "Testing Organization" msgstr "测试的组织结构" -#: src/SUMMARY.md:69 +#: src/SUMMARY.md:73 msgid "Error Handling" msgstr "错误处理" -#: src/SUMMARY.md:72 +#: src/SUMMARY.md:76 msgid "Unrecoverable Errors with panic" msgstr "用panic处理不可恢复的错误" -#: src/SUMMARY.md:73 +#: src/SUMMARY.md:77 msgid "Recoverable Errors with Result" msgstr "用Result处理可恢复的错误" -#: src/SUMMARY.md:75 +#: src/SUMMARY.md:79 msgid "Advanced Features" msgstr "高级特性" -#: src/SUMMARY.md:78 +#: src/SUMMARY.md:82 msgid "Operator Overloading" msgstr "操作符重载" -#: src/SUMMARY.md:82 +#: src/SUMMARY.md:83 +msgid "Macros" +msgstr "宏" + +#: src/SUMMARY.md:87 msgid "Starknet Smart Contracts" msgstr "Starknet智能合约" -#: src/SUMMARY.md:84 +#: src/SUMMARY.md:89 msgid "Introduction to smart-contracts" msgstr "智能合约简介" -#: src/SUMMARY.md:85 -msgid "Writing Starknet Contracts" -msgstr "编写Starknet智能合约" +#: src/SUMMARY.md:90 +msgid "A simple contract" +msgstr "一份简单的合约" + +#: src/SUMMARY.md:91 +msgid "A deeper dive into contracts" +msgstr "深入了解合约" + +#: src/SUMMARY.md:92 +msgid "Storage Variables" +msgstr "存储变量" + +#: src/SUMMARY.md:93 +msgid "Contract Functions" +msgstr "合约函数" + +#: src/SUMMARY.md:94 +msgid "Contract Events" +msgstr "合约的事件" + +#: src/SUMMARY.md:95 +msgid "Reducing boilerplate" +msgstr "减少冗余模板代码" + +#: src/SUMMARY.md:96 +msgid "Optimizing storage costs" +msgstr "优化存储成本" -#: src/SUMMARY.md:86 +#: src/SUMMARY.md:97 msgid "ABIs and Cross-contract Interactions" msgstr "ABI和跨合约交互" -#: src/SUMMARY.md:87 +#: src/SUMMARY.md:98 msgid "ABIs and Interfaces" msgstr "ABI和接口" -#: src/SUMMARY.md:88 +#: src/SUMMARY.md:99 msgid "Contract Dispatchers, Library Dispachers and system calls" msgstr "合约调度器、库调度器和系统调用" -#: src/SUMMARY.md:90 +#: src/SUMMARY.md:100 +msgid "Other examples" +msgstr "其他例子" + +#: src/SUMMARY.md:101 +msgid "Deploying and Interacting with a Voting contract" +msgstr "部署投票合约并与之交互" + +#: src/SUMMARY.md:102 +msgid "L1 <> L2 Messaging" +msgstr "L1 <> L2 间信息传递" + +#: src/SUMMARY.md:103 +msgid "Security Considerations" +msgstr "安全考量" + +#: src/SUMMARY.md:105 msgid "Appendix" msgstr "附录" -#: src/SUMMARY.md:91 +#: src/SUMMARY.md:106 msgid "A - Keywords" msgstr "A - 关键字" -#: src/SUMMARY.md:92 +#: src/SUMMARY.md:107 msgid "B - Operators and Symbols" msgstr "B - 运算符和符号" -#: src/SUMMARY.md:93 +#: src/SUMMARY.md:108 msgid "C - Derivable Traits" msgstr "C - 可派生的 Trait" -#: src/SUMMARY.md:94 +#: src/SUMMARY.md:109 msgid "D - Useful Development Tools" msgstr "D - 实用开发工具" -#: src/SUMMARY.md:95 +#: src/SUMMARY.md:110 msgid "E - Cairo Most Common Types and Traits" msgstr "E - Cairo中最常见的类型和Trait" +#: src/SUMMARY.md:111 +msgid "F - Installing Cairo binaries" +msgstr "F - 安装Cairo二进制文件" + #: src/title-page.md:1 msgid "# The Cairo Programming Language" msgstr "# Cairo编程语言" @@ -238,8 +290,10 @@ msgstr "" "中文版由[StarknetAstro](https://starknet-astro.super.site/)翻译。" #: src/title-page.md:5 -msgid "This version of the text assumes you’re using Cairo v1.1.0. See the “Installation” section of Chapter 1 to install or update Cairo." -msgstr "这个版本的教程假设你使用的是Cairo v1.1.0。请参阅第1章的 \"安装 \"部分来安装或更新Cairo。" +msgid "" +"This version of the text assumes you’re using the [Cairo Compiler](https://github.com/starkware-libs/cairo) [version 2.2.0](https://github.com/starkware-libs/cairo/releases). See the " +"“Installation” section of Chapter 1 to install or update Cairo." +msgstr "本版本假设你使用的是 Cairo v2.2.0,请参阅第一章的 \"安装 \"部分来安装或更新 Cairo。" #: src/ch00-01-foreword.md:1 msgid "# Foreword" @@ -378,631 +432,442 @@ msgstr "" "- Cairo, Sierra and Casm:\n" "- 非确定性的状态:" +#: src/ch01-00-getting-started.md:1 +msgid "# Getting Started" +msgstr "# 入门" + #: src/ch01-01-installation.md:1 msgid "# Installation" msgstr "# 安装" #: src/ch01-01-installation.md:3 -msgid "The first step is to install Cairo. We will download Cairo manually, using cairo repository or with an installation script. You’ll need an internet connection for the download." +msgid "" +"Cairo can be installed by simply downloading [Scarb](https://docs.swmansion.com/scarb/docs). Scarb bundles the Cairo compiler and the Cairo language server together in an easy-to-" +"install package so that you can start writing Cairo code right away." msgstr "" -"第一步是安装Cairo。我们可以手动下载Cairo(使用Cairo仓库)或使用安装脚本。下载过程需要连接互联网。\n" -"译注:如果你生活在中国大陆,你可能需要一些特殊方法来保证能够顺利安装所有的依赖包。" +"只需下载 [Scarb](https://docs.swmansion.com/scarb/docs),即可安装 Cairo。Scarb 将 Cairo 编译器和 Cairo 语言服务器捆绑在一个易于安装的软件包中,这样你就可以立即开始编写 Cairo 代码了。" #: src/ch01-01-installation.md:5 -msgid "### Prerequisites" -msgstr "### 先决条件" +msgid "Scarb is also Cairo's package manager and is heavily inspired by [Cargo](https://doc.rust-lang.org/cargo/), Rust’s build system and package manager." +msgstr "Scarb同样是Cairo的软件包管理器,在很大程度上受到[Cargo](https://doc.rust-lang.org/cargo/)的启发,Rust的构建系统和软件包管理器。" #: src/ch01-01-installation.md:7 -msgid "First you will need to have Rust and Git installed." -msgstr "首先,你需要安装Rust和Git。" +msgid "" +"Scarb handles a lot of tasks for you, such as building your code (either pure Cairo or Starknet contracts), downloading the libraries your code depends on, building those libraries, " +"and provides LSP support for the VSCode Cairo 1 extension." +msgstr "Scarb会为你处理很多任务,比如构建你的代码(纯Cairo或Starknet合约),为你下载你的代码所依赖的库并构建他们,以及为VSCode Cairo 1扩展提供LSP支持。" #: src/ch01-01-installation.md:9 -msgid "" -"```bash\n" -"# Install stable Rust\n" -"rustup override set stable && rustup update\n" -"```" -msgstr "" -"```bash\n" -"# Install stable Rust\n" -"rustup override set stable && rustup update\n" -"```" +msgid "As you write more complex Cairo programs, you might add dependencies, and if you start a project using Scarb, managing external code and dependencies will be a lot easier to do." +msgstr "如果你使用 Scarb 启动项目,管理外部代码和依赖关系就会容易得多。" -#: src/ch01-01-installation.md:14 -msgid "Install [Git](https://git-scm.com/)." -msgstr "安装[Git](https://git-scm.com/)。" +#: src/ch01-01-installation.md:11 +msgid "Let's start by installing Scarb." +msgstr "让我们从安装Scarb开始。" -#: src/ch01-01-installation.md:16 -msgid "## Installing Cairo with a Script ([Installer](https://github.com/franalgaba/cairo-installer) by [Fran](https://github.com/franalgaba))" -msgstr "## 用脚本安装Cairo([Installer](https://github.com/franalgaba/cairo-installer) by [Fran](https://github.com/franalgaba))" +#: src/ch01-01-installation.md:13 +msgid "## Installing Scarb" +msgstr "## 安装Scarb" -#: src/ch01-01-installation.md:18 -msgid "### Install" +#: src/ch01-01-installation.md:15 +msgid "### Requirements" +msgstr "### 要求" + +#: src/ch01-01-installation.md:17 +msgid "Scarb requires a Git executable to be available in the `PATH` environment variable." +msgstr "Scarb需要`PATH`环境变量里有一个Git可执行文件。" + +#: src/ch01-01-installation.md:19 +msgid "### Installation" msgstr "### 安装" -#: src/ch01-01-installation.md:20 -msgid "If you wish to install a specific release of Cairo rather than the latest head, set the `CAIRO_GIT_TAG` environment variable (e.g. `export CAIRO_GIT_TAG=v1.1.0`)." -msgstr "如果你想安装一个特定的Cairo版本,而不是最新版本,可以设置`CAIRO_GIT_TAG`环境变量(比如执行 `export CAIRO_GIT_TAG=v1.1.0` 来设置)。" +#: src/ch01-01-installation.md:21 +msgid "" +"To install Scarb, please refer to the [installation instructions](https://docs.swmansion.com/scarb/download).\n" +"You can simply run the following command in your terminal, then follow the onscreen instructions. This will install the latest stable release." +msgstr "" +"要安装Scarb,请参考[安装说明](https://docs.swmansion.com/scarb/download)。\n" +"你可以简单地在终端运行以下命令,然后按照屏幕上的指示操作。这将安装最新的稳定版本。" -#: src/ch01-01-installation.md:22 +#: src/ch01-01-installation.md:24 msgid "" "```bash\n" -"curl -L https://github.com/franalgaba/cairo-installer/raw/main/bin/cairo-installer | bash\n" +"curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | sh\n" "```" msgstr "" "```bash\n" -"curl -L https://github.com/franalgaba/cairo-installer/raw/main/bin/cairo-installer | bash\n" +"curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | sh\n" "```" -#: src/ch01-01-installation.md:26 -msgid "After installing, follow [these instructions](#set-up-your-shell-environment-for-cairo) to set up your shell environment." -msgstr "安装完毕后,按照[说明](#set-up-your-shell-environment-for-cairo)来设置你的shell环境。" - #: src/ch01-01-installation.md:28 -msgid "### Update" -msgstr "### 更新" +msgid "" +"- Verify installation by running the following command in new terminal session, it should print both Scarb and Cairo language versions, e.g:\n" +"\n" +" ```bash\n" +" $ scarb --version\n" +" scarb 0.7.0 (58cc88efb 2023-08-23)\n" +" cairo: 2.2.0 (https://crates.io/crates/cairo-lang-compiler/2.2.0)\n" +" sierra: 1.3.0\n" +" ```" +msgstr "" +"- 在新的终端Session里输入以下命令来验证是否安装成功, 终端应该同时打印出Scarb 和 Cairo 的版本号, 比如:\n" +"\n" +" ```bash\n" +" $ scarb --version\n" +" scarb 0.7.0 (58cc88efb 2023-08-23)\n" +" cairo: 2.2.0 (https://crates.io/crates/cairo-lang-compiler/2.2.0)\n" +" sierra: 1.3.0\n" +" ```" + +#: src/ch01-02-hello-world.md:1 +msgid "## Hello, World" +msgstr "## Hello, World" -#: src/ch01-01-installation.md:30 +#: src/ch01-02-hello-world.md:3 msgid "" -"```\n" -"rm -fr ~/.cairo\n" -"curl -L https://github.com/franalgaba/cairo-installer/raw/main/bin/cairo-installer | bash\n" -"```" +"Now that you’ve installed Cairo through Scarb, it’s time to write your first Cairo program.\n" +"It’s traditional when learning a new language to write a little program that\n" +"prints the text `Hello, world!` to the screen, so we’ll do the same here!" msgstr "" -"```\n" -"rm -fr ~/.cairo\n" -"curl -L https://github.com/franalgaba/cairo-installer/raw/main/bin/cairo-installer | bash\n" -"```" +"现在你已经通过Scarb安装了Cairo,是时候编写你的第一个Cairo程序了。\n" +"在学习一门新语言时,传统的做法是写一个小程序\n" +"将文字`Hello, world!`打印到屏幕上,所以我们在这里也要这样做!" -#: src/ch01-01-installation.md:35 -msgid "### Uninstall" -msgstr "### 卸载" +#: src/ch01-02-hello-world.md:7 +msgid "" +"> Note: This book assumes basic familiarity with the command line. Cairo makes\n" +"> no specific demands about your editing or tooling or where your code lives, so\n" +"> if you prefer to use an integrated development environment (IDE) instead of\n" +"> the command line, feel free to use your favorite IDE. The Cairo team has developed\n" +"> a VSCode extension for the Cairo language that you can use to get the features from\n" +"> the language server and code highlighting. See [Appendix D][devtools]\n" +"> for more details." +msgstr "" +"> 注意:本书假定对你命令行有基本的了解。Cairo对\n" +"> 对你用什么编辑代码或使用什么开发工具或把你的代码放在哪没有特殊要求,所以\n" +"> 如果你喜欢使用集成开发环境(IDE)而不是\n" +"> 命令行,你完全可以使用你喜欢的IDE。Cairo团队已经开发了\n" +"> Cairo语言的VSCode扩展,你可以用它来获得来自\n" +"> 语言服务器和代码高亮。参见[附录D][devtools]来获取更多细节。" -#: src/ch01-01-installation.md:37 -msgid "Cairo is installed within `$CAIRO_ROOT` (default: ~/.cairo). To uninstall, just remove it:" -msgstr "Cairo被安装在`$CAIRO_ROOT`(默认:~/.cairo)。要卸载它,只需删除它:" +#: src/ch01-02-hello-world.md:15 +msgid "### Creating a Project Directory" +msgstr "### 创建一个项目目录" -#: src/ch01-01-installation.md:39 +#: src/ch01-02-hello-world.md:17 msgid "" -"```bash\n" -"rm -fr ~/.cairo\n" +"You’ll start by making a directory to store your Cairo code. It doesn’t matter\n" +"to Cairo where your code lives, but for the exercises and projects in this book,\n" +"we suggest making a _cairo_projects_ directory in your home directory and keeping all\n" +"your projects there." +msgstr "" +"你首先要做一个目录来存储你的Cairo代码。对于Cairo来说,你的代码放在哪里并不重要。\n" +"但对于本书中的练习和项目来说,我们建议在你的主目录下建立一个 _cairo_projects_ 目录,并将你的所有项目存放在这里。" + +#: src/ch01-02-hello-world.md:22 +msgid "" +"Open a terminal and enter the following commands to make a _cairo_projects_ directory\n" +"and a directory for the “Hello, world!” project within the _cairo_projects_ directory." +msgstr "" +"打开一个终端,输入以下命令,建立一个 _cairo_projects_ 目录\n" +"并在 _cairo_projects_ 目录下为 \"Hello, world!\"项目建立一个目录。" + +#: src/ch01-02-hello-world.md:25 +msgid "" +"> Note: From now on, for each example shown in the book, we assume that\n" +"> you will be working from a Scarb project directory. If you are not using Scarb, and try to run the examples from a different directory, you might need to adjust the commands " +"accordingly or create a Scarb project." +msgstr "" +"> 注意:从现在起,对于书中显示的每个示例,我们都假定\n" +"> 你都是在 Scarb 项目目录中进行编码。如果您没有使用 Scarb,并试图从其他目录运行示例,可能需要相应调整命令或创建一个 Scarb 项目。" + +#: src/ch01-02-hello-world.md:28 +msgid "For Linux, macOS, and PowerShell on Windows, enter this:" +msgstr "对于Linux、macOS和Windows上的PowerShell,输入:" + +#: src/ch01-02-hello-world.md:30 +msgid "" +"```shell\n" +"mkdir ~/cairo_projects\n" +"cd ~/cairo_projects\n" "```" msgstr "" -"```bash\n" -"rm -fr ~/.cairo\n" +"```shell\n" +"mkdir ~/cairo_projects\n" +"cd ~/cairo_projects\n" "```" -#: src/ch01-01-installation.md:43 -msgid "then remove these three lines from .bashrc:" -msgstr "然后从.bashrc中删除这三行:" +#: src/ch01-02-hello-world.md:35 +msgid "For Windows CMD, enter this:" +msgstr "对于Windows CMD,请输入以下内容:" -#: src/ch01-01-installation.md:45 +#: src/ch01-02-hello-world.md:37 msgid "" -"```bash\n" -"export PATH=\"$HOME/.cairo/target/release:$PATH\"\n" +"```cmd\n" +"> mkdir \"%USERPROFILE%\\cairo_projects\"\n" +"> cd /d \"%USERPROFILE%\\cairo_projects\"\n" "```" msgstr "" -"```bash\n" -"export PATH=“$HOME/.cairo/target/release:$PATH”\n" +"```cmd\n" +"> mkdir \"%USERPROFILE%\\cairo_projects\"\n" +"> cd /d \"%USERPROFILE%\\cairo_projects\"\n" "```" -#: src/ch01-01-installation.md:49 -msgid "and finally, restart your shell:" -msgstr "最后,重新启动你的shell:" +#: src/ch01-02-hello-world.md:42 +msgid "### Creating a Project with Scarb" +msgstr "### 用Scarb创建一个项目" + +#: src/ch01-02-hello-world.md:44 +msgid "Let’s create a new project using Scarb." +msgstr "让我们使用 Scarb 创建一个新项目。" -#: src/ch01-01-installation.md:51 +#: src/ch01-02-hello-world.md:46 +msgid "Navigate to your projects directory (or wherever you decided to store your code). Then run the following:" +msgstr "导航到你的项目目录(或你决定放代码的地方)。然后运行以下命令:" + +#: src/ch01-02-hello-world.md:48 msgid "" "```bash\n" -"exec $SHELL\n" +"scarb new hello_world\n" "```" msgstr "" "```bash\n" -"exec $SHELL\n" +"scarb new hello_world\n" "```" -#: src/ch01-01-installation.md:55 -msgid "### Set up your shell environment for Cairo" -msgstr "### 为Cairo设置你的shell环境" +#: src/ch01-02-hello-world.md:52 +msgid "It creates a new directory and project called `hello_world`. We’ve named our project `hello_world`, and Scarb creates its files in a directory of the same name." +msgstr "它创建了一个新的目录和项目,名为`hello_world`。我们把我们的项目命名为`hello_world`,因此Scarb会在同名的目录下创建它的文件。" -#: src/ch01-01-installation.md:57 +#: src/ch01-02-hello-world.md:54 msgid "" -"- Define environment variable `CAIRO_ROOT` to point to the path where\n" -" Cairo will store its data. `$HOME/.cairo` is the default.\n" -" If you installed Cairo via Git checkout, we recommend\n" -" to set it to the same location as where you cloned it.\n" -"- Add the `cairo-*` executables to your `PATH` if it's not already there" +"Go into the `hello_world` directory with the command `cd hello_world`. You’ll see that Scarb has generated two files and one directory for us: a `Scarb.toml` file and a src directory " +"with a `lib.cairo` file inside." +msgstr "用`cd hello_world`命令进入`hello_world`目录。你会看到Scarb已经为我们生成了两个文件和一个目录:一个`Scarb.toml`文件和一个src目录,里面有一个`lib.cairo`文件。" + +#: src/ch01-02-hello-world.md:56 +msgid "It has also initialized a new Git repository along with a `.gitignore` file" +msgstr "它还初始化了一个新的Git仓库和一个`.gitignore`文件" + +#: src/ch01-02-hello-world.md:58 +msgid "" +"> Note: Git is a common version control system. You can stop using version control system by using the `--vcs` flag.\n" +"> Run `scarb new -help` to see the available options." msgstr "" -"- 定义环境变量`CAIRO_ROOT`,以指向Cairo存储自身数据的路径。默认为`$HOME/.cairo`。\n" -" 如果你通过Git checkout安装Cairo,我们建议把它设置到与你Git clone它相同的位置。\n" -"- 将`cairo-*`可执行文件添加到你的`PATH`中,如果还没被自动添加的话" +"> 注意:Git是一个常见的版本控制系统。你可以通过使用`--vcs`标志停止使用版本控制系统。\n" +"> 运行`scarb new -help`以查看可用选项。" -#: src/ch01-01-installation.md:63 -msgid "The below setup should work for the vast majority of users for common use cases." -msgstr "下面的设置应该适用于绝大多数用户的一般使用情况。" +#: src/ch01-02-hello-world.md:61 +msgid "Open _Scarb.toml_ in your text editor of choice. It should look similar to the code in Listing 1-2." +msgstr "在你选择的文本编辑器中打开 _Scarb.toml_ 。它看起来应该与示例1-2中的代码相似。" + +#: src/ch01-02-hello-world.md:63 +msgid "Filename: Scarb.toml" +msgstr "文件名:Scarb.toml" -#: src/ch01-01-installation.md:65 +#: src/ch01-02-hello-world.md:65 msgid "" -"- For **bash**:\n" +"```toml\n" +"[package]\n" +"name = \"hello_world\"\n" +"version = \"0.1.0\"\n" "\n" -" Stock Bash startup files vary widely between distributions in which of them source\n" -" which, under what circumstances, in what order and what additional configuration they perform.\n" -" As such, the most reliable way to get Cairo in all environments is to append Cairo\n" -" configuration commands to both `.bashrc` (for interactive shells)\n" -" and the profile file that Bash would use (for login shells).\n" +"# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest\n" "\n" -" First, add the commands to `~/.bashrc` by running the following in your terminal:\n" +"[dependencies]\n" +"# foo = { path = \"vendor/foo\" }\n" +"```" +msgstr "" +"```toml\n" +"[package]\n" +"name = \"hello_world\"\n" +"version = \"0.1.0\"\n" "\n" -" ```bash\n" -" echo 'export CAIRO_ROOT=\"$HOME/.cairo\"' >> ~/.bashrc\n" -" echo 'command -v cairo-compile >/dev/null || export PATH=\"$CAIRO_ROOT/target/release:$PATH\"' >> ~/.bashrc\n" -" ```\n" -"\n" -" Then, if you have `~/.profile`, `~/.bash_profile` or `~/.bash_login`, add the commands there as well.\n" -" If you have none of these, add them to `~/.profile`.\n" -"\n" -" - to add to `~/.profile`:\n" -"\n" -" ```bash\n" -" echo 'export CAIRO_ROOT=\"$HOME/.cairo\"' >> ~/.profile\n" -" echo 'command -v cairo-compile >/dev/null || export PATH=\"$CAIRO_ROOT/target/release:$PATH\"' >> ~/.profile\n" -" ```\n" -"\n" -" - to add to `~/.bash_profile`:\n" -" ```bash\n" -" echo 'export CAIRO_ROOT=\"$HOME/.cairo\"' >> ~/.bash_profile\n" -" echo 'command -v cairo-compile >/dev/null || export PATH=\"$CAIRO_ROOT/target/release:$PATH\"' >> ~/.bash_profile\n" -" ```\n" -"\n" -"- For **Zsh**:\n" -"\n" -" ```zsh\n" -" echo 'export CAIRO_ROOT=\"$HOME/.cairo\"' >> ~/.zshrc\n" -" echo 'command -v cairo-compile >/dev/null || export PATH=\"$CAIRO_ROOT/target/release:$PATH\"' >> ~/.zshrc\n" -" ```\n" -"\n" -" If you wish to get Cairo in non-interactive login shells as well, also add the commands to `~/.zprofile` or `~/.zlogin`.\n" -"\n" -"- For **Fish shell**:\n" -"\n" -" If you have Fish 3.2.0 or newer, execute this interactively:\n" -"\n" -" ```fish\n" -" set -Ux CAIRO_ROOT $HOME/.cairo\n" -" fish_add_path $CAIRO_ROOT/target/release\n" -" ```\n" -"\n" -" Otherwise, execute the snippet below:\n" -"\n" -" ```fish\n" -" set -Ux CAIRO_ROOT $HOME/.cairo\n" -" set -U fish_user_paths $CAIRO_ROOT/target/release $fish_user_paths\n" -" ```" -msgstr "" -"- 对于**bash** :\n" -"\n" -" 各个发行版间的 Stock Bash 的启动文件在什么情况下调用什么样的文件,以什么顺序执行,并进行哪些额外的配置都存在很大的差异\n" -" 因此,在所有环境中获得 Cairo 的最可靠方法是将 Cairo 配置命令附加到`.bashrc`(用于交互式shell)和Bash将使用的配置文件中。(用于登录shell)。\n" -"\n" -" 首先,通过在终端运行以下命令,将这些命令添加到`~/.bashrc`中:\n" -"\n" -" ```bash\n" -" echo ‘export CAIRO_ROOT=“$HOME/.cairo”’ >> ~/.bashrc\n" -" echo ‘command -v cairo-compile >/dev/null || export PATH=“$CAIRO_ROOT/target/release:$PATH”’ >> ~/.bashrc\n" -" ```\n" -"\n" -" 然后,如果你有 `~/.profile`、`~/.bash_profile`或`~/.bash_login`,也将这些命令添加到它们所对应的文件中。如果没有这些文件,则添加到 `~/.profile`中。\n" -"\n" -" - 添加到 `~/.profile` 中:\n" -"\n" -" ```bash\n" -" echo ‘export CAIRO_ROOT=“$HOME/.cairo”’ >> ~/.profile\n" -" echo ‘command -v cairo-compile >/dev/null || export PATH=“$CAIRO_ROOT/target/release:$PATH”’ >> ~/.profile\n" -" ```\n" -"\n" -" - 添加到`~/.bash_profile`:\n" -" ```bash\n" -" echo ‘export CAIRO_ROOT=“$HOME/.cairo”’ >> ~/.bash_profile\n" -" echo ‘command -v cairo-compile >/dev/null || export PATH=“$CAIRO_ROOT/target/release:$PATH”’ >> ~/.bash_profile\n" -" ```\n" -"\n" -"- 对于**Zsh**:\n" -"\n" -" ```zsh\n" -" echo 'export CAIRO_ROOT=\"$HOME/.cairo\"' >> ~/.zshrc\n" -" echo 'command -v cairo-compile >/dev/null || export PATH=\"$CAIRO_ROOT/target/release:$PATH\"' >> ~/.zshrc\n" -" ```\n" -"\n" -" 如果你希望在非交互式登录shell中也能得到Cairo,也可以将这些命令添加到`~/.zprofile`或`~/.zlogin`。\n" -"\n" -"- 对于**Fish shell**:\n" -"\n" -" 如果你有Fish 3.2.0或更新版本,请以交互方式执行:\n" -"\n" -" ```fish\n" -" set -Ux CAIRO_ROOT $HOME/.cairo\n" -" fish_add_path $CAIRO_ROOT/target/release\n" -" ```\n" -"\n" -" 否则,执行下面的片段:\n" +"# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest\n" "\n" -" ```fish\n" -" set -Ux CAIRO_ROOT $HOME/.cairo\n" -" set -U fish_user_paths $CAIRO_ROOT/target/release $fish_user_paths\n" -" ```" +"[dependencies]\n" +"# foo = { path = \"vendor/foo\" }\n" +"```" -#: src/ch01-01-installation.md:121 +#: src/ch01-02-hello-world.md:76 +msgid "Listing 1-2: Contents of Scarb.toml generated by `scarb new`" +msgstr "示例1-2:由`scarb new`生成的Scarb.toml的内容" + +#: src/ch01-02-hello-world.md:78 +msgid "This file is in the [TOML](https://toml.io/) (Tom’s Obvious, Minimal Language) format, which is Scarb’s configuration format." +msgstr "这个文件是[TOML](https://toml.io/)(Tom's Obvious, Minimal Language)的格式,是Scarb的配置文件格式。" + +#: src/ch01-02-hello-world.md:80 msgid "" -"In MacOS, you might also want to install [Fig](https://fig.io/) which\n" -"provides alternative shell completions for many command line tools with an\n" -"IDE-like popup interface in the terminal window.\n" -"(Note that their completions are independent from Cairo's codebase\n" -"so they might be slightly out of sync for bleeding-edge interface changes.)" -msgstr "" -"在 MacOS 中,你可能还想安装[Fig](https://fig.io/)。它为许多命令行工具提供了替\n" -"代性的 shell 补全功能,并在终端窗口有一个类似于 IDE 的弹出式界面。(注意,他们\n" -"的命令补全功能与Cairo的代码库无关,所以他们有可能有点跟不上Cairo命令行界面的更新)。" +"The first line, `[package]`, is a section heading that indicates that the following statements are configuring a package. As we add more information to this file, we’ll add other " +"sections." +msgstr "第一行,`[package]`,是一个章节标题,表示下面的语句是在配置一个包。随着我们向这个文件添加更多的信息,我们将添加其他章节。" -#: src/ch01-01-installation.md:127 -msgid "### Restart your shell" -msgstr "### 重新启动你的shell" +#: src/ch01-02-hello-world.md:82 +msgid "The next two lines set the configuration information Scarb needs to compile your program: the name and the version of Scarb to use." +msgstr "接下来的两行设置了Scarb在编译你的程序时需要的配置信息:名称和要使用的Scarb版本。" -#: src/ch01-01-installation.md:129 -msgid "for the `PATH` changes to take effect." -msgstr "以使 `PATH`的改变生效。" +#: src/ch01-02-hello-world.md:84 +msgid "" +"The last line, `[dependencies]`, is the start of a section for you to list any of your project’s dependencies. In Cairo, packages of code are referred to as crates. We won’t need any " +"other crates for this project." +msgstr "最后一行,`[dependencies]`,是一个章节的开始,该章节供你列出你的项目的所有依赖。在Cairo中,代码包被称为crate。在这个项目中,我们不需要任何其他的crate。" -#: src/ch01-01-installation.md:131 +#: src/ch01-02-hello-world.md:86 msgid "" -"```sh\n" -"exec \"$SHELL\"\n" +"> Note: If you're building contracts for Starknet, you will need to add the `starknet` dependency as mentioned in the [Scarb documentation](https://docs.swmansion.com/scarb/docs/" +"extensions/starknet/starknet-package.html)." +msgstr "> 注意:如果你要为Starknet构建合约,你需要添加[Scarb文档](https://docs.swmansion.com/scarb/docs/extensions/starknet/starknet-package.html)中提到的`starknet`依赖关系。" + +#: src/ch01-02-hello-world.md:88 +msgid "The other file created by Scarb is `src/lib.cairo`, let's delete all the content and put in the following content, we will explain the reason later." +msgstr "Scarb创建的另一个文件是`src/lib.cairo`,让我们删除其中所有的内容,放入以下内容,我们将在后面解释原因。" + +#: src/ch01-02-hello-world.md:90 +msgid "" +"```rust,noplayground\n" +"mod hello_world;\n" "```" msgstr "" -"```sh\n" -"exec “$SHELL”\n" +"```rust,noplayground\n" +"mod hello_world;\n" "```" -#: src/ch01-01-installation.md:135 -msgid "## Installing Cairo Manually ([Guide](https://github.com/auditless/cairo-template) by [Abdel](https://github.com/abdelhamidbakhta))" -msgstr "## 手动安装Cairo([指南](https://github.com/auditless/cairo-template)由[Abdel](https://github.com/abdelhamidbakhta)提供)" - -#: src/ch01-01-installation.md:137 -msgid "### Step 1: Install Cairo 1.0" -msgstr "### 第1步:安装Cairo 1.0" - -#: src/ch01-01-installation.md:139 -msgid "If you are using an x86 Linux system and can use the release binary, download Cairo here: ." -msgstr "如果你使用的是 x86 Linux 系统,并且可以使用发布的二进制文件,请在这里下载Cairo:。" +#: src/ch01-02-hello-world.md:94 +msgid "Then create a new file called `src/hello_world.cairo` and put the following code in it:" +msgstr "然后创建一个名为`src/hello_world.cairo`的新文件,并将以下代码放入其中:" -#: src/ch01-01-installation.md:141 -msgid "For everyone else, we recommend compiling Cairo from source as follows:" -msgstr "对于其他用户,我们建议从源码编译 Cairo,如下所示:" +#: src/ch01-02-hello-world.md:96 +msgid "Filename: src/hello_world.cairo" +msgstr "文件名: src/hello_world.cairo" -#: src/ch01-01-installation.md:143 +#: src/ch01-02-hello-world.md:98 msgid "" -"```bash\n" -"# Start by defining environment variable CAIRO_ROOT\n" -"export CAIRO_ROOT=\"${HOME}/.cairo\"\n" -"\n" -"# Create .cairo folder if it doesn't exist yet\n" -"mkdir $CAIRO_ROOT\n" -"\n" -"# Clone the Cairo compiler in $CAIRO_ROOT (default root)\n" -"cd $CAIRO_ROOT && git clone git@github.com:starkware-libs/cairo.git .\n" -"\n" -"# OPTIONAL/RECOMMENDED: If you want to install a specific version of the compiler\n" -"# Fetch all tags (versions)\n" -"git fetch --all --tags\n" -"# View tags (you can also do this in the cairo compiler repository)\n" -"git describe --tags `git rev-list --tags`\n" -"# Checkout the version you want\n" -"git checkout tags/v1.1.0\n" -"\n" -"# Generate release binaries\n" -"cargo build --all --release\n" +"```rust,file=hello_world.cairo\n" +"use debug::PrintTrait;\n" +"fn main() {\n" +" 'Hello, World!'.print();\n" +"}\n" "```" msgstr "" -"```bash\n" -"# Start by defining environment variable CAIRO_ROOT\n" -"export CAIRO_ROOT=\"${HOME}/.cairo\"\n" -"\n" -"# Create .cairo folder if it doesn't exist yet\n" -"mkdir $CAIRO_ROOT\n" -"\n" -"# Clone the Cairo compiler in $CAIRO_ROOT (default root)\n" -"cd $CAIRO_ROOT && git clone git@github.com:starkware-libs/cairo.git .\n" -"\n" -"# OPTIONAL/RECOMMENDED: If you want to install a specific version of the compiler\n" -"# Fetch all tags (versions)\n" -"git fetch --all --tags\n" -"# View tags (you can also do this in the cairo compiler repository)\n" -"git describe --tags `git rev-list --tags`\n" -"# Checkout the version you want\n" -"git checkout tags/v1.1.0\n" -"\n" -"# Generate release binaries\n" -"cargo build --all --release\n" +"```rust,file=hello_world.cairo\n" +"use debug::PrintTrait;\n" +"fn main() {\n" +" 'Hello, World!'.print();\n" +"}\n" "```" -#: src/ch01-01-installation.md:165 -msgid "." -msgstr "." +#: src/ch01-02-hello-world.md:105 +msgid "" +"We have just created a file called `lib.cairo`, which contains a module declaration referencing another module named `hello_world`, as well as the file `hello_world.cairo`, " +"containing the implementation details of the `hello_world` module." +msgstr "我们刚刚创建了一个名为`lib.cairo`的文件,其中包含一个模块声明,引用了另一个名为 `hello_world`的模块,以及包含 `hello_world`模块的实现细节的文件`hello_world.cairo`。" -#: src/ch01-01-installation.md:167 -msgid "**NOTE: Keeping Cairo up to date**" -msgstr "**注意:保持Cairo已更新到最新版本**" +#: src/ch01-02-hello-world.md:107 +msgid "Scarb requires your source files to be located within the `src` directory." +msgstr "Scarb要求你的源文件位于src目录中。" -#: src/ch01-01-installation.md:169 +#: src/ch01-02-hello-world.md:109 msgid "" -"Now that your Cairo compiler is in a cloned repository, all you will need to do\n" -"is pull the latest changes and rebuild as follows:" +"The top-level project directory is reserved for README files, license information, configuration files, and any other non-code-related content.\n" +"Scarb ensures a designated location for all project components, maintaining a structured organization." msgstr "" -"现在你的Cairo编译器已经在一个克隆的仓库里了,你所需要做的是拉取最新的修改,\n" -"并按如下方式重新编译:" +"顶层项目目录是为README文件、许可证信息、配置文件和任何其他与代码无关的内容保留的。\n" +"Scarb确保所有项目组件都有一个指定的位置,维持一个结构化的组织架构。" + +#: src/ch01-02-hello-world.md:112 +msgid "" +"If you started a project that doesn’t use Scarb, you can convert it to a project that does use Scarb. Move the project code into the src directory and create an appropriate `Scarb." +"toml` file." +msgstr "如果你启动了一个不使用Scarb的项目,你可以把它转换成一个使用Scarb的项目。将项目代码移到src目录下,并创建一个适当的`Scarb.toml`文件。" + +#: src/ch01-02-hello-world.md:114 +msgid "### Building a Scarb Project" +msgstr "### 编译Scarb项目" + +#: src/ch01-02-hello-world.md:116 +msgid "From your `hello_world` directory, build your project by entering the following command:" +msgstr "在你的`hello_world`目录中,通过输入以下命令来编译你的项目:" -#: src/ch01-01-installation.md:172 +#: src/ch01-02-hello-world.md:118 msgid "" "```bash\n" -"cd $CAIRO_ROOT && git fetch && git pull && cargo build --all --release\n" +"$ scarb build\n" +" Compiling hello_world v0.1.0 (file:///projects/Scarb.toml)\n" +" Finished release target(s) in 0 seconds\n" "```" msgstr "" "```bash\n" -"cd $CAIRO_ROOT && git fetch && git pull && cargo build —all —release\n" +"$ scarb build\n" +" Compiling hello_world v0.1.0 (file:///projects/Scarb.toml)\n" +" Finished release target(s) in 0 seconds\n" "```" -#: src/ch01-01-installation.md:176 -msgid "### Step 2: Add Cairo 1.0 executables to your path" -msgstr "### 第二步:将Cairo 1.0的可执行文件添加到你的路径中" +#: src/ch01-02-hello-world.md:124 +msgid "This command creates a `sierra` file in `target/dev`, let's ignore the `sierra` file for now." +msgstr "这个命令在`target/dev`中创建了一个`sierra`文件,现在我们先忽略`sierra`文件。" + +#: src/ch01-02-hello-world.md:126 +msgid "If you have installed Cairo correctly, you should be able to run and see the following output:" +msgstr "如果你正确安装了Cairo,你应该能够运行并看到以下输出:" -#: src/ch01-01-installation.md:178 +#: src/ch01-02-hello-world.md:128 msgid "" -"```bash\n" -"export PATH=\"$CAIRO_ROOT/target/release:$PATH\"\n" +"```shell\n" +"$ scarb cairo-run\n" +"running hello_world ...\n" +"[DEBUG] Hello, World! (raw: 0x48656c6c6f2c20776f726c6421\n" +"\n" +"Run completed successfully, returning []\n" "```" msgstr "" -"```bash\n" -"export PATH=“$CAIRO_ROOT/target/release:$PATH”\n" +"```shell\n" +"$ scarb cairo-run\n" +"running hello_world ...\n" +"[DEBUG] Hello, World! (raw: 0x48656c6c6f2c20776f726c6421\n" +"\n" +"Run completed successfully, returning []\n" "```" -#: src/ch01-01-installation.md:182 -msgid "**NOTE: If installing from a Linux binary, adapt the destination path accordingly.**" -msgstr "**注意:如果你是在Linux编译的二进制文件,请相应调整目标路径**" - -#: src/ch01-01-installation.md:184 -msgid "### Step 3: Setup Language Server" -msgstr "### 第三步:设置语言服务器" - -#: src/ch01-01-installation.md:186 -msgid "#### VS Code Extension" -msgstr "#### VS代码扩展" +#: src/ch01-02-hello-world.md:136 +msgid "" +"Regardless of your operating system, the string `Hello, world!` should print to\n" +"the terminal." +msgstr "无论你的操作系统如何,终端里都应该打印出字符串`Hello, world!`。" -#: src/ch01-01-installation.md:188 +#: src/ch01-02-hello-world.md:139 msgid "" -"- Disable previous Cairo 0.x extension\n" -"- Install the Cairo 1 extension for proper syntax highlighting and code navigation.\n" -" Just follow the steps indicated [here](https://github.com/starkware-libs/cairo/blob/main/vscode-cairo/README.md)." +"If `Hello, world!` did print, congratulations! You’ve officially written a Cairo\n" +"program. That makes you a Cairo programmer—welcome!" msgstr "" -"- 禁用以前的 Cairo 0.x 扩展\n" -"- 安装Cairo 1扩展以获得正确的语法高亮和代码导航。\n" -"只要按照[这里](https://github.com/starkware-libs/cairo/blob/main/vscode-cairo/README.md)所示的步骤就可以了。" - -#: src/ch01-01-installation.md:192 -msgid "#### Cairo Language Server" -msgstr "#### Cairo语言服务器" +"如果 \"Hello,world!\"打印出来了,那么恭喜你!你已经正式写了一个Cairo程序!\n" +"你已经成为了一名Cairo程序员--欢迎!" -#: src/ch01-01-installation.md:194 -msgid "From [Step 1](#step-1-install-cairo-10-guide-by-abdel), the `cairo-language-server` binary should be built and executing this command will copy its path into your clipboard." -msgstr "在[Step 1](#step-1-install-cairo-10-guide-by-abdel) 中,`cairo-language-server`二进制文件应该已经编译完成,执行这个命令将复制其路径到你的剪贴板。" +#: src/ch01-02-hello-world.md:142 +msgid "### Anatomy of a Cairo Program" +msgstr "### 解析Cairo程序" -#: src/ch01-01-installation.md:196 -msgid "" -"```bash\n" -"which cairo-language-server | pbcopy\n" -"```" -msgstr "" -"```bash\n" -"which cairo-language-server | pbcopy\n" -"```" - -#: src/ch01-01-installation.md:200 -msgid "Update the `languageServerPath` of the Cairo 1.0 extension by pasting the path." -msgstr "将上面复制的路径更新到Cairo 1.0扩展的`languageServerPath`中。" - -#: src/ch01-02-hello-world.md:1 -msgid "## Hello, World" -msgstr "## Hello, World" - -#: src/ch01-02-hello-world.md:3 -msgid "" -"Now that you’ve installed Cairo, it’s time to write your first Cairo program.\n" -"It’s traditional when learning a new language to write a little program that\n" -"prints the text `Hello, world!` to the screen, so we’ll do the same here!" -msgstr "" -"现在你已经安装了Cairo,是时候编写你的第一个Cairo程序了。\n" -"在学习一门新语言时,传统的做法是写一个小程序\n" -"将文字`Hello, world!`打印到屏幕上,所以我们在这里也要这样做!" - -#: src/ch01-02-hello-world.md:7 -msgid "" -"> Note: This book assumes basic familiarity with the command line. Cairo makes\n" -"> no specific demands about your editing or tooling or where your code lives, so\n" -"> if you prefer to use an integrated development environment (IDE) instead of\n" -"> the command line, feel free to use your favorite IDE. The Cairo team has developed\n" -"> a VSCode extension for the Cairo language that you can use to get the features from\n" -"> the language server and code highlighting. See [Appendix B][devtools]\n" -"> for more details." -msgstr "" -"> 注意:本书假定对你命令行有基本的了解。Cairo对\n" -"> 对你用什么编辑代码或使用什么开发工具或把你的代码放在哪没有特殊要求,所以\n" -"> 如果你喜欢使用集成开发环境(IDE)而不是\n" -"> 命令行,你完全可以使用你喜欢的IDE。Cairo团队已经开发了\n" -"> Cairo语言的VSCode扩展,你可以用它来获得来自\n" -"> 语言服务器和代码高亮。参见[附录D][devtools]来了解更多细节。" - -#: src/ch01-02-hello-world.md:15 -msgid "### Creating a Project Directory" -msgstr "### 创建一个项目目录" - -#: src/ch01-02-hello-world.md:17 -msgid "" -"You’ll start by making a directory to store your Cairo code. It doesn’t matter\n" -"to Cairo where your code lives, but for the exercises and projects in this book,\n" -"we suggest making a _cairo_projects_ directory in your home directory and keeping all\n" -"your projects there." -msgstr "" -"你首先要做一个目录来存储你的Cairo代码。对于Cairo来说,你的代码放在哪里并不重要。\n" -"但对于本书中的练习和项目来说,我们建议在你的主目录下建立一个 _cairo_projects_ 目录,并将你的所有项目存放在这里。" - -#: src/ch01-02-hello-world.md:22 -msgid "" -"Open a terminal and enter the following commands to make a _cairo_projects_ directory\n" -"and a directory for the “Hello, world!” project within the _cairo_projects_ directory." -msgstr "" -"打开一个终端,输入以下命令,建立一个 _cairo_projects_ 目录\n" -"并在 _cairo_projects_ 目录下为 \"Hello, world!\"项目建立一个目录。" - -#: src/ch01-02-hello-world.md:25 -msgid "For Linux, macOS, and PowerShell on Windows, enter this:" -msgstr "对于Linux、macOS和Windows上的PowerShell,输入:" - -#: src/ch01-02-hello-world.md:27 -msgid "" -"```console\n" -"mkdir ~/cairo_projects\n" -"cd ~/cairo_projects\n" -"mkdir hello_world\n" -"cd hello_world\n" -"```" -msgstr "" -"```console\n" -"mkdir ~/cairo_projects\n" -"cd ~/cairo_projects\n" -"mkdir hello_world\n" -"cd hello_world\n" -"```" - -#: src/ch01-02-hello-world.md:34 -msgid "For Windows CMD, enter this:" -msgstr "对于Windows CMD,请输入以下内容:" - -#: src/ch01-02-hello-world.md:36 -msgid "" -"```cmd\n" -"> mkdir \"%USERPROFILE%\\projects\"\n" -"> cd /d \"%USERPROFILE%\\projects\"\n" -"> mkdir hello_world\n" -"> cd hello_world\n" -"```" -msgstr "" -"```cmd\n" -"> mkdir “%USERPROFILE%\\projects”\n" -"> cd /d “%USERPROFILE%\\projects”\n" -"> mkdir hello_world\n" -"> cd hello_world\n" -"```" - -#: src/ch01-02-hello-world.md:43 -msgid "### Writing and Running a Cairo Program" -msgstr "### 编写和运行Cairo程序" - -#: src/ch01-02-hello-world.md:45 -msgid "" -"Next, make a new source file and call it _main.cairo_. Cairo files always end with\n" -"the _.cairo_ extension. If you’re using more than one word in your filename, the\n" -"convention is to use an underscore to separate them. For example, use\n" -"_hello_world.cairo_ rather than _helloworld.cairo_." -msgstr "" -"接下来,制作一个新的源代码文件,并将命名为 _main.cairo_ 。Cairo文件的扩展名为 _.cairo_ 。\n" -"如果你在文件名中使用一个以上的单词,惯例是用下划线来分隔它们。\n" -"例如,使用 _hello_world.cairo_ 而不是 _helloworld.cairo_ 。" - -#: src/ch01-02-hello-world.md:50 -msgid "Now open the _main.cairo_ file you just created and enter the code in Listing 1-1." -msgstr "现在打开你刚刚创建的 _main.cairo_ 文件,输入示例1-1中的代码。" - -#: src/ch01-02-hello-world.md:52 src/ch02-05-control-flow.md:9 src/ch02-05-control-flow.md:58 src/ch02-05-control-flow.md:90 -msgid "Filename: main.cairo" -msgstr "文件名:main.cairo" - -#: src/ch01-02-hello-world.md:54 -msgid "" -"```rust,file=hello_world.cairo\n" -"use debug::PrintTrait;\n" -"fn main() {\n" -" 'Hello, world!'.print();\n" -"}\n" -"```" -msgstr "" -"```rust,file=hello_world.cairo\n" -"use debug::PrintTrait;\n" -"fn main() {\n" -" ‘Hello, world!’.print();\n" -"}\n" -"```" - -#: src/ch01-02-hello-world.md:61 -msgid "Listing 1-1: A program that prints `Hello, world!`" -msgstr "示例1-1:一个打印 \"Hello,world\"的程序。" - -#: src/ch01-02-hello-world.md:63 -msgid "" -"Save the file and go back to your terminal window in the\n" -"_~/cairo_projects/hello_world_ directory. Enter the following\n" -"commands to compile and run the file:" -msgstr "" -"保存该文件,并回到你的终端窗口,在\n" -" _~/cairo_projects/hello_world_ 目录。输入以下\n" -"命令来编译和运行该文件:" - -#: src/ch01-02-hello-world.md:67 -msgid "" -"```console\n" -"$ cairo-run main.cairo\n" -"Hello, world!\n" -"```" -msgstr "" -"```console\n" -"$ cairo-run main.cairo\n" -"Hello, world!\n" -"```" - -#: src/ch01-02-hello-world.md:72 -msgid "" -"Regardless of your operating system, the string `Hello, world!` should print to\n" -"the terminal." -msgstr "无论你的操作系统如何,终端里都应该打印出字符串`Hello, world!`。" - -#: src/ch01-02-hello-world.md:75 -msgid "" -"If `Hello, world!` did print, congratulations! You’ve officially written a Cairo\n" -"program. That makes you a Cairo programmer—welcome!" -msgstr "" -"如果 \"Hello,world!\"打印出来了,那么恭喜你!你已经正式写了一个Cairo程序!\n" -"你已经成为了一名Cairo程序员--欢迎!" - -#: src/ch01-02-hello-world.md:78 -msgid "### Anatomy of a Cairo Program" -msgstr "### 解析Cairo程序" - -#: src/ch01-02-hello-world.md:80 +#: src/ch01-02-hello-world.md:144 msgid "" "Let’s review this “Hello, world!” program in detail. Here’s the first piece of\n" "the puzzle:" msgstr "让我们详细回顾一下这个 \"Hello,world!\"程序。这里有拼图的第一部分:" -#: src/ch01-02-hello-world.md:83 +#: src/ch01-02-hello-world.md:147 msgid "" -"```rust,ignore_format\n" +"```rust,noplayground\n" "fn main() {\n" "\n" "}\n" "```" msgstr "" -"```rust,ignore_format\n" +"```rust,noplayground\n" "fn main() {\n" "\n" "}\n" "```" -#: src/ch01-02-hello-world.md:89 +#: src/ch01-02-hello-world.md:153 msgid "" "These lines define a function named `main`. The `main` function is special: it\n" "is always the first code that runs in every executable Cairo program. Here, the\n" @@ -1012,7 +877,7 @@ msgstr "" "这些代码定义了一个名为 `main`的函数。`main`函数很特别:它总是每个可执行的Cairo程序中运行的第一个代码。\n" "这里,第一行声明了一个名为 `main`的函数,没有参数,也不返回。如果有参数,它们会被放在括号`()`里。" -#: src/ch01-02-hello-world.md:94 +#: src/ch01-02-hello-world.md:158 msgid "" "The function body is wrapped in `{}`. Cairo requires curly brackets around all\n" "function bodies. It’s good style to place the opening curly bracket on the same\n" @@ -1022,23 +887,23 @@ msgstr "" "将开头的左大括号与函数声明放在同一行是很好的编码风格。\n" "别忘了在它们中间加一个空格。" -#: src/ch01-02-hello-world.md:98 +#: src/ch01-02-hello-world.md:162 msgid "" "> Note: If you want to stick to a standard style across Cairo projects, you can\n" -"> use the automatic formatter tool called `cairo-format` to format your code in a\n" -"> particular style (more on `cairo-format` in\n" -"> [Appendix B][devtools]). The Cairo team has included this tool\n" +"> use the automatic formatter tool available with `scarb fmt` to format your code in a\n" +"> particular style (more on `scarb fmt` in\n" +"> [Appendix D][devtools]). The Cairo team has included this tool\n" "> with the standard Cairo distribution, as `cairo-run` is, so it should already be\n" "> installed on your computer!" msgstr "" "> 注意:如果你想在Cairo项目中使用一个统一代码风格标准,你可以\n" -"> 使用自动格式化工具`cairo-format`来将你的代码格式化为\n" -"> 特定的代码风格(更多关于`cairo-format`的信息见\n" +"> 使用自动格式化工具`scarb fmt`来将你的代码格式化为\n" +"> 特定的代码风格(更多关于`scarb fmt`的信息见\n" "> [附录D][devtools])。Cairo团队已经将这个工具\n" "> 包含在标准的Cairo发行版中,就像`cairo-run`一样,所以它应该已经被\n" "> 已经安装在你的计算机上了!" -#: src/ch01-02-hello-world.md:105 +#: src/ch01-02-hello-world.md:169 msgid "" "Prior to the main function declaration, The line `use debug::PrintTrait;` is responsible for importing an item defined in another module. In this case, we are importing the " "`PrintTrait` item from the Cairo core library. By doing so, we gain the ability to use the `print()` method on data types that are compatible with printing." @@ -1046,31 +911,31 @@ msgstr "" "在主函数声明之前,`use debug::PrintTrait;`一行负责导入另一个模块中定义的项目。在这个例子中,我们从Cairo核心库中导入了`PrintTrait`项目。通过这样做,我们获得了在可以打印的数据类型上使用" "`print()`方法的能力。" -#: src/ch01-02-hello-world.md:107 +#: src/ch01-02-hello-world.md:171 msgid "The body of the `main` function holds the following code:" msgstr "`main`函数的主体包含以下代码:" -#: src/ch01-02-hello-world.md:109 +#: src/ch01-02-hello-world.md:173 msgid "" -"```rust\n" -" 'Hello, world!'.print();\n" +"```rust,noplayground\n" +" 'Hello, World!'.print();\n" "```" msgstr "" -"```rust\n" -" 'Hello, world!'.print();\n" +"```rust,noplayground\n" +" 'Hello, World!'.print();\n" "```" -#: src/ch01-02-hello-world.md:113 +#: src/ch01-02-hello-world.md:177 msgid "" "This line does all the work in this little program: it prints text to the\n" "screen. There are four important details to notice here." msgstr "这一行完成了这个小程序的所有工作:将文本打印到屏幕上。这里有四个重要的细节需要注意。" -#: src/ch01-02-hello-world.md:116 +#: src/ch01-02-hello-world.md:180 msgid "First, Cairo style is to indent with four spaces, not a tab." msgstr "首先,Cairo的风格是用四个空格缩进,而不是用制表符。" -#: src/ch01-02-hello-world.md:118 +#: src/ch01-02-hello-world.md:182 msgid "" "Second, the `print()` function called is a method from the trait `PrintTrait`. This trait is imported from the Cairo core library, and it defines how to print values to the screen " "for different data types. In our case, our text is defined as a \"short string\", which is an ASCII string that can fit in Cairo's basic data type, which is the `felt252` type. By " @@ -1079,425 +944,153 @@ msgstr "" "第二,调用的`print()`函数是来自trait`PrintTrait`的一个方法。这个trait是从Cairo核心库中导入的,它定义了如何将不同数据类型的值打印到屏幕上。在我们的例子中,我们的文本被定义为 \"short " "string\",这是一个ASCII字符串,可以适合Cairo的基本数据类型,即`felt252`类型。通过调用`'Hello, world!'.print()`,我们正在调用`PrintTrait`trait的`felt252`实现的`print()`方法。" -#: src/ch01-02-hello-world.md:120 +#: src/ch01-02-hello-world.md:184 msgid "" -"Third, you see the `'Hello, world!'` short string. We pass this short string as an argument\n" +"Third, you see the `'Hello, World!'` short string. We pass this short string as an argument\n" "to `print()`, and the short string is printed to the screen." msgstr "第三,看见了`'Hello, world!'`短字符串么。我们把这个短字符串作为一个参数传递给`print()`,因此短字符串被打印到屏幕上。" -#: src/ch01-02-hello-world.md:123 +#: src/ch01-02-hello-world.md:187 msgid "" "Fourth, we end the line with a semicolon (`;`), which indicates that this\n" "expression is over and the next one is ready to begin. Most lines of Cairo code\n" "end with a semicolon." msgstr "第四,我们用分号(`;`)来结束这一行,这表示这个表达式已经结束,下一个表达式准备开始。大多数Cairo的代码行以分号结束。" -#: src/ch01-02-hello-world.md:127 -msgid "" -"Just running with `cairo-run` is fine for simple programs, but as your project\n" -"grows, you’ll want to manage all the options and make it easy to share your\n" -"code. Next, we’ll introduce you to the Scarb tool, which will help you write\n" -"real-world Cairo programs." -msgstr "" -"只用`cairo-run`运行简单的程序是可以的,但随着你的项目\n" -"增长,你会希望管理所有的选项,并使之易于分享你的\n" -"代码。接下来,我们将向你介绍Scarb工具,它将帮助你编写\n" -"真实世界的Cairo程序。" - -#: src/ch01-03-hello-scarb.md:1 -msgid "# Hello, Scarb" -msgstr "# 你好,Scarb" - -#: src/ch01-03-hello-scarb.md:3 -msgid "Scarb is the Cairo package manager and heavily inspired by [Cargo](https://doc.rust-lang.org/cargo/), Rust’s build system and package manager." -msgstr "Scarb是Cairo的软件包管理器,在很大程度上受到[Cargo](https://doc.rust-lang.org/cargo/)的启发,Rust的构建系统和软件包管理器。" - -#: src/ch01-03-hello-scarb.md:5 -msgid "" -"Scarb handles a lot of tasks for you, such as building your code (either pure Cairo or Starknet contracts), downloading the libraries your code depends on, and building those " -"libraries." -msgstr "Scarb为你处理很多任务,比如构建你的代码(纯Cairo或Starknet合约),下载你的代码所依赖的库,并构建这些库。" +#: src/ch01-02-hello-world.md:193 +msgid "### Running tests" +msgstr "## 运行测试" -#: src/ch01-03-hello-scarb.md:7 +#: src/ch01-02-hello-world.md:195 msgid "" -"If we were to build the 'Hello, world!' project using Scarb, only the part of Scarb that handles building the code would be utilized, since the program doesn't require any external " -"dependencies. As you write more complex Cairo programs, you’ll add dependencies, and if you start a project using Scarb, adding dependencies will be much easier to do." +"To run all the tests associated with a particular package, you can use the `scarb test` command.\n" +"It is not a test runner by itself, but rather delegates work to a testing solution of choice. Scarb comes with preinstalled `scarb cairo-test` extension, which bundles Cairo's native " +"test runner. It is the default test runner used by scarb test.\n" +"To use third-party test runners, please refer to [Scarb's documentation](https://docs.swmansion.com/scarb/docs/extensions/testing.html#using-third-party-test-runners)." msgstr "" -"如果我们用Scarb来构建 ‘Hello, world!’ 项目,我们只会用到Scarb处理构建代码的功能,因为该程序不需要任何外部依赖。当你编写更复杂的Cairo程序时,你会增加外部依赖,如果你使用Scarb开始一个项" -"目,增加和管理外部依赖将更容易。" - -#: src/ch01-03-hello-scarb.md:9 -msgid "Let's start by installing Scarb." -msgstr "让我们从安装Scarb开始。" - -#: src/ch01-03-hello-scarb.md:11 -msgid "## Installing Scarb" -msgstr "## 安装Scarb" - -#: src/ch01-03-hello-scarb.md:13 -msgid "### Requirements" -msgstr "### 要求" - -#: src/ch01-03-hello-scarb.md:15 -msgid "Scarb requires a Git executable to be available in the `PATH` environment variable." -msgstr "Scarb需要`PATH`环境变量里有一个Git可执行文件。" +"要运行与特定软件包相关的所有测试,可以使用`scarb test`命令。\n" +"它本身并不是一个测试运行工具,而是将测试工作委托给所选的测试工具。Scarb预装了`scarb cairo-test`扩展,它捆绑了Cairo的本地测试运行器。它也是scarb test默认使用的测试运行器。\n" +"要使用第三方测试运行器,请参考[Scarb文档](https://docs.swmansion.com/scarb/docs/extensions/testing.html#using-third-party-test-runners)。" -#: src/ch01-03-hello-scarb.md:17 -msgid "### Installation" -msgstr "### 安装" +#: src/ch01-02-hello-world.md:199 +msgid "Test functions are marked with the `#[test]` attributes, and running `scarb test` will run all test functions in your codebase under the `src/` directory." +msgstr "测试函数用`#[test]`属性标记,运行`scarb test`将运行代码库中`src/`目录下的所有测试函数。" -#: src/ch01-03-hello-scarb.md:19 -msgid "As for now, Scarb needs manual installation with the following steps:" -msgstr "就目前而言,Scarb需要手动安装,步骤如下:" - -#: src/ch01-03-hello-scarb.md:21 +#: src/ch01-02-hello-world.md:201 msgid "" -"- Download the release archive matching your operating system and CPU architecture, from [Scarb releases on GitHub](https://github.com/software-mansion/scarb/releases)\n" -"- Extract it to a location where you would like to have Scarb installed, e.g. `~/scarb`\n" -"- Add path to the `scarb/bin` directory to your `PATH` environment variable.\n" -"\n" -" This depend on what shell you are using. Let’s take the example of [zsh](https://ohmyz.sh/) and you have extracted Scarb to `~/scarb`:\n" -"\n" -" - Open `~/.zshrc` file in your favorite editor\n" -" - Add the following line to the end of the file: `export PATH=\"$PATH:~/scarb/bin\"`\n" -"\n" -"- Verify installation by running the following command in new terminal session, it should print both Scarb and Cairo language versions, e.g:\n" -"\n" -" ```bash\n" -" $ scarb --version\n" -" scarb 0.3.0 (182a9019d 2023-05-29)\n" -" cairo: 1.1.0 (https://crates.io/crates/cairo-lang-compiler/1.1.0)\n" -" ```" +"```txt\n" +"├── Scarb.toml\n" +"├── src\n" +"│   ├── lib.cairo\n" +"│   └── file.cairo\n" +"```" msgstr "" -"- 从[GitHub上的Scarb发布页](https://github.com/software-mansion/scarb/releases)下载与你的操作系统和CPU架构相匹配的Release档案。\n" -"- 将其解压到你想安装Scarb的位置,例如`~/scarb`。\n" -"- 将`scarb/bin`目录的路径添加到你的`PATH`环境变量中。\n" -"\n" -" 这取决于你使用的是什么shell。让我们以[zsh](https://ohmyz.sh/)为例,将Scarb解压到`~/scarb`后:\n" -"\n" -" - 用你爱用的编辑器打开`~/.zshrc`文件\n" -" - 在文件的末尾添加以下行:`export PATH=\"$PATH:~/scarb/bin\"`。\n" -"\n" -"- 在新的终端会话中运行以下命令来验证安装是否成功,它应该同时打印Scarb和Cairo语言的版本,例如:\n" -"\n" -" ```bash\n" -" $ scarb --version\n" -" scarb 0.3.0 (182a9019d 2023-05-29)\n" -" cairo: 1.1.0 (https://crates.io/crates/cairo-lang-compiler/1.1.0)\n" -" ```" - -#: src/ch01-03-hello-scarb.md:38 -msgid "### Creating a Project with Scarb" -msgstr "### 用Scarb创建一个项目" +"```txt\n" +"├── Scarb.toml\n" +"├── src\n" +"│   ├── lib.cairo\n" +"│   └── file.cairo\n" +"```" -#: src/ch01-03-hello-scarb.md:40 -msgid "Let’s create a new project using Scarb and look at how it differs from our original “Hello, world!” project." -msgstr "让我们用Scarb创建一个新的项目,看看它与我们原来的 \"Hello, world!\"项目有什么不同。" +#: src/ch01-02-hello-world.md:208 +msgid " A sample Scarb project structure" +msgstr "Scarb 项目结构示例" -#: src/ch01-03-hello-scarb.md:42 -msgid "Navigate back to your projects directory (or wherever you decided to store your code). Then run the following:" -msgstr "导航到你的项目目录(或你决定放代码的地方)。然后运行以下命令:" +#: src/ch01-02-hello-world.md:210 +msgid "Let’s recap what we’ve learned so far about Scarb:" +msgstr "让我们回顾一下到目前为止我们所了解到的关于Scarb的情况:" -#: src/ch01-03-hello-scarb.md:44 +#: src/ch01-02-hello-world.md:212 msgid "" -"```bash\n" -"$ scarb new hello_scarb\n" -"```" +"- We can create a project using `scarb new`.\n" +"- We can build a project using `scarb build` to generate the compiled Sierra code.\n" +"- We can define custom scripts in `Scarb.toml` and call them with the `scarb run` command.\n" +"- We can run tests using the `scarb test` command." msgstr "" -"```bash\n" -"$ scarb new hello_scarb\n" -"```" +"- 我们可以使用 `scarb new` 创建项目。\n" +"- 我们可以使用 `scarb build` 生成编译后的 Sierra 代码。\n" +"- 我们可以在 `Scarb.toml` 中定义自定义脚本,并使用 `scarb run` 命令调用它们。\n" +"- 我们可以使用 `scarb test` 命令运行测试。" -#: src/ch01-03-hello-scarb.md:48 -msgid "It creates a new directory and project called hello_scarb. We’ve named our project hello_scarb, and Scarb creates its files in a directory of the same name." -msgstr "它创建了一个新的目录和项目,名为hello_scarb。我们把我们的项目命名为hello_scarb,因此Scarb会在同名的目录下创建它的文件。" - -#: src/ch01-03-hello-scarb.md:50 +#: src/ch01-02-hello-world.md:217 msgid "" -"Go into the hello_scarb directory with the command `cd hello_scarb`. You’ll see that Scarb has generated two files and one directory for us: a `Scarb.toml` file and a src directory " -"with a `lib.cairo` file inside." -msgstr "用`cd hello_scarb`命令进入hello_scarb目录。你会看到Scarb已经为我们生成了两个文件和一个目录:一个`Scarb.toml`文件和一个src目录,里面有一个`lib.cairo`文件。" +"An additional advantage of using Scarb is that the commands are the same no matter which operating system you’re working on. So, at this point, we’ll no longer provide specific " +"instructions for Linux and macOS versus Windows." +msgstr "使用Scarb的另一个好处是,无论你在哪个操作系统上工作,命令都是一样的。所以我们将不再提供Linux和macOS与Windows的具体说明。" -#: src/ch01-03-hello-scarb.md:52 -msgid "It has also initialized a new Git repository along with a `.gitignore` file" -msgstr "它还初始化了一个新的Git仓库和一个`.gitignore`文件" +#: src/ch01-02-hello-world.md:219 +msgid "### Starknet support" +msgstr "### Starknet 支持" -#: src/ch01-03-hello-scarb.md:54 +#: src/ch01-02-hello-world.md:221 msgid "" -"> Note: Git is a common version control system. You can stop using version control system by using the `--vcs` flag.\n" -"> Run `scarb new -help` to see the available options." +"Scarb supports smart contract development for Starknet. To enable this functionality, you'll need to make some configurations in your `Scarb.toml` file.\n" +"You have to add the `starknet` dependency and add a `[[target.starknet-contract]]` section to enable contract compilation." msgstr "" -"> 注意:Git是一个常见的版本控制系统。你可以通过使用`--vcs`标志停止使用版本控制系统。\n" -"> 运行`scarb new -help`以查看可用选项。" - -#: src/ch01-03-hello-scarb.md:57 -msgid "Open _Scarb.toml_ in your text editor of choice. It should look similar to the code in Listing 1-2." -msgstr "在你选择的文本编辑器中打开 _Scarb.toml_ 。它看起来应该与示例1-2中的代码相似。" +"Scarb 支持Starknet的智能合约开发。要启用此功能,你需要在你的 `Scarb.toml` 文件中进行一些配置。\n" +"你必须添加 `starknet`依赖关系,并添加 `[[target.starknet-contract]]` 部分以启用合约编译。" -#: src/ch01-03-hello-scarb.md:59 -msgid "Filename: Scarb.toml" -msgstr "文件名:Scarb.toml" +#: src/ch01-02-hello-world.md:224 +msgid "Below is the minimal Scarb.toml file required for a Starknet contract:" +msgstr "以下是 Starknet 合约最低所需的 Scarb.toml 配置文件:" -#: src/ch01-03-hello-scarb.md:61 +#: src/ch01-02-hello-world.md:226 msgid "" "```toml\n" "[package]\n" -"name = \"hello_scarb\"\n" +"name = \"hello_starknet\"\n" "version = \"0.1.0\"\n" "\n" -"# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest\n" -"\n" "[dependencies]\n" -"# foo = { path = \"vendor/foo\" }\n" +"starknet = \">=2.2.0\"\n" +"\n" +"[[target.starknet-contract]]\n" "```" msgstr "" "```toml\n" "[package]\n" -"name = “hello_scarb”\n" -"version = “0.1.0”\n" -"\n" -"# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest\n" +"name = \"hello_starknet\"\n" +"version = \"0.1.0\"\n" "\n" "[dependencies]\n" -"# foo = { path = “vendor/foo” }\n" +"starknet = \">=2.2.0\"\n" +"\n" +"[[target.starknet-contract]]\n" "```" -#: src/ch01-03-hello-scarb.md:72 -msgid "Listing 1-2: Contents of Scarb.toml generated by `scarb new`" -msgstr "示例1-2:由`scarb new`生成的Scarb.toml的内容" - -#: src/ch01-03-hello-scarb.md:74 -msgid "This file is in the [TOML](https://toml.io/) (Tom’s Obvious, Minimal Language) format, which is Scarb’s configuration format." -msgstr "这个文件是[TOML](https://toml.io/)(Tom's Obvious, Minimal Language)的格式,是Scarb的配置文件格式。" - -#: src/ch01-03-hello-scarb.md:76 +#: src/ch01-02-hello-world.md:237 msgid "" -"The first line, `[package]`, is a section heading that indicates that the following statements are configuring a package. As we add more information to this file, we’ll add other " -"sections." -msgstr "第一行,`[package]`,是一个章节标题,表示下面的语句是在配置一个包。随着我们向这个文件添加更多的信息,我们将添加其他章节。" - -#: src/ch01-03-hello-scarb.md:78 -msgid "The next two lines set the configuration information Scarb needs to compile your program: the name and the version of Scarb to use." -msgstr "接下来的两行设置了Scarb在编译你的程序时需要的配置信息:名称和要使用的Scarb版本。" +"For additional configuration, such as external contract dependencies, please refer to the [Scarb documentation](https://docs.swmansion.com/scarb/docs/extensions/starknet/contract-" +"target.html#compiling-external-contracts)." +msgstr "有关外部合约依赖等更多配置相关的内容,请参阅 [Scarb 文档](https://docs.swmansion.com/scarb/docs/extensions/starknet/contract-target.html#compiling-external-contracts)。" -#: src/ch01-03-hello-scarb.md:80 -msgid "" -"The last line, `[dependencies]`, is the start of a section for you to list any of your project’s dependencies. In Cairo, packages of code are referred to as crates. We won’t need any " -"other crates for this project." -msgstr "最后一行,`[dependencies]`,是一个章节的开始,该章节供你列出你的项目的所有依赖。在Cairo中,代码包被称为crate。在这个项目中,我们不需要任何其他的crate。" +#: src/ch01-02-hello-world.md:239 +msgid "# Summary" +msgstr "# 总结" -#: src/ch01-03-hello-scarb.md:82 -msgid "The other file created by Scarb is `src/lib.cairo`, let's delete all the content and put in the following content, we will explain the reason later." -msgstr "Scarb创建的另一个文件是`src/lib.cairo`,让我们删除其中所有的内容,放入以下内容,我们将在后面解释原因。" +#: src/ch01-02-hello-world.md:241 +msgid "You’re already off to a great start on your Cairo journey! In this chapter, you’ve learned how to:" +msgstr "你的Cairo之旅已经有了一个很好的开始!在本章中,你已经学会了如何:" -#: src/ch01-03-hello-scarb.md:84 +#: src/ch01-02-hello-world.md:243 msgid "" -"```rust\n" -"mod hello_scarb;\n" -"```" +"- Install the latest stable version of Cairo\n" +"- Write and run a “Hello, Scarb!” program using `scarb` directly\n" +"- Create and run a new project using the conventions of Scarb\n" +"- Execute tests using the `scarb test` command" msgstr "" -"```rust\n" -"mod hello_scarb;\n" -"```" +"- 安装最新稳定版本的 Cairo\n" +"- 直接使用 `scarb` 编写并运行 “Hello, world!”程序\n" +"- 使用 Scarb 的默认设置创建并运行一个新项目\n" +"- 使用 `scarb test` 命令执行测试" -#: src/ch01-03-hello-scarb.md:88 -msgid "Then create a new file called `src/hello_scarb.cairo` and put the following code in it:" -msgstr "然后创建一个名为`src/hello_scarb.cairo`的新文件,并将以下代码放入其中:" +#: src/ch01-02-hello-world.md:248 +msgid "This is a great time to build a more substantial program to get used to reading and writing Cairo code." +msgstr "是时候通过建立更多实用程序来熟悉阅读和编写Cairo代码了。" -#: src/ch01-03-hello-scarb.md:90 -msgid "Filename: src/hello_scarb.cairo" -msgstr "文件名: src/hello_scarb.cairo" - -#: src/ch01-03-hello-scarb.md:92 -msgid "" -"```rust,file=hello_scarb.cairo\n" -"use debug::PrintTrait;\n" -"fn main() {\n" -" 'Hello, Scarb!'.print();\n" -"}\n" -"```" -msgstr "" -"```rust,file=hello_scarb.cairo\n" -"use debug::PrintTrait;\n" -"fn main() {\n" -" ‘Hello, Scarb!’.print();\n" -"}\n" -"```" - -#: src/ch01-03-hello-scarb.md:99 -msgid "" -"We have just created a file called `lib.cairo`, which contains a module declaration referencing another module named \"hello_scarb\", as well as the file `hello_scarb.cairo`, " -"containing the implementation details of the \"hello_scarb\" module." -msgstr "我们刚刚创建了一个名为`lib.cairo`的文件,其中包含一个模块声明,引用了另一个名为 \"hello_scarb\"的模块,以及包含 “hello_scarb”模块的实现细节的文件`hello_scarb.cairo`。" - -#: src/ch01-03-hello-scarb.md:101 -msgid "Scarb requires your source files to be located within the src directory." -msgstr "Scarb要求你的源文件位于src目录中。" - -#: src/ch01-03-hello-scarb.md:103 -msgid "" -"The top-level project directory is reserved for README files, license information, configuration files, and any other non-code-related content.\n" -"Scarb ensures a designated location for all project components, maintaining a structured organization." -msgstr "" -"顶层项目目录是为README文件、许可证信息、配置文件和任何其他与代码无关的内容保留的。\n" -"Scarb确保所有项目组件都有一个指定的位置,维持一个结构化的组织架构。" - -#: src/ch01-03-hello-scarb.md:106 -msgid "" -"If you started a project that doesn’t use Scarb, as we did with the “Hello, world!” project, you can convert it to a project that does use Scarb. Move the project code into the src " -"directory and create an appropriate `Scarb.toml` file." -msgstr "" -"如果你启动了一个不使用Scarb的项目,就像我们在 \"Hello, world!\"项目中所做的那样,你可以把它转换成一个使用Scarb的项目。将项目代码移到src目录下,并创建一个适当的`Scarb.toml`文件。" - -#: src/ch01-03-hello-scarb.md:108 -msgid "### Building a Scarb Project" -msgstr "### 编译Scarb项目" - -#: src/ch01-03-hello-scarb.md:110 -msgid "From your hello_scarb directory, build your project by entering the following command:" -msgstr "在你的hello_scarb目录中,通过输入以下命令来编译你的项目:" - -#: src/ch01-03-hello-scarb.md:112 -msgid "" -"```bash\n" -"$ scarb build\n" -" Compiling hello_scarb v0.1.0 (file:///projects/Scarb.toml)\n" -" Finished release target(s) in 0 seconds\n" -"```" -msgstr "" -"```bash\n" -"$ scarb build\n" -" Compiling hello_scarb v0.1.0 (file:///projects/Scarb.toml)\n" -" Finished release target(s) in 0 seconds\n" -"```" - -#: src/ch01-03-hello-scarb.md:118 -msgid "This command creates a `sierra` file in `target/release`, let's ignore the `sierra` file for now." -msgstr "这个命令在`target/release`中创建了一个`sierra`文件,现在我们先忽略`sierra`文件。" - -#: src/ch01-03-hello-scarb.md:120 -msgid "If you have installed Cairo correctly, you should be able to run and see the following output:" -msgstr "如果你正确安装了Cairo,你应该能够运行并看到以下输出:" - -#: src/ch01-03-hello-scarb.md:122 -msgid "" -"```bash\n" -"$ cairo-run src/lib.cairo\n" -"[DEBUG] Hello, Scarb! (raw: 5735816763073854913753904210465)\n" -"\n" -"Run completed successfully, returning []\n" -"```" -msgstr "" -"```bash\n" -"$ cairo-run src/lib.cairo\n" -"[DEBUG] Hello, Scarb! (raw: 5735816763073854913753904210465)\n" -"\n" -"Run completed successfully, returning []\n" -"```" - -#: src/ch01-03-hello-scarb.md:129 -msgid "" -"> Note: You will notice here that we didn't use a Scarb command, but rather a command from the Cairo binaries directly.\n" -"> As Scarb doesn't have a command to execute Cairo code yet, we have to use the `cairo-run` command directly.\n" -"> We will use this command in the rest of the tutorial, but we will also use Scarb commands to initialize projects." -msgstr "" -"> 注意:你会注意到这里我们没有使用Scarb的命令,而是直接使用了Cairo二进制文件的命令。\n" -"> 由于Scarb还没有执行Cairo代码的命令,我们必须直接使用`cairo-run`命令来执行代码。\n" -"> 在接下来的教程中我们将使用这个命令,但我们也将使用Scarb命令来初始化项目。" - -#: src/ch01-03-hello-scarb.md:133 -msgid "### Defining Custom Scripts" -msgstr "### 定义自定义脚本" - -#: src/ch01-03-hello-scarb.md:135 -msgid "" -"We can define Scarb scripts in `Scarb.toml` file, which can be used to execute custom shell scripts.\n" -"Add the following line to your `Scarb.toml` file:" -msgstr "" -"我们可以在`Scarb.toml`文件中定义Scarb脚本,它可以用来执行自定义的shell脚本。\n" -"在你的`Scarb.toml`文件中添加以下一行:" - -#: src/ch01-03-hello-scarb.md:138 -msgid "" -"```toml\n" -"[scripts]\n" -"run-lib = \"cairo-run src/lib.cairo\"\n" -"```" -msgstr "" -"```toml\n" -"[scripts]\n" -"run-lib = \"cairo-run src/lib.cairo\"\n" -"```" - -#: src/ch01-03-hello-scarb.md:143 -msgid "Now you can run the following command to run the project:" -msgstr "现在你可以运行以下命令来运行该项目:" - -#: src/ch01-03-hello-scarb.md:145 -msgid "" -"```bash\n" -"$ scarb run run-lib\n" -"[DEBUG] Hello, Scarb! (raw: 5735816763073854913753904210465)\n" -"\n" -"Run completed successfully, returning []\n" -"```" -msgstr "" -"```bash\n" -"$ scarb run run-lib\n" -"[DEBUG] Hello, Scarb! (raw: 5735816763073854913753904210465)\n" -"\n" -"Run completed successfully, returning []\n" -"```" - -#: src/ch01-03-hello-scarb.md:152 -msgid "Using `scarb run` is a convenient way to run custom shell scripts that can be useful to run files and test your project." -msgstr "使用 \"scarb run \"是运行自定义shell脚本的一种方便的方法,可以用来运行文件和测试你的项目。" - -#: src/ch01-03-hello-scarb.md:154 -msgid "Let’s recap what we’ve learned so far about Scarb:" -msgstr "让我们回顾一下到目前为止我们所了解到的关于Scarb的情况:" - -#: src/ch01-03-hello-scarb.md:156 -msgid "" -"- We can create a project using `scarb new`.\n" -"- We can build a project using `scarb build` to generate the compiled Sierra code.\n" -"- We can define custom scripts in `Scarb.toml` and call them with the `scarb run` command." -msgstr "" -"- 我们可以使用`scarb new`创建一个项目。\n" -"- 我们可以使用`scarb build`建立一个项目,以生成编译后的Sierra代码。\n" -"- 我们可以在`Scarb.toml`中定义自定义脚本,并使用`scarb run`命令调用它们。" - -#: src/ch01-03-hello-scarb.md:160 -msgid "" -"An additional advantage of using Scarb is that the commands are the same no matter which operating system you’re working on. So, at this point, we’ll no longer provide specific " -"instructions for Linux and macOS versus Windows." -msgstr "使用Scarb的另一个好处是,无论你在哪个操作系统上工作,命令都是一样的。所以我们将不再提供Linux和macOS与Windows的具体说明。" - -#: src/ch01-03-hello-scarb.md:162 -msgid "# Summary" -msgstr "# 总结" - -#: src/ch01-03-hello-scarb.md:164 -msgid "You’re already off to a great start on your Cairo journey! In this chapter, you’ve learned how to:" -msgstr "你的Cairo之旅已经有了一个很好的开始!在本章中,你已经学会了如何:" - -#: src/ch01-03-hello-scarb.md:166 -msgid "" -"- Install the latest stable version of Cairo\n" -"- Write and run a “Hello, world!” program using `cairo-run` directly\n" -"- Create and run a new project using the conventions of Scarb" -msgstr "" -"- 安装最新的稳定版本的Cairo\n" -"- 直接使用`cairo-run`编写并运行一个 \"Hello, world!\"程序\n" -"- 使用Scarb创建并运行一个新项目" - -#: src/ch01-03-hello-scarb.md:170 -msgid "This is a great time to build a more substantial program to get used to reading and writing Cairo code." -msgstr "是时候通过建立更多实用程序来熟悉阅读和编写Cairo代码了。" - -#: src/ch02-00-common-programming-concepts.md:1 -msgid "# Common Programming Concepts" -msgstr "# 常见的编程概念" +#: src/ch02-00-common-programming-concepts.md:1 +msgid "# Common Programming Concepts" +msgstr "# 常见的编程概念" #: src/ch02-00-common-programming-concepts.md:3 msgid "" @@ -1546,22 +1139,27 @@ msgid "" "code with the following code, which won’t compile just yet:" msgstr "然后,在你新的 _variables_ 目录下,打开 _src/lib.cairo_ 并将其替换为下面的代码,这段代码还不会被编译:" -#: src/ch02-01-variables-and-mutability.md:17 src/ch02-01-variables-and-mutability.md:77 src/ch02-01-variables-and-mutability.md:155 src/ch02-05-control-flow.md:130 -#: src/ch03-02-references-and-snapshots.md:23 src/ch03-02-references-and-snapshots.md:130 src/ch04-02-an-example-program-using-structs.md:7 -#: src/ch04-02-an-example-program-using-structs.md:48 src/ch04-02-an-example-program-using-structs.md:74 src/ch04-02-an-example-program-using-structs.md:103 -#: src/ch04-02-an-example-program-using-structs.md:136 src/ch04-03-method-syntax.md:18 src/ch04-03-method-syntax.md:93 src/ch04-03-method-syntax.md:135 src/ch04-03-method-syntax.md:192 -#: src/ch04-03-method-syntax.md:231 src/ch06-02-defining-modules-to-control-scope.md:90 src/ch06-02-defining-modules-to-control-scope.md:143 -#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:15 src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:62 -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:10 src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:35 -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:74 src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:131 -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:205 src/ch06-05-separating-modules-into-different-files.md:18 src/ch08-01-how-to-write-tests.md:426 -#: src/ch08-01-how-to-write-tests.md:464 +#: src/ch02-01-variables-and-mutability.md:17 src/ch02-01-variables-and-mutability.md:78 src/ch02-01-variables-and-mutability.md:156 src/ch02-05-control-flow.md:9 +#: src/ch02-05-control-flow.md:58 src/ch02-05-control-flow.md:90 src/ch02-05-control-flow.md:130 src/ch03-01-what-is-ownership.md:255 src/ch03-01-what-is-ownership.md:298 +#: src/ch03-01-what-is-ownership.md:352 src/ch03-02-references-and-snapshots.md:23 src/ch03-02-references-and-snapshots.md:132 src/ch04-01-defining-and-instantiating-structs.md:7 +#: src/ch04-01-defining-and-instantiating-structs.md:26 src/ch04-01-defining-and-instantiating-structs.md:48 src/ch04-01-defining-and-instantiating-structs.md:84 +#: src/ch04-01-defining-and-instantiating-structs.md:120 src/ch04-02-an-example-program-using-structs.md:7 src/ch04-02-an-example-program-using-structs.md:48 +#: src/ch04-02-an-example-program-using-structs.md:74 src/ch04-02-an-example-program-using-structs.md:103 src/ch04-02-an-example-program-using-structs.md:136 +#: src/ch04-03-method-syntax.md:18 src/ch04-03-method-syntax.md:93 src/ch04-03-method-syntax.md:135 src/ch04-03-method-syntax.md:192 src/ch04-03-method-syntax.md:231 +#: src/ch06-02-defining-modules-to-control-scope.md:78 src/ch06-02-defining-modules-to-control-scope.md:131 src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:15 +#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:63 src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:10 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:36 src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:76 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:131 src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:205 +#: src/ch06-05-separating-modules-into-different-files.md:18 src/ch08-01-how-to-write-tests.md:43 src/ch08-01-how-to-write-tests.md:76 src/ch08-01-how-to-write-tests.md:132 +#: src/ch08-01-how-to-write-tests.md:155 src/ch08-01-how-to-write-tests.md:221 src/ch08-01-how-to-write-tests.md:319 src/ch08-01-how-to-write-tests.md:408 +#: src/ch08-01-how-to-write-tests.md:503 src/ch08-01-how-to-write-tests.md:541 src/ch08-02-test-organization.md:19 src/ch09-01-unrecoverable-errors-with-panic.md:9 msgid "Filename: src/lib.cairo" msgstr "文件名: src/lib.cairo" #: src/ch02-01-variables-and-mutability.md:19 msgid "" "```rust,does_not_compile\n" +"//TAG: does_not_compile\n" "use debug::PrintTrait;\n" "fn main() {\n" " let x = 5;\n" @@ -1573,6 +1171,7 @@ msgid "" "```" msgstr "" "```rust,does_not_compile\n" +"//TAG: does_not_compile\n" "use debug::PrintTrait;\n" "fn main() {\n" " let x = 5;\n" @@ -1583,17 +1182,15 @@ msgstr "" "\n" "```" -#: src/ch02-01-variables-and-mutability.md:30 +#: src/ch02-01-variables-and-mutability.md:31 msgid "" -"Save and run the program using `cairo-run src/lib.cairo`. You should receive an error message\n" +"Save and run the program using `scarb cairo-run`. You should receive an error message\n" "regarding an immutability error, as shown in this output:" -msgstr "" -"保存并使用`cairo-run src/lib.cairo`运行该程序。你应该收到一条错误信息\n" -"关于不可变性的错误,如图所示:" +msgstr "保存并使用`scarb cairo-run`运行该程序。你应该收到一条关于不可变性的错误,如下所示:" -#: src/ch02-01-variables-and-mutability.md:33 +#: src/ch02-01-variables-and-mutability.md:34 msgid "" -"```console\n" +"```shell\n" "error: Cannot assign to an immutable variable.\n" " --> lib.cairo:5:5\n" " x = 6;\n" @@ -1602,7 +1199,7 @@ msgid "" "Error: failed to compile: src/lib.cairo\n" "```" msgstr "" -"```console\n" +"```shell\n" "error: Cannot assign to an immutable variable.\n" " --> lib.cairo:5:5\n" " x = 6;\n" @@ -1611,7 +1208,7 @@ msgstr "" "Error: failed to compile: src/lib.cairo\n" "```" -#: src/ch02-01-variables-and-mutability.md:42 +#: src/ch02-01-variables-and-mutability.md:43 msgid "" "This example shows how the compiler helps you find errors in your programs.\n" "Compiler errors can be frustrating, but really they only mean your program\n" @@ -1623,7 +1220,7 @@ msgstr "" "还没有安全地完成你想做的事情;它们并不意味着你不是一个好的程序员。\n" "即使有经验的Caironautes仍然会遇到编译错误。" -#: src/ch02-01-variables-and-mutability.md:47 +#: src/ch02-01-variables-and-mutability.md:48 msgid "" "You received the error message `Cannot assign to an immutable variable.`\n" "because you tried to assign a second value to the immutable `x` variable." @@ -1631,7 +1228,7 @@ msgstr "" "你收到的错误信息是 `Cannot assign to an immutable variable.`。\n" "因为你试图给不可变的`x`变量分配第二个值。" -#: src/ch02-01-variables-and-mutability.md:50 +#: src/ch02-01-variables-and-mutability.md:51 msgid "" "It’s important that we get compile-time errors when we attempt to change a\n" "value that’s designated as immutable because this specific situation can lead to\n" @@ -1649,7 +1246,7 @@ msgstr "" "第一部分代码就有可能以不可预料的方式运行。不得不承认这种 bug 的起因难以跟踪,尤其是第二部分代码只是 _有时_ 会改变值。\n" "Cairo 编译器保证,如果声明一个值不会变,它就真的不会变,所以你不必自己跟踪它。这意味着你的代码更易于推导。" -#: src/ch02-01-variables-and-mutability.md:61 +#: src/ch02-01-variables-and-mutability.md:62 msgid "" "But mutability can be very useful, and can make code more convenient to write.\n" "Although variables are immutable by default, you can make them mutable by\n" @@ -1659,7 +1256,7 @@ msgid "" msgstr "" "不过可变性也是非常有用的,可以用来更方便地编写代码。尽管变量默认是不可变的,你仍然可以在变量名前添加 `mut` 来使其可变。`mut` 也向阅读代码的人表明了其他代码将会改变这个变量值的意图。" -#: src/ch02-01-variables-and-mutability.md:67 +#: src/ch02-01-variables-and-mutability.md:68 msgid "" "However, you might be wondering at this point what exactly happens when a variable\n" "is declared as `mut`, as we previously mentioned that Cairo's memory is immutable.\n" @@ -1674,11 +1271,11 @@ msgstr "" "我们可以清楚地发现变量可变性是以语法糖的形式实现的,它将变量可变性操作转化为一系列的步骤,等同于变量的隐藏(variable shadowing)。\n" "唯一的区别是,在Cairo,变量没有被重新声明,所以它的类型不能改变。" -#: src/ch02-01-variables-and-mutability.md:75 +#: src/ch02-01-variables-and-mutability.md:76 msgid "For example, let’s change _src/lib.cairo_ to the following:" msgstr "例如,让我们把 _src/lib.cairo_ 改为以下内容:" -#: src/ch02-01-variables-and-mutability.md:79 +#: src/ch02-01-variables-and-mutability.md:80 msgid "" "```rust\n" "use debug::PrintTrait;\n" @@ -1700,31 +1297,31 @@ msgstr "" "}\n" "```" -#: src/ch02-01-variables-and-mutability.md:89 +#: src/ch02-01-variables-and-mutability.md:90 msgid "When we run the program now, we get this:" msgstr "当我们现在运行该程序时,我们得到了这个结果:" -#: src/ch02-01-variables-and-mutability.md:91 +#: src/ch02-01-variables-and-mutability.md:92 msgid "" -"```console\n" -"❯ cairo-run src/lib.cairo\n" -"[DEBUG]\t \t(raw: 5)\n" +"```shell\n" +"$ scarb cairo-run\n" +"[DEBUG] (raw: 5)\n" "\n" -"[DEBUG]\t \t(raw: 6)\n" +"[DEBUG] (raw: 6)\n" "\n" "Run completed successfully, returning []\n" "```" msgstr "" -"```console\n" -"❯ cairo-run src/lib.cairo\n" -"[DEBUG]\t \t(raw: 5)\n" +"```shell\n" +"$ scarb cairo-run\n" +"[DEBUG] (raw: 5)\n" "\n" -"[DEBUG]\t \t(raw: 6)\n" +"[DEBUG] (raw: 6)\n" "\n" "Run completed successfully, returning []\n" "```" -#: src/ch02-01-variables-and-mutability.md:100 +#: src/ch02-01-variables-and-mutability.md:101 msgid "" "We’re allowed to change the value bound to `x` from `5` to `6` when `mut` is\n" "used. Ultimately, deciding whether to use mutability or not is up to you and\n" @@ -1733,18 +1330,18 @@ msgstr "" "当使用 `mut` 时,我们将在`x`绑定的值从`5`改为 `6` 。\n" "最终,决定是否使用可变性取决于你自己以及你认为在特定情况下什么是最清楚的。" -#: src/ch02-01-variables-and-mutability.md:104 +#: src/ch02-01-variables-and-mutability.md:105 msgid "### Constants" msgstr "### 常量" -#: src/ch02-01-variables-and-mutability.md:106 +#: src/ch02-01-variables-and-mutability.md:107 msgid "" "Like immutable variables, _constants_ are values that are bound to a name and\n" "are not allowed to change, but there are a few differences between constants\n" "and variables." msgstr "类似于不可变变量,常量 (constants) 是绑定到一个名称的不允许改变的值,不过常量与变量还是有一些区别。" -#: src/ch02-01-variables-and-mutability.md:110 +#: src/ch02-01-variables-and-mutability.md:111 msgid "" "First, you aren’t allowed to use `mut` with constants. Constants aren’t just\n" "immutable by default—they’re always immutable. You declare constants using the\n" @@ -1756,40 +1353,40 @@ msgstr "" "首先,不允许对常量使用 `mut`。常量不仅仅是默认不可变—它总是不可变。声明常量使用 `const` 关键字而不是 `let`,并且 _必须_ 注明值的类型。在下一部分,[“数据类型”][data-types]中会介绍类型" "和类型注解,现在无需关心这些细节,记住总是标注类型即可。" -#: src/ch02-01-variables-and-mutability.md:117 +#: src/ch02-01-variables-and-mutability.md:118 msgid "" "Constants can only be declared in the global scope, which makes\n" "them useful for values that many parts of code need to know about." msgstr "常量可以在任何作用域中声明,包括全局作用域,这在一个值需要被很多部分的代码用到时很有用。" -#: src/ch02-01-variables-and-mutability.md:120 +#: src/ch02-01-variables-and-mutability.md:121 msgid "" "The last difference is that constants may be set only to a constant expression,\n" "not the result of a value that could only be computed at runtime. Only literal constants\n" "are currently supported." msgstr "最后一个区别是,常量只能被设置为常量表达式,而不可以是其他任何只能在运行时计算出的值。目前只支持字面常量。" -#: src/ch02-01-variables-and-mutability.md:124 +#: src/ch02-01-variables-and-mutability.md:125 msgid "Here’s an example of a constant declaration:" msgstr "下面是一个声明常量的例子:" -#: src/ch02-01-variables-and-mutability.md:126 +#: src/ch02-01-variables-and-mutability.md:127 msgid "" -"```rust\n" +"```rust, noplayground\n" "const ONE_HOUR_IN_SECONDS: u32 = 3600;\n" "```" msgstr "" -"```rust\n" +"```rust, noplayground\n" "const ONE_HOUR_IN_SECONDS: u32 = 3600;\n" "```" -#: src/ch02-01-variables-and-mutability.md:130 +#: src/ch02-01-variables-and-mutability.md:131 msgid "" "Cairo's naming convention for constants is to use all uppercase with\n" "underscores between words." msgstr "Cairo的常量命名规则是使用所有大写字母,单词之间使用下划线。" -#: src/ch02-01-variables-and-mutability.md:133 +#: src/ch02-01-variables-and-mutability.md:134 msgid "" "Constants are valid for the entire time a program runs, within the scope in\n" "which they were declared. This property makes constants useful for values in\n" @@ -1800,7 +1397,7 @@ msgstr "" "在声明它的作用域之中,常量在整个程序生命周期中都有效,\n" "此属性使得常量可以作为多处代码使用的全局范围的固定数值,例如一个游戏中玩家可以获取的最高分,或者光速。" -#: src/ch02-01-variables-and-mutability.md:139 +#: src/ch02-01-variables-and-mutability.md:140 msgid "" "Naming hardcoded values used throughout your program as constants is useful in\n" "conveying the meaning of that value to future maintainers of the code. It also\n" @@ -1810,11 +1407,11 @@ msgstr "" "将遍布于应用程序中的硬编码值声明为常量,能帮助后来的代码维护人员了解值的意图。\n" "如果将来需要修改硬编码值,也只需修改汇此处的硬编码值。" -#: src/ch02-01-variables-and-mutability.md:144 +#: src/ch02-01-variables-and-mutability.md:145 msgid "### Shadowing" msgstr "### 隐藏" -#: src/ch02-01-variables-and-mutability.md:146 +#: src/ch02-01-variables-and-mutability.md:147 msgid "" "Variable shadowing refers to the declaration of a\n" "new variable with the same name as a previous variable. Caironautes say that the\n" @@ -1831,7 +1428,7 @@ msgstr "" "直到第二个变量自己也被隐藏或第二个变量的作用域结束。\n" "可以用相同变量名称来隐藏一个变量,以及重复使用 `let` 关键字来多次隐藏,如下所示:" -#: src/ch02-01-variables-and-mutability.md:157 +#: src/ch02-01-variables-and-mutability.md:158 msgid "" "```rust\n" "use debug::PrintTrait;\n" @@ -1863,7 +1460,7 @@ msgstr "" "}\n" "```" -#: src/ch02-01-variables-and-mutability.md:172 +#: src/ch02-01-variables-and-mutability.md:173 msgid "" "This program first binds `x` to a value of `5`. Then it creates a new variable\n" "`x` by repeating `let x =`, taking the original value and adding `1` so the\n" @@ -1876,37 +1473,37 @@ msgstr "" "这个程序首先将 `x` 绑定到值 `5` 上。接着通过 `let x =` 创建了一个新变量 `x` ,获取初始值并加 `1` ,这样 `x` 的值就变成 `6` 了。然后,在使用花括号创建的内部作用域内,第三个 `let` 语句" "也隐藏了 `x` 并创建了一个新的变量,将之前的值乘以 `2` , `x` 得到的值是 `12`。当该作用域结束时,内部 shadowing 的作用域也结束了, `x` 又返回到 `6`。运行这个程序,它会有如下输出:" -#: src/ch02-01-variables-and-mutability.md:180 +#: src/ch02-01-variables-and-mutability.md:181 msgid "" -"```console\n" -"cairo-run src/lib.cairo\n" -"[DEBUG]\tInner scope x value is: \t(raw: 7033328135641142205392067879065573688897582790068499258)\n" +"```shell\n" +"scarb cairo-run\n" +"[DEBUG] Inner scope x value is: (raw: 7033328135641142205392067879065573688897582790068499258)\n" "\n" "[DEBUG]\n" -" \t(raw: 12)\n" +" (raw: 12)\n" "\n" -"[DEBUG]\tOuter scope x value is: \t(raw: 7610641743409771490723378239576163509623951327599620922)\n" +"[DEBUG] Outer scope x value is: (raw: 7610641743409771490723378239576163509623951327599620922)\n" "\n" -"[DEBUG]\t \t(raw: 6)\n" +"[DEBUG] (raw: 6)\n" "\n" "Run completed successfully, returning []\n" "```" msgstr "" -"```console\n" -"cairo-run src/lib.cairo\n" -"[DEBUG]\tInner scope x value is: \t(raw: 7033328135641142205392067879065573688897582790068499258)\n" +"```shell\n" +"scarb cairo-run\n" +"[DEBUG] Inner scope x value is: (raw: 7033328135641142205392067879065573688897582790068499258)\n" "\n" "[DEBUG]\n" -" \t(raw: 12)\n" +" (raw: 12)\n" "\n" -"[DEBUG]\tOuter scope x value is: \t(raw: 7610641743409771490723378239576163509623951327599620922)\n" +"[DEBUG] Outer scope x value is: (raw: 7610641743409771490723378239576163509623951327599620922)\n" "\n" -"[DEBUG]\t \t(raw: 6)\n" +"[DEBUG] (raw: 6)\n" "\n" "Run completed successfully, returning []\n" "```" -#: src/ch02-01-variables-and-mutability.md:194 +#: src/ch02-01-variables-and-mutability.md:195 msgid "" "Shadowing is different from marking a variable as `mut` because we’ll get a\n" "compile-time error if we accidentally try to reassign to this variable without\n" @@ -1918,7 +1515,7 @@ msgstr "" "当不小心尝试对变量重新赋值时,如果没有使用 `let` 关键字,就会导致编译时错误。\n" "通过使用 `let`,我们可以用这个新值进行一些计算,不过计算完之后变量仍然是不可变的。" -#: src/ch02-01-variables-and-mutability.md:200 +#: src/ch02-01-variables-and-mutability.md:201 msgid "" "Another distinction between `mut` and shadowing is that when we use the `let` keyword again,\n" "we are effectively creating a new variable, which allows us to change the type of the\n" @@ -1933,13 +1530,13 @@ msgstr "" "唯一的区别是,通过隐藏变量,即使你改变它的类型。编译器也不会检测到错误\n" "例如,假设我们的程序在`u64` 和 `felt252` 类型之间进行转换。" -#: src/ch02-01-variables-and-mutability.md:208 +#: src/ch02-01-variables-and-mutability.md:209 msgid "" "```rust\n" "use debug::PrintTrait;\n" -"use traits::Into;\n" +"\n" "fn main() {\n" -" let x = 2;\n" +" let x: u64 = 2;\n" " x.print();\n" " let x: felt252 = x.into(); // converts x to a felt, type annotation is required.\n" " x.print()\n" @@ -1948,16 +1545,16 @@ msgid "" msgstr "" "```rust\n" "use debug::PrintTrait;\n" -"use traits::Into;\n" +"\n" "fn main() {\n" -" let x = 2;\n" +" let x: u64 = 2;\n" " x.print();\n" " let x: felt252 = x.into(); // converts x to a felt, type annotation is required.\n" " x.print()\n" "}\n" "```" -#: src/ch02-01-variables-and-mutability.md:219 +#: src/ch02-01-variables-and-mutability.md:220 msgid "" "The first `x` variable has a `u64` type while the second `x` variable has a `felt252` type.\n" "Shadowing thus spares us from having to come up with different names, such as `x_u64`\n" @@ -1969,57 +1566,59 @@ msgstr "" "相反,我们可以重新使用更简单的 `x` 名称。然而,如果我们试图使用\n" "`mut` 来实现,我们会得到一个编译时错误,如下所示:" -#: src/ch02-01-variables-and-mutability.md:224 +#: src/ch02-01-variables-and-mutability.md:225 msgid "" "```rust,does_not_compile\n" +"//TAG: does_not_compile\n" "use debug::PrintTrait;\n" -"use traits::Into;\n" +"\n" "fn main() {\n" -" let mut x = 2;\n" +" let mut x: u64 = 2;\n" " x.print();\n" -" x = x.into();\n" +" x = 100_felt252;\n" " x.print()\n" "}\n" "```" msgstr "" "```rust,does_not_compile\n" +"//TAG: does_not_compile\n" "use debug::PrintTrait;\n" -"use traits::Into;\n" +"\n" "fn main() {\n" -" let mut x = 2;\n" +" let mut x: u64 = 2;\n" " x.print();\n" -" x = x.into();\n" +" x = 100_felt252;\n" " x.print()\n" "}\n" "```" -#: src/ch02-01-variables-and-mutability.md:235 +#: src/ch02-01-variables-and-mutability.md:237 msgid "The error says we were expecting a `u64` (the original type) but we got a different type:" msgstr "这个错误表示我们预期得到一个 `u64` 类型(原始类型),但实际得到了不同的类型:" -#: src/ch02-01-variables-and-mutability.md:237 +#: src/ch02-01-variables-and-mutability.md:239 msgid "" -"```console\n" -"❯ cairo-run src/lib.cairo\n" +"```shell\n" +"$ scarb cairo-run\n" "error: Unexpected argument type. Expected: \"core::integer::u64\", found: \"core::felt252\".\n" -" --> lib.cairo:6:9\n" -" x = x.into();\n" -" ^******^\n" +" --> lib.cairo:9:9\n" +" x = 100_felt252;\n" +" ^*********^\n" "\n" "Error: failed to compile: src/lib.cairo\n" "```" msgstr "" -"```console\n" -"❯ cairo-run src/lib.cairo\n" -"error: Unexpected argument type. Expected: “core::integer::u64”, found: “core::felt252”.\n" -" —> lib.cairo:6:9\n" -" x = x.into();\n" -" ^******^\n" +"```shell\n" +"$ scarb cairo-run\n" +"error: Unexpected argument type. Expected: \"core::integer::u64\", found: \"core::felt252\".\n" +" --> lib.cairo:9:9\n" +" x = 100_felt252;\n" +" ^*********^\n" "\n" "Error: failed to compile: src/lib.cairo\n" "```" -#: src/ch02-01-variables-and-mutability.md:247 +#: src/ch02-01-variables-and-mutability.md:249 msgid "" "Now that we’ve explored how variables work, let’s look at more data types they\n" "can have." @@ -2049,8 +1648,6 @@ msgstr "" #: src/ch02-02-data-types.md:10 msgid "" "```rust\n" -"use traits::TryInto;\n" -"use option::OptionTrait;\n" "fn main() {\n" " let x: felt252 = 3;\n" " let y: u32 = x.try_into().unwrap();\n" @@ -2058,23 +1655,21 @@ msgid "" "```" msgstr "" "```rust\n" -"use traits::TryInto;\n" -"use option::OptionTrait;\n" "fn main() {\n" " let x: felt252 = 3;\n" " let y: u32 = x.try_into().unwrap();\n" "}\n" "```" -#: src/ch02-02-data-types.md:19 +#: src/ch02-02-data-types.md:17 msgid "You’ll see different type annotations for other data types." msgstr "你会看到其它数据类型的各种类型注解。" -#: src/ch02-02-data-types.md:21 +#: src/ch02-02-data-types.md:19 msgid "### Scalar Types" msgstr "### 标量类型" -#: src/ch02-02-data-types.md:23 +#: src/ch02-02-data-types.md:21 msgid "" "A _scalar_ type represents a single value. Cairo has three primary scalar types:\n" "felts, integers, and booleans. You may recognize\n" @@ -2084,11 +1679,11 @@ msgstr "" "felts、整数(integers)和布尔值(booleans)。你可能在其他语言中见过它们。\n" "让我们深入了解它们在 Cairo 中是如何工作的。" -#: src/ch02-02-data-types.md:27 +#: src/ch02-02-data-types.md:25 msgid "#### Felt Type" msgstr "#### Felt 类型" -#: src/ch02-02-data-types.md:29 +#: src/ch02-02-data-types.md:27 msgid "" "In Cairo, if you don't specify the type of a variable or argument, its type defaults to a field element, represented by the keyword `felt252`. In the context of Cairo, when we say “a " "field element” we mean an integer in the range `0 <= x < P`,\n" @@ -2100,7 +1695,7 @@ msgstr "" "其中 `P` 是一个非常大的素数,目前为 `P = 2^{251} + 17 * 2^{192}+1`。当加减乘时,如果结果超出了素数的指定范围,就会发生溢出,然后再加上或减去 P 的适当倍数,使结果回到范围内(也就是说," "结果是以 P 为模数计算的)。" -#: src/ch02-02-data-types.md:32 +#: src/ch02-02-data-types.md:30 msgid "" "The most important difference between integers and field elements is division: Division of field elements (and therefore division in Cairo) is unlike regular CPUs division, where\n" "integer division `x / y` is defined as `[x/y]` where the integer part of the quotient is returned (so you get `7 / 3 = 2`) and it may or may not satisfy the equation `(x / y) * y == " @@ -2110,7 +1705,7 @@ msgstr "" "整数和字段元素之间最重要的区别是除法:字段元素的除法(以及 Cairo 的除法)与普通 CPU 的除法不同,其中整数除法 `x / y` 被定义为`[x/y]`,\n" "其中商的整数部分被返回(所以你得到`7 / 3 = 2`),它可能满足或不满足方程式 `(x / y) * y == x`,这取决于 `x` 是否能被 `y` 除。" -#: src/ch02-02-data-types.md:36 +#: src/ch02-02-data-types.md:34 msgid "" "In Cairo, the result of `x/y` is defined to always satisfy the equation `(x / y) * y == x`. If y divides x as integers, you will get the expected result in Cairo (for example `6 / " "2`\n" @@ -2118,15 +1713,15 @@ msgid "" "But when y does not divide x, you may get a surprising result: For example, since `2 * ((P+1)/2) = P+1 ≡ 1 mod[P]`, the value of `1 / 2` in Cairo is `(P+1)/2` (and not 0 or 0.5), as " "it satisfies the above equation." msgstr "" -"在 Cairo,`x/y` 的结果被定义为总是满足方程式 `(x / y) * y == x`。如果y除以x为整数,你将得到 Cairo 的预期结果(例如,`6 / 2` 确实会得到`3`)。\n" -"但是当 y 不除以 x 时,你可能会得到一个令人惊讶的结果:\n" +"在 Cairo,`x/y` 的结果被定义为总是满足方程式 `(x / y) * y == x`。如果 y 作为整数可以整除 x ,你将得到 Cairo 的预期结果(例如,`6 / 2` 确实会得到`3`)。\n" +"但是当 y 不能整除 x 时,你可能会得到一个令人惊讶的结果:\n" "例如,由于 `2 * ((P+1)/2) = P+1 ≡ 1 mod[P]`,在 Cairo 中 `1 / 2` 的值是 `(P+1)/2`(而不是0或0.5),因为它满足上述公式。" -#: src/ch02-02-data-types.md:40 +#: src/ch02-02-data-types.md:38 msgid "#### Integer Types" msgstr "#### 整数类型" -#: src/ch02-02-data-types.md:42 +#: src/ch02-02-data-types.md:40 msgid "" "The felt252 type is a fundamental type that serves as the basis for creating all types in the core library.\n" "However, it is highly recommended for programmers to use the integer types instead of the `felt252` type whenever possible, as the `integer` types come with added security features " @@ -2143,11 +1738,11 @@ msgstr "" "一个 _integer_ 是一个没有小数部分的数字。这个类型声明指出了该类型可以用来存储整数的比特位。\n" "表3-1显示了Cairo中内建的整数类型。我们可以使用这些变体中的任何一种来声明一个整数值的类型。" -#: src/ch02-02-data-types.md:49 +#: src/ch02-02-data-types.md:47 msgid "Table 3-1: Integer Types in Cairo" msgstr "表格3-1: Cairo 的整数类型" -#: src/ch02-02-data-types.md:51 +#: src/ch02-02-data-types.md:49 msgid "" "| Length | Unsigned |\n" "| ------- | -------- |\n" @@ -2169,7 +1764,7 @@ msgstr "" "| 256-bit | `u256` |\n" "| 32-bit | `usize` |" -#: src/ch02-02-data-types.md:61 +#: src/ch02-02-data-types.md:59 msgid "" "Each variant has an explicit size. Note that for now, the `usize` type is just an alias for `u32`; however, it might be useful when in the future Cairo can be compiled to MLIR.\n" "As variables are unsigned, they can't contain a negative number. This code will cause the program to panic:" @@ -2177,7 +1772,7 @@ msgstr "" "每个变量都有一个明确的大小。注意,现在,`usize `类型只是 `u32` 的别名;然而,当将来 Cairo 可以被编译为 MLIR 时,它可能会很有用。\n" "由于变量是无符号的,它们不能包含一个负数。这段代码会引起程序出现错误:" -#: src/ch02-02-data-types.md:64 +#: src/ch02-02-data-types.md:62 msgid "" "```rust\n" "fn sub_u8s(x: u8, y: u8) -> u8 {\n" @@ -2199,7 +1794,7 @@ msgstr "" "}\n" "```" -#: src/ch02-02-data-types.md:74 +#: src/ch02-02-data-types.md:72 msgid "" "You can write integer literals in any of the forms shown in Table 3-2. Note\n" "that number literals that can be multiple numeric types allow a type suffix,\n" @@ -2209,11 +1804,11 @@ msgstr "" "请注意可以是多种数字类型的数字字面值允许使用类型后缀,\n" "例如像 `57_u8` 这样指定类型。" -#: src/ch02-02-data-types.md:78 +#: src/ch02-02-data-types.md:76 msgid "Table 3-2: Integer Literals in Cairo" msgstr "表3-2:Cairo 的整数类型字面值" -#: src/ch02-02-data-types.md:80 +#: src/ch02-02-data-types.md:78 msgid "" "| Numeric literals | Example |\n" "| ---------------- | --------- |\n" @@ -2229,7 +1824,7 @@ msgstr "" "| Octal (八进制) | `0o04321` |\n" "| Binary (二进制) | `0b01` |" -#: src/ch02-02-data-types.md:87 +#: src/ch02-02-data-types.md:85 msgid "" "So how do you know which type of integer to use? Try to estimate the max value your int can have and choose the good size.\n" "The primary situation in which you’d use `usize` is when indexing some sort of collection." @@ -2237,11 +1832,11 @@ msgstr "" "那么,你如何知道要使用哪种类型的整数?试着估计你用的 int 的最大值,然后选择合适的大小。\n" " `usize` 的主要是用在为某种集合做索引时。" -#: src/ch02-02-data-types.md:90 +#: src/ch02-02-data-types.md:88 msgid "#### Numeric Operations" msgstr "#### 数值运算" -#: src/ch02-02-data-types.md:92 +#: src/ch02-02-data-types.md:90 msgid "" "Cairo supports the basic mathematical operations you’d expect for all the integer\n" "types: addition, subtraction, multiplication, division, and remainder. Integer\n" @@ -2250,9 +1845,9 @@ msgid "" msgstr "" "Cairo 支持所有整数类型的基本数学运算:\n" "加法、减法、乘法、除法和取余。\n" -"整数除法将向最接近的整数截断。以下代码展示了如何在 `let` 语句中使用它们:" +"整数除法将向最接近0的整数截断。以下代码展示了如何在 `let` 语句中使用它们:" -#: src/ch02-02-data-types.md:97 +#: src/ch02-02-data-types.md:95 msgid "" "```rust\n" "fn main() {\n" @@ -2294,21 +1889,21 @@ msgstr "" "}\n" "```" -#: src/ch02-02-data-types.md:117 +#: src/ch02-02-data-types.md:115 msgid "" "Each expression in these statements uses a mathematical operator and evaluates\n" "to a single value, which is then bound to a variable." msgstr "这些语句中的每个表达式使用了一个数学运算符并计算出了一个值,然后绑定给一个变量。" -#: src/ch02-02-data-types.md:120 +#: src/ch02-02-data-types.md:118 msgid "[Appendix B][appendix_b] contains a list of all operators that Cairo provides." msgstr "[附录 B][appendix_b] 包含了一个Cairo中所有操作符的列表。" -#: src/ch02-02-data-types.md:122 +#: src/ch02-02-data-types.md:120 msgid "#### The Boolean Type" msgstr "#### 布尔类型" -#: src/ch02-02-data-types.md:124 +#: src/ch02-02-data-types.md:122 msgid "" "As in most other programming languages, a Boolean type in Cairo has two possible\n" "values: `true` and `false`. Booleans are one felt252 in size. The Boolean type in\n" @@ -2317,7 +1912,7 @@ msgstr "" "正如其他大部分编程语言一样,Cairo 中的布尔类型有两个可能的值:`true` 和 `false`。布尔型的大小为一个 felt252。\n" "布尔类型在 Cairo 中是用 `bool` 来指定的。例如:" -#: src/ch02-02-data-types.md:128 +#: src/ch02-02-data-types.md:126 msgid "" "```rust\n" "fn main() {\n" @@ -2335,7 +1930,7 @@ msgstr "" "}\n" "```" -#: src/ch02-02-data-types.md:136 +#: src/ch02-02-data-types.md:134 msgid "" "The main way to use Boolean values is through conditionals, such as an `if`\n" "expression. We’ll cover how `if` expressions work in Cairo in the [“Control\n" @@ -2344,11 +1939,11 @@ msgstr "" "使用布尔值的主要方式是通过条件语句,如 `if` 表达式。\n" "我们将在[\"控制流”][control-flow]部分介绍 `if` 表达式在 Cairo 中的工作原理。" -#: src/ch02-02-data-types.md:140 +#: src/ch02-02-data-types.md:138 msgid "#### The Short String Type" msgstr "#### 短字符串类型" -#: src/ch02-02-data-types.md:142 +#: src/ch02-02-data-types.md:140 msgid "" "Cairo doesn't have a native type for strings, but you can store characters forming what we call a \"short string\" inside `felt252`s. A short string has a max length of 31 chars. " "This is to ensure that it can fit in a single felt (a felt is 252 bits, one ASCII char is 8 bits).\n" @@ -2358,7 +1953,7 @@ msgstr "" "252位,一个 ASCII 字符是 8 位)。\n" "可以通过把值放在单引号之间来声明短字符串,下面是一些例子:" -#: src/ch02-02-data-types.md:145 +#: src/ch02-02-data-types.md:143 msgid "" "```rust\n" "# fn main() {\n" @@ -2374,37 +1969,33 @@ msgstr "" "# }\n" "```" -#: src/ch02-02-data-types.md:152 +#: src/ch02-02-data-types.md:150 msgid "### Type casting" msgstr "### 类型转换" -#: src/ch02-02-data-types.md:154 +#: src/ch02-02-data-types.md:152 msgid "In Cairo, you can convert types scalar types from one type to another by using the `try_into` and `into` methods provided by the `TryInto` and `Into` traits, respectively." msgstr "在 Cairo 中,你可以使用 `TryInto` 和 `Into` 特性提供的 `try_into` 和 `into` 方法在标量类型之间进行显式类型转换。" -#: src/ch02-02-data-types.md:156 +#: src/ch02-02-data-types.md:154 msgid "" "The `try_into` method allows for safe type casting when the target type might not fit the source value. Keep in mind that `try_into` returns an `Option` type, which you'll need to " "unwrap to access the new value." msgstr "`try_into` 方法允许在目标类型可能不适合源值时进行安全的类型转换。请记住,`try_into` 会返回一个 `Option` 类型,你需要解开(unwrap)这个类型来访问新的值。" -#: src/ch02-02-data-types.md:158 +#: src/ch02-02-data-types.md:156 msgid "On the other hand, the `into` method can be used for type casting when success is guaranteed, such as when the source type is smaller than the destination type." msgstr "另一方面,当转换必然成功时,如源类型小于目标类型时,`into` 方法可用于类型转换。" -#: src/ch02-02-data-types.md:160 +#: src/ch02-02-data-types.md:158 msgid "" "To perform the conversion, call `var.into()` or `var.try_into()` on the source value to cast it to another type. The new variable's type must be explicitly defined, as demonstrated " "in the example below." msgstr "为了进行转换,在源值上调用 `var.into()` 或 `var.try_into()` 来将其转换为另一种类型。新变量的类型必须被明确定义,如下面的例子所示。" -#: src/ch02-02-data-types.md:162 +#: src/ch02-02-data-types.md:160 msgid "" "```rust\n" -"use traits::TryInto;\n" -"use traits::Into;\n" -"use option::OptionTrait;\n" -"\n" "fn main() {\n" " let my_felt252 = 10;\n" " // Since a felt252 might not fit in a u8, we need to unwrap the Option type\n" @@ -2422,10 +2013,6 @@ msgid "" "```" msgstr "" "```rust\n" -"use traits::TryInto;\n" -"use traits::Into;\n" -"use option::OptionTrait;\n" -"\n" "fn main() {\n" " let my_felt252 = 10;\n" " // Since a felt252 might not fit in a u8, we need to unwrap the Option type\n" @@ -2442,11 +2029,11 @@ msgstr "" "}\n" "```" -#: src/ch02-02-data-types.md:183 +#: src/ch02-02-data-types.md:177 msgid "### The Tuple Type" msgstr "### 元组类型" -#: src/ch02-02-data-types.md:185 +#: src/ch02-02-data-types.md:179 msgid "" "A _tuple_ is a general way of grouping together a number of values with a\n" "variety of types into one compound type. Tuples have a fixed length: once\n" @@ -2455,7 +2042,7 @@ msgstr "" "_元组_ 是一个将多个其他类型的值组合进一个复合类型的主要方式。\n" "元组长度固定:一旦声明,其长度不会增大或缩小。" -#: src/ch02-02-data-types.md:189 +#: src/ch02-02-data-types.md:183 msgid "" "We create a tuple by writing a comma-separated list of values inside\n" "parentheses. Each position in the tuple has a type, and the types of the\n" @@ -2466,7 +2053,7 @@ msgstr "" "元组中的每一个位置都有一个类型,而且这些不同值的类型也不必是相同的。\n" "这个例子中使用了可选的类型注解:" -#: src/ch02-02-data-types.md:194 +#: src/ch02-02-data-types.md:188 msgid "" "```rust\n" "fn main() {\n" @@ -2480,7 +2067,7 @@ msgstr "" "}\n" "```" -#: src/ch02-02-data-types.md:200 +#: src/ch02-02-data-types.md:194 msgid "" "The variable `tup` binds to the entire tuple because a tuple is considered a\n" "single compound element. To get the individual values out of a tuple, we can\n" @@ -2490,7 +2077,7 @@ msgstr "" "为了从元组中获取单个值,可以使用模式匹配(pattern matching)\n" "来解构(destructure)元组值,像这样:" -#: src/ch02-02-data-types.md:204 +#: src/ch02-02-data-types.md:198 msgid "" "```rust\n" "use debug::PrintTrait;\n" @@ -2518,7 +2105,7 @@ msgstr "" "}\n" "```" -#: src/ch02-02-data-types.md:217 +#: src/ch02-02-data-types.md:211 msgid "" "This program first creates a tuple and binds it to the variable `tup`. It then\n" "uses a pattern with `let` to take `tup` and turn it into three separate\n" @@ -2532,7 +2119,7 @@ msgstr "" "因为它将一个元组拆成了三个部分。最后,程序打印出了 `y` 的值,\n" "也就是 `6`。" -#: src/ch02-02-data-types.md:223 +#: src/ch02-02-data-types.md:217 msgid "" "We can also declare the tuple with value and types at the same time.\n" "For example:" @@ -2540,7 +2127,7 @@ msgstr "" "我们也可以同时用 value 和 name 来声明元组。\n" "比如说:" -#: src/ch02-02-data-types.md:226 +#: src/ch02-02-data-types.md:220 msgid "" "```rust\n" "fn main() {\n" @@ -2554,11 +2141,11 @@ msgstr "" "}\n" "```" -#: src/ch02-02-data-types.md:232 +#: src/ch02-02-data-types.md:226 msgid "### The unit type ()" msgstr "### unit类型 ()" -#: src/ch02-02-data-types.md:234 +#: src/ch02-02-data-types.md:228 msgid "" "A _unit type_ is a type which has only one value `()`.\n" "It is represented by a tuple with no elements.\n" @@ -2568,7 +2155,7 @@ msgstr "" "它由一个没有元素的元组来表示。\n" "它的大小总是为零,并且它在编译后的代码中一定不存在。" -#: src/ch02-03-functions.md:1 src/ch99-01-02-writing-starknet-contracts.md:134 +#: src/ch02-03-functions.md:1 msgid "## Functions" msgstr "## 函数" @@ -2653,14 +2240,14 @@ msgstr "" #: src/ch02-03-functions.md:40 msgid "" -"```console\n" -"$ cairo-run src/lib.cairo\n" +"```shell\n" +"$ scarb cairo-run\n" "[DEBUG] Hello, world! (raw: 5735816763073854953388147237921)\n" "[DEBUG] Another function. (raw: 22265147635379277118623944509513687592494)\n" "```" msgstr "" -"```console\n" -"$ cairo-run src/lib.cairo\n" +"```shell\n" +"$ scarb cairo-run\n" "[DEBUG] Hello, world! (raw: 5735816763073854953388147237921)\n" "[DEBUG] Another function. (raw: 22265147635379277118623944509513687592494)\n" "```" @@ -2725,15 +2312,15 @@ msgstr "" msgid "Try running this program; you should get the following output:" msgstr "尝试运行这个程序;你应该得到以下输出:" -#: src/ch02-03-functions.md:76 src/ch02-03-functions.md:256 +#: src/ch02-03-functions.md:76 src/ch02-03-functions.md:277 msgid "" -"```console\n" -"$ cairo-run src/lib.cairo\n" +"```shell\n" +"$ scarb cairo-run\n" "[DEBUG] (raw: 5)\n" "```" msgstr "" -"```console\n" -"$ cairo-run src/lib.cairo\n" +"```shell\n" +"$ scarb cairo-run\n" "[DEBUG] (raw: 5)\n" "```" @@ -2808,21 +2395,21 @@ msgstr "" #: src/ch02-03-functions.md:111 msgid "" "Let’s try running this code. Replace the program currently in your _functions_\n" -"project’s _src/lib.cairo_ file with the preceding example and run it using `cairo-run src/lib.cairo`:" +"project’s _src/lib.cairo_ file with the preceding example and run it using `scarb cairo-run`:" msgstr "" -"让我们试着运行这段代码。将目前在你的 _functions_ \n" -"项目的 _src/lib.cairo_ 文件中的程序,并使用 `cairo-run src/lib.cairo` 来运行它:" +"让我们试着运行这段代码。用前面的示例替换当前在你的 _functions_\n" +"项目的 _src/lib.cairo_ 文件中的程序,然后使用 `scarb cairo-run` 运行它:" #: src/ch02-03-functions.md:114 msgid "" -"```console\n" -"$ cairo-run src/lib.cairo\n" +"```shell\n" +"$ scarb cairo-run\n" "[DEBUG] (raw: 5)\n" "[DEBUG] (raw: 6)\n" "```" msgstr "" -"```console\n" -"$ cairo-run src/lib.cairo\n" +"```shell\n" +"$ scarb cairo-run\n" "[DEBUG] (raw: 5)\n" "[DEBUG] (raw: 6)\n" "```" @@ -2836,10 +2423,56 @@ msgstr "" "程序输出包含这些值。" #: src/ch02-03-functions.md:123 +msgid "#### Named parameters" +msgstr "### 命名参数" + +#: src/ch02-03-functions.md:125 +msgid "" +"In Cairo, named parameters allow you to specify the names of arguments when you call a function. This makes the function calls more readable and self-descriptive.\n" +"If you want to use named parameters, you need to specify the name of the parameter and the value you want to pass to it. The syntax is `parameter_name: value`. If you pass a variable " +"that has the same name as the parameter, you can simply write `:parameter_name` instead of `parameter_name: variable_name`." +msgstr "" +"在 Cairo 中,命名参数允许您在调用函数时指定参数的名称。这使得函数调用更具可读性和自描述性。\n" +"如果你想使用命名参数,你需要指定参数的名称和你想传递给它的值。语法是 `parameter_name: value`。如果你传递的变量与参数名称相同,你可以简写为 `:parameter_name`,而不是 `parameter_name: " +"variable_name`。" + +#: src/ch02-03-functions.md:128 +msgid "Here is an example:" +msgstr "下面是一个例子:" + +#: src/ch02-03-functions.md:130 +msgid "" +"```rust\n" +"fn foo(x: u8, y: u8) {}\n" +"\n" +"fn main() {\n" +" let first_arg = 3;\n" +" let second_arg = 4;\n" +" foo(x: first_arg, y: second_arg);\n" +" let x = 1;\n" +" let y = 2;\n" +" foo(:x, :y)\n" +"}\n" +"```" +msgstr "" +"```rust\n" +"fn foo(x: u8, y: u8) {}\n" +"\n" +"fn main() {\n" +" let first_arg = 3;\n" +" let second_arg = 4;\n" +" foo(x: first_arg, y: second_arg);\n" +" let x = 1;\n" +" let y = 2;\n" +" foo(:x, :y)\n" +"}\n" +"```" + +#: src/ch02-03-functions.md:143 msgid "### Statements and Expressions" msgstr "### 语句和表达式" -#: src/ch02-03-functions.md:125 +#: src/ch02-03-functions.md:145 msgid "" "Function bodies are made up of a series of statements optionally ending in an\n" "expression. So far, the functions we’ve covered haven’t included an ending\n" @@ -2855,7 +2488,7 @@ msgstr "" "(expression-based)的语言,这是一个需要理解的(不同于其他语言)\n" "重要区别。其他语言并没有这样的区别,所以让我们看看语句与表达式有什么区别以及这些区别是如何影响函数体的。" -#: src/ch02-03-functions.md:133 +#: src/ch02-03-functions.md:153 msgid "" "- **Statements** are instructions that perform some action and do not return\n" " a value.\n" @@ -2864,7 +2497,7 @@ msgstr "" "- **语句**(Statements)是执行一些操作但不返回值的指令。\n" "- **表达式**(Expressions)计算并产生一个值。让我们看一些例子。" -#: src/ch02-03-functions.md:137 +#: src/ch02-03-functions.md:157 msgid "" "We’ve actually already used statements and expressions. Creating a variable and\n" "assigning a value to it with the `let` keyword is a statement. In Listing 2-1,\n" @@ -2873,7 +2506,7 @@ msgstr "" "实际上,我们已经使用过语句和表达式。\n" "使用 `let` 关键字创建变量并绑定一个值是一个语句。在示例 2-1 中,`let y = 6;`; 是一个语句。" -#: src/ch02-03-functions.md:141 +#: src/ch02-03-functions.md:161 msgid "" "```rust\n" "fn main() {\n" @@ -2887,17 +2520,17 @@ msgstr "" "}\n" "```" -#: src/ch02-03-functions.md:147 +#: src/ch02-03-functions.md:167 msgid "Listing 2-1: A `main` function declaration containing one statement" msgstr "示例2-1:一个包含一条语句的 `main` 函数声明" -#: src/ch02-03-functions.md:149 +#: src/ch02-03-functions.md:169 msgid "" "Function definitions are also statements; the entire preceding example is a\n" "statement in itself." msgstr "函数定义也是语句,上面整个例子本身就是一个语句。" -#: src/ch02-03-functions.md:152 +#: src/ch02-03-functions.md:172 msgid "" "Statements do not return values. Therefore, you can’t assign a `let` statement\n" "to another variable, as the following code tries to do; you’ll get an error:" @@ -2905,28 +2538,30 @@ msgstr "" "语句不返回值。因此,不能把 `let` 语句赋值给另一个变量,比如下面的例子尝试做\n" "的,会产生一个错误:" -#: src/ch02-03-functions.md:155 +#: src/ch02-03-functions.md:175 msgid "" -"```rust,does_not_compile,ignore_format\n" +"```rust, noplayground\n" +"//TAG: does_not_compile, ignore_fmt\n" "fn main() {\n" " let x = (let y = 6);\n" "}\n" "```" msgstr "" -"```rust,does_not_compile,ignore_format\n" +"```rust, noplayground\n" +"//TAG: does_not_compile, ignore_fmt\n" "fn main() {\n" " let x = (let y = 6);\n" "}\n" "```" -#: src/ch02-03-functions.md:161 +#: src/ch02-03-functions.md:182 msgid "When you run this program, the error you’ll get looks like this:" msgstr "当你运行这个程序时,你将得到的错误看起来是这样:" -#: src/ch02-03-functions.md:163 +#: src/ch02-03-functions.md:184 msgid "" -"```console\n" -"$ cairo-run src/lib.cairo\n" +"```shell\n" +"$ scarb cairo-run\n" "error: Missing token TerminalRParen.\n" " --> src/lib.cairo:2:14\n" " let x = (let y = 6);\n" @@ -2947,29 +2582,29 @@ msgid "" " let x = (let y = 6);\n" "```" msgstr "" -"```console\n" -"$ cairo-run src/lib.cairo\n" +"```shell\n" +"$ scarb cairo-run\n" "error: Missing token TerminalRParen.\n" -" —> src/lib.cairo:2:14\n" +" --> src/lib.cairo:2:14\n" " let x = (let y = 6);\n" " ^\n" "\n" "error: Missing token TerminalSemicolon.\n" -" —> src/lib.cairo:2:14\n" +" --> src/lib.cairo:2:14\n" " let x = (let y = 6);\n" " ^\n" "\n" "error: Missing token TerminalSemicolon.\n" -" —> src/lib.cairo:2:14\n" +" --> src/lib.cairo:2:14\n" " let x = (let y = 6);\n" " ^\n" "\n" "error: Skipped tokens. Expected: statement.\n" -" —> src/lib.cairo:2:14\n" +" --> src/lib.cairo:2:14\n" " let x = (let y = 6);\n" "```" -#: src/ch02-03-functions.md:185 +#: src/ch02-03-functions.md:206 msgid "" "The `let y = 6` statement does not return a value, so there isn’t anything for\n" "`x` to bind to. This is different from what happens in other languages, such as\n" @@ -2981,7 +2616,7 @@ msgstr "" "中的情况不同,比如说 C 和 Ruby,其中赋值会返回赋值的值。\n" "在这些语言中,你可以写 `x = y = 6`,让 `x`和 `y` 都有值 `6`;但在 Cairo 中不是这样的。" -#: src/ch02-03-functions.md:191 +#: src/ch02-03-functions.md:212 msgid "" "Expressions evaluate to a value and make up most of the rest of the code that\n" "you’ll write in Cairo. Consider a math operation, such as `5 + 6`, which is an\n" @@ -2996,7 +2631,7 @@ msgstr "" "表达式可以是语句的一部分:在示例 2-1 中,语句 `let y = 6;` 中的 `6` 是一个表达式,它计算出的值是 `6` 。\n" "函数调用是一个表达式。宏调用也是一个表达式。用大括号创建的一个新的块作用域同样也是一个表达式,例如:" -#: src/ch02-03-functions.md:199 +#: src/ch02-03-functions.md:220 msgid "" "```rust\n" "use debug::PrintTrait;\n" @@ -3022,27 +2657,27 @@ msgstr "" "}\n" "```" -#: src/ch02-03-functions.md:211 +#: src/ch02-03-functions.md:232 msgid "This expression:" msgstr "这个表达式:" -#: src/ch02-03-functions.md:213 +#: src/ch02-03-functions.md:234 msgid "" -"```rust, does_not_compile, ignore_format\n" +"```rust, noplayground\n" "{\n" " let x = 3;\n" " x + 1\n" "}\n" "```" msgstr "" -"```rust, does_not_compile, ignore_format\n" +"```rust, noplayground\n" "{\n" " let x = 3;\n" " x + 1\n" "}\n" "```" -#: src/ch02-03-functions.md:220 +#: src/ch02-03-functions.md:241 msgid "" "is a block that, in this case, evaluates to `4`. That value gets bound to `y`\n" "as part of the `let` statement. Note that the `x + 1` line doesn’t have a\n" @@ -3057,11 +2692,11 @@ msgstr "" "分号。如果在表达式的结尾加上分号,它就变成了语句,而语句不会返回值。\n" "在接下来学习具有返回值的函数和表达式时要谨记这一点。" -#: src/ch02-03-functions.md:228 +#: src/ch02-03-functions.md:249 msgid "### Functions with Return Values" msgstr "### 具有返回值的函数" -#: src/ch02-03-functions.md:230 +#: src/ch02-03-functions.md:251 msgid "" "Functions can return values to the code that calls them. We don’t name return\n" "values, but we must declare their type after an arrow (`->`). In Cairo, the\n" @@ -3076,7 +2711,7 @@ msgstr "" "`return` 关键字和指定值,可从函数中提前返回;但大部分函数隐式的返回最后的表达式。\n" "这是一个有返回值的函数的例子:" -#: src/ch02-03-functions.md:238 +#: src/ch02-03-functions.md:259 msgid "" "```rust\n" "use debug::PrintTrait;\n" @@ -3104,7 +2739,7 @@ msgstr "" "}\n" "```" -#: src/ch02-03-functions.md:251 +#: src/ch02-03-functions.md:272 msgid "" "There are no function calls, or even `let` statements in the `five`\n" "function—just the number `5` by itself. That’s a perfectly valid function in\n" @@ -3115,7 +2750,7 @@ msgstr "" " Cairo 中是一个完全有效的函数。注意,也指定了函数返回值的类型,就是\n" " `-> u32`。尝试运行代码;输出应该看起来像这样:" -#: src/ch02-03-functions.md:261 +#: src/ch02-03-functions.md:282 msgid "" "The `5` in `five` is the function’s return value, which is why the return type\n" "is `u32`. Let’s examine this in more detail. There are two important bits:\n" @@ -3127,17 +2762,17 @@ msgstr "" "码。有两个重要的部分:首先,`let x = five();` 这一行表明我们使用函数的返回值初\n" "始化一个变量。因为 `five` 函数返回 `5`,这一行与如下代码相同:" -#: src/ch02-03-functions.md:267 +#: src/ch02-03-functions.md:288 msgid "" -"```rust, does_not_compile\n" +"```rust, noplayground\n" "let x = 5;\n" "```" msgstr "" -"```rust, does_not_compile\n" +"```rust, noplayground\n" "let x = 5;\n" "```" -#: src/ch02-03-functions.md:271 +#: src/ch02-03-functions.md:292 msgid "" "Second, the `five` function has no parameters and defines the type of the\n" "return value, but the body of the function is a lonely `5` with no semicolon\n" @@ -3148,7 +2783,7 @@ msgstr "" "有分号,因为这是一个表达式,我们想要返回它的值。\n" "让我们看看另一个例子:" -#: src/ch02-03-functions.md:276 +#: src/ch02-03-functions.md:297 msgid "" "```rust\n" "use debug::PrintTrait;\n" @@ -3178,7 +2813,7 @@ msgstr "" "}\n" "```" -#: src/ch02-03-functions.md:290 +#: src/ch02-03-functions.md:311 msgid "" "Running this code will print `[DEBUG] (raw: 6)`. But if we place a\n" "semicolon at the end of the line containing `x + 1`, changing it from an\n" @@ -3187,9 +2822,10 @@ msgstr "" "运行这段代码将打印 `[DEBUG] (raw: 6)`。但是如果在包含 `x + 1` 的行尾放置一个\n" "分号,把它从一个表达式变成一个语句,我们会看到一个错误:" -#: src/ch02-03-functions.md:294 +#: src/ch02-03-functions.md:315 msgid "" "```rust,does_not_compile\n" +"//TAG: does_not_compile\n" "use debug::PrintTrait;\n" "\n" "fn main() {\n" @@ -3204,6 +2840,7 @@ msgid "" "```" msgstr "" "```rust,does_not_compile\n" +"//TAG: does_not_compile\n" "use debug::PrintTrait;\n" "\n" "fn main() {\n" @@ -3217,21 +2854,21 @@ msgstr "" "}\n" "```" -#: src/ch02-03-functions.md:308 +#: src/ch02-03-functions.md:330 msgid "Compiling this code produces an error, as follows:" msgstr "编译这段代码会产生一个错误,如下所示:" -#: src/ch02-03-functions.md:310 +#: src/ch02-03-functions.md:332 msgid "" -"```console\n" +"```shell\n" "error: Unexpected return type. Expected: \"core::integer::u32\", found: \"()\".\n" "```" msgstr "" -"```console\n" +"```shell\n" "error: Unexpected return type. Expected: \"core::integer::u32\", found: \"()\".\n" "```" -#: src/ch02-03-functions.md:314 +#: src/ch02-03-functions.md:336 msgid "" "The main error message, `Unexpected return type`, reveals the core issue with this\n" "code. The definition of the function `plus_one` says that it will return an\n" @@ -3349,12 +2986,12 @@ msgstr "尝试运行这段代码;你应该看到以下输出:" #: src/ch02-05-control-flow.md:31 msgid "" -"```console\n" +"```shell\n" "$ cairo-run main.cairo\n" "[DEBUG]\tcondition was false\n" "```" msgstr "" -"```console\n" +"```shell\n" "$ cairo-run main.cairo\n" "[DEBUG]\tcondition was false\n" "```" @@ -3365,22 +3002,22 @@ msgstr "让我们试着改变 `number` 的值使条件为 `true` 时看看会发 #: src/ch02-05-control-flow.md:38 msgid "" -"```rust, does_not_compile\n" +"```rust, noplayground\n" " let number = 5;\n" "```" msgstr "" -"```rust, does_not_compile\n" +"```rust, noplayground\n" " let number = 5;\n" "```" #: src/ch02-05-control-flow.md:42 msgid "" -"```console\n" +"```shell\n" "$ cairo-run main.cairo\n" "condition was true\n" "```" msgstr "" -"```console\n" +"```shell\n" "$ cairo-run main.cairo\n" "condition was true\n" "```" @@ -3391,13 +3028,13 @@ msgstr "还值得注意的是,这段代码中的条件必须是一个 `bool` #: src/ch02-05-control-flow.md:49 msgid "" -"```console\n" +"```shell\n" "$ cairo-run main.cairo\n" "thread 'main' panicked at 'Failed to specialize: `enum_match`. Error: Could not specialize libfunc `enum_match` with generic_args: [Type(ConcreteTypeId { id: 1, debug_name: " "None })]. Error: Provided generic argument is unsupported.', crates/cairo-lang-sierra-generator/src/utils.rs:256:9\n" "```" msgstr "" -"```console\n" +"```shell\n" "$ cairo-run main.cairo\n" "thread 'main' panicked at 'Failed to specialize: `enum_match`. Error: Could not specialize libfunc `enum_match` with generic_args: [Type(ConcreteTypeId { id: 1, debug_name: " "None })]. Error: Provided generic argument is unsupported.', crates/cairo-lang-sierra-generator/src/utils.rs:256:9\n" @@ -3455,11 +3092,11 @@ msgstr "这个程序有四种可能的路径。运行后,你应该看到以下 #: src/ch02-05-control-flow.md:80 msgid "" -"```console\n" +"```shell\n" "[DEBUG]\tnumber is 3\n" "```" msgstr "" -"```console\n" +"```shell\n" "[DEBUG]\tnumber is 3\n" "```" @@ -3521,12 +3158,12 @@ msgstr "" #: src/ch02-05-control-flow.md:109 msgid "" -"```console\n" +"```shell\n" "$ cairo-run main.cairo\n" "[DEBUG]\tcondition was true\n" "```" msgstr "" -"```console\n" +"```shell\n" "$ cairo-run main.cairo\n" "[DEBUG]\tcondition was true\n" "```" @@ -3574,7 +3211,7 @@ msgid "" " let mut i: usize = 0;\n" " loop {\n" " if i > 10 {\n" -" break ();\n" +" break;\n" " }\n" " 'again!'.print();\n" " }\n" @@ -3587,7 +3224,7 @@ msgstr "" " let mut i: usize = 0;\n" " loop {\n" " if i > 10 {\n" -" break ();\n" +" break ;\n" " }\n" " 'again!'.print();\n" " }\n" @@ -3609,8 +3246,8 @@ msgstr "" #: src/ch02-05-control-flow.md:152 msgid "" -"```console\n" -"❯ cairo-run src/lib.cairo --available-gas=20000000\n" +"```shell\n" +"$ scarb cairo-run --available-gas=20000000\n" "[DEBUG]\tagain \t(raw: 418346264942)\n" "\n" "[DEBUG]\tagain \t(raw: 418346264942)\n" @@ -3623,8 +3260,8 @@ msgid "" "Remaining gas: 1050\n" "```" msgstr "" -"```console\n" -"❯ cairo-run src/lib.cairo --available-gas=20000000\n" +"```shell\n" +"$ scarb cairo-run --available-gas=20000000\n" "[DEBUG]\tagain \t(raw: 418346264942)\n" "\n" "[DEBUG]\tagain \t(raw: 418346264942)\n" @@ -3666,7 +3303,7 @@ msgid "" " let mut i: usize = 0;\n" " loop {\n" " if i > 10 {\n" -" break ();\n" +" break;\n" " }\n" " 'again'.print();\n" " i += 1;\n" @@ -3680,7 +3317,7 @@ msgstr "" " let mut i: usize = 0;\n" " loop {\n" " if i > 10 {\n" -" break ();\n" +" break;\n" " }\n" " 'again'.print();\n" " i += 1;\n" @@ -3702,7 +3339,7 @@ msgid "" " let mut i: usize = 0;\n" " loop {\n" " if i > 10 {\n" -" break ();\n" +" break;\n" " }\n" " if i == 5 {\n" " i += 1;\n" @@ -3720,7 +3357,7 @@ msgstr "" " let mut i: usize = 0;\n" " loop {\n" " if i > 10 {\n" -" break ();\n" +" break;\n" " }\n" " if i == 5 {\n" " i += 1;\n" @@ -3802,25 +3439,51 @@ msgstr "" "在循环的每一次迭代中,我们检查 `counter` 是否等于 `10`,然后在 `counter` 变量中加 `1`。当条件得到满足时,我们使用 `break` 关键字,其值为 `counter * 2`。在循环之后,我们用一个\n" "分号来结束给`result`赋值的语句。最后,我们打印`result`中的值,在本例中是`20`。" -#: src/ch02-06-common-collections.md:1 +#: src/ch02-05-control-flow.md:242 src/ch02-99-02-dictionaries.md:528 src/ch04-03-method-syntax.md:286 src/ch06-05-separating-modules-into-different-files.md:99 +msgid "## Summary" +msgstr "## 总结" + +#: src/ch02-05-control-flow.md:244 +msgid "" +"You made it! This was a sizable chapter: you learned about variables, data types, functions, comments,\n" +"`if` expressions and loops! To practice with the concepts discussed in this chapter,\n" +"try building programs to do the following:" +msgstr "" +"你成功了!这一章很重要:你学到了变量、数据类型、函数、注释、\n" +"`if` 表达式和循环!要练习本章讨论的概念、\n" +"尝试编写程序来完成下列操作:" + +#: src/ch02-05-control-flow.md:248 +msgid "" +"- Generate the _n_-th Fibonacci number.\n" +"- Compute the factorial of a number _n_." +msgstr "" +"- 产生第 _n_ 个斐波那契数。\n" +"- 计算一个数字的阶乘 _n_ 。" + +#: src/ch02-05-control-flow.md:251 +msgid "Now, we’ll review the common collection types in Cairo in the next chapter." +msgstr "现在,我们将在下一章回顾 Cairo 中常见的集合类型。" + +#: src/ch02-99-00-common-collections.md:1 msgid "## Common Collections" msgstr "## 常见集合" -#: src/ch02-06-common-collections.md:3 +#: src/ch02-99-00-common-collections.md:3 msgid "" -"Cairo1 provides a set of common collection types that can be used to store and manipulate data. These collections are designed to be efficient, flexible, and easy to use. This " -"section introduces the primary collection types available in Cairo1: `Array` and `Felt252Dict` (coming soon)." -msgstr "Cairo1提供了一套常用的集合类型,可用于存储和操作数据。这些集合被设计成高效、灵活和易于使用。本节介绍了Cairo1中的主要集合类型:`Array`和`Felt252Dict`(即将推出)。" +"Cairo provides a set of common collection types that can be used to store and manipulate data. These collections are designed to be efficient, flexible, and easy to use. This section " +"introduces the primary collection types available in Cairo: Arrays and Dictionaries." +msgstr "Cairo 提供了一组常用的集合类型,可用于存储和处理数据。这些集合设计得高效、灵活、易于使用。本节将介绍 Cairo 中可用的主要集合类型:数组和字典。" -#: src/ch02-06-common-collections.md:5 -msgid "### Array" -msgstr "### 数组" +#: src/ch02-99-01-arrays.md:1 +msgid "## Arrays" +msgstr "## 数组" -#: src/ch02-06-common-collections.md:7 +#: src/ch02-99-01-arrays.md:3 msgid "An array is a collection of elements of the same type. You can create and use array methods by importing the `array::ArrayTrait` trait." msgstr "一个数组是相同类型元素的集合。你可以通过导入`array::ArrayTrait`特质来创建和使用数组方法。" -#: src/ch02-06-common-collections.md:9 +#: src/ch02-99-01-arrays.md:5 msgid "" "An important thing to note is that arrays have limited modifications options. Arrays are, in fact, queues whose values can't be modified.\n" "This has to do with the fact that once a memory slot is written to, it cannot be overwritten, but only read from it. You can only append items to the end of an array and remove items " @@ -3829,19 +3492,17 @@ msgstr "" "需要注意的一个重要问题是,数组的修改选项有限。事实上,数组是队列,其值不能被修改。\n" "这与这样一个事实有关:一旦一个内存槽被写入,它就不能被覆盖,而只能从其中读出。你只能用`pop_front`将项目追加到数组的末端,并从前面删除项目。" -#: src/ch02-06-common-collections.md:12 -msgid "#### Creating an Array" -msgstr "#### 创建一个数组" +#: src/ch02-99-01-arrays.md:8 +msgid "### Creating an Array" +msgstr "### 创建一个数组" -#: src/ch02-06-common-collections.md:14 +#: src/ch02-99-01-arrays.md:10 msgid "Creating an Array is done with the `ArrayTrait::new()` call. Here is an example of the creation of an array to which we append 3 elements:" msgstr "创建一个数组是通过调用`ArrayTrait::new()`完成的。下面是一个创建3个元素的数组的例子:" -#: src/ch02-06-common-collections.md:16 +#: src/ch02-99-01-arrays.md:12 msgid "" "```rust\n" -"use array::ArrayTrait;\n" -"\n" "fn main() {\n" " let mut a = ArrayTrait::new();\n" " a.append(0);\n" @@ -3851,8 +3512,6 @@ msgid "" "```" msgstr "" "```rust\n" -"use array::ArrayTrait;\n" -"\n" "fn main() {\n" " let mut a = ArrayTrait::new();\n" " a.append(0);\n" @@ -3861,61 +3520,67 @@ msgstr "" "}\n" "```" -#: src/ch02-06-common-collections.md:27 -msgid "You can pass the expected type of items inside the array when instantiating the array like this" -msgstr "你可以在实例化数组时传递数组内项目的预期类型,像这样" +#: src/ch02-99-01-arrays.md:21 +msgid "When required, you can pass the expected type of items inside the array when instantiating the array like this, or explicitly define the type the variable." +msgstr "需要时,你可以在实例化数组时像下面这样传递数组内部项的预期类型,或者明确定义变量的类型。" -#: src/ch02-06-common-collections.md:29 +#: src/ch02-99-01-arrays.md:23 msgid "" -"```rust, does_not_compile\n" +"```rust, noplayground\n" "let mut arr = ArrayTrait::::new();\n" "```" msgstr "" -"```rust, does_not_compile\n" +"```rust, noplayground\n" "let mut arr = ArrayTrait::::new();\n" "```" -#: src/ch02-06-common-collections.md:33 -msgid "#### Updating an Array" -msgstr "#### 更新一个数组" +#: src/ch02-99-01-arrays.md:27 +msgid "" +"```rust, noplayground\n" +"let mut arr:Array = ArrayTrait::new();\n" +"```" +msgstr "" +"```rust, noplayground\n" +"let mut arr:Array = ArrayTrait::new();\n" +"```" + +#: src/ch02-99-01-arrays.md:31 +msgid "### Updating an Array" +msgstr "### 更新一个数组" -#: src/ch02-06-common-collections.md:35 -msgid "##### Adding Elements" -msgstr "##### 添加元素" +#: src/ch02-99-01-arrays.md:33 +msgid "#### Adding Elements" +msgstr "#### 添加元素" -#: src/ch02-06-common-collections.md:37 +#: src/ch02-99-01-arrays.md:35 msgid "To add an element to the end of an array, you can use the `append()` method:" msgstr "要在一个数组的末尾添加一个元素,可以使用`append()`方法:" -#: src/ch02-06-common-collections.md:39 +#: src/ch02-99-01-arrays.md:37 msgid "" "```rust\n" -"# use array::ArrayTrait;\n" -"# \n" "# fn main() {\n" "# let mut a = ArrayTrait::new();\n" -" a.append(0);\n" +"# a.append(0);\n" "# a.append(1);\n" -"# a.append(2);\n" +" a.append(2);\n" "# }\n" "```" msgstr "" "```rust\n" -"# use array::ArrayTrait;\n" -"# \n" "# fn main() {\n" "# let mut a = ArrayTrait::new();\n" -" a.append(0);\n" +"# a.append(0);\n" "# a.append(1);\n" -"# a.append(2);\n" +" a.append(2);\n" "# }\n" "```" -#: src/ch02-06-common-collections.md:50 -msgid "##### Removing Elements" -msgstr "##### 移除元素" +#: src/ch02-99-01-arrays.md:46 +msgid "#### Removing Elements" +msgstr "#### 移除元素" -#: src/ch02-06-common-collections.md:52 +#: src/ch02-99-01-arrays.md:48 msgid "" "You can only remove elements from the front of an array by using the `pop_front()` method.\n" "This method returns an `Option` containing the removed element, or `Option::None` if the array is empty." @@ -3923,11 +3588,9 @@ msgstr "" "要从一个数组的前面移除一个元素,你可以使用`pop_front()`方法。\n" "该方法返回一个包含被移除元素的`Option`。如果数组为空,则返回`Option::None`。" -#: src/ch02-06-common-collections.md:55 +#: src/ch02-99-01-arrays.md:51 msgid "" "```rust\n" -"use option::OptionTrait;\n" -"use array::ArrayTrait;\n" "use debug::PrintTrait;\n" "\n" "fn main() {\n" @@ -3942,8 +3605,6 @@ msgid "" "```" msgstr "" "```rust\n" -"use option::OptionTrait;\n" -"use array::ArrayTrait;\n" "use debug::PrintTrait;\n" "\n" "fn main() {\n" @@ -3957,11 +3618,11 @@ msgstr "" "}\n" "```" -#: src/ch02-06-common-collections.md:71 +#: src/ch02-99-01-arrays.md:65 msgid "The above code will print `10` as we remove the first element that was added." msgstr "上面的代码将打印`10`,因为我们删除了第一个被添加的元素。" -#: src/ch02-06-common-collections.md:73 +#: src/ch02-99-01-arrays.md:67 msgid "" "In Cairo, memory is immutable, which means that it is not possible to modify the elements of an array once they've been added. You can only add elements to the end of an array and " "remove elements from the front of an array. These operations do not require memory mutation, as they involve updating pointers rather than directly modifying the memory cells." @@ -3969,16 +3630,16 @@ msgstr "" "在Cairo中,内存是不可改变的,这意味着一旦数组中的元素被添加,就不可能修改它们。你只能将元素添加到数组的末端,并从数组的前端移除元素。这些操作不需要内存突变,因为它们涉及到更新指针而不" "是直接修改内存单元。" -#: src/ch02-06-common-collections.md:75 -msgid "#### Reading Elements from an Array" -msgstr "#### 从一个数组中读取元素" +#: src/ch02-99-01-arrays.md:69 +msgid "### Reading Elements from an Array" +msgstr "### 从数组中读取元素" -#: src/ch02-06-common-collections.md:77 +#: src/ch02-99-01-arrays.md:71 msgid "" "To access array elements, you can use `get()` or `at()` array methods that return different types. Using `arr.at(index)` is equivalent to using the subscripting operator `arr[index]`." msgstr "为了访问数组元素,你可以使用`get()`或`at()`数组方法,它们返回不同的类型。使用`arr.at(index)`等同于使用下标操作符`arr[index]`。" -#: src/ch02-06-common-collections.md:79 +#: src/ch02-99-01-arrays.md:73 msgid "" "The `get` function returns an `Option>`, which means it returns an option to a Box type (Cairo's smart-pointer type) containing a snapshot to the element at the specified " "index if that element exists in the array. If the element doesn't exist, `get` returns `None`. This method is useful when you expect to access indices that may not be within the " @@ -3988,7 +3649,7 @@ msgstr "" "`get`函数返回一个`Option>,这意味着它返回一个Box类型(Cairo的智能指针类型)的选项,包含一个指向指定索引的元素的快照,如果该元素在数组中存在。如果该元素不存在,`get`返回" "`None'。当你期望访问可能不在数组范围内的索引,并且希望优雅地处理这种情况而不发生恐慌时,这个方法很有用。快照将在[引用和快照](ch03-02-references-and-snapshots.md)章节中详细解释。" -#: src/ch02-06-common-collections.md:81 +#: src/ch02-99-01-arrays.md:75 msgid "" "The `at` function, on the other hand, directly returns a snapshot to the element at the specified index using the `unbox()` operator to extract the value stored in a box. If the " "index is out of bounds, a panic error occurs. You should only use at when you want the program to panic if the provided index is out of the array's bounds, which can prevent " @@ -3997,14 +3658,13 @@ msgstr "" "另一方面,`at`函数直接返回一个快照到指定索引的元素,使用`unbox()`操作符来提取存储在一个盒子里的值。如果索引超出了范围,就会发生一个恐慌性错误。你应该只在希望程序在提供的索引超出数组的" "边界时发生恐慌时使用at,这样可以防止意外的行为。" -#: src/ch02-06-common-collections.md:83 +#: src/ch02-99-01-arrays.md:77 msgid "In summary, use `at` when you want to panic on out-of-bounds access attempts, and use `get` when you prefer to handle such cases gracefully without panicking." msgstr "总之,当你想对越界访问尝试进行恐慌时,请使用`at`,而当你想优雅地处理这种情况而不恐慌时,请使用`get`。" -#: src/ch02-06-common-collections.md:85 +#: src/ch02-99-01-arrays.md:79 msgid "" "```rust\n" -"use array::ArrayTrait;\n" "fn main() {\n" " let mut a = ArrayTrait::new();\n" " a.append(0);\n" @@ -4016,7 +3676,6 @@ msgid "" "```" msgstr "" "```rust\n" -"use array::ArrayTrait;\n" "fn main() {\n" " let mut a = ArrayTrait::new();\n" " a.append(0);\n" @@ -4027,7 +3686,7 @@ msgstr "" "}\n" "```" -#: src/ch02-06-common-collections.md:97 +#: src/ch02-99-01-arrays.md:90 msgid "" "In this example, the variable named `first` will get the value `0` because that\n" "is the value at index `0` in the array. The variable named `second` will get\n" @@ -4037,15 +3696,13 @@ msgstr "" "是数组中索引为`0'的值。名为`second'的变量将得到\n" "从数组中的索引`1`处获得数值`1'。" -#: src/ch02-06-common-collections.md:101 +#: src/ch02-99-01-arrays.md:94 msgid "Here is an example with the `get()` method:" msgstr "下面是一个使用`get()`方法的例子:" -#: src/ch02-06-common-collections.md:103 +#: src/ch02-99-01-arrays.md:96 msgid "" -"```rust,ignore_format\n" -"use array::ArrayTrait;\n" -"use box::BoxTrait;\n" +"```rust\n" "fn main() -> u128 {\n" " let mut arr = ArrayTrait::::new();\n" " arr.append(100);\n" @@ -4054,7 +3711,7 @@ msgid "" " match arr.get(index_to_access) {\n" " Option::Some(x) => {\n" " *x.unbox()\n" -" // Don't worry about * for now, if you are curious see Chapter 3.2 #desnap operator\n" +" // Don't worry about * for now, if you are curious see Chapter 4.2 #desnap operator\n" " // It basically means \"transform what get(idx) returned into a real value\"\n" " },\n" " Option::None(_) => {\n" @@ -4066,9 +3723,7 @@ msgid "" "}\n" "```" msgstr "" -"```rust,ignore_format\n" -"use array::ArrayTrait;\n" -"use box::BoxTrait;\n" +"```rust\n" "fn main() -> u128 {\n" " let mut arr = ArrayTrait::::new();\n" " arr.append(100);\n" @@ -4077,7 +3732,7 @@ msgstr "" " match arr.get(index_to_access) {\n" " Option::Some(x) => {\n" " *x.unbox()\n" -" // Don't worry about * for now, if you are curious see Chapter 3.2 #desnap operator\n" +" // Don't worry about * for now, if you are curious see Chapter 4.2 #desnap operator\n" " // It basically means \"transform what get(idx) returned into a real value\"\n" " },\n" " Option::None(_) => {\n" @@ -4089,32 +3744,29 @@ msgstr "" "}\n" "```" -#: src/ch02-06-common-collections.md:126 -msgid "#### Size related methods" -msgstr "#### 数组体积相关的方法" +#: src/ch02-99-01-arrays.md:117 +msgid "### Size related methods" +msgstr "### 数组大小相关的方法" -#: src/ch02-06-common-collections.md:128 +#: src/ch02-99-01-arrays.md:119 msgid "To determine the number of elements in an array, use the `len()` method. The return is of type `usize`." msgstr "要确定一个数组中的元素数量,请使用`len()`方法。其返回值为`usize`类型。" -#: src/ch02-06-common-collections.md:130 +#: src/ch02-99-01-arrays.md:121 msgid "If you want to check if an array is empty or not, you can use the `is_empty()` method, which returns `true` if the array is empty and `false` otherwise." msgstr "如果你想检查一个数组是否为空,你可以使用`is_empty()`方法,如果数组为空,返回`true`,否则返回`false`。" -#: src/ch02-06-common-collections.md:132 -msgid "#### Storing multiple types with Enums" -msgstr "#### 用Enums存储多种类型" +#: src/ch02-99-01-arrays.md:123 +msgid "### Storing multiple types with Enums" +msgstr "### 用Enums存储多种类型" -#: src/ch02-06-common-collections.md:134 +#: src/ch02-99-01-arrays.md:125 msgid "If you want to store elements of different types in an array, you can use an `Enum` to define a custom data type that can hold multiple types." msgstr "如果你想在一个数组中存储不同类型的元素,你可以使用`Enum`来定义一个可以容纳多种类型的自定义数据类型。" -#: src/ch02-06-common-collections.md:136 +#: src/ch02-99-01-arrays.md:127 msgid "" "```rust\n" -"use array::ArrayTrait;\n" -"use traits::Into;\n" -"\n" "#[derive(Copy, Drop)]\n" "enum Data {\n" " Integer: u128,\n" @@ -4131,9 +3783,6 @@ msgid "" "```" msgstr "" "```rust\n" -"use array::ArrayTrait;\n" -"use traits::Into;\n" -"\n" "#[derive(Copy, Drop)]\n" "enum Data {\n" " Integer: u128,\n" @@ -4149,11 +3798,11 @@ msgstr "" "}\n" "```" -#: src/ch02-06-common-collections.md:155 -msgid "#### Span" -msgstr "#### Span" +#: src/ch02-99-01-arrays.md:143 +msgid "### Span" +msgstr "### Span" -#: src/ch02-06-common-collections.md:157 +#: src/ch02-99-01-arrays.md:145 msgid "" "`Span` is a struct that represents a snapshot of an `Array`. It is designed to provide safe and controlled access to the elements of an array without modifying the original array. " "Span is particularly useful for ensuring data integrity and avoiding borrowing issues when passing arrays between functions or when performing read-only operations (cf. [References " @@ -4162,2276 +3811,2510 @@ msgstr "" "`Span`是一个结构,代表一个 \"数组 \"的快照(snapshot)。它被设计用来提供对数组元素的安全和控制的访问,而不需要修改原始数组。Span对于确保数据的完整性和避免在函数间传递数组或执行只读操" "作时的借用问题特别有用(参见[引用和快照](ch03-02-references-and-snapshots.md))" -#: src/ch02-06-common-collections.md:159 +#: src/ch02-99-01-arrays.md:147 msgid "All methods provided by `Array` can also be used with `Span`, with the exception of the `append()` method." msgstr "除了 `append()`方法外,`Array`提供的其他所有方法都可以用于 `Span`。" -#: src/ch02-06-common-collections.md:161 -msgid "##### Turning an Array into span" -msgstr "##### 将一个数组变成span" +#: src/ch02-99-01-arrays.md:149 +msgid "#### Turning an Array into span" +msgstr "#### 将一个数组变成span" -#: src/ch02-06-common-collections.md:163 +#: src/ch02-99-01-arrays.md:151 msgid "To create a `Span` of an `Array`, call the `span()` method:" msgstr "要创建一个 `Array`的 `Span` ,请调用`span()`方法:" -#: src/ch02-06-common-collections.md:165 +#: src/ch02-99-01-arrays.md:153 msgid "" "```rust\n" -"# use array::ArrayTrait;\n" -"# \n" "# fn main() {\n" -"# let mut array = ArrayTrait::new();\n" -" array.span()\n" +"# let mut array: Array = ArrayTrait::new();\n" +"# array.span();\n" "# }\n" "```" msgstr "" "```rust\n" -"# use array::ArrayTrait;\n" -"# \n" "# fn main() {\n" -"# let mut array = ArrayTrait::new();\n" -" array.span()\n" +"# let mut array: Array = ArrayTrait::new();\n" +"# array.span();\n" "# }\n" "```" -#: src/ch02-06-common-collections.md:174 src/ch04-03-method-syntax.md:286 src/ch06-05-separating-modules-into-different-files.md:98 -msgid "## Summary" -msgstr "## 总结" +#: src/ch02-99-02-dictionaries.md:1 +msgid "## Dictionaries" +msgstr "## 字典" -#: src/ch02-06-common-collections.md:176 +#: src/ch02-99-02-dictionaries.md:3 msgid "" -"You made it! This was a sizable chapter: you learned about variables, data types, functions, comments,\n" -"`if` expressions, loops, and common collections! To practice with the concepts discussed in this chapter,\n" -"try building programs to do the following:" +"Cairo provides in its core library a dictionary-like type. The `Felt252Dict` data type represents a collection of key-value pairs where each key is unique and associated with a " +"corresponding value. This type of data structure is known differently across different programming languages such as maps, hash tables, associative arrays and many others." msgstr "" -"你成功了!这是一个相当大的章节:你学习了变量、数据类型、函数、注释、\n" -"`if`表达式、循环和常见的集合!为了练习本章所讨论的概念、\n" -"试着建立程序来做以下事情:" +"Cairo在其核心库中提供了一个类似字典的类型。`Felt252Dict` 数据类型表示键值对的集合,其中每个键都是唯一的,并与相应的值相关联。这种类型的数据结构在不同的编程语言中有不同的名称,如映" +"射、哈希表、关联数组等。" -#: src/ch02-06-common-collections.md:180 +#: src/ch02-99-02-dictionaries.md:5 msgid "" -"- Generate the _n_-th Fibonacci number.\n" -"- Compute the factorial of a number _n_." -msgstr "" -"- 产生第 _n_ 个斐波那契数。\n" -"- 计算一个数字的阶乘 _n_ 。" +"The `Felt252Dict` type is useful when you want to organize your data in a certain way for which using an `Array` and indexing doesn't suffice. Cairo dictionaries also allow the " +"programmer to easily simulate the existence of mutable memory when there is none." +msgstr "`Felt252Dict` 类型在你想以某种方式组织数据而使用`Array`和索引不能满足要求时非常有用。Cairo字典还允许程序员在内存非可变的情况下轻松地模拟可变内存。" -#: src/ch02-06-common-collections.md:183 +#: src/ch02-99-02-dictionaries.md:7 +msgid "### Basic Use of Dictionaries" +msgstr "### 字典的基本用法" + +#: src/ch02-99-02-dictionaries.md:9 msgid "" -"When you’re ready to move on, we’ll talk about a concept that Cairo shares with Rust and that _doesn’t_\n" -"commonly exist in other programming languages: ownership." -msgstr "当你准备好继续前进时,我们将讨论一个Cairo与Rust共有,而在其他编程语言中通常不存在的概念:所有权。" +"It is normal in other languages when creating a new dictionary to define the data types of both key and value. In Cairo, the key type is restricted to `felt252` leaving only the " +"possibility to specify the value data type, represented by `T` in `Felt252Dict`." +msgstr "在其他语言中, 当创建一个新的字典时, 通常需要定义键和值的数据类型。在Cairo中,键类型被限制为`felt252`,你只能指定值数据的类型,这在`Felt252Dict`中用`T`表示。" -#: src/ch03-00-understanding-ownership.md:1 -msgid "# Understanding Cairo's Ownership system" -msgstr "# 了解Cairo的所有权制度" +#: src/ch02-99-02-dictionaries.md:11 +msgid "The core functionality of a `Felt252Dict` is implemented in the trait `Felt252DictTrait` which includes all basic operations. Among them we can find:" +msgstr "`Felt252Dict`的核心功能在trait `Felt252DictTrait`中实现,它包括所有的基本操作。在其中我们可以看到:" -#: src/ch03-00-understanding-ownership.md:3 +#: src/ch02-99-02-dictionaries.md:13 msgid "" -"Cairo is a language built around a linear type system that allows us to\n" -"statically ensure that in every Cairo program, a value is used exactly once.\n" -"This linear type system helps preventing runtime errors by ensuring that operations that could cause such errors, such as writing twice to a memory cell, are detected at compile " -"time.\n" -"This is achieved by implementing an ownership system\n" -"and forbidding copying and dropping values by default. In this chapter, we’ll\n" -"talk about Cairo's ownership system as well as references and snapshots." +"1. `insert(felt252, T) -> ()` to write values to a dictionary instance and\n" +"2. `get(felt252) -> T` to read values from it." msgstr "" -"Cairo是一种围绕着线性类型系统建立的语言,它允许我们\n" -"静态地确保在每个Cairo程序中,一个值只被使用一次。\n" -"这种线性类型系统有助于防止运行时错误,因为它可以确保在编译时检测到可能导致这种错误的操作,如向一个内存单元写两次。\n" -"这是通过实施一个所有权系统来实现的\n" -"并在默认情况下禁止复制和丢弃数值。在本章中,我们将\n" -"讨论Cairo的所有权系统以及引用和快照(snapshot)。" - -#: src/ch03-01-what-is-ownership.md:1 -msgid "## What Is Ownership?" -msgstr "## 什么是所有权?" +"1. `insert(felt252, T) -> ()`向字典实例写入值,以及\n" +"2. `get(felt252) -> T` 从字典中读取值。" -#: src/ch03-01-what-is-ownership.md:3 +#: src/ch02-99-02-dictionaries.md:16 msgid "" -"Cairo implements an ownership system to ensure the safety and correctness of its compiled code.\n" -"The ownership mechanism complements the linear type system, which enforces that objects are used exactly once.\n" -"This helps prevent common operations that can produce runtime errors, such as illegal memory address\n" -"references or multiple writes to the same memory address, and ensures the soundness of Cairo programs\n" -"by checking at compile time that all the dictionaries are squashed." -msgstr "" -"Cairo实现了一个所有权系统以确保其编译代码的安全性和正确性。\n" -"所有权机制是对线性类型系统的补充,该系统规定对象只能使用一次。\n" -"这有助于防止可能产生运行时错误的常见操作,如非法的内存地址引用或对同一内存地址的多次写入,\n" -"并通过在编译时检查所有的字典是否被压缩(squash)来确保Cairo程序的正确性。" +"These functions allow us to manipulate dictionaries like in any other language. In the following example, we create a dictionary to represent a mapping between individuals and their " +"balance:" +msgstr "这些函数允许我们使用其他语言一样的方法来操作字典。在下面的示例中,我们创建一个字典来表示个体及其余额之间的映射:" -#: src/ch03-01-what-is-ownership.md:9 +#: src/ch02-99-02-dictionaries.md:18 msgid "" -"Now that we’re past basic Cairo syntax, we won’t include all the `fn main() {`\n" -"code in examples, so if you’re following along, make sure to put the following\n" -"examples inside a `main` function manually. As a result, our examples will be a\n" -"bit more concise, letting us focus on the actual details rather than\n" -"boilerplate code." +"```rust\n" +"fn main() {\n" +" let mut balances: Felt252Dict = Default::default();\n" +"\n" +" balances.insert('Alex', 100);\n" +" balances.insert('Maria', 200);\n" +"\n" +" let alex_balance = balances.get('Alex');\n" +" assert(alex_balance == 100, 'Balance is not 100');\n" +"\n" +" let maria_balance = balances.get('Maria');\n" +" assert(maria_balance == 200, 'Balance is not 200');\n" +"}\n" +"```" msgstr "" -"既然我们已经掌握了Cairo基本语法,我们将不会在之后的例子中包含 `fn main() {` 代码,\n" -"所以如果你是一路跟过来的,必须手动将之后例子的代码放入一个 `main` 函数中。\n" -"这样,例子将显得更加简明,使我们可以关注实际细节而不是样板代码。" - -#: src/ch03-01-what-is-ownership.md:15 -msgid "### Ownership Rules" -msgstr "### 所有权规则" +"```rust\n" +"fn main() {\n" +" let mut balances: Felt252Dict = Default::default();\n" +"\n" +" balances.insert('Alex', 100);\n" +" balances.insert('Maria', 200);\n" +"\n" +" let alex_balance = balances.get('Alex');\n" +" assert(alex_balance == 100, 'Balance is not 100');\n" +"\n" +" let maria_balance = balances.get('Maria');\n" +" assert(maria_balance == 200, 'Balance is not 200');\n" +"}\n" +"```" -#: src/ch03-01-what-is-ownership.md:17 +#: src/ch02-99-02-dictionaries.md:33 msgid "" -"First, let’s take a look at the ownership rules. Keep these rules in mind as we\n" -"work through the examples that illustrate them:" -msgstr "首先,让我们看一下所有权规则。请牢记这些规则,我们将通过例子来说明它们:" +"The first thing we do is import `Felt252DictTrait` which brings to scope all the methods we need to interact with the dictionary. Next, we create a new instance of `Felt252Dict` " +"by using the `default` method of the `Default` trait and added two individuals, each one with their own balance, using the `insert` method. Finally, we checked the balance of our " +"users with the `get` method." +msgstr "" +"我们做的第一件事是导入`Felt252DictTrait`,它将我们需要与字典交互的所有方法导入到作用域。接下来,我们使用`Default`trait的`default`方法创建一个新的`Felt252Dict`实例,并使用`insert`" +"方法添加两个个体,每个个体都有自己的余额。最后,我们使用`get`方法检查了用户的余额。" -#: src/ch03-01-what-is-ownership.md:20 +#: src/ch02-99-02-dictionaries.md:35 msgid "" -"- Each value in Cairo has an _owner_.\n" -"- There can only be one owner at a time.\n" -"- When the owner goes out of scope, the value will be _dropped_." +"Throughout the book we have talked about how Cairo's memory is immutable, meaning you can only write to a memory cell once but the `Felt252Dict` type represents a way to overcome " +"this obstacle. We will explain how this is implemented later on in [Dictionaries Underneath](#dictionaries-underneath)." msgstr "" -"- Cairo的每个值都有一个 _所有者_ 。\n" -"- 在同一时间只能有一个所有者。\n" -"- 当所有者超出作用域(scope)时,该值将被 _丢弃_ 。" +"在整本书中,我们都在说Cairo的内存是不可变的,这意味着你只能向一个内存单元写入一次,但是 `Felt252Dict` 类型代表了一种克服这一障碍的方法。我们将在后面的[深入Cairo的字典]" +"(#dictionaries-underneath)中解释如何实现。" -#: src/ch03-01-what-is-ownership.md:24 -msgid "### Variable Scope" -msgstr "### 变量作用域" - -#: src/ch03-01-what-is-ownership.md:26 -msgid "" -"As a first example of ownership, we’ll look at the _scope_ of some variables. A\n" -"scope is the range within a program for which an item is valid. Take the\n" -"following variable:" -msgstr "在所有权的第一个例子中,我们看看一些变量的 作用域( _scope_ )。作用域是一个项(item)在程序中有效的范围。假设有这样一个变量:" +#: src/ch02-99-02-dictionaries.md:37 +msgid "Building upon our previous example, let us show a code example where the balance of the same user changes:" +msgstr "在前面示例的基础上,让我们展示一个同一用户的余额产生变化的代码示例:" -#: src/ch03-01-what-is-ownership.md:30 +#: src/ch02-99-02-dictionaries.md:39 msgid "" "```rust\n" -"let s = 'hello';\n" +"fn main() {\n" +" let mut balances: Felt252Dict = Default::default();\n" +"\n" +" // Insert Alex with 100 balance\n" +" balances.insert('Alex', 100);\n" +" // Check that Alex has indeed 100 asociated with him\n" +" let alex_balance = balances.get('Alex');\n" +" assert(alex_balance == 100, 'Alex balance is not 100');\n" +"\n" +" // Insert Alex again, this time with 200 balance\n" +" balances.insert('Alex', 200);\n" +" // Check the new balance is correct\n" +" let alex_balance_2 = balances.get('Alex');\n" +" assert(alex_balance_2 == 200, 'Alex balance is not 200');\n" +"}\n" "```" msgstr "" "```rust\n" -"let s = ‘hello’;\n" +"fn main() {\n" +" let mut balances: Felt252Dict = Default::default();\n" +"\n" +" // Insert Alex with 100 balance\n" +" balances.insert('Alex', 100);\n" +" // Check that Alex has indeed 100 asociated with him\n" +" let alex_balance = balances.get('Alex');\n" +" assert(alex_balance == 100, 'Alex balance is not 100');\n" +"\n" +" // Insert Alex again, this time with 200 balance\n" +" balances.insert('Alex', 200);\n" +" // Check the new balance is correct\n" +" let alex_balance_2 = balances.get('Alex');\n" +" assert(alex_balance_2 == 200, 'Alex balance is not 200');\n" +"}\n" "```" -#: src/ch03-01-what-is-ownership.md:34 +#: src/ch02-99-02-dictionaries.md:57 msgid "" -"The variable `s` refers to a short string, where the value of the string is\n" -"hardcoded into the text of our program. The variable is valid from the point at\n" -"which it’s declared until the end of the current _scope_. Listing 3-1 shows a\n" -"program with comments annotating where the variable `s` would be valid." +"Notice how in this example we added the _Alex_ individual twice, each time using a different balance and each time that we checked for its balance it had the last value inserted! " +"`Felt252Dict` effectively allows us to \"rewrite\" the stored value for any given key." msgstr "" -"变量`s`指的是一个短字符串,字符串的值被硬编码到我们的程序文本中。\n" -"这个变量从它被声明的那一刻起,一直到当前 _scope_ 的结束,都是有效的。\n" -"示例3-1的程序中的注释标明了变量 `s` 在何处是有效的。" +"注意在这个示例中,我们是添加 _Alex_ 这个个体两次,每次都使用了不同的余额,并且每次我们检查它的余额时,它都显示出了最新的值!`Felt252Dict`使得我们可以 \"重写 \"任何给定的键中所存储" +"值。" -#: src/ch03-01-what-is-ownership.md:39 +#: src/ch02-99-02-dictionaries.md:59 msgid "" -"```rust\n" -"# fn main() {\n" -" { // s is not valid here, it’s not yet declared\n" -" let s = 'hello'; // s is valid from this point forward\n" -"\n" -" // do stuff with s\n" -" } // this scope is now over, and s is no longer valid\n" -"# }\n" -"```" +"Before heading on and explaining how dictionaries are implemented it is worth mentioning that once you instantiate a `Felt252Dict`, behind the scenes all keys have their " +"associated values initialized as zero. This means that if for example, you tried to get the balance of an inexistent user you will get 0 instead of an error or an undefined value. " +"This also means there is no way to delete data from a dictionary. Something to take into account when incorporating this structure into your code." msgstr "" -"```rust\n" -"# fn main() {\n" -" { // s is not valid here, it’s not yet declared\n" -" let s = 'hello'; // s is valid from this point forward\n" -"\n" -" // do stuff with s\n" -" } // this scope is now over, and s is no longer valid\n" -"# }\n" -"```" +"在继续解释字典是如何实现的之前,值得一提的是,一旦你实例化了一个 `Felt252Dict`,其所有的键值都将被初始化为0。这意味着,例如,如果你试图获取一个不存在的用户的余额,你将得到0,而不是" +"一个错误或未定义的值。这也意味着无法从字典中删除数据。在代码中使用这歌结构纳时你需要考虑到这一点。" -#: src/ch03-01-what-is-ownership.md:49 +#: src/ch02-99-02-dictionaries.md:61 msgid "" -"Listing 3-1: A variable and the scope in which it is\n" -"valid" -msgstr "示例3-1:一个变量和其有效的作用域" +"Until this point, we have seen all the basic features of `Felt252Dict` and how it mimics the same behavior as the corresponding data structures in any other language, that is, " +"externally of course. Cairo is at its core a non-deterministic Turing-complete programming language, very different from any other popular language in existence, which as a " +"consequence means that dictionaries are implemented very differently as well!" +msgstr "" +"到此为止,我们已经了解了 `Felt252Dict` 的所有基本特性,以及它是如何在外部表现上模仿其他语言中相应数据结构的。Cairo的核心是一种非确定的图灵完备的编程语言,与其他任何流行的语言都有很" +"大的不同,这意味着字典的实现也有很大的不同!" -#: src/ch03-01-what-is-ownership.md:52 -msgid "In other words, there are two important points in time here:" -msgstr "换句话说,这里有两个重要的时间点:" +#: src/ch02-99-02-dictionaries.md:63 +msgid "" +"In the following sections, we are going to give some insights about `Felt252Dict` inner mechanisms and the compromises that were taken to make them work. After that, we are going " +"to take a look at how to use dictionaries with other data structures as well as use the `entry` method as another way to interact with them." +msgstr "" +"在下面的章节中,我们将深入介绍 `Felt252Dict` 的内部机制以及为使其正常工作而做出的妥协。之后,我们将介绍如何将字典与其他数据结构一起使用,以及使用`entry`方法作为与字典交互的另一种方" +"式。" + +#: src/ch02-99-02-dictionaries.md:65 +msgid "### Dictionaries Underneath" +msgstr "### 深入Cairo的字典" -#: src/ch03-01-what-is-ownership.md:54 +#: src/ch02-99-02-dictionaries.md:67 msgid "" -"- When `s` comes _into_ scope, it is valid.\n" -"- It remains valid until it goes _out of_ scope." +"One of the constraints of Cairo's non-deterministic design is that its memory system is immutable, so in order to simulate mutability, the language implements `Felt252Dict` as a " +"list of entries. Each of the entries represents a time when a dictionary was accessed for reading/updating/writing purposes. An entry has three fields:" msgstr "" -"- 当`s`进入 _进入作用域_ 时,它就是有效的。\n" -"- 这一直持续到它 _离开_ 作用域 为止。" +"Cairo的非确定性设计的限制之一是它的内存系统是不可变的,因此为了模拟可变性,语言将`Felt252Dict`实现为一个条目(entry)列表。每个条目代表了字典被读取/更新/写入的时间。一个条目有三个字" +"段:" -#: src/ch03-01-what-is-ownership.md:57 +#: src/ch02-99-02-dictionaries.md:69 msgid "" -"At this point, the relationship between scopes and when variables are valid is\n" -"similar to that in other programming languages. Now we’ll build on top of this\n" -"understanding by using the `Array` type we introduced in the [previous chapter](ch02-06-common-collections.md)." +"1. A `key` field that identifies the value for this key-value pair of the dictionary.\n" +"2. A `previous_value` field that indicates which previous value was held at `key`.\n" +"3. A `new_value` field that indicates the new value that is held at `key`." msgstr "" -"目前为止,变量是否有效与作用域的关系跟其他编程语言是类似的。\n" -"现在我们在此基础上通过在[前一章](ch02-06-common-collections.md)中介绍的`Array`类型进一步理解。" +"1.一个 `key`字段,用于标识字典中键值对的值。\n" +"2.一个`previous_value`字段,表示`key`所拥有的前一个值。\n" +"3.一个`new_value`字段,用于指明`key`所拥有的新值。" -#: src/ch03-01-what-is-ownership.md:61 -msgid "### Ownership with the `Array` Type" -msgstr "### `Array` 类型的所有权" +#: src/ch02-99-02-dictionaries.md:73 +msgid "" +"If we try implementing `Felt252Dict` using high-level structures we would internally define it as `Array>` where each `Entry` has information about what key-value pair " +"it represents and the previous and new values it holds. The definition of `Entry` would be:" +msgstr "" +"如果我们尝试使用高级结构来实现 `Felt252Dict`,我们将在内部把它定义为 `Array>` 其中每个 `Entry` 都有关于它代表的键值对的信息,以及它持有的前一个值和新值。`Entry` 的" +"定义如下:" -#: src/ch03-01-what-is-ownership.md:63 +#: src/ch02-99-02-dictionaries.md:75 msgid "" -"To illustrate the rules of ownership, we need a data type that is more complex.\n" -"The types covered in the [“Data Types”][data-types] section\n" -"of Chapter 2 are of a known size, can be\n" -"quickly and trivially copied to make a new, independent instance if another\n" -"part of code needs to use the same value in a different scope, and can easily\n" -"be dropped when they're no longer used. But what is the behavior with the `Array` type whose size\n" -"is unknown at compile time and which can't be trivially copied?" +"```rust,noplayground\n" +"struct Entry {\n" +" key: felt252,\n" +" previous_value: T,\n" +" new_value: T,\n" +"}\n" +"```" msgstr "" -"为了演示所有权的规则,我们需要一个比第二章 [“Data Types”][data-types] 中讲到的类型都要复杂的数据类型。\n" -"前面介绍的类型都是已知大小的,如果代码的另一部分需要在不同的作用域中使用相同的值,可以快速简单地复制它们来创建一个新的独立实例,并且当离开作用域时被丢弃。\n" -"但当编译时大小未知且无法被简单复制的`Array`会怎么样?" +"```rust,noplayground\n" +"struct Entry {\n" +" key: felt252,\n" +" previous_value: T,\n" +" new_value: T,\n" +"}\n" +"```" -#: src/ch03-01-what-is-ownership.md:71 -msgid "Here is a short reminder of what an array looks like:" -msgstr "这里简单回忆一下数组的样子:" +#: src/ch02-99-02-dictionaries.md:83 +msgid "For each time we interact with a `Felt252Dict` a new `Entry` will be registered:" +msgstr "每次我们与`Felt252Dict`交互时,都会产生一个新的`Entry`并注册:" + +#: src/ch02-99-02-dictionaries.md:85 +msgid "" +"- A `get` would register an entry where there is no change in state, and previous and new values are stored with the same value.\n" +"- An `insert` would register a new `Entry` where the `new_value` would be the element being inserted, and the `previous_value` the last element inserted before this. In case it is " +"the first entry for a certain key, then the previous value will be zero." +msgstr "" +"- `get` 将注册一个状态没有发生变化的条目,以前的值和新值以相同的值存储。\n" +"- 一个`insert`将注册一个新的`Entry`,其中`new_value`是被插入的元素,`previous_value`是在此之前插入的最后一个元素。如果这是某个键的第一个条目,那么之前的值将为0。" -#: src/ch03-01-what-is-ownership.md:73 +#: src/ch02-99-02-dictionaries.md:88 +msgid "" +"The use of this entry list shows how there isn't any rewriting, just the creation of new memory cells per `Felt252Dict` interaction. Let's show an example of this using the " +"`balances` dictionary from the previous section and inserting the users 'Alex' and 'Maria':" +msgstr "条目列表的使用展示了这里没有任何值的覆盖,只是在每次`Felt252Dict`交互中创建新的存储单元。让我们使用上一节中的 `balances` 字典并插入用户 'Alex' 和 'Maria' 来展示一个例子:" + +#: src/ch02-99-02-dictionaries.md:90 msgid "" "```rust\n" -"# use array::ArrayTrait;\n" +"# struct Entry {\n" +"# key: felt252,\n" +"# previous_value: T,\n" +"# new_value: T,\n" +"# }\n" +"# \n" "# fn main() {\n" -" let mut arr = ArrayTrait::::new();\n" -" arr.append(1);\n" -" arr.append(2);\n" +"# let mut balances: Felt252Dict = Default::default();\n" +" balances.insert('Alex', 100_u64);\n" +" balances.insert('Maria', 50_u64);\n" +" balances.insert('Alex', 200_u64);\n" +" balances.get('Maria');\n" "# }\n" "```" msgstr "" "```rust\n" -"# use array::ArrayTrait;\n" +"# struct Entry {\n" +"# key: felt252,\n" +"# previous_value: T,\n" +"# new_value: T,\n" +"# }\n" +"# \n" "# fn main() {\n" -" let mut arr = ArrayTrait::::new();\n" -" arr.append(1);\n" -" arr.append(2);\n" +"# let mut balances: Felt252Dict = Default::default();\n" +" balances.insert('Alex', 100_u64);\n" +" balances.insert('Maria', 50_u64);\n" +" balances.insert('Alex', 200_u64);\n" +" balances.get('Maria');\n" "# }\n" "```" -#: src/ch03-01-what-is-ownership.md:82 +#: src/ch02-99-02-dictionaries.md:106 +msgid "These instructions would then produce the following list of entries:" +msgstr "这些指令将产生以下条目列表:" + +#: src/ch02-99-02-dictionaries.md:108 msgid "" -"So, how does the ownership system ensure that each cell is never written to more than once?\n" -"Consider the following code, where we try to pass the same instance of an array in two consecutive\n" -"function calls:" +"| key | previous | new |\n" +"| :---: | -------- | --- |\n" +"| Alex | 0 | 100 |\n" +"| Maria | 0 | 50 |\n" +"| Alex | 100 | 200 |\n" +"| Maria | 50 | 50 |" msgstr "" -"那么,所有权系统如何确保每个内存单元不会被写入超过一次?\n" -"考虑一下下面的代码,我们试图在两个连续的函数调用中传递同一个数组实例:" +"| key | previous | new |\n" +"| :---: | -------- | --- |\n" +"| Alex | 0 | 100 |\n" +"| Maria | 0 | 50 |\n" +"| Alex | 100 | 200 |\n" +"| Maria | 50 | 50 |" -#: src/ch03-01-what-is-ownership.md:86 +#: src/ch02-99-02-dictionaries.md:115 msgid "" -"```rust,does_not_compile\n" -"use array::ArrayTrait;\n" -"fn foo(arr: Array) {}\n" -"\n" -"fn bar(arr: Array) {}\n" -"\n" -"fn main() {\n" -" let mut arr = ArrayTrait::::new();\n" -" foo(arr);\n" -" bar(arr);\n" -"}\n" -"```" +"Notice that since 'Alex' was inserted twice, it appears twice and the `previous` and `current` values are set properly. Also reading from 'Maria' registered an entry with no change " +"from previous to current values." +msgstr "注意,由于'Alex'被插入了两次,所以它出现了两次,并且'previous'和'current'值被正确的设置。从'Maria'中读取的数据也是一个条目,从前值到现值没有发生变化。" + +#: src/ch02-99-02-dictionaries.md:117 +msgid "" +"This approach to implementing `Felt252Dict` means that for each read/write operation, there is a scan for the whole entry list in search of the last entry with the same `key`. " +"Once the entry has been found, its `new_value` is extracted and used on the new entry to be added as the `previous_value`. This means that interacting with `Felt252Dict` has a " +"worst-case time complexity of `O(n)` where `n` is the number of entries in the list." msgstr "" -"```rust,does_not_compile\n" -"use array::ArrayTrait;\n" -"fn foo(arr: Array) {}\n" -"\n" -"fn bar(arr: Array) {}\n" -"\n" -"fn main() {\n" -" let mut arr = ArrayTrait::::new();\n" -" foo(arr);\n" -" bar(arr);\n" -"}\n" -"```" +"这种实现 `Felt252Dict` 的方法意味着每一次读/写操作,都要扫描整个条目列表,寻找最后一个具有相同 `key`的条目。一旦条目被找到,它的`new_value`就会被提取出来,并作为`previous_value`添" +"加到新的条目中。这意味着与 `Felt252Dict` 交互的最坏情况下的时间复杂度为 `O(n)`,其中 `n` 是列表中的条目数。" -#: src/ch03-01-what-is-ownership.md:99 +#: src/ch02-99-02-dictionaries.md:119 msgid "" -"In this case, we try to pass the same array instance `arr` by value to the functions `foo` and `bar`, which means\n" -"that the parameter used in both function calls is the same instance of the array. If you append a value to the array\n" -"in `foo`, and then try to append another value to the same array in `bar`, what would happen is that\n" -"you would attempt to try to write to the same memory cell twice, which is not allowed in Cairo.\n" -"To prevent this, the ownership of the `arr` variable moves from the `main` function to the `foo` function. When trying\n" -"to call `bar` with `arr` as a parameter, the ownership of `arr` was already moved to the first call. The ownership\n" -"system thus prevents us from using the same instance of `arr` in `foo`." +"If you pour some thought into alternate ways of implementing `Felt252Dict` you'd surely find them, probably even ditching completely the need for a `previous_value` field, " +"nonetheless, since Cairo is not your normal language this won't work.\n" +"One of the purposes of Cairo is, with the STARK proof system, to generate proofs of computational integrity. This means that you need to verify that program execution is correct and " +"inside the boundaries of Cairo restrictions. One of those boundary checks consists of \"dictionary squashing\" and that requires information on both previous and new values for every " +"entry." msgstr "" -"在这种情况下,我们试图将同一个数组实例`arr`通过值传递给函数`foo`和`bar`,这意味着两个函数调用的参数都是同一个数组实例。\n" -"如果你在`foo`中向数组添加一个值,然后再在`bar`中向数组添加一个值,会发生什么呢?\n" -"你会试图向同一个内存单元写两次,这在Cairo中是不允许的。\n" -"为了防止这种情况,`arr`变量的所有权从`main`函数转移到`foo`函数。当试图以`arr`为参数调用`bar`时,`arr`的所有权早已再第一次调用时被转移。\n" -"所有权系统阻止了我们在`foo`中使用相同的`arr`实例。" +"如果你花点心思,你肯定会找到其他实现`Felt252Dict`的方法,其中一些方法甚至可能完全抛弃对`previous_value`字段的需求,然而,由于Cairo不是普通的编程语言,这是不可行的。\n" +"Cairo的目的之一是通过STARK证明系统来生成计算完整性的证明。这意味着你需要验证程序的执行是否正确,是否在Cairo的限制范围内。其中一个边界检查包括 \"字典压缩\",这需要每个条目的前值和新值" +"的信息。" -#: src/ch03-01-what-is-ownership.md:107 -msgid "Running the code above will result in a compile-time error:" -msgstr "运行上面的代码将导致一个编译时错误:" +#: src/ch02-99-02-dictionaries.md:122 +msgid "### Squashing Dictionaries" +msgstr "### 字典压缩" -#: src/ch03-01-what-is-ownership.md:109 +#: src/ch02-99-02-dictionaries.md:124 msgid "" -"```console\n" -"error: Variable was previously moved. Trait has no implementation in context: core::traits::Copy::>\n" -" --> array.cairo:6:9\n" -" let mut arr = ArrayTrait::::new();\n" -" ^*****^\n" -"```" +"To verify that the proof generated by a Cairo program execution that used a `Felt252Dict` is correct we need to check that there wasn't any illegal tampering with the dictionary. " +"This is done through a method called `squash_dict` that reviews each entry of the entry list and checks that access to the dictionary remains coherent throughout the execution." msgstr "" -"```console\n" -"error: Variable was previously moved. Trait has no implementation in context: core::traits::Copy::>\n" -" --> array.cairo:6:9\n" -" let mut arr = ArrayTrait::::new();\n" -" ^*****^\n" -"```" +"为了验证使用`Felt252Dict`的Cairo程序执行所生成的证明是否正确,我们需要检查字典是否被非法篡改。这是通过一个名为`squash_dict`的方法来完成的,这个方法会审查条目列表中的每一个条目,并" +"检查字典的访问在整个执行过程中是否保持一致。" -#: src/ch03-01-what-is-ownership.md:116 -msgid "### The `Copy` Trait" -msgstr "### `Copy` Trait" +#: src/ch02-99-02-dictionaries.md:126 +msgid "" +"The process of squashing is as follows: given all entries with certain key `k`, taken in the same order as they were inserted, verify that the ith entry `new_value` is equal to the " +"ith + 1 entry `previous_value`." +msgstr "压缩过程如下:给定所有具有特定键`k`的条目,按照它们被插入的相同顺序,验证第i个条目`new_value`是否等于第i+1个条目`previous_value`。" + +#: src/ch02-99-02-dictionaries.md:128 +msgid "For example, given the following entry list:" +msgstr "例如,给定以下条目列表:" -#: src/ch03-01-what-is-ownership.md:118 +#: src/ch02-99-02-dictionaries.md:130 msgid "" -"If a type implements the `Copy` trait, passing it to a function will not move the ownership of the value to the function called, but will instead pass a copy of the value.\n" -"You can implement the `Copy` trait on your type by adding the `#[derive(Copy)]` annotation to your type definition. However, Cairo won't allow a type to be annotated with Copy if the " -"type itself or any of its components don't implement the Copy trait.\n" -"While Arrays and Dictionaries can't be copied, custom types that don't contain either of them can be." +"| key | previous | new |\n" +"| :-----: | -------- | --- |\n" +"| Alex | 0 | 150 |\n" +"| Maria | 0 | 100 |\n" +"| Charles | 0 | 70 |\n" +"| Maria | 100 | 250 |\n" +"| Alex | 150 | 40 |\n" +"| Alex | 40 | 300 |\n" +"| Maria | 250 | 190 |\n" +"| Alex | 300 | 90 |" msgstr "" -"如果一个类型实现了`Copy`Trait,把它传递给一个函数将不会把值的所有权转移给被调用的函数,而是传递一个值的副本。\n" -"你可以通过在你的类型定义中添加`#[derive(Copy)]`标注来实现`Copy` Trait。然而,如果一个类型本身或其任何组件没有实现Copy Trait,Cairo将不允许该类型被标注为Copy。\n" -"虽然数组和字典不能被复制,但不包含它们的自定义类型可以被复制。" +"| key | previous | new |\n" +"| :-----: | -------- | --- |\n" +"| Alex | 0 | 150 |\n" +"| Maria | 0 | 100 |\n" +"| Charles | 0 | 70 |\n" +"| Maria | 100 | 250 |\n" +"| Alex | 150 | 40 |\n" +"| Alex | 40 | 300 |\n" +"| Maria | 250 | 190 |\n" +"| Alex | 300 | 90 |" + +#: src/ch02-99-02-dictionaries.md:141 +msgid "After squashing, the entry list would be reduced to:" +msgstr "压缩后,条目列表将缩减为:" -#: src/ch03-01-what-is-ownership.md:122 +#: src/ch02-99-02-dictionaries.md:143 msgid "" -"```rust,ignore_format\n" -"#[derive(Copy, Drop)]\n" -"struct Point {\n" -" x: u128,\n" -" y: u128,\n" -"}\n" -"\n" -"fn main() {\n" -" let p1 = Point { x: 5, y: 10 };\n" -" foo(p1);\n" -" foo(p1);\n" -"}\n" -"\n" -"fn foo(p: Point) {\n" -" // do something with p\n" -"}\n" -"```" +"| key | previous | new |\n" +"| :-----: | -------- | --- |\n" +"| Alex | 0 | 90 |\n" +"| Maria | 0 | 190 |\n" +"| Charles | 0 | 70 |" msgstr "" -"```rust,ignore_format\n" -"#[derive(Copy, Drop)]\n" -"struct Point {\n" -" x: u128,\n" -" y: u128,\n" -"}\n" -"\n" -"fn main() {\n" -" let p1 = Point { x: 5, y: 10 };\n" -" foo(p1);\n" -" foo(p1);\n" -"}\n" -"\n" -"fn foo(p: Point) {\n" -" // do something with p\n" -"}\n" -"```" +"| key | previous | new |\n" +"| :-----: | -------- | --- |\n" +"| Alex | 0 | 90 |\n" +"| Maria | 0 | 190 |\n" +"| Charles | 0 | 70 |" -#: src/ch03-01-what-is-ownership.md:140 +#: src/ch02-99-02-dictionaries.md:149 +msgid "In case of a change on any of the values of the first table, squashing would have failed during runtime." +msgstr "如果第一张表中的任何值发生变化,则在运行期间压缩将会失败。" + +#: src/ch02-99-02-dictionaries.md:151 +msgid "### Dictionary Destruction" +msgstr "#### 字典的析构" + +#: src/ch02-99-02-dictionaries.md:153 msgid "" -"In this example, we can pass `p1` twice to the foo function because the `Point` type implements the `Copy` trait. This means that when we pass `p1` to `foo`, we are actually passing " -"a copy of `p1`, and the ownership of `p1` remains with the main function.\n" -"If you remove the `Copy` trait derivation from the `Point` type, you will get a compile-time error when trying to compile the code." +"If you run the examples from [Basic Use of Dictionaries](#basic-use-of-dictionaries) you'd notice that there was never a call to squash dictionary, but the program compiled " +"successfully nonetheless. What happened behind the scene was that squash was called automatically via the `Felt252Dict` implementation of the `Destruct` trait. This call " +"occurred just before the `balance` dictionary went out of scope." msgstr "" -"在这个例子中,我们可以向foo函数传递两次`p1`,因为`Point`类型实现了`Copy`trait。这意味着当我们把`p1`传递给`foo`时,我们实际上是在传递`p1`的副本,而`p1`的所有权仍然属于主函数。\n" -"如果你从`Point`类型中删除`Copy`trait的派生,当你试图编译代码时,你会得到一个编译时错误。" +"如果你运行[字典的基本用法](#basic-use-of-dictionaries)中的示例,你会发现那些例子从来没有调用过字典压缩,但程序还是编译成功了。这是因为在背后,squash通过`Destruct` trait的" +"`Felt252Dict`实现了被自动调用。这个调用发生在`balance`字典离开作用域之前。" -#: src/ch03-01-what-is-ownership.md:143 -msgid "_Don't worry about the `Struct` keyword. We will introduce this in [Chapter 4](ch04-00-using-structs-to-structure-related-data.md)._" -msgstr "_不要担心`Struct`关键字。我们将在[第四章](ch04-00-using-structs-to-structure-related-data.md)中介绍_" +#: src/ch02-99-02-dictionaries.md:155 +msgid "" +"The `Destruct` trait represents another way of removing instances out of scope apart from `Drop`. The main difference between these two is that `Drop` is treated as a no-op " +"operation, meaning it does not generate new CASM while `Destruct` does not have this restriction. The only type which actively uses the `Destruct` trait is `Felt252Dict`, " +"for every other type `Destruct` and `Drop` are synonyms. You can read more about these traits in [Drop and Destruct](/appendix-03-derivable-traits.md#drop-and-destruct)." +msgstr "" +"除 `Drop` 之外,`Destruct` 特质代表了另一种将实例移出作用域的方法。这两者之间的主要区别在于 `Drop` 被视为一个 no-op 操作,这意味着它不会产生新的 CASM,而 `Destruct` 没有这" +"个限制。唯一主动使用`Destruct`特性的类型是`Felt252Dict`,对于其他类型`Destruct`和`Drop`是同义词。你可以在[Drop and Destruct](/appendix-03-derivable-traits.md#drop and-" +"destruct)中阅读更多关于这些特质的信息。" -#: src/ch03-01-what-is-ownership.md:145 -msgid "### The `Drop` Trait" -msgstr "### `Drop` Trait" +#: src/ch02-99-02-dictionaries.md:157 +msgid "Later in [Dictionaries as Struct Members](#dictionaries-as-struct-members), we will have a hands-on example where we implement the `Destruct` trait for a custom type." +msgstr "在 [Dictionaries as Struct Members](#dictionaries-as-struct-members)后面,我们将有一个实践示例,我们将为自定义类型实现 `Destruct` trait。" -#: src/ch03-01-what-is-ownership.md:147 +#: src/ch02-99-02-dictionaries.md:159 +msgid "### More Dictionaries" +msgstr "### 更多字典范例" + +#: src/ch02-99-02-dictionaries.md:161 msgid "" -"You may have noticed that the `Point` type in the previous example also implements the `Drop` trait. In Cairo, a value cannot go out of scope unless it has been previously moved.\n" -"For example, the following code will not compile, because the struct `A` is not moved before it goes out of scope:" +"Up to this point, we have given a comprehensive overview of the functionality of `Felt252Dict` as well as how and why it is implemented in a certain way. If you haven't understood " +"all of it, don't worry because in this section we will have some more examples using dictionaries." +msgstr "到此为止,我们已经全面地介绍了`Felt252Dict`的功能,以及它是如何和为什么以某种方式实现的。如果您还没有完全理解,请不要担心,因为在本节中我们将提供更多使用字典的示例。" + +#: src/ch02-99-02-dictionaries.md:163 +msgid "" +"We will start by explaining the `entry` method which is part of a dictionary basic functionality included in `Felt252DictTrait` which we didn't mention at the beginning. Soon " +"after, we will see examples of how `Felt252Dict` [interacts](#dictionaries-of-complex-types) with other complex types such as `Array` and how to [implement](#dictionaries-as-" +"struct-members) a struct with a dictionary as a member." msgstr "" -"你可能已经注意到,前面例子中的`Point`类型也实现了`Drop` trait。在Cairo中,一个值不能超出其作用域,除非它之前被移动过。\n" -"例如,下面的代码将无法编译,因为结构体`A`在超出作用域之前没有被移动:" +"我们将首先解释`entry`方法,它是`Felt252DictTrait`中包含的字典基本功能的一部分,我们在开始时没有提到。很快,我们将看到`Felt252Dict`如何与其他复杂类型如`Array`[交互]" +"(#dictionaries-of-complex-types)的例子,以及如何[实现](#dictionaries-as-struct-members)一个以字典为成员的结构体。" -#: src/ch03-01-what-is-ownership.md:150 +#: src/ch02-99-02-dictionaries.md:165 +msgid "### Entry and Finalize" +msgstr "### 条目(Entry)和最终确定(Finalize)" + +#: src/ch02-99-02-dictionaries.md:167 msgid "" -"```rust,does_not_compile\n" -"struct A {}\n" -"\n" -"fn main() {\n" -" A {}; // error: Value not dropped.\n" -"}\n" +"In the [Dictionaries Underneath](#dictionaries-underneath) section, we explained how `Felt252Dict` internally worked. It was a list of entries for each time the dictionary was " +"accessed in any manner. It would first find the last entry given a certain `key` and then update it accordingly to whatever operation it was executing. The Cairo language gives us " +"the tools to replicate this ourselves through the `entry` and `finalize` methods." +msgstr "" +"在 [Dictionaries Underneath](#dictionaries-underneath) 部分,我们解释了 `Felt252Dict` 内部是如何工作的。它是每次以任何方式访问字典时的条目列表。它会首先找到给定`key`的最后一个条" +"目,然后根据执行的操作更新它。Cairo语言通过`entry`和`finalize`方法为我们提供了复制这种方式的工具。" + +#: src/ch02-99-02-dictionaries.md:169 +msgid "" +"The `entry` method comes as part of `Felt252DictTrait` with the purpose of creating a new entry given a certain key. Once called, this method takes ownership of the dictionary and " +"returns the entry to update. The method signature is as follows:" +msgstr "`entry` 方法作为`Felt252DictTrait` 的一部分,目的是在给定键的情况下创建一个新的条目。一旦被调用,该方法将获得字典的所有权并返回要更新的条目。方法签名如下:" + +#: src/ch02-99-02-dictionaries.md:171 +msgid "" +"```rust,noplayground\n" +"fn entry(self: Felt252Dict, key: felt252) -> (Felt252DictEntry, T) nopanic\n" "```" msgstr "" -"```rust,does_not_compile\n" -"struct A {}\n" -"\n" -"fn main() {\n" -" A {}; // error: Value not dropped.\n" -"}\n" +"```rust,noplayground\n" +"fn entry(self: Felt252Dict, key: felt252) -> (Felt252DictEntry, T) nopanic\n" "```" -#: src/ch03-01-what-is-ownership.md:158 +#: src/ch02-99-02-dictionaries.md:175 msgid "" -"This is to ensure the soundness of Cairo programs. Soundness refers to the fact that if a\n" -"statement during the execution of the program is false, no cheating prover can convince an\n" -"honest verifier that it is true. In our case, we want to ensure the consistency of\n" -"consecutive dictionary key updates during program execution, which is only checked when\n" -"the dictionaries are `squashed` - which moves the ownership of the dictionary to the\n" -"`squash` method, thus allowing the dictionary to go out of scope. Unsquashed dictionaries\n" -"are dangerous, as a malicious prover could prove the correctness of inconsistent updates." -msgstr "" -"这是为了确保Cairo程序的健全性。健全性指的是,如果在程序执行过程中的一个语句是假的,任何作弊的验证者都不可能说服一个诚实的验证者相信它是真的。\n" -"在我们的案例中,我们要确保程序执行过程中连续的字典键的更新的一致性。\n" -"这只有在字典被压缩(`squashed`)时才会进行检查--它将字典的所有权转移到了`squash`方法,从而允许字典超出作用域。未被压缩的字典是危险的,因为恶意的证明者可以证明不一致更新的正确性。" +"The first input parameter takes ownership of the dictionary while the second one is used to create the appropriate entry. It returns a tuple containing a `Felt252DictEntry`, which " +"is the type used by Cairo to represent dictionary entries, and a `T` representing the value held previously." +msgstr "第一个输入参数获得字典的所有权,第二个参数用于创建相应的条目。它返回一个元组,包含一个`Felt252DictEntry`,这是Cairo用来表示字典条目的类型,和一个`T`,代表之前持有的值。" -#: src/ch03-01-what-is-ownership.md:166 +#: src/ch02-99-02-dictionaries.md:177 +msgid "The next thing to do is to update the entry with the new value. For this, we use the `finalize` method which inserts the entry and returns ownership of the dictionary:" +msgstr "接下来要做的是用新值更新条目。为此,我们使用`finalize`方法插入条目并返回字典的所有权:" + +#: src/ch02-99-02-dictionaries.md:179 msgid "" -"However, types that implement the `Drop` trait are allowed to go out of scope without being explicitly moved. When a value of a type that implements the `Drop` trait goes out of " -"scope, the `Drop` implementation is called on the type, which moves the value to the `drop` function, allowing it to go out of scope - This is what we call \"dropping\" a value.\n" -"It is important to note that the implementation of drop is a \"no-op\", meaning that it doesn't perform any actions other than allowing the value to go out of scope." +"```rust,noplayground\n" +"fn finalize(self: Felt252DictEntry, new_value: T) -> Felt252Dict {\n" +"```" msgstr "" -"然而,实现了`Drop` trait的类型被允许超出作用域而不被明确移动。当一个实现了`Drop` trait的类型的值超出作用域时,`Drop`的实现会被调用,它将值移动到`drop`函数中,允许它超出作用域--这就是" -"我们所说的 \"丢弃 \"一个值。\n" -"值得注意的是,drop的实现是一个 \"no-op\",也就是说,除了允许值离开作用域之外,它不执行任何其他操作。" +"```rust,noplayground\n" +"fn finalize(self: Felt252DictEntry, new_value: T) -> Felt252Dict {\n" +"```" + +#: src/ch02-99-02-dictionaries.md:183 +msgid "This method receives the entry and the new value as a parameter and returns the updated dictionary." +msgstr "该方法接收条目和新值作为参数,并返回更新后的字典。" -#: src/ch03-01-what-is-ownership.md:169 +#: src/ch02-99-02-dictionaries.md:185 +msgid "Let us see an example using `entry` and `finalize`. Imagine we would like to implement our own version of the `get` method from a dictionary. We should then do the following:" +msgstr "让我们看一个使用`entry`和`finalize`的例子。想象一下,我们想从字典中实现我们自己版本的`get`方法。我们应该这样做:" + +#: src/ch02-99-02-dictionaries.md:187 msgid "" -"The `Drop` implementation can be derived for all types, allowing them to be dropped when going out of scope, except for dictionaries (`Felt252Dict`) and types containing " -"dictionaries.\n" -"For example, the following code compiles:" +"1. Create the new entry to add using the `entry` method\n" +"2. Insert back the entry where the `new_value` equals the `previous_value`.\n" +"3. Return the value." msgstr "" -"除了字典(`Felt252Dict`)和包含字典的类型外,所有类型都可以派生`Drop`的实现,使得它们可以在超出作用域时被丢弃。\n" -"例如,下面的代码可以正常编译:" +"1.使用`entry`方法创建要添加的新条目\n" +"2.插入`new_value`等于`previous_value`的条目。\n" +"3.返回值。" -#: src/ch03-01-what-is-ownership.md:172 +#: src/ch02-99-02-dictionaries.md:191 +msgid "Implementing our custom get would look like this:" +msgstr "实现我们的自定义get将如下所示:" + +#: src/ch02-99-02-dictionaries.md:193 msgid "" -"```rust\n" -"#[derive(Drop)]\n" -"struct A {}\n" +"```rust,noplayground\n" +"use dict::Felt252DictEntryTrait;\n" "\n" -"fn main() {\n" -" A {}; // Now there is no error.\n" +"fn custom_get, impl TDrop: Drop, impl TCopy: Copy>(\n" +" ref dict: Felt252Dict, key: felt252\n" +") -> T {\n" +" // Get the new entry and the previous value held at `key`\n" +" let (entry, prev_value) = dict.entry(key);\n" +"\n" +" // Store the value to return\n" +" let return_value = prev_value;\n" +"\n" +" // Update the entry with `prev_value` and get back ownership of the dictionary\n" +" dict = entry.finalize(prev_value);\n" +"\n" +" // Return the read value\n" +" return_value\n" "}\n" "```" msgstr "" -"```rust\n" -"#[derive(Drop)]\n" -"struct A {}\n" +"```rust,noplayground\n" +"use dict::Felt252DictEntryTrait;\n" "\n" -"fn main() {\n" -" A {}; // Now there is no error.\n" +"fn custom_get, impl TDrop: Drop, impl TCopy: Copy>(\n" +" ref dict: Felt252Dict, key: felt252\n" +") -> T {\n" +" // Get the new entry and the previous value held at `key`\n" +" let (entry, prev_value) = dict.entry(key);\n" +"\n" +" // Store the value to return\n" +" let return_value = prev_value;\n" +"\n" +" // Update the entry with `prev_value` and get back ownership of the dictionary\n" +" dict = entry.finalize(prev_value);\n" +"\n" +" // Return the read value\n" +" return_value\n" "}\n" "```" -#: src/ch03-01-what-is-ownership.md:181 -msgid "### The `Destruct` Trait" -msgstr "### `Destruct` Trait" +#: src/ch02-99-02-dictionaries.md:213 +msgid "Implementing the `insert` method would follow a similar workflow, except for inserting a new value when finalizing. If we were to implement it, it would look like the following:" +msgstr "实现`insert`方法将遵循类似的工作流程,除了在最终确定时插入一个新值。如果我们要实现它,它将看起来像下面这样:" -#: src/ch03-01-what-is-ownership.md:183 +#: src/ch02-99-02-dictionaries.md:215 msgid "" -"Manually calling the `squash` method on a dictionary is not very convenient, and it is easy to forget to do so. To make it easier to use dictionaries, Cairo provides the `Destruct` " -"trait, which allows you to specify the behavior of a type when it goes out of scope. While Dictionaries don't implement the `Drop` trait, they do implement the `Destruct` trait, " -"which allows them to automatically be `squashed` when they go out of scope. This means that you can use dictionaries without having to manually call the `squash` method." +"```rust,noplayground\n" +"use dict::Felt252DictEntryTrait;\n" +"\n" +"fn custom_insert<\n" +" T,\n" +" impl TDefault: Felt252DictValue,\n" +" impl TDestruct: Destruct,\n" +" impl TPrint: PrintTrait,\n" +" impl TDrop: Drop\n" +">(\n" +" ref dict: Felt252Dict, key: felt252, value: T\n" +") {\n" +" // Get the last entry associated with `key`\n" +" // Notice that if `key` does not exists, _prev_value will\n" +" // be the default value of T.\n" +" let (entry, _prev_value) = dict.entry(key);\n" +"\n" +" // Insert `entry` back in the dictionary with the updated value,\n" +" // and recieve ownership of the dictionary\n" +" dict = entry.finalize(value);\n" +"}\n" +"```" msgstr "" -"手动调用字典上的 `squash` 方法不是很方便,而且很容易忘记这样做。为了方便使用字典,Cairo 提供了 `Destruct` trait,它允许你指定一个类型超出作用域时的行为。虽然字典没有实现`Drop` trait," -"但它们实现了`Destruct`trait,这允许它们在超出作用域时自动被`squashed`,因此你可以不需要手动调用`squash`方法。" +"```rust,noplayground\n" +"use dict::Felt252DictEntryTrait;\n" +"\n" +"fn custom_insert<\n" +" T,\n" +" impl TDefault: Felt252DictValue,\n" +" impl TDestruct: Destruct,\n" +" impl TPrint: PrintTrait,\n" +" impl TDrop: Drop\n" +">(\n" +" ref dict: Felt252Dict, key: felt252, value: T\n" +") {\n" +" // Get the last entry associated with `key`\n" +" // Notice that if `key` does not exists, _prev_value will\n" +" // be the default value of T.\n" +" let (entry, _prev_value) = dict.entry(key);\n" +"\n" +" // Insert `entry` back in the dictionary with the updated value,\n" +" // and recieve ownership of the dictionary\n" +" dict = entry.finalize(value);\n" +"}\n" +"```" -#: src/ch03-01-what-is-ownership.md:185 -msgid "Consider the following example, in which we define a custom type that contains a dictionary:" -msgstr "下面的这个例子中,我们定义了一个包含字典的自定义类型:" +#: src/ch02-99-02-dictionaries.md:238 +msgid "As a finalizing note, these two methods are implemented in a similar way to how `insert` and `get` are implemented for `Felt252Dict`. This code shows some example usage:" +msgstr "最后要说明的是,这两个方法的实现方式类似于`Felt252Dict`的`insert`和`get`的实现方式。这段代码展示了一些使用示例:" -#: src/ch03-01-what-is-ownership.md:187 +#: src/ch02-99-02-dictionaries.md:240 msgid "" -"```rust,does_not_compile\n" -"use dict::Felt252DictTrait;\n" +"```rust\n" +"# use dict::Felt252DictEntryTrait;\n" +"# \n" +"# use debug::PrintTrait;\n" +"# \n" +"# fn custom_get, impl TDrop: Drop, impl TCopy: Copy>(\n" +"# ref dict: Felt252Dict, key: felt252\n" +"# ) -> T {\n" +"# // Get the new entry and the previous value held at `key`\n" +"# let (entry, prev_value) = dict.entry(key);\n" +"# \n" +"# // Store the value to return\n" +"# let return_value = prev_value;\n" +"# \n" +"# // Update the entry with `prev_value` and get back ownership of the dictionary\n" +"# dict = entry.finalize(prev_value);\n" +"# \n" +"# // Return the read value\n" +"# return_value\n" +"# }\n" +"# \n" +"# fn custom_insert<\n" +"# T,\n" +"# impl TDefault: Felt252DictValue,\n" +"# impl TDestruct: Destruct,\n" +"# impl TPrint: PrintTrait,\n" +"# impl TDrop: Drop\n" +"# >(\n" +"# ref dict: Felt252Dict, key: felt252, value: T\n" +"# ) {\n" +"# // Get the last entry associated with `key`\n" +"# // Notice that if `key` does not exists, _prev_value will\n" +"# // be the default value of T.\n" +"# let (entry, _prev_value) = dict.entry(key);\n" +"# \n" +"# // Insert `entry` back in the dictionary with the updated value,\n" +"# // and recieve ownership of the dictionary\n" +"# dict = entry.finalize(value);\n" +"# }\n" +"# \n" +"fn main() {\n" +" let mut dict: Felt252Dict = Default::default();\n" "\n" -"struct A {\n" -" dict: Felt252Dict\n" -"}\n" +" custom_insert(ref dict, '0', 100);\n" "\n" -"fn main() {\n" -" A { dict: Felt252DictTrait::new() };\n" +" let val = custom_get(ref dict, '0');\n" +"\n" +" assert(val == 100, 'Expecting 100');\n" "}\n" +"# \n" +"# \n" "```" msgstr "" -"```rust,does_not_compile\n" -"use dict::Felt252DictTrait;\n" +"```rust\n" +"# use dict::Felt252DictEntryTrait;\n" +"# \n" +"# use debug::PrintTrait;\n" +"# \n" +"# fn custom_get, impl TDrop: Drop, impl TCopy: Copy>(\n" +"# ref dict: Felt252Dict, key: felt252\n" +"# ) -> T {\n" +"# // Get the new entry and the previous value held at `key`\n" +"# let (entry, prev_value) = dict.entry(key);\n" +"# \n" +"# // Store the value to return\n" +"# let return_value = prev_value;\n" +"# \n" +"# // Update the entry with `prev_value` and get back ownership of the dictionary\n" +"# dict = entry.finalize(prev_value);\n" +"# \n" +"# // Return the read value\n" +"# return_value\n" +"# }\n" +"# \n" +"# fn custom_insert<\n" +"# T,\n" +"# impl TDefault: Felt252DictValue,\n" +"# impl TDestruct: Destruct,\n" +"# impl TPrint: PrintTrait,\n" +"# impl TDrop: Drop\n" +"# >(\n" +"# ref dict: Felt252Dict, key: felt252, value: T\n" +"# ) {\n" +"# // Get the last entry associated with `key`\n" +"# // Notice that if `key` does not exists, _prev_value will\n" +"# // be the default value of T.\n" +"# let (entry, _prev_value) = dict.entry(key);\n" +"# \n" +"# // Insert `entry` back in the dictionary with the updated value,\n" +"# // and recieve ownership of the dictionary\n" +"# dict = entry.finalize(value);\n" +"# }\n" +"# \n" +"fn main() {\n" +" let mut dict: Felt252Dict = Default::default();\n" "\n" -"struct A {\n" -" dict: Felt252Dict\n" -"}\n" +" custom_insert(ref dict, '0', 100);\n" "\n" -"fn main() {\n" -" A { dict: Felt252DictTrait::new() };\n" +" let val = custom_get(ref dict, '0');\n" +"\n" +" assert(val == 100, 'Expecting 100');\n" "}\n" +"# \n" +"# \n" "```" -#: src/ch03-01-what-is-ownership.md:199 -msgid "If you try to run this code, you will get a compile-time error:" -msgstr "如果你试图运行这段代码,你会得到一个编译时错误:" +#: src/ch02-99-02-dictionaries.md:293 +msgid "### Dictionaries of types not supported natively" +msgstr "### 非远胜支持类型的字典" -#: src/ch03-01-what-is-ownership.md:201 +#: src/ch02-99-02-dictionaries.md:295 msgid "" -"```console\n" -"error: Variable not dropped. Trait has no implementation in context: core::traits::Drop::. Trait has no implementation in context: core::traits::Destruct::.\n" -" --> temp7.cairo:7:5\n" -" A {\n" -" ^*^\n" -"```" +"One restriction of `Felt252Dict` that we haven't talked about is the trait `Felt252DictValue`.\n" +"This trait defines the `zero_default` method which is the one that gets called when a value does not exist in the dictionary.\n" +"This is implemented by some common data types, such as most unsigned integers, `bool` and `felt252` - but it is not implemented for more complex ones types such as arrays, structs " +"(including `u256`), and other types from the core library.\n" +"This means that making a dictionary of types not natively supported is not a straightforward task, because you would need to write a couple of trait implementations in order to make " +"the data type a valid dictionary value type.\n" +"To compensate this, you can wrap your type inside a `Nullable`." msgstr "" -"```console\n" -"error: Variable not dropped. Trait has no implementation in context: core::traits::Drop::. Trait has no implementation in context: core::traits::Destruct::.\n" -" --> temp7.cairo:7:5\n" -" A {\n" -" ^*^\n" -"```" +"`Felt252Dict`的一个限制我们还没有讨论过,那就是 `Felt252DictValue` trait。\n" +"该特质定义了 `zero_default` 方法,当字典中不存在某个值时,就会调用该方法。\n" +"一些常见的数据类型(如大多数无符号整数、`bool` 和 `felt252`)实现了该方法,但更复杂的数据类型,如数组、结构体(包括 `u256`)和核心库中的其他类型,则没有实现该方法。\n" +"这就意味着,将不受原生支持的类型封装成字典并不是一件简单的事情,因为您需要编写一些trait的实现,才能使这些数据类型成为有效的字典值类型。\n" +"为了弥补这一不足,您可以将您的类型封装在 `Nullable`中。" -#: src/ch03-01-what-is-ownership.md:208 +#: src/ch02-99-02-dictionaries.md:301 msgid "" -"When A goes out of scope, it can't be dropped as it implements neither the `Drop` (as it contains a dictionary and can't `derive(Drop)`) nor the `Destruct` trait. To fix this, we can " -"derive the `Destruct` trait implementation for the `A` type:" +"`Nullable` is a smart pointer type that can either point to a value or be `null` in the absence of value. It is usually used in Object Oriented Programming Languages when a " +"reference doesn't point anywhere. The difference with `Option` is that the wrapped value is stored inside a `Box` data type. The `Box` type, inspired by Rust, allows us to " +"allocate a new memory segment for our type, and access this segment using a pointer that can only be manipulated in one place at a time." msgstr "" -"当A超出作用域时,它不能被丢弃,因为它既没有实现`Drop`(因为它包含一个字典,不能派生`derive(Drop)`)也没有实现`Destruct` trait。为了解决这个问题,我们可以为`A`类型派生出`Destruct` " -"trait的实现:" +"`Nullable` 是一种智能指针类型,既可以指向一个值,也可以在没有值的情况下为 `null`。当引用不指向任何地方时,它通常用于面向对象编程语言。与 `Option` 不同的是,封装的值存储在 `Box` " +"数据类型中。受 Rust 的启发,`Box` 类型允许我们为我们的类型分配一个新的内存段,并使用一个指针访问该内存段,该指针一次只能在一个地方操作。" -#: src/ch03-01-what-is-ownership.md:210 +#: src/ch02-99-02-dictionaries.md:303 msgid "" -"```rust\n" +"Let's show using an example. We will try to store a `Span` inside a dictionary. For that, we will use `Nullable` and `Box`. Also, we are storing a `Span` and not an " +"`Array` because the latter does not implement the `Copy` trait which is required for reading from a dictionary." +msgstr "" +"让我们来举例说明。我们将尝试在字典中存储一个`Span`。为此,我们将使用 `Nullable` 和 `Box`。另外,我们要存储的是一个 `Span` 而不是一个 `Array` ,因为后者没有实现 " +"`Copy` 特性,而从字典中读取数据是需要这个特性的。" + +#: src/ch02-99-02-dictionaries.md:305 +msgid "" +"```rust,noplayground\n" "use dict::Felt252DictTrait;\n" -"\n" -"#[derive(Destruct)]\n" -"struct A {\n" -" dict: Felt252Dict\n" -"}\n" +"use nullable::{nullable_from_box, match_nullable, FromNullableResult};\n" "\n" "fn main() {\n" -" A { dict: Felt252DictTrait::new() }; // No error here\n" -"}\n" +" // Create the dictionary\n" +" let mut d: Felt252Dict>> = Default::default();\n" +"\n" +" // Crate the array to insert\n" +" let mut a = ArrayTrait::new();\n" +" a.append(8);\n" +" a.append(9);\n" +" a.append(10);\n" +"\n" +" // Insert it as a `Span`\n" +" d.insert(0, nullable_from_box(BoxTrait::new(a.span())));\n" +"\n" +"//...\n" "```" msgstr "" -"```rust\n" +"```rust,noplayground\n" "use dict::Felt252DictTrait;\n" -"\n" -"#[derive(Destruct)]\n" -"struct A {\n" -" dict: Felt252Dict\n" -"}\n" +"use nullable::{nullable_from_box, match_nullable, FromNullableResult};\n" "\n" "fn main() {\n" -" A { dict: Felt252DictTrait::new() }; // No error here\n" -"}\n" +" // Create the dictionary\n" +" let mut d: Felt252Dict>> = Default::default();\n" +"\n" +" // Crate the array to insert\n" +" let mut a = ArrayTrait::new();\n" +" a.append(8);\n" +" a.append(9);\n" +" a.append(10);\n" +"\n" +" // Insert it as a `Span`\n" +" d.insert(0, nullable_from_box(BoxTrait::new(a.span())));\n" +"\n" +"//...\n" "```" -#: src/ch03-01-what-is-ownership.md:223 -msgid "Now, when `A` goes out of scope, its dictionary will be automatically `squashed`, and the program will compile." -msgstr "现在,当`A`超出作用域时,它的字典将被自动`squashed`,并且程序将被编译。" +#: src/ch02-99-02-dictionaries.md:325 +msgid "" +"In this code snippet, the first thing we did was to create a new dictionary `d`. We want it to hold a `Nullable`. After that, we created an array and filled it with values." +msgstr "在这段代码中,我们首先创建了一个新的字典`d`。我们希望它保存一个`Nullable`。然后,我们创建了一个数组,并在其中填入值。" -#: src/ch03-01-what-is-ownership.md:225 -msgid "### Copy Array data with Clone" -msgstr "### 用Clone复制数组数据" +#: src/ch02-99-02-dictionaries.md:327 +msgid "The last step is inserting the array as a span inside the dictionary. Notice that we didn't do that directly, but instead, we took some steps in between:" +msgstr "最后一步是在字典中插入数组。请注意,我们并没有直接这样做,而是在中间采取了一些步骤:" -#: src/ch03-01-what-is-ownership.md:227 +#: src/ch02-99-02-dictionaries.md:329 msgid "" -"If we _do_ want to deeply copy the data of an `Array`, we can use a common method called `clone`. We’ll discuss method syntax in Chapter 5, but because methods are a common feature " -"in many\n" -"programming languages, you’ve probably seen them before." +"1. We wrapped the array inside a `Box` using the `new` method from `BoxTrait`.\n" +"2. We wrapped the `Box` inside a nullable using the `nullable_from_box` function.\n" +"3. Finally, we inserted the result." msgstr "" -"如果我们确实想深入复制一个 \"数组 \"的数据,我们可以使用一个叫做 `clone`的通用方法。\n" -"我们将在第5章中讨论方法的语法,但由于方法是许多编程语言的共同特征,你可能已经见过它们了。" - -#: src/ch03-01-what-is-ownership.md:230 -msgid "Here’s an example of the `clone` method in action." -msgstr "下面是一个 `clone` 方法的实例。" +"1.我们使用`BoxTrait`中的`new`方法将数组封装在`Box`中。\n" +"2.我们使用`nullable_from_box`函数将`Box`封装在nullable中。\n" +"3.最后,我们插入了上面的结果。" -#: src/ch03-01-what-is-ownership.md:232 -msgid "> Note: in the following example, we need to import the `Clone` trait from the corelib `clone` module, and its implementation for the array type from the `array` module." -msgstr "> 注意:在下面的例子中,我们需要从corelib的`clone`模块中导入`clone`trait,并从`array`模块中导入其对数组类型的实现。" +#: src/ch02-99-02-dictionaries.md:333 +msgid "Once the element is inside the dictionary, and we want to get it, we follow the same steps but in reverse order. The following code shows how to achieve that:" +msgstr "一旦元素存在字典中,并且我们想获取它,我们将遵循相同的步骤,但顺序相反。下面的代码展示了如何实现这一点:" -#: src/ch03-01-what-is-ownership.md:234 +#: src/ch02-99-02-dictionaries.md:335 msgid "" -"```rust\n" -"use array::ArrayTrait;\n" -"use clone::Clone;\n" -"use array::ArrayTCloneImpl;\n" -"fn main() {\n" -" let arr1 = ArrayTrait::::new();\n" -" let arr2 = arr1.clone();\n" +"```rust,noplayground\n" +"//...\n" +"\n" +" // Get value back\n" +" let val = d.get(0);\n" +"\n" +" // Search the value and assert it is not null\n" +" let span = match match_nullable(val) {\n" +" FromNullableResult::Null(()) => panic_with_felt252('No value found'),\n" +" FromNullableResult::NotNull(val) => val.unbox(),\n" +" };\n" +"\n" +" // Verify we are having the right values\n" +" assert(*span.at(0) == 8, 'Expecting 8');\n" +" assert(*span.at(1) == 9, 'Expecting 9');\n" +" assert(*span.at(2) == 10, 'Expecting 10');\n" "}\n" "```" msgstr "" -"```rust\n" -"use array::ArrayTrait;\n" -"use clone::Clone;\n" -"use array::ArrayTCloneImpl;\n" -"fn main() {\n" -" let arr1 = ArrayTrait::::new();\n" -" let arr2 = arr1.clone();\n" +"```rust,noplayground\n" +"//...\n" +"\n" +" // Get value back\n" +" let val = d.get(0);\n" +"\n" +" // Search the value and assert it is not null\n" +" let span = match match_nullable(val) {\n" +" FromNullableResult::Null(()) => panic_with_felt252('No value found'),\n" +" FromNullableResult::NotNull(val) => val.unbox(),\n" +" };\n" +"\n" +" // Verify we are having the right values\n" +" assert(*span.at(0) == 8, 'Expecting 8');\n" +" assert(*span.at(1) == 9, 'Expecting 9');\n" +" assert(*span.at(2) == 10, 'Expecting 10');\n" "}\n" "```" -#: src/ch03-01-what-is-ownership.md:244 -msgid "> Note: you will need to run `cairo-run` with the `--available-gas=2000000` option to run this example, because it uses a loop and must be ran with a gas limit." -msgstr "> 注意:你需要用`--available-gas=2000000`选项运行`cairo-run`来运行这个例子,因为它使用了一个循环,运行时必须有gas限制。" +#: src/ch02-99-02-dictionaries.md:354 +msgid "Here we:" +msgstr "我们在这里:" -#: src/ch03-01-what-is-ownership.md:246 +#: src/ch02-99-02-dictionaries.md:356 msgid "" -"When you see a call to `clone`, you know that some arbitrary code is being\n" -"executed and that code may be expensive. It’s a visual indicator that something\n" -"different is going on." +"1. Read the value using `get`.\n" +"2. Verified it is non-null using the `match_nullable` function.\n" +"3. Unwrapped the value inside the box and asserted it was correct." msgstr "" -"当你看到对`clone`的调用时,你知道一些特定的代码被执行而且这些代码可能相当消耗资源。\n" -"你很容易察觉到一些不寻常的事情正在发生。" - -#: src/ch03-01-what-is-ownership.md:250 -msgid "### Ownership and Functions" -msgstr "### 所有权与函数" +"1.使用`get`读取值。\n" +"2.使用`match_nullable`函数验证其为非空值。\n" +"3.解压缩Box内的值,并断言它是正确的。" -#: src/ch03-01-what-is-ownership.md:252 -msgid "" -"Passing a variable to a function will either move it or copy it. As seen in the Array section, passing an `Array` as a function parameter transfers its ownership; let's see what " -"happens with other types." -msgstr "将一个变量传递给一个函数,要么移动它,要么复制它。正如在数组部分所看到的,将 `Array` 作为一个函数参数传递同时会传递它的所有权;让我们看看其他类型会发生什么。" - -#: src/ch03-01-what-is-ownership.md:254 -msgid "" -"Listing 3-3 has an example with some annotations\n" -"showing where variables go into and out of scope." -msgstr "示例3-3使用注释展示变量何时进入和离开作用域。" +#: src/ch02-99-02-dictionaries.md:360 +msgid "The complete script would look like this:" +msgstr "完整的脚本如下:" -#: src/ch03-01-what-is-ownership.md:257 src/ch03-01-what-is-ownership.md:299 src/ch03-01-what-is-ownership.md:352 -msgid "Filename: src/main.cairo" -msgstr "文件名: src/main.cairo" - -#: src/ch03-01-what-is-ownership.md:259 +#: src/ch02-99-02-dictionaries.md:362 msgid "" -"```rust,ignore_format\n" -"#[derive(Drop)]\n" -"struct MyStruct{}\n" +"```rust\n" "\n" -"fn main() {\n" -" let my_struct = MyStruct{}; // my_struct comes into scope\n" +"use dict::Felt252DictTrait;\n" +"use nullable::{nullable_from_box, match_nullable, FromNullableResult};\n" "\n" -" takes_ownership(my_struct); // my_struct's value moves into the function...\n" -" // ... and so is no longer valid here\n" +"fn main() {\n" +" // Create the dictionary\n" +" let mut d: Felt252Dict>> = Default::default();\n" "\n" -" let x = 5; // x comes into scope\n" +" // Crate the array to insert\n" +" let mut a = ArrayTrait::new();\n" +" a.append(8);\n" +" a.append(9);\n" +" a.append(10);\n" "\n" -" makes_copy(x); // x would move into the function,\n" -" // but u128 implements Copy, so it is okay to still\n" -" // use x afterward\n" +" // Insert it as a `Span`\n" +" d.insert(0, nullable_from_box(BoxTrait::new(a.span())));\n" "\n" -"} // Here, x goes out of scope and is dropped.\n" +" // Get value back\n" +" let val = d.get(0);\n" "\n" +" // Search the value and assert it is not null\n" +" let span = match match_nullable(val) {\n" +" FromNullableResult::Null(()) => panic_with_felt252('No value found'),\n" +" FromNullableResult::NotNull(val) => val.unbox(),\n" +" };\n" "\n" -"fn takes_ownership(some_struct: MyStruct) { // some_struct comes into scope\n" -"} // Here, some_struct goes out of scope and `drop` is called.\n" +" // Verify we are having the right values\n" +" assert(*span.at(0) == 8, 'Expecting 8');\n" +" assert(*span.at(1) == 9, 'Expecting 9');\n" +" assert(*span.at(2) == 10, 'Expecting 10');\n" +"}\n" "\n" -"fn makes_copy(some_uinteger: u128) { // some_uinteger comes into scope\n" -"} // Here, some_integer goes out of scope and is dropped.\n" "```" msgstr "" -"```rust,ignore_format\n" -"#[derive(Drop)]\n" -"struct MyStruct{}\n" +"```rust\n" +"\n" +"use dict::Felt252DictTrait;\n" +"use nullable::{nullable_from_box, match_nullable, FromNullableResult};\n" "\n" "fn main() {\n" -" let my_struct = MyStruct{}; // my_struct comes into scope\n" +" // Create the dictionary\n" +" let mut d: Felt252Dict>> = Default::default();\n" "\n" -" takes_ownership(my_struct); // my_struct's value moves into the function...\n" -" // ... and so is no longer valid here\n" +" // Crate the array to insert\n" +" let mut a = ArrayTrait::new();\n" +" a.append(8);\n" +" a.append(9);\n" +" a.append(10);\n" "\n" -" let x = 5; // x comes into scope\n" +" // Insert it as a `Span`\n" +" d.insert(0, nullable_from_box(BoxTrait::new(a.span())));\n" "\n" -" makes_copy(x); // x would move into the function,\n" -" // but u128 implements Copy, so it is okay to still\n" -" // use x afterward\n" +" // Get value back\n" +" let val = d.get(0);\n" "\n" -"} // Here, x goes out of scope and is dropped.\n" +" // Search the value and assert it is not null\n" +" let span = match match_nullable(val) {\n" +" FromNullableResult::Null(()) => panic_with_felt252('No value found'),\n" +" FromNullableResult::NotNull(val) => val.unbox(),\n" +" };\n" "\n" +" // Verify we are having the right values\n" +" assert(*span.at(0) == 8, 'Expecting 8');\n" +" assert(*span.at(1) == 9, 'Expecting 9');\n" +" assert(*span.at(2) == 10, 'Expecting 10');\n" +"}\n" "\n" -"fn takes_ownership(some_struct: MyStruct) { // some_struct comes into scope\n" -"} // Here, some_struct goes out of scope and `drop` is called.\n" +"```" + +#: src/ch02-99-02-dictionaries.md:397 +msgid "### Dictionaries as Struct Members" +msgstr "### 作为结构体成员的字典" + +#: src/ch02-99-02-dictionaries.md:399 +msgid "" +"Defining dictionaries as struct members is possible in Cairo but correctly interacting with them may not be entirely seamless. Let's try implementing a custom _user database_ that " +"will allow us to add users and query them. We will need to define a struct to represent the new type and a trait to define its functionality:" +msgstr "" +"在Cairo中可将字典定义为结构体成员,但正确地与它们交互可能不是完全无障碍的。让我们尝试实现一个自定义的_user数据库,它将允许我们添加用户并查询他们。我们需要定义一个struct来表示新的类" +"型,并定义一个trait来定义其功能:" + +#: src/ch02-99-02-dictionaries.md:401 +msgid "" +"```rust,noplayground\n" +"struct UserDatabase {\n" +" users_amount: u64,\n" +" balances: Felt252Dict,\n" +"}\n" "\n" -"fn makes_copy(some_uinteger: u128) { // some_uinteger comes into scope\n" -"} // Here, some_integer goes out of scope and is dropped.\n" +"trait UserDatabaseTrait {\n" +" fn new() -> UserDatabase;\n" +" fn add_user>(ref self: UserDatabase, name: felt252, balance: T);\n" +" fn get_user>(ref self: UserDatabase, name: felt252) -> T;\n" +"}\n" +"```" +msgstr "" +"```rust,noplayground\n" +"struct UserDatabase {\n" +" users_amount: u64,\n" +" balances: Felt252Dict,\n" +"}\n" +"\n" +"trait UserDatabaseTrait {\n" +" fn new() -> UserDatabase;\n" +" fn add_user>(ref self: UserDatabase, name: felt252, balance: T);\n" +" fn get_user>(ref self: UserDatabase, name: felt252) -> T;\n" +"}\n" "```" -#: src/ch03-01-what-is-ownership.md:285 +#: src/ch02-99-02-dictionaries.md:414 msgid "" -"Listing 3-3: Functions with ownership and scope\n" -"annotated" -msgstr "示例3-3:带有所有权和作用域注释的函数" +"Our new type `UserDatabase` represents a database of users. It is generic over the balances of the users, giving major flexibility to whoever uses our data type. Its two members " +"are:" +msgstr "我们的新类型`UserDatabase`表示用户数据库。它用泛型表示用户的余额,给使用我们的数据类型的人提供了很大的灵活性。它的两个成员是:" -#: src/ch03-01-what-is-ownership.md:288 +#: src/ch02-99-02-dictionaries.md:416 msgid "" -"If we tried to use `my_struct` after the call to `takes_ownership`, Cairo would throw a\n" -"compile-time error. These static checks protect us from mistakes. Try adding\n" -"code to `main` that uses `my_struct` and `x` to see where you can use them and where\n" -"the ownership rules prevent you from doing so." +"- `users_amount`, the number of users currently inserted and\n" +"- `balances`, a mapping of each user to its balance." msgstr "" -"如果我们试图在调用`takes_ownership`之后使用`my_struct`,Cairo会抛出一个编译时错误。\n" -"这些静态检查可以保护我们不犯错误。试着在`main`中添加使用`my_struct`和`x`的代码,看看哪里可以使用它们,\n" -"哪里所有权规则将会阻止你这样做。" +"- `users_amount`,当前插入的用户数量。\n" +"- `balances`,每个用户与其余额的映射。" -#: src/ch03-01-what-is-ownership.md:293 -msgid "### Return Values and Scope" -msgstr "### 返回值与作用域" +#: src/ch02-99-02-dictionaries.md:419 +msgid "The database core functionality is defined by `UserDatabaseTrait`. The following methods are defined:" +msgstr "数据库核心功能由`UserDatabaseTrait`定义。定义了以下方法:" -#: src/ch03-01-what-is-ownership.md:295 +#: src/ch02-99-02-dictionaries.md:421 msgid "" -"Returning values can also transfer ownership. Listing 3-4 shows an example of a\n" -"function that returns some value, with similar annotations as those in Listing\n" -"4-3." +"- `new` for easily creating new `UserDatabase` types.\n" +"- `add_user` to insert users in the database.\n" +"- `get_user` to find users in the database." msgstr "" -"返回值也可以转移所有权。示例3-4显示了一个例子\n" -"该函数返回一些值,其注释与示例4-3中的相似。" +"- `new`用于方便创建新的`UserDatabase`类型。\n" +"- `add_user`用于在数据库中插入用户。\n" +"- `get_user`用于在数据库中查找用户。" -#: src/ch03-01-what-is-ownership.md:301 +#: src/ch02-99-02-dictionaries.md:425 msgid "" -"```rust,ignore_format\n" -"#[derive(Drop)]\n" -"struct A {}\n" -"\n" -"fn main() {\n" -" let a1 = gives_ownership(); // gives_ownership moves its return\n" -" // value into a1\n" -"\n" -" let a2 = A {}; // a2 comes into scope\n" -"\n" -" let a3 = takes_and_gives_back(a2); // a2 is moved into\n" -" // takes_and_gives_back, which also\n" -" // moves its return value into a3\n" -"\n" -"} // Here, a3 goes out of scope and is dropped. a2 was moved, so nothing\n" -" // happens. a1 goes out of scope and is dropped.\n" -"\n" -"fn gives_ownership() -> A { // gives_ownership will move its\n" -" // return value into the function\n" -" // that calls it\n" +"The only remaining step is to implement each of the methods in `UserDatabaseTrait`, but since we are working with [generic types](/src/ch07-00-generic-types-and-traits.md) we also " +"need to correctly establish the requirements of `T` so it can be a valid `Felt252Dict` value type:" +msgstr "" +"剩下的步骤就是实现`UserDatabaseTrait`中的每一个方法,但是由于我们使用的是[泛型](/src/ch07-00-generic-types-and-traits.md),我们还需要正确地建立`T`的要求,这样它才能成为一个有效的" +"`Felt252Dict`值类型:" + +#: src/ch02-99-02-dictionaries.md:427 +msgid "" +"1. `T` should implement the `Copy` since it's required for getting values from a `Felt252Dict`.\n" +"2. All value types of a dictionary implement the `Felt252DictValue`, our generic type should do as well.\n" +"3. To insert values, `Felt252DictTrait` requires all value types to be destructible." +msgstr "" +"1.`T` 应该实现 `Copy`,因为从 `Felt252Dict` 获取值需要它。\n" +"2.所有字典的值类型都实现了 `Felt252DictValue`,我们的泛型也应该实现。\n" +"3.为了插入值,`Felt252DictTrait`要求所有的值类型都是可析构的。" + +#: src/ch02-99-02-dictionaries.md:431 +msgid "The implementation, with all restriction in place, would be as follow:" +msgstr "在所有限制条件均已实现的情况下,执行情况如下:" + +#: src/ch02-99-02-dictionaries.md:433 +msgid "" +"```rust,noplayground\n" "\n" -" let some_a = A {}; // some_a comes into scope\n" "\n" -" some_a // some_a is returned and\n" -" // moves ownership to the calling\n" -" // function\n" -"}\n" +"impl UserDatabaseImpl> of UserDatabaseTrait {\n" +" // Creates a database\n" +" fn new() -> UserDatabase {\n" +" UserDatabase { users_amount: 0, balances: Default::default() }\n" +" }\n" "\n" -"// This function takes an instance some_a of A and returns it\n" -"fn takes_and_gives_back(some_a: A) -> A { // some_a comes into\n" -" // scope\n" +" // Get the user\n" +" fn get_user>(ref self: UserDatabase, name: felt252) -> T {\n" +" self.balances.get(name)\n" +" }\n" "\n" -" some_a // some_a is returned and moves\n" -" // ownership to the calling\n" -" // function\n" +" // Add a user\n" +" fn add_user>(ref self: UserDatabase, name: felt252, balance: T) {\n" +" self.balances.insert(name, balance);\n" +" self.users_amount += 1;\n" +" }\n" "}\n" "```" msgstr "" -"```rust,ignore_format\n" -"#[derive(Drop)]\n" -"struct A {}\n" -"\n" -"fn main() {\n" -" let a1 = gives_ownership(); // gives_ownership moves its return\n" -" // value into a1\n" -"\n" -" let a2 = A {}; // a2 comes into scope\n" -"\n" -" let a3 = takes_and_gives_back(a2); // a2 is moved into\n" -" // takes_and_gives_back, which also\n" -" // moves its return value into a3\n" -"\n" -"} // Here, a3 goes out of scope and is dropped. a2 was moved, so nothing\n" -" // happens. a1 goes out of scope and is dropped.\n" +"```rust,noplayground\n" "\n" -"fn gives_ownership() -> A { // gives_ownership will move its\n" -" // return value into the function\n" -" // that calls it\n" -"\n" -" let some_a = A {}; // some_a comes into scope\n" "\n" -" some_a // some_a is returned and\n" -" // moves ownership to the calling\n" -" // function\n" -"}\n" +"impl UserDatabaseImpl> of UserDatabaseTrait {\n" +" // Creates a database\n" +" fn new() -> UserDatabase {\n" +" UserDatabase { users_amount: 0, balances: Default::default() }\n" +" }\n" "\n" -"// This function takes an instance some_a of A and returns it\n" -"fn takes_and_gives_back(some_a: A) -> A { // some_a comes into\n" -" // scope\n" +" // Get the user\n" +" fn get_user>(ref self: UserDatabase, name: felt252) -> T {\n" +" self.balances.get(name)\n" +" }\n" "\n" -" some_a // some_a is returned and moves\n" -" // ownership to the calling\n" -" // function\n" +" // Add a user\n" +" fn add_user>(ref self: UserDatabase, name: felt252, balance: T) {\n" +" self.balances.insert(name, balance);\n" +" self.users_amount += 1;\n" +" }\n" "}\n" "```" -#: src/ch03-01-what-is-ownership.md:339 +#: src/ch02-99-02-dictionaries.md:455 msgid "" -"Listing 3-4: Transferring ownership of return\n" -"values" +"Our database implementation is almost complete, except for one thing: the compiler doesn't know how to make a `UserDatabase` go out of scope, since it doesn't implement the " +"`Drop` trait, nor the `Destruct` trait.\n" +"Since it has a `Felt252Dict` as a member, it cannot be dropped, so we are forced to implement the `Destruct` trait manually (refer to the [Ownership](ch03-01-what-is-ownership." +"md#the-drop-trait) chapter for more information).\n" +"Using `#[derive(Destruct)]` on top of the `UserDatabase` definition won't work because of the use of [genericity](/src/ch07-00-generic-types-and-traits.md) in the struct " +"definition. We need to code the `Destruct` trait implementation by ourselves:" msgstr "" -"示例3-4:转移返回值的所有权\n" -"" - -#: src/ch03-01-what-is-ownership.md:342 -msgid "When a variable goes out of scope, its value is dropped, unless ownership of the value has been moved to another variable." -msgstr "当一个变量超出作用域时,它的值会被丢弃,除非值的所有权被转移到另一个变量上。" +"我们的数据库实现几乎已经完成,除了一点:编译器不知道如何让 `UserDatabase` 脱离作用域,因为它没有实现 `Drop` 特性,也没有实现 `Destruct` 特性。\n" +"由于它有一个 `Felt252Dict` 作为成员,它不能被丢弃,所以我们不得不手动实现 `Destruct` 特性(更多信息请参阅 [所有权](ch03-01-what-is-ownership.md#the-drop-trait) 章节)。\n" +"在 `UserDatabase` 定义之上使用 `#[derive(Destruct)]`是行不通的,因为在 struct 定义中使用了 [泛型](/src/ch07-00-generic-types-and-traits.md) 。我们需要自己编写实现 `Destruct` " +"trait的代码:" -#: src/ch03-01-what-is-ownership.md:344 +#: src/ch02-99-02-dictionaries.md:459 msgid "" -"While this works, taking ownership and then returning ownership with every\n" -"function is a bit tedious. What if we want to let a function use a value but\n" -"not take ownership? It’s quite annoying that anything we pass in also needs to\n" -"be passed back if we want to use it again, in addition to any data resulting\n" -"from the body of the function that we might want to return as well." +"```rust,noplayground\n" +"impl UserDatabaseDestruct<\n" +" T, impl TDrop: Drop, impl TDefault: Felt252DictValue\n" +"> of Destruct> {\n" +" fn destruct(self: UserDatabase) nopanic {\n" +" self.balances.squash();\n" +" }\n" +"}\n" +"```" msgstr "" -"虽然这样是可以的,但是在每一个函数中都获取所有权并接着返回所有权有些啰嗦。\n" -"如果我们想要函数使用一个值但不获取所有权该怎么办呢?\n" -"除此之外,我们也可能想返回函数体中产生的一些数据。" +"```rust,noplayground\n" +"impl UserDatabaseDestruct<\n" +" T, impl TDrop: Drop, impl TDefault: Felt252DictValue\n" +"> of Destruct> {\n" +" fn destruct(self: UserDatabase) nopanic {\n" +" self.balances.squash();\n" +" }\n" +"}\n" +"```" -#: src/ch03-01-what-is-ownership.md:350 -msgid "Cairo does let us return multiple values using a tuple, as shown in Listing 3-5." -msgstr "Cairo的确让我们可以使用一个元组返回多个值,如示例3-5所示。" +#: src/ch02-99-02-dictionaries.md:469 +msgid "Implementing `Destruct` for `UserDatabase` was our last step to get a fully functional database. We can now try it out:" +msgstr "为`UserDatabase`实现`Destruct`是我们得到一个功能齐全的数据库的最后一步。现在我们可以试试了:" -#: src/ch03-01-what-is-ownership.md:354 +#: src/ch02-99-02-dictionaries.md:471 msgid "" "```rust\n" -"use array::ArrayTrait;\n" +"# struct UserDatabase {\n" +"# users_amount: u64,\n" +"# balances: Felt252Dict,\n" +"# }\n" +"# \n" +"# trait UserDatabaseTrait {\n" +"# fn new() -> UserDatabase;\n" +"# fn add_user>(ref self: UserDatabase, name: felt252, balance: T);\n" +"# fn get_user>(ref self: UserDatabase, name: felt252) -> T;\n" +"# }\n" +"# \n" +"# impl UserDatabaseImpl> of UserDatabaseTrait {\n" +"# // Creates a database\n" +"# fn new() -> UserDatabase {\n" +"# UserDatabase { users_amount: 0, balances: Default::default() }\n" +"# }\n" +"# \n" +"# // Get the user\n" +"# fn get_user>(ref self: UserDatabase, name: felt252) -> T {\n" +"# self.balances.get(name)\n" +"# }\n" +"# \n" +"# // Add a user\n" +"# fn add_user>(ref self: UserDatabase, name: felt252, balance: T) {\n" +"# self.balances.insert(name, balance);\n" +"# self.users_amount += 1;\n" +"# }\n" +"# }\n" +"# \n" +"# impl UserDatabaseDestruct<\n" +"# T, impl TDrop: Drop, impl TDefault: Felt252DictValue\n" +"# > of Destruct> {\n" +"# fn destruct(self: UserDatabase) nopanic {\n" +"# self.balances.squash();\n" +"# }\n" +"# }\n" +"# \n" "fn main() {\n" -" let arr1 = ArrayTrait::::new();\n" +" let mut db = UserDatabaseTrait::new();\n" "\n" -" let (arr2, len) = calculate_length(arr1);\n" -"}\n" +" db.add_user('Alex', 100);\n" +" db.add_user('Maria', 80);\n" "\n" -"fn calculate_length(arr: Array) -> (Array, usize) {\n" -" let length = arr.len(); // len() returns the length of an array\n" +" db.add_user('Alex', 40);\n" +" db.add_user('Maria', 0);\n" "\n" -" (arr, length)\n" +" let alex_latest_balance = db.get_user('Alex');\n" +" let maria_latest_balance = db.get_user('Maria');\n" +"\n" +" assert(alex_latest_balance == 40, 'Expected 40');\n" +" assert(maria_latest_balance == 0, 'Expected 0');\n" "}\n" +"# \n" +"# \n" "```" msgstr "" "```rust\n" -"use array::ArrayTrait;\n" +"# struct UserDatabase {\n" +"# users_amount: u64,\n" +"# balances: Felt252Dict,\n" +"# }\n" +"# \n" +"# trait UserDatabaseTrait {\n" +"# fn new() -> UserDatabase;\n" +"# fn add_user>(ref self: UserDatabase, name: felt252, balance: T);\n" +"# fn get_user>(ref self: UserDatabase, name: felt252) -> T;\n" +"# }\n" +"# \n" +"# impl UserDatabaseImpl> of UserDatabaseTrait {\n" +"# // Creates a database\n" +"# fn new() -> UserDatabase {\n" +"# UserDatabase { users_amount: 0, balances: Default::default() }\n" +"# }\n" +"# \n" +"# // Get the user\n" +"# fn get_user>(ref self: UserDatabase, name: felt252) -> T {\n" +"# self.balances.get(name)\n" +"# }\n" +"# \n" +"# // Add a user\n" +"# fn add_user>(ref self: UserDatabase, name: felt252, balance: T) {\n" +"# self.balances.insert(name, balance);\n" +"# self.users_amount += 1;\n" +"# }\n" +"# }\n" +"# \n" +"# impl UserDatabaseDestruct<\n" +"# T, impl TDrop: Drop, impl TDefault: Felt252DictValue\n" +"# > of Destruct> {\n" +"# fn destruct(self: UserDatabase) nopanic {\n" +"# self.balances.squash();\n" +"# }\n" +"# }\n" +"# \n" "fn main() {\n" -" let arr1 = ArrayTrait::::new();\n" +" let mut db = UserDatabaseTrait::new();\n" "\n" -" let (arr2, len) = calculate_length(arr1);\n" -"}\n" +" db.add_user('Alex', 100);\n" +" db.add_user('Maria', 80);\n" "\n" -"fn calculate_length(arr: Array) -> (Array, usize) {\n" -" let length = arr.len(); // len() returns the length of an array\n" +" db.add_user('Alex', 40);\n" +" db.add_user('Maria', 0);\n" "\n" -" (arr, length)\n" +" let alex_latest_balance = db.get_user('Alex');\n" +" let maria_latest_balance = db.get_user('Maria');\n" +"\n" +" assert(alex_latest_balance == 40, 'Expected 40');\n" +" assert(maria_latest_balance == 0, 'Expected 0');\n" "}\n" +"# \n" +"# \n" "```" -#: src/ch03-01-what-is-ownership.md:369 -msgid "Listing 3-5: Returning ownership of parameters" -msgstr "示例3-5:返回参数的所有权" +#: src/ch02-99-02-dictionaries.md:530 +msgid "Well done! You finished this chapter on arrays and dictionaries in Cairo. These data structures may be a bit challenging to grasp, but they are really useful." +msgstr "干得好!你已经完成了Cairo中关于数组和字典的章节。要掌握这些数据结构可能有点难度,但它们确实非常有用。" -#: src/ch03-01-what-is-ownership.md:371 -msgid "" -"But this is too much ceremony and a lot of work for a concept that should be\n" -"common. Luckily for us, Cairo has two features for using a value without\n" -"transferring ownership, called _references_ and _snapshots_." -msgstr "" -"但是这未免有些形式主义,而且这种场景应该很常见。\n" -"幸运的是,Cairo提供了两个功能可以在不转移所有权的情况下使用一个值,\n" -"称为 引用( _references_ )和 快照( _snapshots_ )。" +#: src/ch02-99-02-dictionaries.md:532 +msgid "When you’re ready to move on, we’ll talk about a concept that Cairo shares with Rust and that _doesn’t_ commonly exist in other programming languages: ownership." +msgstr "当你准备好继续前进时,我们将讨论一个Cairo与Rust共有,而在其他编程语言中通常 _不存在_ 的概念:所有权。" -#: src/ch03-02-references-and-snapshots.md:1 -msgid "## References and Snapshots" -msgstr "## 引用和快照" +#: src/ch03-00-understanding-ownership.md:1 +msgid "# Understanding Cairo's Ownership system" +msgstr "# 了解Cairo的所有权制度" -#: src/ch03-02-references-and-snapshots.md:3 +#: src/ch03-00-understanding-ownership.md:3 msgid "" -"The issue with the tuple code in Listing 3-5 is that we have to return the\n" -"`Array` to the calling function so we can still use the `Array` after the\n" -"call to `calculate_length`, because the `Array` was moved into\n" -"`calculate_length`." +"Cairo is a language built around a linear type system that allows us to\n" +"statically ensure that in every Cairo program, a value is used exactly once.\n" +"This linear type system helps preventing runtime errors by ensuring that operations that could cause such errors, such as writing twice to a memory cell, are detected at compile " +"time.\n" +"This is achieved by implementing an ownership system\n" +"and forbidding copying and dropping values by default. In this chapter, we’ll\n" +"talk about Cairo's ownership system as well as references and snapshots." msgstr "" -"示例3-5中元组代码的问题是,因为 `Array`的所有权被移到了`calculate_length`中。\n" -"我们必须返回`Array`给调用的函数,这样我们在调用`calculate_length`后才仍然可以使用`Array`。" +"Cairo是一种围绕着线性类型系统建立的语言,它允许我们\n" +"静态地确保在每个Cairo程序中,一个值只被使用一次。\n" +"这种线性类型系统有助于防止运行时错误,因为它可以确保在编译时检测到可能导致这种错误的操作,如向一个内存单元写两次。\n" +"这是通过实施一个所有权系统来实现的\n" +"并在默认情况下禁止复制和丢弃数值。在本章中,我们将\n" +"讨论Cairo的所有权系统以及引用和快照(snapshot)。" -#: src/ch03-02-references-and-snapshots.md:8 -msgid "### Snapshots" -msgstr "### 快照(Snapshots)" +#: src/ch03-01-what-is-ownership.md:1 +msgid "## What Is Ownership?" +msgstr "## 什么是所有权?" -#: src/ch03-02-references-and-snapshots.md:10 +#: src/ch03-01-what-is-ownership.md:3 msgid "" -"Instead, we can provide a _snapshot_ of the `Array` value. In Cairo, a snapshot\n" -"is an immutable view of a value at a certain point in time. In the previous chapter,\n" -"we talked about how Cairo's ownership system prevents us from using a value after\n" -"we've moved it, protecting us from potentially writing twice to the same memory cell when\n" -"appending values to arrays. However, it's not very convenient. Let's see how we can retain ownership\n" -"of the value in the calling function using snapshots." +"Cairo implements an ownership system to ensure the safety and correctness of its compiled code.\n" +"The ownership mechanism complements the linear type system, which enforces that objects are used exactly once.\n" +"This helps prevent common operations that can produce runtime errors, such as illegal memory address\n" +"references or multiple writes to the same memory address, and ensures the soundness of Cairo programs\n" +"by checking at compile time that all the dictionaries are squashed." msgstr "" -"不过,我们可以提供一个`Array`值的 _snapshot_ 。在Cairo,一个快照是一个在某个时间点上的不可改变的值的视图。\n" -"在上一章中,我们谈到了Cairo的所有权系统是如何防止我们在移动一个值后使用它,从而防止我们在向数组添加值时不会潜在地多次写入相同的内存单元。\n" -"然而,这不是很方便。让我们看看如何使用快照在调用函数中保留值的所有权。" +"Cairo实现了一个所有权系统以确保其编译代码的安全性和正确性。\n" +"所有权机制是对线性类型系统的补充,该系统规定对象只能使用一次。\n" +"这有助于防止可能产生运行时错误的常见操作,如非法的内存地址引用或对同一内存地址的多次写入,\n" +"并通过在编译时检查所有的字典是否被压缩(squash)来确保Cairo程序的正确性。" -#: src/ch03-02-references-and-snapshots.md:17 +#: src/ch03-01-what-is-ownership.md:9 msgid "" -"Here is how you would define and use a `calculate_length` function that takes a\n" -"snapshot to an array as a parameter instead of taking ownership of the underlying value. In this example,\n" -"the `calculate_length` function returns the length of the array passed as parameter.\n" -"As we're passing it as a snapshot, which is an immutable view of the array, we can be sure that\n" -"the `calculate_length` function will not mutate the array, and ownership of the array is kept in the main function." +"Now that we’re past basic Cairo syntax, we won’t include all the `fn main() {`\n" +"code in examples, so if you’re following along, make sure to put the following\n" +"examples inside a `main` function manually. As a result, our examples will be a\n" +"bit more concise, letting us focus on the actual details rather than\n" +"boilerplate code." msgstr "" -"下面是你如何定义和使用一个`calculate_length` 函数,它以一个快照作为参数,而不是获取底层值的所有权。在这个例子中、\n" -"`calculate_length`函数返回作为参数的数组的长度。\n" -"因为我们是以快照的形式传递的,这是一个不可改变的数组视图,我们可以确定\n" -"`calculate_length`函数不会改变数组,数组的所有权被保留在主函数中。" +"既然我们已经掌握了Cairo基本语法,我们将不会在之后的例子中包含 `fn main() {` 代码,\n" +"所以如果你是一路跟过来的,必须手动将之后例子的代码放入一个 `main` 函数中。\n" +"这样,例子将显得更加简明,使我们可以关注实际细节而不是样板代码。" -#: src/ch03-02-references-and-snapshots.md:25 +#: src/ch03-01-what-is-ownership.md:15 +msgid "### Ownership Rules" +msgstr "### 所有权规则" + +#: src/ch03-01-what-is-ownership.md:17 msgid "" -"```rust,ignore_format\n" -"use array::ArrayTrait;\n" -"use debug::PrintTrait;\n" -"\n" -"fn main() {\n" -" let mut arr1 = ArrayTrait::::new();\n" -" let first_snapshot = @arr1; // Take a snapshot of `arr1` at this point in time\n" -" arr1.append(1); // Mutate `arr1` by appending a value\n" -" let first_length = calculate_length(\n" -" first_snapshot\n" -" ); // Calculate the length of the array when the snapshot was taken\n" -" let second_length = calculate_length(@arr1); // Calculate the current length of the array\n" -" first_length.print();\n" -" second_length.print();\n" -"}\n" -"\n" -"fn calculate_length(arr: @Array) -> usize {\n" -" arr.len()\n" -"}\n" -"```" -msgstr "" -"```rust,ignore_format\n" -"use array::ArrayTrait;\n" -"use debug::PrintTrait;\n" -"\n" -"fn main() {\n" -" let mut arr1 = ArrayTrait::::new();\n" -" let first_snapshot = @arr1; // Take a snapshot of `arr1` at this point in time\n" -" arr1.append(1); // Mutate `arr1` by appending a value\n" -" let first_length = calculate_length(\n" -" first_snapshot\n" -" ); // Calculate the length of the array when the snapshot was taken\n" -" let second_length = calculate_length(@arr1); // Calculate the current length of the array\n" -" first_length.print();\n" -" second_length.print();\n" -"}\n" -"\n" -"fn calculate_length(arr: @Array) -> usize {\n" -" arr.len()\n" -"}\n" -"```" +"First, let’s take a look at the ownership rules. Keep these rules in mind as we\n" +"work through the examples that illustrate them:" +msgstr "首先,让我们看一下所有权规则。请牢记这些规则,我们将通过例子来说明它们:" -#: src/ch03-02-references-and-snapshots.md:46 +#: src/ch03-01-what-is-ownership.md:20 msgid "" -"> Note: It is only possible to call the `len()` method on an array snapshot because it is defined as such in the `ArrayTrait` trait. If you try to call a method that is not defined " -"for snapshots on a snapshot, you will get a compilation error. However, you can call methods expecting a snapshot on non-snapshot types." +"- Each value in Cairo has an _owner_.\n" +"- There can only be one owner at a time.\n" +"- When the owner goes out of scope, the value will be _dropped_." msgstr "" -"> 注意:只有在数组快照上才能调用 `len()` 方法,因为它在 `ArrayTrait` trait中被定义成这样。如果你试图在一个快照上调用一个没有为快照定义的方法,你会得到一个编译错误。然而,你可以在非快" -"照类型上调用快照的方法。" +"- Cairo的每个值都有一个 _所有者_ 。\n" +"- 在同一时间只能有一个所有者。\n" +"- 当所有者超出作用域(scope)时,该值将被 _丢弃_ 。" -#: src/ch03-02-references-and-snapshots.md:48 -msgid "The output of this program is:" -msgstr "这个程序的输出是:" +#: src/ch03-01-what-is-ownership.md:24 +msgid "### Variable Scope" +msgstr "### 变量作用域" -#: src/ch03-02-references-and-snapshots.md:50 +#: src/ch03-01-what-is-ownership.md:26 msgid "" -"```console\n" -"[DEBUG]\t \t(raw: 0)\n" -"\n" -"[DEBUG]\t \t(raw: 1)\n" -"\n" -"Run completed successfully, returning []\n" +"As a first example of ownership, we’ll look at the _scope_ of some variables. A\n" +"scope is the range within a program for which an item is valid. Take the\n" +"following variable:" +msgstr "在所有权的第一个例子中,我们看看一些变量的 作用域( _scope_ )。作用域是一个项(item)在程序中有效的范围。假设有这样一个变量:" + +#: src/ch03-01-what-is-ownership.md:30 +msgid "" +"```rust,noplayground\n" +"let s = 'hello';\n" "```" msgstr "" -"```console\n" -"[DEBUG]\t \t(raw: 0)\n" -"\n" -"[DEBUG]\t \t(raw: 1)\n" -"\n" -"Run completed successfully, returning []\n" +"```rust,noplayground\n" +"let s = 'hello';\n" "```" -#: src/ch03-02-references-and-snapshots.md:58 +#: src/ch03-01-what-is-ownership.md:34 msgid "" -"First, notice that all the tuple code in the variable declaration and the function return value is gone. Second, note\n" -"that we pass `@arr1` into `calculate_length` and, in its definition, we take `@Array` rather than `Array`." +"The variable `s` refers to a short string, where the value of the string is\n" +"hardcoded into the text of our program. The variable is valid from the point at\n" +"which it’s declared until the end of the current _scope_. Listing 3-1 shows a\n" +"program with comments annotating where the variable `s` would be valid." msgstr "" -"首先,注意到变量声明和函数返回值中的所有元组代码都消失了。\n" -"第二,注意看我们把`@arr1`传入`calculate_length`,因此在它的定义中,我们采用`@Array`,而不是`Array`。" - -#: src/ch03-02-references-and-snapshots.md:61 -msgid "Let’s take a closer look at the function call here:" -msgstr "让我们仔细看一下这里的函数调用:" +"变量`s`指的是一个短字符串,字符串的值被硬编码到我们的程序文本中。\n" +"这个变量从它被声明的那一刻起,一直到当前 _scope_ 的结束,都是有效的。\n" +"示例3-1的程序中的注释标明了变量 `s` 在何处是有效的。" -#: src/ch03-02-references-and-snapshots.md:63 +#: src/ch03-01-what-is-ownership.md:39 msgid "" "```rust\n" -"# use array::ArrayTrait;\n" -"# use debug::PrintTrait;\n" -"# \n" +"# //TAG: ignore_fmt\n" "# fn main() {\n" -"# let mut arr1 = ArrayTrait::::new();\n" -"# let first_snapshot = @arr1; // Take a snapshot of `arr1` at this point in time\n" -"# arr1.append(1); // Mutate `arr1` by appending a value\n" -"# let first_length = calculate_length(\n" -"# first_snapshot\n" -"# ); // Calculate the length of the array when the snapshot was taken\n" -" let second_length = calculate_length(@arr1); // Calculate the current length of the array\n" -"# first_length.print();\n" -"# second_length.print();\n" -"# }\n" -"# \n" -"# fn calculate_length(arr: @Array) -> usize {\n" -"# arr.len()\n" +" { // s is not valid here, it’s not yet declared\n" +" let s = 'hello'; // s is valid from this point forward\n" +"\n" +" // do stuff with s\n" +" } // this scope is now over, and s is no longer valid\n" "# }\n" "```" msgstr "" "```rust\n" -"# use array::ArrayTrait;\n" -"# use debug::PrintTrait;\n" -"# \n" +"# //TAG: ignore_fmt\n" "# fn main() {\n" -"# let mut arr1 = ArrayTrait::::new();\n" -"# let first_snapshot = @arr1; // Take a snapshot of `arr1` at this point in time\n" -"# arr1.append(1); // Mutate `arr1` by appending a value\n" -"# let first_length = calculate_length(\n" -"# first_snapshot\n" -"# ); // Calculate the length of the array when the snapshot was taken\n" -" let second_length = calculate_length(@arr1); // Calculate the current length of the array\n" -"# first_length.print();\n" -"# second_length.print();\n" -"# }\n" -"# \n" -"# fn calculate_length(arr: @Array) -> usize {\n" -"# arr.len()\n" +" { // s is not valid here, it’s not yet declared\n" +" let s = 'hello'; // s is valid from this point forward\n" +"\n" +" // do stuff with s\n" +" } // this scope is now over, and s is no longer valid\n" "# }\n" "```" -#: src/ch03-02-references-and-snapshots.md:84 +#: src/ch03-01-what-is-ownership.md:50 msgid "" -"The `@arr1` syntax lets us create a snapshot of the value in `arr1`. Because a snapshot is an immutable view of a value, the value it points to cannot be modified through the " -"snapshot, and the value it refers to will not be dropped once the snapshot stops being used." -msgstr "`@arr1`语法让我们为`arr1`中的值创建了一个快照。因为快照是一个值的不可改变的视图,它所指向的值不能通过快照被修改,因此即使快照停止被使用,它所指向的值也不会被丢弃。" +"Listing 3-1: A variable and the scope in which it is\n" +"valid" +msgstr "示例3-1:一个变量和其有效的作用域" -#: src/ch03-02-references-and-snapshots.md:86 -msgid "Similarly, the signature of the function uses `@` to indicate that the type of the parameter `arr` is a snapshot. Let’s add some explanatory annotations:" -msgstr "同样,函数的签名使用`@`来表示参数`arr`的类型是一个快照。让我们添加一些解释性的注解:" +#: src/ch03-01-what-is-ownership.md:53 +msgid "In other words, there are two important points in time here:" +msgstr "换句话说,这里有两个重要的时间点:" -#: src/ch03-02-references-and-snapshots.md:88 +#: src/ch03-01-what-is-ownership.md:55 msgid "" -"```rust\n" -"fn calculate_length(\n" -" array_snapshot: @Array\n" -") -> usize { // array_snapshot is a snapshot of an Array\n" -" array_snapshot.len()\n" -"} // Here, array_snapshot goes out of scope and is dropped.\n" -"// However, because it is only a view of what the original array `arr` contains, the original `arr` can still be used.\n" -"```" +"- When `s` comes _into_ scope, it is valid.\n" +"- It remains valid until it goes _out of_ scope." msgstr "" -"```rust\n" -"fn calculate_length(\n" -" array_snapshot: @Array\n" -") -> usize { // array_snapshot is a snapshot of an Array\n" -" array_snapshot.len()\n" -"} // Here, array_snapshot goes out of scope and is dropped.\n" -"// However, because it is only a view of what the original array `arr` contains, the original `arr` can still be used.\n" -"```" +"- 当`s`进入 _进入作用域_ 时,它就是有效的。\n" +"- 这一直持续到它 _离开_ 作用域 为止。" -#: src/ch03-02-references-and-snapshots.md:97 +#: src/ch03-01-what-is-ownership.md:58 msgid "" -"The scope in which the variable `array_snapshot` is valid is the same as any function parameter’s scope, but the underlying value of the snapshot is not dropped when `array_snapshot` " -"stops being used. When functions have snapshots as parameters instead of the actual values, we won’t need to return the values in order to give back ownership of the original value, " -"because we never had it." +"At this point, the relationship between scopes and when variables are valid is\n" +"similar to that in other programming languages. Now we’ll build on top of this\n" +"understanding by using the `Array` type we introduced in the [previous chapter](ch02-06-common-collections.md)." msgstr "" -"变量`array_snapshot`的有效范围与任何函数参数的范围相同,但当`array_snapshot`停止使用时,快照的底层值不会被丢弃。当函数有快照作为参数而不是实际的值时,我们将不需要返回值以归还原始值的" -"所有权,因为我们从未拥有过它。" +"目前为止,变量是否有效与作用域的关系跟其他编程语言是类似的。\n" +"现在我们在此基础上通过在[前一章](ch02-06-common-collections.md)中介绍的`Array`类型进一步理解。" -#: src/ch03-02-references-and-snapshots.md:99 +#: src/ch03-01-what-is-ownership.md:62 +msgid "### Ownership with the `Array` Type" +msgstr "### `Array` 类型的所有权" + +#: src/ch03-01-what-is-ownership.md:64 msgid "" -"Snapshots can be converted back into regular values using the `desnap` operator `*`, as long as the value type is copyable (which is not the case for Arrays, as they don't implement " -"`Copy`). In the following example, we want to calculate the area of a rectangle, but we don't want to take ownership of the rectangle in the `calculate_area` function, because we " -"might want to use the rectangle again after the function call. Since our function doesn't mutate the rectangle instance, we can pass the snapshot of the rectangle to the function, " -"and then transform the snapshots back into values using the `desnap` operator `*`." +"To illustrate the rules of ownership, we need a data type that is more complex.\n" +"The types covered in the [“Data Types”][data-types] section\n" +"of Chapter 2 are of a known size, can be\n" +"quickly and trivially copied to make a new, independent instance if another\n" +"part of code needs to use the same value in a different scope, and can easily\n" +"be dropped when they're no longer used. But what is the behavior with the `Array` type whose size\n" +"is unknown at compile time and which can't be trivially copied?" msgstr "" -"快照可以通过`desnap`操作符`*`转换回常规值,只要值的类型是可复制的(数组不是这样,因为它们没有实现`Copy`)。在下面的例子中,我们想计算一个矩形的面积,但我们不想在`calculate_area`函数中" -"占有这个矩形的所有权,因为我们可能想在函数调用后再次使用这个矩形。由于我们的函数不会改变矩形实例,我们可以将矩形的快照传递给函数,然后用`desnap`操作符`*`将快照转化回数值。" +"为了演示所有权的规则,我们需要一个比第二章 [“Data Types”][data-types] 中讲到的类型都要复杂的数据类型。\n" +"前面介绍的类型都是已知大小的,如果代码的另一部分需要在不同的作用域中使用相同的值,可以快速简单地复制它们来创建一个新的独立实例,并且当离开作用域时被丢弃。\n" +"但当编译时大小未知且无法被简单复制的`Array`会怎么样?" -#: src/ch03-02-references-and-snapshots.md:101 -msgid "The snapshot type is always copyable and droppable, so that you can use it multiple times without worrying about ownership transfers." -msgstr "快照类型始终是可复制和可删除的,因此你可以多次使用它而不必担心所有权的转移。" +#: src/ch03-01-what-is-ownership.md:72 +msgid "Here is a short reminder of what an array looks like:" +msgstr "这里简单回忆一下数组的样子:" -#: src/ch03-02-references-and-snapshots.md:103 +#: src/ch03-01-what-is-ownership.md:74 msgid "" "```rust\n" -"use debug::PrintTrait;\n" -"\n" -"#[derive(Copy, Drop)]\n" -"struct Rectangle {\n" -" height: u64,\n" -" width: u64,\n" -"}\n" -"\n" -"fn main() {\n" -" let rec = Rectangle { height: 3, width: 10 };\n" -" let area = calculate_area(@rec);\n" -" area.print();\n" -"}\n" -"\n" -"fn calculate_area(rec: @Rectangle) -> u64 {\n" -" // As rec is a snapshot to a Rectangle, its fields are also snapshots of the fields types.\n" -" // We need to transform the snapshots back into values using the desnap operator `*`.\n" -" // This is only possible if the type is copyable, which is the case for u64.\n" -" // Here, `*` is used for both multiplying the height and width and for desnapping the snapshots.\n" -" *rec.height * *rec.width\n" +"# fn main() {\n" +"# let mut arr = ArrayTrait::::new();\n" +" arr.append(1);\n" +" arr.append(2);\n" "}\n" "```" msgstr "" "```rust\n" -"use debug::PrintTrait;\n" -"\n" -"#[derive(Copy, Drop)]\n" -"struct Rectangle {\n" -" height: u64,\n" -" width: u64,\n" -"}\n" -"\n" -"fn main() {\n" -" let rec = Rectangle { height: 3, width: 10 };\n" -" let area = calculate_area(@rec);\n" -" area.print();\n" -"}\n" -"\n" -"fn calculate_area(rec: @Rectangle) -> u64 {\n" -" // As rec is a snapshot to a Rectangle, its fields are also snapshots of the fields types.\n" -" // We need to transform the snapshots back into values using the desnap operator `*`.\n" -" // This is only possible if the type is copyable, which is the case for u64.\n" -" // Here, `*` is used for both multiplying the height and width and for desnapping the snapshots.\n" -" *rec.height * *rec.width\n" +"# fn main() {\n" +"# let mut arr = ArrayTrait::::new();\n" +" arr.append(1);\n" +" arr.append(2);\n" "}\n" "```" -#: src/ch03-02-references-and-snapshots.md:127 +#: src/ch03-01-what-is-ownership.md:82 msgid "" -"But, what happens if we try to modify something we’re passing as snapshot? Try the code in\n" -"Listing 3-6. Spoiler alert: it doesn’t work!" +"So, how does the ownership system ensure that each cell is never written to more than once?\n" +"Consider the following code, where we try to pass the same instance of an array in two consecutive\n" +"function calls:" msgstr "" -"但是,如果我们试图修改我们作为快照传递的东西会发生什么?试试下面的代码\n" -"示例3-6。剧透一下:它不起作用!" +"那么,所有权系统如何确保每个内存单元不会被写入超过一次?\n" +"考虑一下下面的代码,我们试图在两个连续的函数调用中传递同一个数组实例:" -#: src/ch03-02-references-and-snapshots.md:132 +#: src/ch03-01-what-is-ownership.md:86 msgid "" "```rust,does_not_compile\n" -"// does_not_compile\n" -"#[derive(Copy, Drop)]\n" -"struct Rectangle {\n" -" height: u64,\n" -" width: u64,\n" -"}\n" +"//TAG: does_not_run\n" "\n" -"fn main() {\n" -" let rec = Rectangle { height: 3, width: 10 };\n" -" flip(@rec);\n" -"}\n" +"fn foo(arr: Array) {}\n" "\n" -"fn flip(rec: @Rectangle) {\n" -" let temp = rec.height;\n" -" rec.height = rec.width;\n" -" rec.width = temp;\n" +"fn bar(arr: Array) {}\n" +"\n" +"fn main() {\n" +" let mut arr = ArrayTrait::::new();\n" +" foo(arr);\n" +" bar(arr);\n" "}\n" "```" msgstr "" "```rust,does_not_compile\n" -"// does_not_compile\n" -"#[derive(Copy, Drop)]\n" -"struct Rectangle {\n" -" height: u64,\n" -" width: u64,\n" -"}\n" +"//TAG: does_not_run\n" "\n" -"fn main() {\n" -" let rec = Rectangle { height: 3, width: 10 };\n" -" flip(@rec);\n" -"}\n" +"fn foo(arr: Array) {}\n" "\n" -"fn flip(rec: @Rectangle) {\n" -" let temp = rec.height;\n" -" rec.height = rec.width;\n" -" rec.width = temp;\n" +"fn bar(arr: Array) {}\n" +"\n" +"fn main() {\n" +" let mut arr = ArrayTrait::::new();\n" +" foo(arr);\n" +" bar(arr);\n" "}\n" "```" -#: src/ch03-02-references-and-snapshots.md:152 -msgid "Listing 3-6: Attempting to modify a snapshot value" -msgstr "示例3-6:试图修改一个快照值" +#: src/ch03-01-what-is-ownership.md:100 +msgid "" +"In this case, we try to pass the same array instance `arr` by value to the functions `foo` and `bar`, which means\n" +"that the parameter used in both function calls is the same instance of the array. If you append a value to the array\n" +"in `foo`, and then try to append another value to the same array in `bar`, what would happen is that\n" +"you would attempt to try to write to the same memory cell twice, which is not allowed in Cairo.\n" +"To prevent this, the ownership of the `arr` variable moves from the `main` function to the `foo` function. When trying\n" +"to call `bar` with `arr` as a parameter, the ownership of `arr` was already moved to the first call. The ownership\n" +"system thus prevents us from using the same instance of `arr` in `foo`." +msgstr "" +"在这种情况下,我们试图将同一个数组实例`arr`通过值传递给函数`foo`和`bar`,这意味着两个函数调用的参数都是同一个数组实例。\n" +"如果你在`foo`中向数组添加一个值,然后再在`bar`中向数组添加一个值,会发生什么呢?\n" +"你会试图向同一个内存单元写两次,这在Cairo中是不允许的。\n" +"为了防止这种情况,`arr`变量的所有权从`main`函数转移到`foo`函数。当试图以`arr`为参数调用`bar`时,`arr`的所有权早已再第一次调用时被转移。\n" +"所有权系统阻止了我们在`foo`中使用相同的`arr`实例。" -#: src/ch03-02-references-and-snapshots.md:154 -msgid "Here’s the error:" -msgstr "这里有一个错误:" +#: src/ch03-01-what-is-ownership.md:108 +msgid "Running the code above will result in a compile-time error:" +msgstr "运行上面的代码将导致一个编译时错误:" -#: src/ch03-02-references-and-snapshots.md:156 +#: src/ch03-01-what-is-ownership.md:110 msgid "" -"```console\n" -"error: Invalid left-hand side of assignment.\n" -" --> ownership.cairo:15:5\n" -" rec.height = rec.width;\n" -" ^********^\n" +"```shell\n" +"error: Variable was previously moved. Trait has no implementation in context: core::traits::Copy::>\n" +" --> array.cairo:6:9\n" +" let mut arr = ArrayTrait::::new();\n" +" ^*****^\n" "```" msgstr "" -"```console\n" -"error: Invalid left-hand side of assignment.\n" -" --> ownership.cairo:15:5\n" -" rec.height = rec.width;\n" -" ^********^\n" +"```shell\n" +"error: Variable was previously moved. Trait has no implementation in context: core::traits::Copy::>\n" +" --> array.cairo:6:9\n" +" let mut arr = ArrayTrait::::new();\n" +" ^*****^\n" "```" -#: src/ch03-02-references-and-snapshots.md:163 -msgid "The compiler prevents us from modifying values associated to snapshots." -msgstr "编译器阻止我们修改与快照相关的值。" - -#: src/ch03-02-references-and-snapshots.md:165 -msgid "### Mutable References" -msgstr "### 可变引用" +#: src/ch03-01-what-is-ownership.md:117 +msgid "### The `Copy` Trait" +msgstr "### `Copy` Trait" -#: src/ch03-02-references-and-snapshots.md:167 +#: src/ch03-01-what-is-ownership.md:119 msgid "" -"We can achieve the behavior we want in Listing 3-6 by using a _mutable reference_ instead of a snapshot. Mutable references are actually mutable values passed to a function that are " -"implicitly returned at the end of the function, returning ownership to the calling context. By doing so, they allow you to mutate the value passed while keeping ownership of it by " -"returning it automatically at the end of the execution.\n" -"In Cairo, a parameter can be passed as _mutable reference_ using the `ref` modifier." +"If a type implements the `Copy` trait, passing it to a function will not move the ownership of the value to the function called, but will instead pass a copy of the value.\n" +"You can implement the `Copy` trait on your type by adding the `#[derive(Copy)]` annotation to your type definition. However, Cairo won't allow a type to be annotated with Copy if the " +"type itself or any of its components don't implement the Copy trait.\n" +"While Arrays and Dictionaries can't be copied, custom types that don't contain either of them can be." msgstr "" -"在示例3-6中,我们也可以通过使用 _mutable reference_ 而不是快照来实现我们想要的行为。可变引用实际上是传递给函数的可变值,在函数结束时被隐式返回,将所有权返回给调用的上下文。通过这样" -"做,它们允许你对传递的值进行改变,同时通过在执行结束时自动返回来保持对它的所有权。\n" -"在Cairo中,一个参数可以使用`ref`修饰符作为 _mutable reference_ 传递。" - -#: src/ch03-02-references-and-snapshots.md:170 -msgid "> **Note**: In Cairo, a parameter can only be passed as _mutable reference_ using the `ref` modifier if the variable is declared as mutable with `mut`." -msgstr "> **注意**:在Cairo中,只有在变量用`mut`声明为可变的情况下,才能使用`ref`修饰符将参数作为可变的引用传递。" - -#: src/ch03-02-references-and-snapshots.md:172 -msgid "In Listing 3-7, we use a mutable reference to modify the value of the `height` and `width` fields of the `Rectangle` instance in the `flip` function." -msgstr "在示例3-7中,我们使用一个可变的引用来修改`Rectangle`实例在`flip`函数中的`height`和`width`字段的值。" +"如果一个类型实现了`Copy`Trait,把它传递给一个函数将不会把值的所有权转移给被调用的函数,而是传递一个值的副本。\n" +"你可以通过在你的类型定义中添加`#[derive(Copy)]`标注来实现`Copy` Trait。然而,如果一个类型本身或其任何组件没有实现Copy Trait,Cairo将不允许该类型被标注为Copy。\n" +"虽然数组和字典不能被复制,但不包含它们的自定义类型可以被复制。" -#: src/ch03-02-references-and-snapshots.md:174 +#: src/ch03-01-what-is-ownership.md:123 msgid "" -"```rust\n" -"use debug::PrintTrait;\n" +"```rust,ignore_format\n" "#[derive(Copy, Drop)]\n" -"struct Rectangle {\n" -" height: u64,\n" -" width: u64,\n" +"struct Point {\n" +" x: u128,\n" +" y: u128,\n" "}\n" "\n" "fn main() {\n" -" let mut rec = Rectangle { height: 3, width: 10 };\n" -" flip(ref rec);\n" -" rec.height.print();\n" -" rec.width.print();\n" +" let p1 = Point { x: 5, y: 10 };\n" +" foo(p1);\n" +" foo(p1);\n" "}\n" "\n" -"fn flip(ref rec: Rectangle) {\n" -" let temp = rec.height;\n" -" rec.height = rec.width;\n" -" rec.width = temp;\n" +"fn foo(p: Point) { // do something with p\n" "}\n" "```" msgstr "" -"```rust\n" -"use debug::PrintTrait;\n" +"```rust,ignore_format\n" "#[derive(Copy, Drop)]\n" -"struct Rectangle {\n" -" height: u64,\n" -" width: u64,\n" +"struct Point {\n" +" x: u128,\n" +" y: u128,\n" "}\n" "\n" "fn main() {\n" -" let mut rec = Rectangle { height: 3, width: 10 };\n" -" flip(ref rec);\n" -" rec.height.print();\n" -" rec.width.print();\n" +" let p1 = Point { x: 5, y: 10 };\n" +" foo(p1);\n" +" foo(p1);\n" "}\n" "\n" -"fn flip(ref rec: Rectangle) {\n" -" let temp = rec.height;\n" -" rec.height = rec.width;\n" -" rec.width = temp;\n" +"fn foo(p: Point) { // do something with p\n" "}\n" "```" -#: src/ch03-02-references-and-snapshots.md:196 -msgid "Listing 3-7: Use of a mutable reference to modify a value" -msgstr "示例 3-7:使用一个可变的引用来修改一个值" - -#: src/ch03-02-references-and-snapshots.md:198 +#: src/ch03-01-what-is-ownership.md:140 msgid "" -"First, we change `rec` to be `mut`. Then we pass a mutable reference of `rec` into `flip` with `ref rec`, and update the function signature to accept a mutable reference with `ref " -"rec: Rectangle`. This makes it very clear that the `flip` function will mutate the value of the `Rectangle` instance passed as parameter." +"In this example, we can pass `p1` twice to the foo function because the `Point` type implements the `Copy` trait. This means that when we pass `p1` to `foo`, we are actually passing " +"a copy of `p1`, and the ownership of `p1` remains with the main function.\n" +"If you remove the `Copy` trait derivation from the `Point` type, you will get a compile-time error when trying to compile the code." msgstr "" -"首先,我们把`rec`改成`mut`。然后我们用 `ref rec` 将 `rec` 的可变引用传入 `flip` ,并更新函数签名,用 `ref rec: Rectangle`接受可变引用。这很清楚地表明,`flip`函数将改变作为参数传递的" -"`Rectangle`实例的值。" +"在这个例子中,我们可以向foo函数传递两次`p1`,因为`Point`类型实现了`Copy`trait。这意味着当我们把`p1`传递给`foo`时,我们实际上是在传递`p1`的副本,而`p1`的所有权仍然属于主函数。\n" +"如果你从`Point`类型中删除`Copy`trait的派生,当你试图编译代码时,你会得到一个编译时错误。" -#: src/ch03-02-references-and-snapshots.md:200 -msgid "The output of the program is:" -msgstr "程序的输出是:" +#: src/ch03-01-what-is-ownership.md:143 +msgid "_Don't worry about the `Struct` keyword. We will introduce this in [Chapter 4](ch04-00-using-structs-to-structure-related-data.md)._" +msgstr "_不要担心`Struct`关键字。我们将在[第四章](ch04-00-using-structs-to-structure-related-data.md)中介绍_" -#: src/ch03-02-references-and-snapshots.md:202 +#: src/ch03-01-what-is-ownership.md:145 +msgid "### The `Drop` Trait" +msgstr "### `Drop` Trait" + +#: src/ch03-01-what-is-ownership.md:147 msgid "" -"```console\n" -"[DEBUG]\n" -" (raw: 10)\n" +"You may have noticed that the `Point` type in the previous example also implements the `Drop` trait. In Cairo, a value cannot go out of scope unless it has been previously moved.\n" +"For example, the following code will not compile, because the struct `A` is not moved before it goes out of scope:" +msgstr "" +"你可能已经注意到,前面例子中的`Point`类型也实现了`Drop` trait。在Cairo中,一个值不能超出其作用域,除非它之前被移动过。\n" +"例如,下面的代码将无法编译,因为结构体`A`在超出作用域之前没有被移动:" + +#: src/ch03-01-what-is-ownership.md:150 +msgid "" +"```rust,does_not_compile\n" +"//TAG: does_not_compile\n" +"struct A {}\n" "\n" -"[DEBUG]\t (raw: 3)\n" +"fn main() {\n" +" A {}; // error: Value not dropped.\n" +"}\n" "```" msgstr "" -"```console\n" -"[DEBUG]\n" -" (raw: 10)\n" +"```rust,does_not_compile\n" +"//TAG: does_not_compile\n" +"struct A {}\n" "\n" -"[DEBUG]\t (raw: 3)\n" +"fn main() {\n" +" A {}; // error: Value not dropped.\n" +"}\n" "```" -#: src/ch03-02-references-and-snapshots.md:209 -msgid "As expected, the `height` and `width` fields of the `rec` variable have been swapped." -msgstr "正如预期的那样, `rec` 变量的 `height` 和 `width` 字段被调换了。" - -#: src/ch03-02-references-and-snapshots.md:211 -msgid "### Small recap" -msgstr "### 小结" - -#: src/ch03-02-references-and-snapshots.md:213 -msgid "Let’s recap what we’ve discussed about ownership, snapshots, and references:" -msgstr "让我们回顾一下我们已经讨论过的关于所有权、快照和引用的内容:" - -#: src/ch03-02-references-and-snapshots.md:215 +#: src/ch03-01-what-is-ownership.md:159 msgid "" -"- At any given time, a variable can only have one owner.\n" -"- You can pass a variable by-value, by-snapshot, or by-reference to a function.\n" -"- If you pass-by-value, ownership of the variable is transferred to the function.\n" -"- If you want to keep ownership of the variable and know that your function won’t mutate it, you can pass it as a snapshot with `@`.\n" -"- If you want to keep ownership of the variable and know that your function will mutate it, you can pass it as a mutable reference with `ref`." +"This is to ensure the soundness of Cairo programs. Soundness refers to the fact that if a\n" +"statement during the execution of the program is false, no cheating prover can convince an\n" +"honest verifier that it is true. In our case, we want to ensure the consistency of\n" +"consecutive dictionary key updates during program execution, which is only checked when\n" +"the dictionaries are `squashed` - which moves the ownership of the dictionary to the\n" +"`squash` method, thus allowing the dictionary to go out of scope. Unsquashed dictionaries\n" +"are dangerous, as a malicious prover could prove the correctness of inconsistent updates." msgstr "" -"- 在任何时候,一个变量只能有一个所有者。\n" -"- 你可以将一个变量以值的方式、以快照的方式、或以引用的方式传递给一个函数。\n" -"- 如果你按值传递,变量的所有权就会转移到函数中。\n" -"- 如果你想保留变量的所有权,并且知道你的函数不会改变它,你可以用`@`把它作为一个快照传递。\n" -"- 如果你想保留变量的所有权,并且知道你的函数会改变它,你可以用`ref`把它作为一个可改变的引用来传递。" - -#: src/ch04-00-using-structs-to-structure-related-data.md:1 -msgid "# Using Structs to Structure Related Data" -msgstr "# 使用结构体组织相关联的数据" +"这是为了确保Cairo程序的健全性。健全性指的是,如果在程序执行过程中的一个语句是假的,任何作弊的验证者都不可能说服一个诚实的验证者相信它是真的。\n" +"在我们的案例中,我们要确保程序执行过程中连续的字典键的更新的一致性。\n" +"这只有在字典被压缩(`squashed`)时才会进行检查--它将字典的所有权转移到了`squash`方法,从而允许字典超出作用域。未被压缩的字典是危险的,因为恶意的证明者可以证明不一致更新的正确性。" -#: src/ch04-00-using-structs-to-structure-related-data.md:3 +#: src/ch03-01-what-is-ownership.md:167 msgid "" -"A struct, or structure, is a custom data type that lets you package together and name multiple related values that make up a meaningful group. If you’re familiar with an object-" -"oriented language, a struct is like an object’s data attributes. In this chapter, we’ll compare and contrast tuples with structs to build on what you already know and demonstrate " -"when structs are a better way to group data." +"However, types that implement the `Drop` trait are allowed to go out of scope without being explicitly moved. When a value of a type that implements the `Drop` trait goes out of " +"scope, the `Drop` implementation is called on the type, which moves the value to the `drop` function, allowing it to go out of scope - This is what we call \"dropping\" a value.\n" +"It is important to note that the implementation of drop is a \"no-op\", meaning that it doesn't perform any actions other than allowing the value to go out of scope." msgstr "" -"结构体( _struct_ ),或称 _structure_ ,是一种自定义的数据类型,允许你包装和命名多个相关的值,从而形成一个有意义的组合。如果你熟悉一门面向对象语言,struct 就像对象中的数据属性。在本" -"章中,我们会对元组和结构体进行比较和对比,并演示什么时候结构体是一种更好的数据分组方式。" +"然而,实现了`Drop` trait的类型被允许超出作用域而不被明确移动。当一个实现了`Drop` trait的类型的值超出作用域时,`Drop`的实现会被调用,它将值移动到`drop`函数中,允许它超出作用域--这就是" +"我们所说的 \"丢弃 \"一个值。\n" +"值得注意的是,drop的实现是一个 \"no-op\",也就是说,除了允许值离开作用域之外,它不执行任何其他操作。" -#: src/ch04-00-using-structs-to-structure-related-data.md:5 +#: src/ch03-01-what-is-ownership.md:170 msgid "" -"We’ll demonstrate how to define and instantiate structs. We’ll discuss how to define associated functions, especially the kind of associated functions called methods, to specify " -"behavior associated with a struct type. Structs and enums (discussed in the next chapter) are the building blocks for creating new types in your program’s domain to take full " -"advantage of Cairo's compile-time type checking." +"The `Drop` implementation can be derived for all types, allowing them to be dropped when going out of scope, except for dictionaries (`Felt252Dict`) and types containing " +"dictionaries.\n" +"For example, the following code compiles:" msgstr "" -"我们还将演示如何定义和实例化结构体,并讨论如何定义关联函数,特别是被称为 _方法_ 的关联函数,以指定与结构体类型相关的行为。你可以在程序中基于结构体和枚举(enum)(将在下一章讨论)创建" -"新类型,以充分利用 Cairo 的编译时类型检查。" - -#: src/ch04-01-defining-and-instantiating-structs.md:1 -msgid "# Defining and Instantiating Structs" -msgstr "# 结构体的定义和实例化" +"除了字典(`Felt252Dict`)和包含字典的类型外,所有类型都可以派生`Drop`的实现,使得它们可以在超出作用域时被丢弃。\n" +"例如,下面的代码可以正常编译:" -#: src/ch04-01-defining-and-instantiating-structs.md:3 +#: src/ch03-01-what-is-ownership.md:173 msgid "" -"Structs are similar to tuples, discussed in [The Data Types](ch02-02-data-types.md) section, in that both hold multiple related values. Like tuples, the pieces of a struct can be " -"different types. Unlike with tuples, in a struct you’ll name each piece of data so it’s clear what the values mean. Adding these names means that structs are more flexible than " -"tuples: you don’t have to rely on the order of the data to specify or access the values of an instance." +"```rust\n" +"#[derive(Drop)]\n" +"struct A {}\n" +"\n" +"fn main() {\n" +" A {}; // Now there is no error.\n" +"}\n" +"```" msgstr "" -"结构体与[数据类型](ch02-02-data-types.md)一节中讨论的元组类似,它们都包含多个相关的值。和元组一样,结构体的每一部分可以是不同类型。但不同于元组,结构体需要命名各部分数据以便能清楚的表" -"明其值的意义。由于有了这些名字,结构体比元组更灵活:不需要依赖顺序来指定或访问实例中的值。" +"```rust\n" +"#[derive(Drop)]\n" +"struct A {}\n" +"\n" +"fn main() {\n" +" A {}; // Now there is no error.\n" +"}\n" +"```" -#: src/ch04-01-defining-and-instantiating-structs.md:5 +#: src/ch03-01-what-is-ownership.md:182 +msgid "### The `Destruct` Trait" +msgstr "### `Destruct` Trait" + +#: src/ch03-01-what-is-ownership.md:184 msgid "" -"To define a struct, we enter the keyword `struct` and name the entire struct. A struct’s name should describe the significance of the pieces of data being grouped together. Then, " -"inside curly brackets, we define the names and types of the pieces of data, which we call fields. For example, Listing 4-1 shows a struct that stores information about a user account." +"Manually calling the `squash` method on a dictionary is not very convenient, and it is easy to forget to do so. To make it easier to use dictionaries, Cairo provides the `Destruct` " +"trait, which allows you to specify the behavior of a type when it goes out of scope. While Dictionaries don't implement the `Drop` trait, they do implement the `Destruct` trait, " +"which allows them to automatically be `squashed` when they go out of scope. This means that you can use dictionaries without having to manually call the `squash` method." msgstr "" -"定义结构体,需要使用 `struct` 关键字并为整个结构体提供一个名字。结构体的名字需要描述它所组合的数据的意义。接着,在大括号中,定义每一部分数据的名字和类型,我们称为 字段(field)。例" -"如,示例 4-1 展示了一个存储用户账号信息的结构体。" +"手动调用字典上的 `squash` 方法不是很方便,而且很容易忘记这样做。为了方便使用字典,Cairo 提供了 `Destruct` trait,它允许你指定一个类型超出作用域时的行为。虽然字典没有实现`Drop` trait," +"但它们实现了`Destruct`trait,这允许它们在超出作用域时自动被`squashed`,因此你可以不需要手动调用`squash`方法。" -#: src/ch04-01-defining-and-instantiating-structs.md:7 src/ch04-01-defining-and-instantiating-structs.md:26 src/ch04-01-defining-and-instantiating-structs.md:48 -#: src/ch04-01-defining-and-instantiating-structs.md:83 src/ch04-01-defining-and-instantiating-structs.md:118 -msgid "Filename: structs.cairo" -msgstr "文件名:structs.cairo" +#: src/ch03-01-what-is-ownership.md:186 +msgid "Consider the following example, in which we define a custom type that contains a dictionary:" +msgstr "下面的这个例子中,我们定义了一个包含字典的自定义类型:" -#: src/ch04-01-defining-and-instantiating-structs.md:9 +#: src/ch03-01-what-is-ownership.md:188 msgid "" -"```rust\n" -"#[derive(Copy, Drop)]\n" -"struct User {\n" -" active: bool,\n" -" username: felt252,\n" -" email: felt252,\n" -" sign_in_count: u64,\n" +"```rust,does_not_compile\n" +"//TAG: does_not_compile\n" +"\n" +"struct A {\n" +" dict: Felt252Dict\n" +"}\n" +"\n" +"fn main() {\n" +" A { dict: Default::default() };\n" "}\n" "```" msgstr "" -"```rust\n" -"#[derive(Copy, Drop)]\n" -"struct User {\n" -" active: bool,\n" -" username: felt252,\n" -" email: felt252,\n" -" sign_in_count: u64,\n" +"```rust,does_not_compile\n" +"//TAG: does_not_compile\n" +"\n" +"struct A {\n" +" dict: Felt252Dict\n" +"}\n" +"\n" +"fn main() {\n" +" A { dict: Default::default() };\n" "}\n" "```" -#: src/ch04-01-defining-and-instantiating-structs.md:19 -msgid "Listing 4-1: A `User` struct definition" -msgstr "示例4-1:一个 `User` 结构定义" +#: src/ch03-01-what-is-ownership.md:200 +msgid "If you try to run this code, you will get a compile-time error:" +msgstr "如果你试图运行这段代码,你会得到一个编译时错误:" -#: src/ch04-01-defining-and-instantiating-structs.md:21 +#: src/ch03-01-what-is-ownership.md:202 msgid "" -"To use a struct after we’ve defined it, we create an _instance_ of that struct by specifying concrete values for each of the fields.\n" -"We create an instance by stating the name of the struct and then add curly brackets containing _key: value_ pairs, where the keys are the names of the fields and the values are the " -"data we want to store in those fields. We don’t have to specify the fields in the same order in which we declared them in the struct. In other words, the struct definition is like a " -"general template for the type, and instances fill in that template with particular data to create values of the type." +"```shell\n" +"error: Variable not dropped. Trait has no implementation in context: core::traits::Drop::. Trait has no implementation in context: core::traits::Destruct::.\n" +" --> temp7.cairo:7:5\n" +" A {\n" +" ^*^\n" +"```" msgstr "" -"一旦定义了结构体后,为了使用它,通过为每个字段指定具体值来创建这个结构体的 *实例*。\n" -"我们创建一个实例需要以结构体的名字开头,接着在大括号中使用 `key: value` 键 - 值对的形式提供字段,其中 key 是字段的名字,value 是需要存储在字段中的数据值。实例中字段的顺序不需要和它们" -"在结构体中声明的顺序一致。换句话说,结构体的定义就像一个类型的通用模板,而实例则会在这个模板中放入特定数据来创建这个类型的值。" +"```shell\n" +"error: Variable not dropped. Trait has no implementation in context: core::traits::Drop::. Trait has no implementation in context: core::traits::Destruct::.\n" +" --> temp7.cairo:7:5\n" +" A {\n" +" ^*^\n" +"```" -#: src/ch04-01-defining-and-instantiating-structs.md:24 -msgid "For example, we can declare a particular user as shown in Listing 4-2." -msgstr "例如,我们可以如示例4-2所示声明一个特定的用户。" +#: src/ch03-01-what-is-ownership.md:209 +msgid "" +"When A goes out of scope, it can't be dropped as it implements neither the `Drop` (as it contains a dictionary and can't `derive(Drop)`) nor the `Destruct` trait. To fix this, we can " +"derive the `Destruct` trait implementation for the `A` type:" +msgstr "" +"当A超出作用域时,它不能被丢弃,因为它既没有实现`Drop`(因为它包含一个字典,不能派生`derive(Drop)`)也没有实现`Destruct` trait。为了解决这个问题,我们可以为`A`类型派生出`Destruct` " +"trait的实现:" -#: src/ch04-01-defining-and-instantiating-structs.md:28 +#: src/ch03-01-what-is-ownership.md:211 msgid "" "```rust\n" -"#[derive(Copy, Drop)]\n" -"struct User {\n" -" active: bool,\n" -" username: felt252,\n" -" email: felt252,\n" -" sign_in_count: u64,\n" +"#[derive(Destruct)]\n" +"struct A {\n" +" dict: Felt252Dict\n" "}\n" +"\n" "fn main() {\n" -" let user1 = User {\n" -" active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" -" };\n" +" A { dict: Default::default() }; // No error here\n" "}\n" -"\n" "```" msgstr "" "```rust\n" -"#[derive(Copy, Drop)]\n" -"struct User {\n" -" active: bool,\n" -" username: felt252,\n" -" email: felt252,\n" -" sign_in_count: u64,\n" +"#[derive(Destruct)]\n" +"struct A {\n" +" dict: Felt252Dict\n" "}\n" +"\n" "fn main() {\n" -" let user1 = User {\n" -" active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" -" };\n" +" A { dict: Default::default() }; // No error here\n" "}\n" -"\n" "```" -#: src/ch04-01-defining-and-instantiating-structs.md:44 -msgid "Listing 4-2: Creating an instance of the `User` struct" -msgstr "示例4-2:创建一个`User`结构的实例" +#: src/ch03-01-what-is-ownership.md:222 +msgid "Now, when `A` goes out of scope, its dictionary will be automatically `squashed`, and the program will compile." +msgstr "现在,当`A`超出作用域时,它的字典将被自动`squashed`,并且程序将被编译。" -#: src/ch04-01-defining-and-instantiating-structs.md:46 +#: src/ch03-01-what-is-ownership.md:224 +msgid "### Copy Array data with Clone" +msgstr "### 用Clone复制数组数据" + +#: src/ch03-01-what-is-ownership.md:226 msgid "" -"To get a specific value from a struct, we use dot notation. For example, to access this user’s email address, we use `user1.email`. If the instance is mutable, we can change a value " -"by using the dot notation and assigning into a particular field. Listing 4-3 shows how to change the value in the `email` field of a mutable `User` instance." +"If we _do_ want to deeply copy the data of an `Array`, we can use a common method called `clone`. We’ll discuss method syntax in Chapter 5, but because methods are a common feature " +"in many\n" +"programming languages, you’ve probably seen them before." msgstr "" -"为了从结构体中获取某个特定的值,可以使用点号。举个例子,想要用户的邮箱地址,可以用 `user1.email`。如果结构体的实例是可变的,我们可以使用点号并为对应的字段赋值。示例 4-3 展示了如何改变" -"一个可变的 `User` 实例中 `email` 字段的值。" +"如果我们确实想深入复制一个 \"数组 \"的数据,我们可以使用一个叫做 `clone`的通用方法。\n" +"我们将在第5章中讨论方法的语法,但由于方法是许多编程语言的共同特征,你可能已经见过它们了。" -#: src/ch04-01-defining-and-instantiating-structs.md:50 +#: src/ch03-01-what-is-ownership.md:229 +msgid "Here’s an example of the `clone` method in action." +msgstr "下面是一个 `clone` 方法的实例。" + +#: src/ch03-01-what-is-ownership.md:231 +msgid "> Note: in the following example, we need to import the `Clone` trait from the corelib `clone` module, and its implementation for the array type from the `array` module." +msgstr "> 注意:在下面的例子中,我们需要从corelib的`clone`模块中导入`clone`trait,并从`array`模块中导入其对数组类型的实现。" + +#: src/ch03-01-what-is-ownership.md:233 msgid "" "```rust\n" -"# #[derive(Copy, Drop)]\n" -"# struct User {\n" -"# active: bool,\n" -"# username: felt252,\n" -"# email: felt252,\n" -"# sign_in_count: u64,\n" -"# }\n" +"use clone::Clone;\n" +"use array::ArrayTCloneImpl;\n" "fn main() {\n" -" let mut user1 = User {\n" -" active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" -" };\n" -" user1.email = 'anotheremail@example.com';\n" +" let arr1 = ArrayTrait::::new();\n" +" let arr2 = arr1.clone();\n" "}\n" -"# \n" -"# fn build_user(email: felt252, username: felt252) -> User {\n" -"# User { active: true, username: username, email: email, sign_in_count: 1, }\n" -"# }\n" -"# \n" -"# fn build_user_short(email: felt252, username: felt252) -> User {\n" -"# User { active: true, username: username, email: email, sign_in_count: 1, }\n" -"# }\n" -"# \n" "```" msgstr "" "```rust\n" -"# #[derive(Copy, Drop)]\n" -"# struct User {\n" -"# active: bool,\n" -"# username: felt252,\n" -"# email: felt252,\n" -"# sign_in_count: u64,\n" -"# }\n" +"use clone::Clone;\n" +"use array::ArrayTCloneImpl;\n" "fn main() {\n" -" let mut user1 = User {\n" -" active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" -" };\n" -" user1.email = 'anotheremail@example.com';\n" +" let arr1 = ArrayTrait::::new();\n" +" let arr2 = arr1.clone();\n" "}\n" -"# \n" -"# fn build_user(email: felt252, username: felt252) -> User {\n" -"# User { active: true, username: username, email: email, sign_in_count: 1, }\n" -"# }\n" -"# \n" -"# fn build_user_short(email: felt252, username: felt252) -> User {\n" -"# User { active: true, username: username, email: email, sign_in_count: 1, }\n" -"# }\n" -"# \n" "```" -#: src/ch04-01-defining-and-instantiating-structs.md:75 -msgid "Listing 4-3: Changing the value in the email field of a `User` instance" -msgstr "示例4-3:改变`User`实例的电子邮件字段中的值" - -#: src/ch04-01-defining-and-instantiating-structs.md:77 -msgid "Note that the entire instance must be mutable; Cairo doesn’t allow us to mark only certain fields as mutable." -msgstr "注意,整个实例必须是可变的;Cairo不允许我们只把某些字段标记为可变的。" - -#: src/ch04-01-defining-and-instantiating-structs.md:79 -msgid "As with any expression, we can construct a new instance of the struct as the last expression in the function body to implicitly return that new instance." -msgstr "与任何表达式一样,我们可以在函数主体的最后一个表达式中构造一个新的结构体实例,以隐式返回该新实例。" - -#: src/ch04-01-defining-and-instantiating-structs.md:81 -msgid "" -"Listing 4-4 shows a `build_user` function that returns a `User` instance with the given email and username. The `active` field gets the value of `true`, and the `sign_in_count` gets " -"a value of `1`." -msgstr "示例4-4显示了一个`build_user`函数,该函数返回一个`User`实例,并给出了电子邮件和用户名。`active`字段的值为`true`,`sign_in_count`的值为`1`。" +#: src/ch03-01-what-is-ownership.md:242 +msgid "> Note: you will need to run `scarb cairo-run` with the `--available-gas=2000000` option to run this example, because it uses a loop and must be ran with a gas limit." +msgstr "> 注意:你需要用`--available-gas=2000000`选项运行`scarb cairo-run`来运行这个例子,因为它使用了一个循环,运行时必须有gas限制。" -#: src/ch04-01-defining-and-instantiating-structs.md:85 +#: src/ch03-01-what-is-ownership.md:244 msgid "" -"```rust\n" -"# #[derive(Copy, Drop)]\n" -"# struct User {\n" -"# active: bool,\n" -"# username: felt252,\n" -"# email: felt252,\n" -"# sign_in_count: u64,\n" -"# }\n" -"# fn main() {\n" -"# let mut user1 = User {\n" -"# active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" -"# };\n" -"# user1.email = 'anotheremail@example.com';\n" -"# }\n" -"# \n" -"fn build_user(email: felt252, username: felt252) -> User {\n" -" User { active: true, username: username, email: email, sign_in_count: 1, }\n" -"}\n" -"# \n" -"# fn build_user_short(email: felt252, username: felt252) -> User {\n" -"# User { active: true, username: username, email: email, sign_in_count: 1, }\n" -"# }\n" -"# \n" -"```" +"When you see a call to `clone`, you know that some arbitrary code is being\n" +"executed and that code may be expensive. It’s a visual indicator that something\n" +"different is going on." msgstr "" -"```rust\n" -"# #[derive(Copy, Drop)]\n" -"# struct User {\n" -"# active: bool,\n" -"# username: felt252,\n" -"# email: felt252,\n" -"# sign_in_count: u64,\n" -"# }\n" -"# fn main() {\n" -"# let mut user1 = User {\n" -"# active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" -"# };\n" -"# user1.email = 'anotheremail@example.com';\n" -"# }\n" -"# \n" -"fn build_user(email: felt252, username: felt252) -> User {\n" -" User { active: true, username: username, email: email, sign_in_count: 1, }\n" -"}\n" -"# \n" -"# fn build_user_short(email: felt252, username: felt252) -> User {\n" -"# User { active: true, username: username, email: email, sign_in_count: 1, }\n" -"# }\n" -"# \n" -"```" +"当你看到对`clone`的调用时,你知道一些特定的代码被执行而且这些代码可能相当消耗资源。\n" +"你很容易察觉到一些不寻常的事情正在发生。" -#: src/ch04-01-defining-and-instantiating-structs.md:110 -msgid "Listing 4-4: A `build_user` function that takes an email and username and returns a `User` instance" -msgstr "示例4-4:一个`build_user`函数,接收电子邮件和用户名,并返回一个`User`实例" +#: src/ch03-01-what-is-ownership.md:248 +msgid "### Ownership and Functions" +msgstr "### 所有权与函数" -#: src/ch04-01-defining-and-instantiating-structs.md:112 +#: src/ch03-01-what-is-ownership.md:250 msgid "" -"It makes sense to name the function parameters with the same name as the struct fields, but having to repeat the `email` and `username` field names and variables is a bit tedious. If " -"the struct had more fields, repeating each name would get even more annoying. Luckily, there’s a convenient shorthand!" -msgstr "" -"为函数参数起与结构体字段相同的名字是可以理解的,但必须重复`email`和`username`字段的名称和变量就有点乏味了。如果结构体有更多字段,重复每个名称就更加烦人了。幸运的是,有一个方便的简写语" -"法!" - -#: src/ch04-01-defining-and-instantiating-structs.md:114 -msgid "## Using the Field Init Shorthand" -msgstr "## 使用字段初始化简写语法" +"Passing a variable to a function will either move it or copy it. As seen in the Array section, passing an `Array` as a function parameter transfers its ownership; let's see what " +"happens with other types." +msgstr "将一个变量传递给一个函数,要么移动它,要么复制它。正如在数组部分所看到的,将 `Array` 作为一个函数参数传递同时会传递它的所有权;让我们看看其他类型会发生什么。" -#: src/ch04-01-defining-and-instantiating-structs.md:116 +#: src/ch03-01-what-is-ownership.md:252 msgid "" -"Because the parameter names and the struct field names are exactly the same in Listing 4-4, we can use the field init shorthand syntax to rewrite `build_user` so it behaves exactly " -"the same but doesn’t have the repetition of `username` and `email`, as shown in Listing 4-5." -msgstr "" -"因为示例 5-4 中的参数名与字段名都完全相同,我们可以使用字段初始化简写语法(field init shorthand)来重写 `build_user`,这样其行为与之前完全相同,不过无需重复 `username` 和 `email` 了," -"如示例 5-5 所示。" +"Listing 3-3 has an example with some annotations\n" +"showing where variables go into and out of scope." +msgstr "示例3-3使用注释展示变量何时进入和离开作用域。" -#: src/ch04-01-defining-and-instantiating-structs.md:120 +#: src/ch03-01-what-is-ownership.md:257 msgid "" "```rust\n" -"# #[derive(Copy, Drop)]\n" -"# struct User {\n" -"# active: bool,\n" -"# username: felt252,\n" -"# email: felt252,\n" -"# sign_in_count: u64,\n" -"# }\n" -"# fn main() {\n" -"# let mut user1 = User {\n" -"# active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" -"# };\n" -"# user1.email = 'anotheremail@example.com';\n" -"# }\n" -"# \n" -"# fn build_user(email: felt252, username: felt252) -> User {\n" -"# User { active: true, username: username, email: email, sign_in_count: 1, }\n" -"# }\n" -"# \n" -"fn build_user_short(email: felt252, username: felt252) -> User {\n" -" User { active: true, username: username, email: email, sign_in_count: 1, }\n" -"}\n" -"# \n" +"//TAG: ignore_fmt\n" +"#[derive(Drop)]\n" +"struct MyStruct{}\n" +"\n" +"fn main() {\n" +" let my_struct = MyStruct{}; // my_struct comes into scope\n" +"\n" +" takes_ownership(my_struct); // my_struct's value moves into the function...\n" +" // ... and so is no longer valid here\n" +"\n" +" let x = 5; // x comes into scope\n" +"\n" +" makes_copy(x); // x would move into the function,\n" +" // but u128 implements Copy, so it is okay to still\n" +" // use x afterward\n" +"\n" +"} // Here, x goes out of scope and is dropped.\n" +"\n" +"\n" +"fn takes_ownership(some_struct: MyStruct) { // some_struct comes into scope\n" +"} // Here, some_struct goes out of scope and `drop` is called.\n" +"\n" +"fn makes_copy(some_uinteger: u128) { // some_uinteger comes into scope\n" +"} // Here, some_integer goes out of scope and is dropped.\n" "```" msgstr "" "```rust\n" -"# #[derive(Copy, Drop)]\n" -"# struct User {\n" -"# active: bool,\n" -"# username: felt252,\n" -"# email: felt252,\n" -"# sign_in_count: u64,\n" -"# }\n" -"# fn main() {\n" -"# let mut user1 = User {\n" -"# active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" -"# };\n" -"# user1.email = 'anotheremail@example.com';\n" -"# }\n" -"# \n" -"# fn build_user(email: felt252, username: felt252) -> User {\n" -"# User { active: true, username: username, email: email, sign_in_count: 1, }\n" -"# }\n" -"# \n" -"fn build_user_short(email: felt252, username: felt252) -> User {\n" -" User { active: true, username: username, email: email, sign_in_count: 1, }\n" -"}\n" -"# \n" +"//TAG: ignore_fmt\n" +"#[derive(Drop)]\n" +"struct MyStruct{}\n" +"\n" +"fn main() {\n" +" let my_struct = MyStruct{}; // my_struct comes into scope\n" +"\n" +" takes_ownership(my_struct); // my_struct's value moves into the function...\n" +" // ... and so is no longer valid here\n" +"\n" +" let x = 5; // x comes into scope\n" +"\n" +" makes_copy(x); // x would move into the function,\n" +" // but u128 implements Copy, so it is okay to still\n" +" // use x afterward\n" +"\n" +"} // Here, x goes out of scope and is dropped.\n" +"\n" +"\n" +"fn takes_ownership(some_struct: MyStruct) { // some_struct comes into scope\n" +"} // Here, some_struct goes out of scope and `drop` is called.\n" +"\n" +"fn makes_copy(some_uinteger: u128) { // some_uinteger comes into scope\n" +"} // Here, some_integer goes out of scope and is dropped.\n" "```" -#: src/ch04-01-defining-and-instantiating-structs.md:145 +#: src/ch03-01-what-is-ownership.md:284 msgid "" -"Listing 4-5: A `build_user` function that uses field init shorthand because the `username` and `email` parameters have the same name as struct fields" -msgstr "示例4-5: `build_user`函数使用了字段初始化简写语法,因为`username`和`email`参数与结构体字段同名," +"Listing 3-3: Functions with ownership and scope\n" +"annotated" +msgstr "示例3-3:带有所有权和作用域注释的函数" -#: src/ch04-01-defining-and-instantiating-structs.md:147 +#: src/ch03-01-what-is-ownership.md:287 msgid "" -"Here, we’re creating a new instance of the `User` struct, which has a field named `email`. We want to set the `email` field’s value to the value in the `email` parameter of the " -"`build_user` function. Because the `email` field and the `email` parameter have the same name, we only need to write `email` rather than `email: email`." +"If we tried to use `my_struct` after the call to `takes_ownership`, Cairo would throw a\n" +"compile-time error. These static checks protect us from mistakes. Try adding\n" +"code to `main` that uses `my_struct` and `x` to see where you can use them and where\n" +"the ownership rules prevent you from doing so." msgstr "" -"这里,我们正在创建一个新的 `User` 结构体实例,它有一个名为 `email`的字段。我们希望将`email`字段的值设置为`build_user`函数的`email`参数中的值。因为`email`字段和`email`参数有相同的名" -"字,我们只需要写`email`而不是`email: email`。" - -#: src/ch04-02-an-example-program-using-structs.md:1 -msgid "# An Example Program Using Structs" -msgstr "# 结构体示例程序" +"如果我们试图在调用`takes_ownership`之后使用`my_struct`,Cairo会抛出一个编译时错误。\n" +"这些静态检查可以保护我们不犯错误。试着在`main`中添加使用`my_struct`和`x`的代码,看看哪里可以使用它们,\n" +"哪里所有权规则将会阻止你这样做。" -#: src/ch04-02-an-example-program-using-structs.md:3 -msgid "" -"To understand when we might want to use structs, let’s write a program that calculates the area of a rectangle. We’ll start by using single variables, and then refactor the program " -"until we’re using structs instead." -msgstr "为了理解何时会需要使用结构体,让我们编写一个计算长方形面积的程序。我们会从单独的变量开始,接着重构程序直到使用结构体替代他们为止。" +#: src/ch03-01-what-is-ownership.md:292 +msgid "### Return Values and Scope" +msgstr "### 返回值与作用域" -#: src/ch04-02-an-example-program-using-structs.md:5 +#: src/ch03-01-what-is-ownership.md:294 msgid "" -"Let’s make a new project with Scarb called _rectangles_ that will take the width and height of a rectangle specified in pixels and calculate the area of the rectangle. Listing 4-6 " -"shows a short program with one way of doing exactly that in our project’s _src/lib.cairo_." +"Returning values can also transfer ownership. Listing 3-4 shows an example of a\n" +"function that returns some value, with similar annotations as those in Listing\n" +"4-3." msgstr "" -"让我们用Scarb做一个名为 _rectangles_ 的新项目,它获取以像素为单位的长方形的宽度和高度,并计算出长方形的面积。示例4-6显示了位于项目中的 _src/lib.cairo_ 中的小程序,它刚刚好实现此功能。" +"返回值也可以转移所有权。示例3-4显示了一个例子\n" +"该函数返回一些值,其注释与示例4-3中的相似。" -#: src/ch04-02-an-example-program-using-structs.md:9 +#: src/ch03-01-what-is-ownership.md:300 msgid "" "```rust\n" -"use debug::PrintTrait;\n" +"//TAG: ignore_fmt\n" +"#[derive(Drop)]\n" +"struct A {}\n" +"\n" "fn main() {\n" -" let width1 = 30;\n" -" let height1 = 10;\n" -" let area = area(width1, height1);\n" -" area.print();\n" +" let a1 = gives_ownership(); // gives_ownership moves its return\n" +" // value into a1\n" +"\n" +" let a2 = A {}; // a2 comes into scope\n" +"\n" +" let a3 = takes_and_gives_back(a2); // a2 is moved into\n" +" // takes_and_gives_back, which also\n" +" // moves its return value into a3\n" +"\n" +"} // Here, a3 goes out of scope and is dropped. a2 was moved, so nothing\n" +" // happens. a1 goes out of scope and is dropped.\n" +"\n" +"fn gives_ownership() -> A { // gives_ownership will move its\n" +" // return value into the function\n" +" // that calls it\n" +"\n" +" let some_a = A {}; // some_a comes into scope\n" +"\n" +" some_a // some_a is returned and\n" +" // moves ownership to the calling\n" +" // function\n" "}\n" "\n" -"fn area(width: u64, height: u64) -> u64 {\n" -" width * height\n" +"// This function takes an instance some_a of A and returns it\n" +"fn takes_and_gives_back(some_a: A) -> A { // some_a comes into\n" +" // scope\n" +"\n" +" some_a // some_a is returned and moves\n" +" // ownership to the calling\n" +" // function\n" "}\n" "```" msgstr "" "```rust\n" -"use debug::PrintTrait;\n" +"//TAG: ignore_fmt\n" +"#[derive(Drop)]\n" +"struct A {}\n" +"\n" "fn main() {\n" -" let width1 = 30;\n" -" let height1 = 10;\n" -" let area = area(width1, height1);\n" -" area.print();\n" +" let a1 = gives_ownership(); // gives_ownership moves its return\n" +" // value into a1\n" +"\n" +" let a2 = A {}; // a2 comes into scope\n" +"\n" +" let a3 = takes_and_gives_back(a2); // a2 is moved into\n" +" // takes_and_gives_back, which also\n" +" // moves its return value into a3\n" +"\n" +"} // Here, a3 goes out of scope and is dropped. a2 was moved, so nothing\n" +" // happens. a1 goes out of scope and is dropped.\n" +"\n" +"fn gives_ownership() -> A { // gives_ownership will move its\n" +" // return value into the function\n" +" // that calls it\n" +"\n" +" let some_a = A {}; // some_a comes into scope\n" +"\n" +" some_a // some_a is returned and\n" +" // moves ownership to the calling\n" +" // function\n" "}\n" "\n" -"fn area(width: u64, height: u64) -> u64 {\n" -" width * height\n" +"// This function takes an instance some_a of A and returns it\n" +"fn takes_and_gives_back(some_a: A) -> A { // some_a comes into\n" +" // scope\n" +"\n" +" some_a // some_a is returned and moves\n" +" // ownership to the calling\n" +" // function\n" "}\n" "```" -#: src/ch04-02-an-example-program-using-structs.md:23 -msgid "Listing 4-6: Calculating the area of a rectangle specified by separate width and height variables" -msgstr "示例4-6:通过分别指定长方形的宽和高的变量来计算长方形面积" +#: src/ch03-01-what-is-ownership.md:339 +msgid "" +"Listing 3-4: Transferring ownership of return\n" +"values" +msgstr "" +"示例3-4:转移返回值的所有权\n" +"" -#: src/ch04-02-an-example-program-using-structs.md:25 -msgid "Now run the program with `cairo-run src/lib.cairo`:" -msgstr "现在用`cairo-run src/lib.cairo`运行该程序:" +#: src/ch03-01-what-is-ownership.md:342 +msgid "When a variable goes out of scope, its value is dropped, unless ownership of the value has been moved to another variable." +msgstr "当一个变量超出作用域时,它的值会被丢弃,除非值的所有权被转移到另一个变量上。" -#: src/ch04-02-an-example-program-using-structs.md:27 +#: src/ch03-01-what-is-ownership.md:344 msgid "" -"```bash\n" -"$ cairo-run src/lib.cairo\n" -"[DEBUG] , (raw: 300)\n" -"\n" -"Run completed successfully, returning []\n" -"```" +"While this works, taking ownership and then returning ownership with every\n" +"function is a bit tedious. What if we want to let a function use a value but\n" +"not take ownership? It’s quite annoying that anything we pass in also needs to\n" +"be passed back if we want to use it again, in addition to any data resulting\n" +"from the body of the function that we might want to return as well." msgstr "" -"```bash\n" -"$ cairo-run src/lib.cairo\n" -"[DEBUG] , (raw: 300)\n" -"\n" -"Run completed successfully, returning []\n" -"```" - -#: src/ch04-02-an-example-program-using-structs.md:34 -msgid "This code succeeds in figuring out the area of the rectangle by calling the `area` function with each dimension, but we can do more to make this code clear and readable." -msgstr "这段代码通过调用每个维度的`area`函数,成功地算出了矩形的面积,但我们仍然可以修改这段代码来使它的意义更加明确,并且增加可读性。" +"虽然这样是可以的,但是在每一个函数中都获取所有权并接着返回所有权有些啰嗦。\n" +"如果我们想要函数使用一个值但不获取所有权该怎么办呢?\n" +"除此之外,我们也可能想返回函数体中产生的一些数据。" -#: src/ch04-02-an-example-program-using-structs.md:36 -msgid "The issue with this code is evident in the signature of `area`:" -msgstr "这段代码的问题在 `area` 的签名中很明显:" +#: src/ch03-01-what-is-ownership.md:350 +msgid "Cairo does let us return multiple values using a tuple, as shown in Listing 3-5." +msgstr "Cairo的确让我们可以使用一个元组返回多个值,如示例3-5所示。" -#: src/ch04-02-an-example-program-using-structs.md:38 +#: src/ch03-01-what-is-ownership.md:354 msgid "" "```rust\n" -"fn area(width: u64, height: u64) -> u64 {\n" +"fn main() {\n" +" let arr1 = ArrayTrait::::new();\n" +"\n" +" let (arr2, len) = calculate_length(arr1);\n" +"}\n" +"\n" +"fn calculate_length(arr: Array) -> (Array, usize) {\n" +" let length = arr.len(); // len() returns the length of an array\n" +"\n" +" (arr, length)\n" +"}\n" "```" msgstr "" "```rust\n" -"fn area(width: u64, height: u64) -> u64 {\n" +"fn main() {\n" +" let arr1 = ArrayTrait::::new();\n" +"\n" +" let (arr2, len) = calculate_length(arr1);\n" +"}\n" +"\n" +"fn calculate_length(arr: Array) -> (Array, usize) {\n" +" let length = arr.len(); // len() returns the length of an array\n" +"\n" +" (arr, length)\n" +"}\n" "```" -#: src/ch04-02-an-example-program-using-structs.md:42 +#: src/ch03-01-what-is-ownership.md:368 +msgid "Listing 3-5: Returning ownership of parameters" +msgstr "示例3-5:返回参数的所有权" + +#: src/ch03-01-what-is-ownership.md:370 msgid "" -"The `area` function is supposed to calculate the area of one rectangle, but the function we wrote has two parameters, and it’s not clear anywhere in our program that the parameters " -"are related. It would be more readable and more manageable to group width and height together. We’ve already discussed one way we might do that in [Chapter 3](ch02-02-data-types." -"html#the-tuple-type): using tuples." +"But this is too much ceremony and a lot of work for a concept that should be\n" +"common. Luckily for us, Cairo has two features for using a value without\n" +"transferring ownership, called _references_ and _snapshots_." msgstr "" -"`area`函数应该是计算一个矩形的面积,但是我们写的函数有两个参数,而且在我们的程序中没有任何地方明确说明这些参数的关系。如果把宽度和高度放在一起,会更有可读性,也更容易管理。我们已经在" -"[第三章](ch02-02-data-types.html#the-tuple-type)中讨论了一种我们可以做到的方法:使用元组。" +"但是这未免有些形式主义,而且这种场景应该很常见。\n" +"幸运的是,Cairo提供了两个功能可以在不转移所有权的情况下使用一个值,\n" +"称为 引用( _references_ )和 快照( _snapshots_ )。" -#: src/ch04-02-an-example-program-using-structs.md:44 -msgid "## Refactoring with Tuples" -msgstr "## 使用元组重构" +#: src/ch03-02-references-and-snapshots.md:1 +msgid "## References and Snapshots" +msgstr "## 引用和快照" -#: src/ch04-02-an-example-program-using-structs.md:46 -msgid "Listing 4-7 shows another version of our program that uses tuples." -msgstr "示例4-7显示了我们使用元组的另一个程序版本。" +#: src/ch03-02-references-and-snapshots.md:3 +msgid "" +"The issue with the tuple code in Listing 3-5 is that we have to return the\n" +"`Array` to the calling function so we can still use the `Array` after the\n" +"call to `calculate_length`, because the `Array` was moved into\n" +"`calculate_length`." +msgstr "" +"示例3-5中元组代码的问题是,因为 `Array`的所有权被移到了`calculate_length`中。\n" +"我们必须返回`Array`给调用的函数,这样我们在调用`calculate_length`后才仍然可以使用`Array`。" -#: src/ch04-02-an-example-program-using-structs.md:50 +#: src/ch03-02-references-and-snapshots.md:8 +msgid "### Snapshots" +msgstr "### 快照(Snapshots)" + +#: src/ch03-02-references-and-snapshots.md:10 +msgid "" +"Instead, we can provide a _snapshot_ of the `Array` value. In Cairo, a snapshot\n" +"is an immutable view of a value at a certain point in time. In the previous chapter,\n" +"we talked about how Cairo's ownership system prevents us from using a value after\n" +"we've moved it, protecting us from potentially writing twice to the same memory cell when\n" +"appending values to arrays. However, it's not very convenient. Let's see how we can retain ownership\n" +"of the value in the calling function using snapshots." +msgstr "" +"不过,我们可以提供一个`Array`值的 _snapshot_ 。在Cairo,一个快照是一个在某个时间点上的不可改变的值的视图。\n" +"在上一章中,我们谈到了Cairo的所有权系统是如何防止我们在移动一个值后使用它,从而防止我们在向数组添加值时不会潜在地多次写入相同的内存单元。\n" +"然而,这不是很方便。让我们看看如何使用快照在调用函数中保留值的所有权。" + +#: src/ch03-02-references-and-snapshots.md:17 +msgid "" +"Here is how you would define and use a `calculate_length` function that takes a\n" +"snapshot to an array as a parameter instead of taking ownership of the underlying value. In this example,\n" +"the `calculate_length` function returns the length of the array passed as parameter.\n" +"As we're passing it as a snapshot, which is an immutable view of the array, we can be sure that\n" +"the `calculate_length` function will not mutate the array, and ownership of the array is kept in the main function." +msgstr "" +"下面是你如何定义和使用一个`calculate_length` 函数,它以一个快照作为参数,而不是获取底层值的所有权。在这个例子中、\n" +"`calculate_length`函数返回作为参数的数组的长度。\n" +"因为我们是以快照的形式传递的,这是一个不可改变的数组视图,我们可以确定\n" +"`calculate_length`函数不会改变数组,数组的所有权被保留在主函数中。" + +#: src/ch03-02-references-and-snapshots.md:25 msgid "" "```rust\n" "use debug::PrintTrait;\n" +"\n" "fn main() {\n" -" let rectangle = (30, 10);\n" -" let area = area(rectangle);\n" -" area.print(); // print out the area\n" +" let mut arr1 = ArrayTrait::::new();\n" +" let first_snapshot = @arr1; // Take a snapshot of `arr1` at this point in time\n" +" arr1.append(1); // Mutate `arr1` by appending a value\n" +" let first_length = calculate_length(\n" +" first_snapshot\n" +" ); // Calculate the length of the array when the snapshot was taken\n" +" let second_length = calculate_length(@arr1); // Calculate the current length of the array\n" +" first_length.print();\n" +" second_length.print();\n" "}\n" "\n" -"fn area(dimension: (u64, u64)) -> u64 {\n" -" let (x, y) = dimension;\n" -" x * y\n" +"fn calculate_length(arr: @Array) -> usize {\n" +" arr.len()\n" "}\n" "```" msgstr "" "```rust\n" "use debug::PrintTrait;\n" +"\n" "fn main() {\n" -" let rectangle = (30, 10);\n" -" let area = area(rectangle);\n" -" area.print(); // print out the area\n" +" let mut arr1 = ArrayTrait::::new();\n" +" let first_snapshot = @arr1; // Take a snapshot of `arr1` at this point in time\n" +" arr1.append(1); // Mutate `arr1` by appending a value\n" +" let first_length = calculate_length(\n" +" first_snapshot\n" +" ); // Calculate the length of the array when the snapshot was taken\n" +" let second_length = calculate_length(@arr1); // Calculate the current length of the array\n" +" first_length.print();\n" +" second_length.print();\n" "}\n" "\n" -"fn area(dimension: (u64, u64)) -> u64 {\n" -" let (x, y) = dimension;\n" -" x * y\n" +"fn calculate_length(arr: @Array) -> usize {\n" +" arr.len()\n" "}\n" "```" -#: src/ch04-02-an-example-program-using-structs.md:64 -msgid "Listing 4-7: Specifying the width and height of the rectangle with a tuple" -msgstr "示例4-7:用一个元组指定矩形的宽度和高度" - -#: src/ch04-02-an-example-program-using-structs.md:66 +#: src/ch03-02-references-and-snapshots.md:45 msgid "" -"In one way, this program is better. Tuples let us add a bit of structure, and we’re now passing just one argument. But in another way, this version is less clear: tuples don’t name " -"their elements, so we have to index into the parts of the tuple, making our calculation less obvious." +"> Note: It is only possible to call the `len()` method on an array snapshot because it is defined as such in the `ArrayTrait` trait. If you try to call a method that is not defined " +"for snapshots on a snapshot, you will get a compilation error. However, you can call methods expecting a snapshot on non-snapshot types." msgstr "" -"在某种程度上说,这个程序更好一点了。元组帮助我们增加了一些结构性,并且现在只需传一个参数。不过在另一方面,这个版本却有一点不明确了:元组并没有给出元素的名称,所以计算变得更费解了,因" -"为不得不使用索引来获取元组的每一部分。" - -#: src/ch04-02-an-example-program-using-structs.md:68 -msgid "" -"Mixing up the width and height wouldn’t matter for the area calculation, but if we want to calculate the difference, it would matter! We would have to keep in mind that `width` is " -"the tuple index `0` and `height` is the tuple index `1`. This would be even harder for someone else to figure out and keep in mind if they were to use our code. Because we haven’t " -"conveyed the meaning of our data in our code, it’s now easier to introduce errors." -msgstr "" -"混淆宽度和高度对于计算面积来说并不重要,但是如果我们想计算差值,那就很重要了。我们必须记住 `width` 是元组索引`0`, `height` 是元组索引`1`。如果其他人要使用这些代码,他们必须要搞清楚这" -"一点,并也要牢记于心。很容易忘记或者混淆这些值而造成错误,因为我们没有在代码中传达数据的意图。" - -#: src/ch04-02-an-example-program-using-structs.md:70 -msgid "## Refactoring with Structs: Adding More Meaning" -msgstr "## 使用结构体重构:赋予更多意义" +"> 注意:只有在数组快照上才能调用 `len()` 方法,因为它在 `ArrayTrait` trait中被定义成这样。如果你试图在一个快照上调用一个没有为快照定义的方法,你会得到一个编译错误。然而,你可以在非快" +"照类型上调用快照的方法。" -#: src/ch04-02-an-example-program-using-structs.md:72 -msgid "We use structs to add meaning by labeling the data. We can transform the tuple we’re using into a struct with a name for the whole as well as names for the parts." -msgstr "我们使用结构体为数据命名来为其赋予意义。我们可以将我们正在使用的元组转换成一个有整体名称而且每个部分也有对应名字的结构体。" +#: src/ch03-02-references-and-snapshots.md:47 +msgid "The output of this program is:" +msgstr "这个程序的输出是:" -#: src/ch04-02-an-example-program-using-structs.md:76 +#: src/ch03-02-references-and-snapshots.md:49 msgid "" -"```rust,ignore_format\n" -"use debug::PrintTrait;\n" -"\n" -"struct Rectangle {\n" -" width: u64,\n" -" height: u64,\n" -"}\n" +"```shell\n" +"[DEBUG]\t \t(raw: 0)\n" "\n" -"fn main() {\n" -" let rectangle = Rectangle { width: 30, height: 10, };\n" -" let area = area(rectangle);\n" -" area.print(); // print out the area\n" -"}\n" +"[DEBUG]\t \t(raw: 1)\n" "\n" -"fn area(rectangle: Rectangle) -> u64 {\n" -" rectangle.width * rectangle.height\n" -"}\n" +"Run completed successfully, returning []\n" "```" msgstr "" -"```rust,ignore_format\n" -"use debug::PrintTrait;\n" -"\n" -"struct Rectangle {\n" -" width: u64,\n" -" height: u64,\n" -"}\n" +"```shell\n" +"[DEBUG]\t \t(raw: 0)\n" "\n" -"fn main() {\n" -" let rectangle = Rectangle { width: 30, height: 10, };\n" -" let area = area(rectangle);\n" -" area.print(); // print out the area\n" -"}\n" +"[DEBUG]\t \t(raw: 1)\n" "\n" -"fn area(rectangle: Rectangle) -> u64 {\n" -" rectangle.width * rectangle.height\n" -"}\n" +"Run completed successfully, returning []\n" "```" -#: src/ch04-02-an-example-program-using-structs.md:95 -msgid "Listing 4-8: Defining a `Rectangle` struct" -msgstr "示例 4-8:定义一个`Rectangle`结构" - -#: src/ch04-02-an-example-program-using-structs.md:97 +#: src/ch03-02-references-and-snapshots.md:57 msgid "" -"Here we’ve defined a struct and named it `Rectangle`. Inside the curly brackets, we defined the fields as `width` and `height`, both of which have type `u64`. Then, in `main`, we " -"created a particular instance of `Rectangle` that has a width of `30` and a height of `10`. Our `area` function is now defined with one parameter, which we’ve named `rectangle` which " -"is of type `Rectangle` struct. We can then access the fields of the instance with dot notation, and it gives descriptive names to the values rather than using the tuple index values " -"of `0` and `1`." +"First, notice that all the tuple code in the variable declaration and the function return value is gone. Second, note\n" +"that we pass `@arr1` into `calculate_length` and, in its definition, we take `@Array` rather than `Array`." msgstr "" -"这里我们定义了一个结构,并将其命名为 `Rectangle`。在大括号中,我们将字段定义为 `width` 和 `height`,它们的类型都是 `u64`。然后,在`main`中,我们创建了一个`Rectangle`的特殊实例,它的宽" -"度是`30`,高度是`10`。我们的 `area`函数现在定义了一个名为 `rectangle`参数,它是`Rectangle`结构类型。然后我们可以用点符号来访问实例的字段,它给这些值起了描述性的名字,而不是使用`0`和" -"`1`的元组索引值。结构体胜在更清晰明了。" - -#: src/ch04-02-an-example-program-using-structs.md:99 -msgid "## Adding Useful Functionality with Trait" -msgstr "## 用Trait增加实用功能" +"首先,注意到变量声明和函数返回值中的所有元组代码都消失了。\n" +"第二,注意看我们把`@arr1`传入`calculate_length`,因此在它的定义中,我们采用`@Array`,而不是`Array`。" -#: src/ch04-02-an-example-program-using-structs.md:101 -msgid "" -"It’d be useful to be able to print an instance of `Rectangle` while we’re debugging our program and see the values for all its fields. Listing 4-9 tries using the `print` as we have " -"used in previous chapters. This won’t work." -msgstr "在调试程序时打印出 `Rectangle` 实例来查看其所有字段的值非常有用。示例 4-9 像前面章节那样尝试使用 `print`。但这并不管用。" +#: src/ch03-02-references-and-snapshots.md:60 +msgid "Let’s take a closer look at the function call here:" +msgstr "让我们仔细看一下这里的函数调用:" -#: src/ch04-02-an-example-program-using-structs.md:105 +#: src/ch03-02-references-and-snapshots.md:62 msgid "" "```rust\n" -"use debug::PrintTrait;\n" -"\n" -"struct Rectangle {\n" -" width: u64,\n" -" height: u64,\n" -"}\n" -"\n" -"fn main() {\n" -" let rectangle = Rectangle { width: 30, height: 10, };\n" -" rectangle.print();\n" -"}\n" +"# use debug::PrintTrait;\n" +"# \n" +"# fn main() {\n" +"# let mut arr1 = ArrayTrait::::new();\n" +"# let first_snapshot = @arr1; // Take a snapshot of `arr1` at this point in time\n" +"# arr1.append(1); // Mutate `arr1` by appending a value\n" +"# let first_length = calculate_length(\n" +"# first_snapshot\n" +"# ); // Calculate the length of the array when the snapshot was taken\n" +"# let second_length = calculate_length(@arr1); // Calculate the current length of the array\n" +" first_length.print();\n" +"# second_length.print();\n" +"# }\n" +"# \n" +"# fn calculate_length(arr: @Array) -> usize {\n" +"# arr.len()\n" +"# }\n" "```" msgstr "" "```rust\n" -"use debug::PrintTrait;\n" -"\n" -"struct Rectangle {\n" -" width: u64,\n" -" height: u64,\n" -"}\n" -"\n" -"fn main() {\n" -" let rectangle = Rectangle { width: 30, height: 10, };\n" -" rectangle.print();\n" -"}\n" +"# use debug::PrintTrait;\n" +"# \n" +"# fn main() {\n" +"# let mut arr1 = ArrayTrait::::new();\n" +"# let first_snapshot = @arr1; // Take a snapshot of `arr1` at this point in time\n" +"# arr1.append(1); // Mutate `arr1` by appending a value\n" +"# let first_length = calculate_length(\n" +"# first_snapshot\n" +"# ); // Calculate the length of the array when the snapshot was taken\n" +"# let second_length = calculate_length(@arr1); // Calculate the current length of the array\n" +" first_length.print();\n" +"# second_length.print();\n" +"# }\n" +"# \n" +"# fn calculate_length(arr: @Array) -> usize {\n" +"# arr.len()\n" +"# }\n" "```" -#: src/ch04-02-an-example-program-using-structs.md:119 -msgid "Listing 4-9: Attempting to print a `Rectangle` instance" -msgstr "示例 4-9:试图打印一个 `Rectangle`实例" +#: src/ch03-02-references-and-snapshots.md:82 +msgid "" +"The `@arr1` syntax lets us create a snapshot of the value in `arr1`. Because a snapshot is an immutable view of a value, the value it points to cannot be modified through the " +"snapshot, and the value it refers to will not be dropped once the snapshot stops being used." +msgstr "`@arr1`语法让我们为`arr1`中的值创建了一个快照。因为快照是一个值的不可改变的视图,它所指向的值不能通过快照被修改,因此即使快照停止被使用,它所指向的值也不会被丢弃。" -#: src/ch04-02-an-example-program-using-structs.md:121 -msgid "When we compile this code, we get an error with this message:" -msgstr "当我们编译这段代码时,我们得到了一个错误,有这样的信息:" +#: src/ch03-02-references-and-snapshots.md:84 +msgid "Similarly, the signature of the function uses `@` to indicate that the type of the parameter `arr` is a snapshot. Let’s add some explanatory annotations:" +msgstr "同样,函数的签名使用`@`来表示参数`arr`的类型是一个快照。让我们添加一些解释性的注解:" -#: src/ch04-02-an-example-program-using-structs.md:123 +#: src/ch03-02-references-and-snapshots.md:86 msgid "" -"```bash\n" -"$ cairo-compile src/lib.cairo\n" -"error: Method `print` not found on type \"../src::Rectangle\". Did you import the correct trait and impl?\n" -" --> lib.cairo:16:15\n" -" rectangle.print();\n" -" ^***^\n" -"\n" -"Error: Compilation failed.\n" +"```rust, noplayground\n" +"fn calculate_length(\n" +" array_snapshot: @Array\n" +") -> usize { // array_snapshot is a snapshot of an Array\n" +" array_snapshot.len()\n" +"} // Here, array_snapshot goes out of scope and is dropped.\n" +"// However, because it is only a view of what the original array `arr` contains, the original `arr` can still be used.\n" "```" msgstr "" -"```bash\n" -"$ cairo-compile src/lib.cairo\n" -"error: Method `print` not found on type \"../src::Rectangle\". Did you import the correct trait and impl?\n" -" --> lib.cairo:16:15\n" -" rectangle.print();\n" -" ^***^\n" -"\n" -"Error: Compilation failed.\n" +"```rust, noplayground\n" +"fn calculate_length(\n" +" array_snapshot: @Array\n" +") -> usize { // array_snapshot is a snapshot of an Array\n" +" array_snapshot.len()\n" +"} // Here, array_snapshot goes out of scope and is dropped.\n" +"// However, because it is only a view of what the original array `arr` contains, the original `arr` can still be used.\n" "```" -#: src/ch04-02-an-example-program-using-structs.md:133 +#: src/ch03-02-references-and-snapshots.md:95 msgid "" -"The `print` trait is implemented for many data types, but not for the `Rectangle` struct. We can fix this by implementing the `PrintTrait` trait on `Rectangle` as shown in Listing " -"4-10.\n" -"To learn more about traits, see [Traits in Cairo](ch07-02-traits-in-cairo.md)." +"The scope in which the variable `array_snapshot` is valid is the same as any function parameter’s scope, but the underlying value of the snapshot is not dropped when `array_snapshot` " +"stops being used. When functions have snapshots as parameters instead of the actual values, we won’t need to return the values in order to give back ownership of the original value, " +"because we never had it." msgstr "" -"许多数据类型都实现了 `print` trait,但 `Rectangle` 结构没有。我们可以通过在`Rectangle`上实现`PrintTrait` trait来解决这个问题,如示例4-10所示。\n" -"要了解更多关于traits的信息,请参阅[Traits in Cairo](ch07-02-traits-in-cairo.md)。" +"变量`array_snapshot`的有效范围与任何函数参数的范围相同,但当`array_snapshot`停止使用时,快照的底层值不会被丢弃。当函数有快照作为参数而不是实际的值时,我们将不需要返回值以归还原始值的" +"所有权,因为我们从未拥有过它。" -#: src/ch04-02-an-example-program-using-structs.md:138 +#: src/ch03-02-references-and-snapshots.md:97 +msgid "#### Desnap Operator" +msgstr "#### Desnap 操作符" + +#: src/ch03-02-references-and-snapshots.md:99 msgid "" -"```rust,ignore_format\n" +"To convert a snapshot back into a regular value, you can use the `desnap` operator `*`, which serves as the opposite of the `@` operator: the snapshot value is copied to a new " +"variable." +msgstr "要将快照转换回常规值,可以使用 `desnap` 操作符 `*`,它的作用与 `@`操作符相反:快照值被复制到一个新变量中。" + +#: src/ch03-02-references-and-snapshots.md:101 +msgid "" +"It's important to note that during this conversion process, the value it points to is copied into a new variable. This enables multiple uses of the underlying value without concerns " +"about ownership transfers. This also means that the value pointed to by the snapshot must be copyable (which is not the case for Arrays, as they don't implement `Copy`)." +msgstr "" +"值得注意的是,在这个转换过程中,它所指向的值会被复制到一个新变量中。这样就可以多次使用底层值,而不必担心所有权转移。这也意味着快照指向的值必须是可复制的(而数组则不然,因为它们没有实" +"现 `Copy`)。" + +#: src/ch03-02-references-and-snapshots.md:103 +msgid "" +"In the following example, we want to calculate the area of a rectangle, but we don't want to take ownership of the rectangle in the `calculate_area` function, because we might want " +"to use the rectangle again after the function call. Since our function doesn't mutate the rectangle instance, we can pass the snapshot of the rectangle to the function, and then " +"transform the snapshots back into values using the `desnap` operator `*`." +msgstr "" +"在下面的示例中,我们要计算一个矩形的面积,但我们不想在`calculate_area`函数中取得矩形的所有权,因为我们可能想在函数调用后再次使用该矩形。由于我们的函数不会更改矩形实例,因此我们可以将" +"矩形的快照传递给函数,然后使用 `desnap` 操作符 `*` 将快照转换回值。" + +#: src/ch03-02-references-and-snapshots.md:105 +msgid "" +"```rust\n" "use debug::PrintTrait;\n" "\n" +"#[derive(Copy, Drop)]\n" "struct Rectangle {\n" -" width: u64,\n" " height: u64,\n" +" width: u64,\n" "}\n" "\n" "fn main() {\n" -" let rectangle = Rectangle { width: 30, height: 10, };\n" -" rectangle.print();\n" +" let rec = Rectangle { height: 3, width: 10 };\n" +" let area = calculate_area(@rec);\n" +" area.print();\n" "}\n" "\n" -"impl RectanglePrintImpl of PrintTrait {\n" -" fn print(self: Rectangle) {\n" -" self.width.print();\n" -" self.height.print();\n" -" }\n" +"fn calculate_area(rec: @Rectangle) -> u64 {\n" +" // As rec is a snapshot to a Rectangle, its fields are also snapshots of the fields types.\n" +" // We need to transform the snapshots back into values using the desnap operator `*`.\n" +" // This is only possible if the type is copyable, which is the case for u64.\n" +" // Here, `*` is used for both multiplying the height and width and for desnapping the snapshots.\n" +" *rec.height * *rec.width\n" "}\n" "```" msgstr "" -"```rust,ignore_format\n" +"```rust\n" "use debug::PrintTrait;\n" "\n" +"#[derive(Copy, Drop)]\n" "struct Rectangle {\n" -" width: u64,\n" " height: u64,\n" +" width: u64,\n" "}\n" "\n" "fn main() {\n" -" let rectangle = Rectangle { width: 30, height: 10, };\n" -" rectangle.print();\n" +" let rec = Rectangle { height: 3, width: 10 };\n" +" let area = calculate_area(@rec);\n" +" area.print();\n" "}\n" "\n" -"impl RectanglePrintImpl of PrintTrait {\n" -" fn print(self: Rectangle) {\n" -" self.width.print();\n" -" self.height.print();\n" -" }\n" +"fn calculate_area(rec: @Rectangle) -> u64 {\n" +" // As rec is a snapshot to a Rectangle, its fields are also snapshots of the fields types.\n" +" // We need to transform the snapshots back into values using the desnap operator `*`.\n" +" // This is only possible if the type is copyable, which is the case for u64.\n" +" // Here, `*` is used for both multiplying the height and width and for desnapping the snapshots.\n" +" *rec.height * *rec.width\n" "}\n" "```" -#: src/ch04-02-an-example-program-using-structs.md:159 -msgid "Listing 4-10: Implementing the `PrintTrait` trait on `Rectangle`" -msgstr "示例4-10:在`Rectangle`上实现`PrintTrait` trait" +#: src/ch03-02-references-and-snapshots.md:129 +msgid "" +"But, what happens if we try to modify something we’re passing as snapshot? Try the code in\n" +"Listing 3-6. Spoiler alert: it doesn’t work!" +msgstr "" +"但是,如果我们试图修改我们作为快照传递的东西会发生什么?试试下面的代码\n" +"示例3-6。剧透一下:它不起作用!" -#: src/ch04-02-an-example-program-using-structs.md:161 -msgid "Nice! It’s not the prettiest output, but it shows the values of all the fields for this instance, which would definitely help during debugging." -msgstr "很好!这不是最漂亮的输出,但它显示了这个实例的所有字段的值,这在调试时肯定会有帮助。" - -#: src/ch04-03-method-syntax.md:1 -msgid "## Method Syntax" -msgstr "## 方法语法(Method Syntax)" - -#: src/ch04-03-method-syntax.md:3 -msgid "" -"_Methods_ are similar to functions: we declare them with the `fn` keyword and a\n" -"name, they can have parameters and a return value, and they contain some code\n" -"that’s run when the method is called from somewhere else. Unlike functions,\n" -"methods are defined within the context of a type and their first parameter is\n" -"always `self`, which represents the instance of the type the method is being\n" -"called on. For those familiar with Rust, Cairo's approach might be confusing,\n" -"as methods cannot be defined directly on types. Instead, you must define a trait\n" -"and an implementation associated with the type for which the method is intended." -msgstr "" -"_方法_(method)与函数类似:它们使用 `fn` 关键字和名称声明,可以拥有参数和返回值,同时包含在某处调用该方法时会执行的代码。不过方法与函数是不同的,因为它们在结构体的上下文中被定义,并" -"且它们第一个参数总是 `self`,它代表调用该方法的结构体实例。\n" -"对于那些熟悉Rust的人来说,Cairo的方法可能会令人困惑,因为方法不能被直接定义在类型上。\n" -"相反,你必须定义一个trait和一个与该方法所在类型相关的实现。" - -#: src/ch04-03-method-syntax.md:12 -msgid "### Defining Methods" -msgstr "### 定义方法" - -#: src/ch04-03-method-syntax.md:14 -msgid "" -"Let’s change the `area` function that has a `Rectangle` instance as a parameter\n" -"and instead make an `area` method defined on the `RectangleTrait` trait, as shown\n" -"in Listing 4-13." -msgstr "" -"让我们把前面实现的获取一个 `Rectangle` 实例作为参数的 `area` 函数,\n" -"改写成一个定义于 `RectangleTrait` trait 上的 `area` 方法,如示例4-13所示。" - -#: src/ch04-03-method-syntax.md:20 +#: src/ch03-02-references-and-snapshots.md:134 msgid "" -"```rust\n" -"use debug::PrintTrait;\n" +"```rust,does_not_compile\n" +"//TAG: does_not_compile\n" "#[derive(Copy, Drop)]\n" "struct Rectangle {\n" -" width: u64,\n" " height: u64,\n" -"}\n" -"\n" -"trait RectangleTrait {\n" -" fn area(self: @Rectangle) -> u64;\n" -"}\n" -"\n" -"impl RectangleImpl of RectangleTrait {\n" -" fn area(self: @Rectangle) -> u64 {\n" -" (*self.width) * (*self.height)\n" -" }\n" +" width: u64,\n" "}\n" "\n" "fn main() {\n" -" let rect1 = Rectangle { width: 30, height: 50, };\n" +" let rec = Rectangle { height: 3, width: 10 };\n" +" flip(@rec);\n" +"}\n" "\n" -" rect1.area().print();\n" +"fn flip(rec: @Rectangle) {\n" +" let temp = rec.height;\n" +" rec.height = rec.width;\n" +" rec.width = temp;\n" "}\n" "```" msgstr "" -"```rust\n" -"use debug::PrintTrait;\n" +"```rust,does_not_compile\n" +"//TAG: does_not_compile\n" "#[derive(Copy, Drop)]\n" "struct Rectangle {\n" -" width: u64,\n" " height: u64,\n" -"}\n" -"\n" -"trait RectangleTrait {\n" -" fn area(self: @Rectangle) -> u64;\n" -"}\n" -"\n" -"impl RectangleImpl of RectangleTrait {\n" -" fn area(self: @Rectangle) -> u64 {\n" -" (*self.width) * (*self.height)\n" -" }\n" +" width: u64,\n" "}\n" "\n" "fn main() {\n" -" let rect1 = Rectangle { width: 30, height: 50, };\n" +" let rec = Rectangle { height: 3, width: 10 };\n" +" flip(@rec);\n" +"}\n" "\n" -" rect1.area().print();\n" +"fn flip(rec: @Rectangle) {\n" +" let temp = rec.height;\n" +" rec.height = rec.width;\n" +" rec.width = temp;\n" "}\n" "```" -#: src/ch04-03-method-syntax.md:45 -msgid "" -"Listing 4-13: Defining an `area` method to use on the\n" -"`Rectangle` " -msgstr "示例4-13:定义一个用在`Rectangle` 上的 `area` 方法 " +#: src/ch03-02-references-and-snapshots.md:154 +msgid "Listing 3-6: Attempting to modify a snapshot value" +msgstr "示例3-6:试图修改一个快照值" -#: src/ch04-03-method-syntax.md:48 -msgid "" -"To define the function within the context of `Rectangle`, we start by defining a `trait`\n" -"block with the signature of the method that we want to implement. Traits are not linked to\n" -"a specific type; only the `self` parameter of the method defines which type it can be used\n" -"with. Then, we define an `impl` (implementation) block for `RectangleTrait`, that defines\n" -"the behavior of the methods implemented. Everything within this `impl` block will be\n" -"associated with the type of the `self` parameter of the method called. While it is technically\n" -"possible to define methods for multiple types within the same `impl` block, it is not\n" -"a recommended practice, as it can lead to confusion. We recommend that the type of the `self` parameter\n" -"stays consistent within the same `impl` block.\n" -"Then we move the `area` function within the `impl` curly brackets and change the first (and in this case, only)\n" -"parameter to be `self` in the signature and everywhere within the body. In\n" -"`main`, where we called the `area` function and passed `rect1` as an argument,\n" -"we can instead use the _method syntax_ to call the `area` method on our `Rectangle`\n" -"instance. The method syntax goes after an instance: we add a dot followed by\n" -"the method name, parentheses, and any arguments." -msgstr "" -"为了使函数定义于 `Rectangle` 的上下文中,我们开始了一个 `trait` 块,其中包含我们想要实现的方法的签名。\n" -"Traits 并不与一个特定的类型所链接;只有方法的 `self` 参数定义了它可以用于哪种类型。然后,我们为 `RectangleTrait` 定义一个 `impl`(实现)块,它定义了实现的方法的行为。\n" -"这个 `impl` 块中的所有内容都将与被调用方法的 `self` 参数的类型相关。虽然在技术上可以在同一个 `impl` 块中定义多种类型的方法,但这并不是一个值得推荐的做法。\n" -"因为它可能会导致混乱。我们建议`self`参数的类型在同一个 `impl` 块中保持一致。\n" -"然后我们将`area`函数移到`impl`大括号内,并在签名和正文的所有地方将第一个(在本例中是唯一的)参数改为`self`。在`main`中,我们调用`area`函数并传递`rect1`作为参数、\n" -"\n" -"我们可以使用 _method syntax_ 在我们的`Rectangle`实例上调用`area`方法。\n" -"方法语法是:在一个实例的后面,加上一个点号,后跟方法名、圆括号以及任何参数。" +#: src/ch03-02-references-and-snapshots.md:156 +msgid "Here’s the error:" +msgstr "这里有一个错误:" -#: src/ch04-03-method-syntax.md:64 +#: src/ch03-02-references-and-snapshots.md:158 msgid "" -"Methods must have a parameter named `self` of the type they will be applied to for their first parameter.\n" -"Note that we used the `@` snapshot operator in front of the `Rectangle` type in the function signature.\n" -"By doing so, we indicate that this method takes an immutable snapshot of the `Rectangle` instance, which is\n" -"automatically created by the compiler when passing the instance to the method.\n" -"Methods can take ownership of `self`, use `self` with snapshots as we’ve done here, or use a mutable reference to `self`\n" -"using the `ref self: T` syntax." +"```shell\n" +"error: Invalid left-hand side of assignment.\n" +" --> ownership.cairo:15:5\n" +" rec.height = rec.width;\n" +" ^********^\n" +"```" msgstr "" -"方法必须有一个名为 `self` 的类型参数作为它们将要应用的类型的第一个参数。请注意,我们在函数签名中在 `Rectangle` 类型前面使用了 `@` 快照运算符。这样做,我们表示此方法获取 `Rectangle` 实" -"例的不可变快照,编译器在将实例传递给该方法时会自动创建。方法可以获取 `self` 实例的所有权,像我们在这里所做的那样使用快照的 `self`,或使用 `ref self: T` 语法使用 `self` 的可变引用。" +"```shell\n" +"error: Invalid left-hand side of assignment.\n" +" --> ownership.cairo:15:5\n" +" rec.height = rec.width;\n" +" ^********^\n" +"```" -#: src/ch04-03-method-syntax.md:71 -msgid "" -"We chose `self: @Rectangle` here for the same reason we used `@Rectangle` in the function\n" -"version: we don’t want to take ownership, and we just want to read the data in\n" -"the struct, not write to it. If we wanted to change the instance that we’ve\n" -"called the method on as part of what the method does, we’d use `ref self: Rectangle` as\n" -"the first parameter. Having a method that takes ownership of the instance by\n" -"using just `self` as the first parameter is rare; this technique is usually\n" -"used when the method transforms `self` into something else and you want to\n" -"prevent the caller from using the original instance after the transformation." -msgstr "" -"我们在这里选择 `self: @Rectangle` 与函数版本中使用 `@Rectangle` 的原因相同:我们不想要所有权,只是想读取结构体中的数据,而不是对它进行写入。如果我们想要作为方法的一部分更改调用方法的" -"实例,我们将使用 `ref self: Rectangle` 作为第一个参数。通过仅使用 `self` 作为第一个参数来使方法获取实例的所有权是很少见的;这种技术通常用在当方法将 `self` 转换成别的实例的时候,这时我" -"们想要防止调用者在转换之后使用原始的实例。" +#: src/ch03-02-references-and-snapshots.md:165 +msgid "The compiler prevents us from modifying values associated to snapshots." +msgstr "编译器阻止我们修改与快照相关的值。" -#: src/ch04-03-method-syntax.md:80 -msgid "" -"Observe the use of the desnap operator `*` within the area method when accessing the struct's members.\n" -"This is necessary because the struct is passed as a snapshot, and all of its field values are of type `@T`,\n" -"requiring them to be desnapped in order to manipulate them." -msgstr "" -"在访问结构体的成员时,请注意在区域方法中使用 _desnap_ 操作符`*`。\n" -"这是必要的,因为该结构是以快照形式传递的,其所有字段值都是`@T`类型、\n" -"需要对它们进行解快照,以便对其进行操作。" +#: src/ch03-02-references-and-snapshots.md:167 +msgid "### Mutable References" +msgstr "### 可变引用" -#: src/ch04-03-method-syntax.md:84 +#: src/ch03-02-references-and-snapshots.md:169 msgid "" -"The main reason for using methods instead of functions is for organization and code clarity. We’ve put all the things we can do with an instance of a type in one combination of " -"`trait` & `impl` blocks, rather than making future users\n" -"of our code search for capabilities of `Rectangle` in various places in the\n" -"library we provide. However, we can define multiple combinations of `trait` & `impl` blocks for the same type at different places, which can be useful for a more granular code " -"organization. For example, you could implement\n" -"the `Add` trait for your type in one `impl` block, and the `Sub` trait in another block." +"We can achieve the behavior we want in Listing 3-6 by using a _mutable reference_ instead of a snapshot. Mutable references are actually mutable values passed to a function that are " +"implicitly returned at the end of the function, returning ownership to the calling context. By doing so, they allow you to mutate the value passed while keeping ownership of it by " +"returning it automatically at the end of the execution.\n" +"In Cairo, a parameter can be passed as _mutable reference_ using the `ref` modifier." msgstr "" -"使用方法而不是函数的主要原因是为了组织和代码的清晰性。我们把所有我们能对一个类型的实例做的操作都放在一组`trait`和`impl`块的组合中,而不是让未来的用户在我们提供的库中的不同地方搜索 " -"`Rectangle`的函数。\n" -"然而,我们可以在不同的地方为同一类型定义多个`trait`和`impl`块的组合,这对更细化的代码组织很有用。例如,你可以在一个`impl`块中为你的类型实现 `impl` trait ,在另一个块中实现 `Sub` " -"trait 。" +"在示例3-6中,我们也可以通过使用 _mutable reference_ 而不是快照来实现我们想要的行为。可变引用实际上是传递给函数的可变值,在函数结束时被隐式返回,将所有权返回给调用的上下文。通过这样" +"做,它们允许你对传递的值进行改变,同时通过在执行结束时自动返回来保持对它的所有权。\n" +"在Cairo中,一个参数可以使用`ref`修饰符作为 _mutable reference_ 传递。" -#: src/ch04-03-method-syntax.md:89 -msgid "" -"Note that we can choose to give a method the same name as one of the struct’s\n" -"fields. For example, we can define a method on `Rectangle` that is also named\n" -"`width`:" -msgstr "请注意,我们可以选择将方法的名称与结构中的一个字段相同。例如,我们可以在 `Rectangle` 上定义一个方法,并命名为`width`:" +#: src/ch03-02-references-and-snapshots.md:172 +msgid "> **Note**: In Cairo, a parameter can only be passed as _mutable reference_ using the `ref` modifier if the variable is declared as mutable with `mut`." +msgstr "> **注意**:在Cairo中,只有在变量用`mut`声明为可变的情况下,才能使用`ref`修饰符将参数作为可变的引用传递。" -#: src/ch04-03-method-syntax.md:95 +#: src/ch03-02-references-and-snapshots.md:174 +msgid "In Listing 3-7, we use a mutable reference to modify the value of the `height` and `width` fields of the `Rectangle` instance in the `flip` function." +msgstr "在示例3-7中,我们使用一个可变的引用来修改`Rectangle`实例在`flip`函数中的`height`和`width`字段的值。" + +#: src/ch03-02-references-and-snapshots.md:176 msgid "" "```rust\n" "use debug::PrintTrait;\n" "#[derive(Copy, Drop)]\n" "struct Rectangle {\n" -" width: u64,\n" " height: u64,\n" +" width: u64,\n" "}\n" "\n" -"trait RectangleTrait {\n" -" fn width(self: @Rectangle) -> bool;\n" -"}\n" -"\n" -"impl RectangleImpl of RectangleTrait {\n" -" fn width(self: @Rectangle) -> bool {\n" -" (*self.width) > 0\n" -" }\n" +"fn main() {\n" +" let mut rec = Rectangle { height: 3, width: 10 };\n" +" flip(ref rec);\n" +" rec.height.print();\n" +" rec.width.print();\n" "}\n" "\n" -"fn main() {\n" -" let rect1 = Rectangle { width: 30, height: 50, };\n" -" rect1.width().print();\n" +"fn flip(ref rec: Rectangle) {\n" +" let temp = rec.height;\n" +" rec.height = rec.width;\n" +" rec.width = temp;\n" "}\n" "```" msgstr "" @@ -6439,8061 +6322,14061 @@ msgstr "" "use debug::PrintTrait;\n" "#[derive(Copy, Drop)]\n" "struct Rectangle {\n" -" width: u64,\n" " height: u64,\n" +" width: u64,\n" "}\n" "\n" -"trait RectangleTrait {\n" -" fn width(self: @Rectangle) -> bool;\n" -"}\n" -"\n" -"impl RectangleImpl of RectangleTrait {\n" -" fn width(self: @Rectangle) -> bool {\n" -" (*self.width) > 0\n" -" }\n" +"fn main() {\n" +" let mut rec = Rectangle { height: 3, width: 10 };\n" +" flip(ref rec);\n" +" rec.height.print();\n" +" rec.width.print();\n" "}\n" "\n" -"fn main() {\n" -" let rect1 = Rectangle { width: 30, height: 50, };\n" -" rect1.width().print();\n" +"fn flip(ref rec: Rectangle) {\n" +" let temp = rec.height;\n" +" rec.height = rec.width;\n" +" rec.width = temp;\n" "}\n" "```" -#: src/ch04-03-method-syntax.md:119 +#: src/ch03-02-references-and-snapshots.md:198 +msgid "Listing 3-7: Use of a mutable reference to modify a value" +msgstr "示例 3-7:使用一个可变的引用来修改一个值" + +#: src/ch03-02-references-and-snapshots.md:200 msgid "" -"Here, we’re choosing to make the `width` method return `true` if the value in\n" -"the instance’s `width` field is greater than `0` and `false` if the value is\n" -"`0`: we can use a field within a method of the same name for any purpose. In\n" -"`main`, when we follow `rect1.width` with parentheses, Cairo knows we mean the\n" -"method `width`. When we don’t use parentheses, Cairo knows we mean the field\n" -"`width`." +"First, we change `rec` to be `mut`. Then we pass a mutable reference of `rec` into `flip` with `ref rec`, and update the function signature to accept a mutable reference with `ref " +"rec: Rectangle`. This makes it very clear that the `flip` function will mutate the value of the `Rectangle` instance passed as parameter." msgstr "" -"在这里,我们选择让`width`方法在实例的`width`字段中的值大于0时返回`true`,在值为0时返回`false` :我们可以在同名方法的字段内使用任何目的。在`main`中,当我们在`rect1.width`后面跟着括号" -"时,Cairo知道我们意思是`width`方法。当我们不使用括号时,Cairo知道我们指的是`width`字段。" - -#: src/ch04-03-method-syntax.md:126 -msgid "### Methods with More Parameters" -msgstr "### 带有更多参数的方法" +"首先,我们把`rec`改成`mut`。然后我们用 `ref rec` 将 `rec` 的可变引用传入 `flip` ,并更新函数签名,用 `ref rec: Rectangle`接受可变引用。这很清楚地表明,`flip`函数将改变作为参数传递的" +"`Rectangle`实例的值。" -#: src/ch04-03-method-syntax.md:128 -msgid "" -"Let’s practice using methods by implementing a second method on the `Rectangle`\n" -"struct. This time we want an instance of `Rectangle` to take another instance\n" -"of `Rectangle` and return `true` if the second `Rectangle` can fit completely\n" -"within `self` (the first `Rectangle`); otherwise, it should return `false`.\n" -"That is, once we’ve defined the `can_hold` method, we want to be able to write\n" -"the program shown in Listing 4-14." -msgstr "" -"让我们通过在`Rectangle`结构体上实现第二个方法来练习使用方法。这次,我们希望让`Rectangle`的实例接收另一个`Rectangle`的实例。如果第二个`Rectangle`可以完全适应`self` (第一个" -"`Rectangle`)就返回 `true` ; 否则,它应该返回`false`。也就是说,一旦我们定义了`can_hold`方法,我们希望能够编写列表4-14中显示的程序。" +#: src/ch03-02-references-and-snapshots.md:202 +msgid "The output of the program is:" +msgstr "程序的输出是:" -#: src/ch04-03-method-syntax.md:137 +#: src/ch03-02-references-and-snapshots.md:204 msgid "" -"```rust,does_not_compile\n" -"use debug::PrintTrait;\n" -"#[derive(Copy, Drop)]\n" -"struct Rectangle {\n" -" width: u64,\n" -" height: u64,\n" -"}\n" -"\n" -"fn main() {\n" -" let rect1 = Rectangle { width: 30, height: 50, };\n" -" let rect2 = Rectangle { width: 10, height: 40, };\n" -" let rect3 = Rectangle { width: 60, height: 45, };\n" -"\n" -" 'Can rect1 hold rect2?'.print();\n" -" rect1.can_hold(@rect2).print();\n" +"```shell\n" +"[DEBUG]\n" +" (raw: 10)\n" "\n" -" 'Can rect1 hold rect3?'.print();\n" -" rect1.can_hold(@rect3).print();\n" -"}\n" +"[DEBUG]\t (raw: 3)\n" "```" msgstr "" -"```rust,does_not_compile\n" -"use debug::PrintTrait;\n" -"#[derive(Copy, Drop)]\n" -"struct Rectangle {\n" -" width: u64,\n" -" height: u64,\n" -"}\n" -"\n" -"fn main() {\n" -" let rect1 = Rectangle { width: 30, height: 50, };\n" -" let rect2 = Rectangle { width: 10, height: 40, };\n" -" let rect3 = Rectangle { width: 60, height: 45, };\n" -"\n" -" 'Can rect1 hold rect2?'.print();\n" -" rect1.can_hold(@rect2).print();\n" +"```shell\n" +"[DEBUG]\n" +" (raw: 10)\n" "\n" -" 'Can rect1 hold rect3?'.print();\n" -" rect1.can_hold(@rect3).print();\n" -"}\n" +"[DEBUG]\t (raw: 3)\n" "```" -#: src/ch04-03-method-syntax.md:158 +#: src/ch03-02-references-and-snapshots.md:211 +msgid "As expected, the `height` and `width` fields of the `rec` variable have been swapped." +msgstr "正如预期的那样, `rec` 变量的 `height` 和 `width` 字段被调换了。" + +#: src/ch03-02-references-and-snapshots.md:213 +msgid "### Small recap" +msgstr "### 小结" + +#: src/ch03-02-references-and-snapshots.md:215 +msgid "Let’s recap what we’ve discussed about ownership, snapshots, and references:" +msgstr "让我们回顾一下我们已经讨论过的关于所有权、快照和引用的内容:" + +#: src/ch03-02-references-and-snapshots.md:217 msgid "" -"Listing 4-14: Using the as-yet-unwritten `can_hold`\n" -"method" -msgstr "示例4-14:使用尚未编写的`can_hold`方法" +"- At any given time, a variable can only have one owner.\n" +"- You can pass a variable by-value, by-snapshot, or by-reference to a function.\n" +"- If you pass-by-value, ownership of the variable is transferred to the function.\n" +"- If you want to keep ownership of the variable and know that your function won’t mutate it, you can pass it as a snapshot with `@`.\n" +"- If you want to keep ownership of the variable and know that your function will mutate it, you can pass it as a mutable reference with `ref`." +msgstr "" +"- 在任何时候,一个变量只能有一个所有者。\n" +"- 你可以将一个变量以值的方式、以快照的方式、或以引用的方式传递给一个函数。\n" +"- 如果你按值传递,变量的所有权就会转移到函数中。\n" +"- 如果你想保留变量的所有权,并且知道你的函数不会改变它,你可以用`@`把它作为一个快照传递。\n" +"- 如果你想保留变量的所有权,并且知道你的函数会改变它,你可以用`ref`把它作为一个可改变的引用来传递。" -#: src/ch04-03-method-syntax.md:161 +#: src/ch04-00-using-structs-to-structure-related-data.md:1 +msgid "# Using Structs to Structure Related Data" +msgstr "# 使用结构体组织相关联的数据" + +#: src/ch04-00-using-structs-to-structure-related-data.md:3 msgid "" -"The expected output would look like the following because both dimensions of\n" -"`rect2` are smaller than the dimensions of `rect1`, but `rect3` is wider than\n" -"`rect1`:" +"A struct, or structure, is a custom data type that lets you package together and name multiple related values that make up a meaningful group. If you’re familiar with an object-" +"oriented language, a struct is like an object’s data attributes. In this chapter, we’ll compare and contrast tuples with structs to build on what you already know and demonstrate " +"when structs are a better way to group data." msgstr "" -"预期的输出结果如下,因为`rect2`的两个尺寸都小于`rect1`的尺寸。\n" -"但`rect3`的宽度大于`rect1`:" +"结构体( _struct_ ),或称 _structure_ ,是一种自定义的数据类型,允许你包装和命名多个相关的值,从而形成一个有意义的组合。如果你熟悉一门面向对象语言,struct 就像对象中的数据属性。在本" +"章中,我们会对元组和结构体进行比较和对比,并演示什么时候结构体是一种更好的数据分组方式。" -#: src/ch04-03-method-syntax.md:165 +#: src/ch04-00-using-structs-to-structure-related-data.md:5 msgid "" -"```text\n" -"❯ cairo-run src/lib.cairo\n" -"[DEBUG]\tCan rec1 hold rect2? \t(raw: 384675147322001379018464490539350216396261044799)\n" -"\n" -"[DEBUG]\ttrue \t(raw: 1953658213)\n" -"\n" -"[DEBUG]\tCan rect1 hold rect3? \t(raw: 384675147322001384331925548502381811111693612095)\n" -"\n" -"[DEBUG]\tfalse \t(raw: 439721161573)\n" -"\n" -"```" +"We’ll demonstrate how to define and instantiate structs. We’ll discuss how to define associated functions, especially the kind of associated functions called methods, to specify " +"behavior associated with a struct type. Structs and enums (discussed in the next chapter) are the building blocks for creating new types in your program’s domain to take full " +"advantage of Cairo's compile-time type checking." msgstr "" -"```text\n" -"❯ cairo-run src/lib.cairo\n" -"[DEBUG]\tCan rec1 hold rect2? \t(raw: 384675147322001379018464490539350216396261044799)\n" -"\n" -"[DEBUG]\ttrue \t(raw: 1953658213)\n" -"\n" -"[DEBUG]\tCan rect1 hold rect3? \t(raw: 384675147322001384331925548502381811111693612095)\n" -"\n" -"[DEBUG]\tfalse \t(raw: 439721161573)\n" -"\n" -"```" +"我们还将演示如何定义和实例化结构体,并讨论如何定义关联函数,特别是被称为 _方法_ 的关联函数,以指定与结构体类型相关的行为。你可以在程序中基于结构体和枚举(enum)(将在下一章讨论)创建" +"新类型,以充分利用 Cairo 的编译时类型检查。" -#: src/ch04-03-method-syntax.md:177 +#: src/ch04-01-defining-and-instantiating-structs.md:1 +msgid "# Defining and Instantiating Structs" +msgstr "# 结构体的定义和实例化" + +#: src/ch04-01-defining-and-instantiating-structs.md:3 msgid "" -"We know we want to define a method, so it will be within the `trait RectangleTrait`\n" -"and `impl RectangleImpl of RectangleTrait` blocks.\n" -"The method name will be `can_hold`, and it will take a snapshot\n" -"of another `Rectangle` as a parameter. We can tell what the type of the\n" -"parameter will be by looking at the code that calls the method:\n" -"`rect1.can_hold(@rect2)` passes in `@rect2`, which is a snapshot to\n" -"`rect2`, an instance of `Rectangle`. This makes sense because we only need to\n" -"read `rect2` (rather than write, which would mean we’d need a mutable borrow),\n" -"and we want `main` to retain ownership of `rect2` so we can use it again after\n" -"calling the `can_hold` method. The return value of `can_hold` will be a\n" -"Boolean, and the implementation will check whether the width and height of\n" -"`self` are greater than the width and height of the other `Rectangle`,\n" -"respectively. Let’s add the new `can_hold` method to the `trait` and `impl` blocks from\n" -"Listing 4-13, shown in Listing 4-15." +"Structs are similar to tuples, discussed in [The Data Types](ch02-02-data-types.md) section, in that both hold multiple related values. Like tuples, the pieces of a struct can be " +"different types. Unlike with tuples, in a struct you’ll name each piece of data so it’s clear what the values mean. Adding these names means that structs are more flexible than " +"tuples: you don’t have to rely on the order of the data to specify or access the values of an instance." msgstr "" -"我们需要定义一个方法,将它放置在在`trait RectangleTrait`和`impl RectangleImpl of RectangleTrait` 块中。该方法名为 `can_hold`,它将接收另一个`Rectangle`的快照作为参数。我们可以通过查看" -"调用该方法的代码来确定参数的类型:`rect1.can_hold(@rect2)`将`@rect2`作为快照传递给`rect2`,它是`Rectangle`的一个实例。这是有意义的,因为我们只需要读取`rect2`(而不是写入,这意味着我们" -"需要一个可变借用),我们希望`main`保留对`rect2`的所有权,以便在调用`can_hold` 方法后再次使用它。`can_hold` 的返回值将是一个布尔值,实现将检查`self`的宽度和高度是否分别大于另一" -"`Rectangle`的宽度和高度。让我们将新的`can_hold`方法添加到示例4-13中的`trait`和`impl` 块中,如示例4-15所示。" +"结构体与[数据类型](ch02-02-data-types.md)一节中讨论的元组类似,它们都包含多个相关的值。和元组一样,结构体的每一部分可以是不同类型。但不同于元组,结构体需要命名各部分数据以便能清楚的表" +"明其值的意义。由于有了这些名字,结构体比元组更灵活:不需要依赖顺序来指定或访问实例中的值。" -#: src/ch04-03-method-syntax.md:194 +#: src/ch04-01-defining-and-instantiating-structs.md:5 msgid "" -"```rust\n" -"trait RectangleTrait {\n" -" fn area(self: @Rectangle) -> u64;\n" -" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" -"}\n" -"\n" -"impl RectangleImpl of RectangleTrait {\n" -" fn area(self: @Rectangle) -> u64 {\n" -" *self.width * *self.height\n" -" }\n" -"\n" -" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" -" *self.width > *other.width & *self.height > *other.height\n" -" }\n" +"To define a struct, we enter the keyword `struct` and name the entire struct. A struct’s name should describe the significance of the pieces of data being grouped together. Then, " +"inside curly brackets, we define the names and types of the pieces of data, which we call fields. For example, Listing 4-1 shows a struct that stores information about a user account." +msgstr "" +"定义结构体,需要使用 `struct` 关键字并为整个结构体提供一个名字。结构体的名字需要描述它所组合的数据的意义。接着,在大括号中,定义每一部分数据的名字和类型,我们称为 字段(field)。例" +"如,示例 4-1 展示了一个存储用户账号信息的结构体。" + +#: src/ch04-01-defining-and-instantiating-structs.md:9 +msgid "" +"```rust, noplayground\n" +"#[derive(Copy, Drop)]\n" +"struct User {\n" +" active: bool,\n" +" username: felt252,\n" +" email: felt252,\n" +" sign_in_count: u64,\n" "}\n" "```" msgstr "" -"```rust\n" -"trait RectangleTrait {\n" -" fn area(self: @Rectangle) -> u64;\n" -" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" -"}\n" -"\n" -"impl RectangleImpl of RectangleTrait {\n" -" fn area(self: @Rectangle) -> u64 {\n" -" *self.width * *self.height\n" -" }\n" -"\n" -" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" -" *self.width > *other.width & *self.height > *other.height\n" -" }\n" +"```rust, noplayground\n" +"#[derive(Copy, Drop)]\n" +"struct User {\n" +" active: bool,\n" +" username: felt252,\n" +" email: felt252,\n" +" sign_in_count: u64,\n" "}\n" "```" -#: src/ch04-03-method-syntax.md:211 -msgid "" -"Listing 4-15: Implementing the `can_hold` method on\n" -"`Rectangle` that takes another `Rectangle` instance as a parameter" -msgstr "示例4-15: 在`Rectangle`上实现`can_hold`方法,该方法接收另一个`Rectangle`实例作为参数" +#: src/ch04-01-defining-and-instantiating-structs.md:19 +msgid "Listing 4-1: A `User` struct definition" +msgstr "示例4-1:一个 `User` 结构定义" -#: src/ch04-03-method-syntax.md:214 +#: src/ch04-01-defining-and-instantiating-structs.md:21 msgid "" -"When we run this code with the `main` function in Listing 4-14, we’ll get our\n" -"desired output. Methods can take multiple parameters that we add to the\n" -"signature after the `self` parameter, and those parameters work just like\n" -"parameters in functions." +"To use a struct after we’ve defined it, we create an _instance_ of that struct by specifying concrete values for each of the fields.\n" +"We create an instance by stating the name of the struct and then add curly brackets containing _key: value_ pairs, where the keys are the names of the fields and the values are the " +"data we want to store in those fields. We don’t have to specify the fields in the same order in which we declared them in the struct. In other words, the struct definition is like a " +"general template for the type, and instances fill in that template with particular data to create values of the type." msgstr "" -"当我们在示例 4-14中的`main`函数中运行这段代码时,我们将得到我们想要的输出。\n" -"方法可以接收多个参数,我们可以在`self`参数之后在函数签名中添加这些参数,\n" -"这些参数与函数中的参数工作原理相同。" +"一旦定义了结构体后,为了使用它,通过为每个字段指定具体值来创建这个结构体的 *实例*。\n" +"我们创建一个实例需要以结构体的名字开头,接着在大括号中使用 `key: value` 键 - 值对的形式提供字段,其中 key 是字段的名字,value 是需要存储在字段中的数据值。实例中字段的顺序不需要和它们" +"在结构体中声明的顺序一致。换句话说,结构体的定义就像一个类型的通用模板,而实例则会在这个模板中放入特定数据来创建这个类型的值。" -#: src/ch04-03-method-syntax.md:219 -msgid "### Accessing implementation functions" -msgstr "### 访问实现里的函数" +#: src/ch04-01-defining-and-instantiating-structs.md:24 +msgid "For example, we can declare a particular user as shown in Listing 4-2." +msgstr "例如,我们可以如示例4-2所示声明一个特定的用户。" -#: src/ch04-03-method-syntax.md:221 -msgid "" -"All functions defined within a `trait` and `impl` block can be directly addressed\n" -"using the `::` operator on the implementation name.\n" -"Functions in traits that aren’t methods are often used for constructors that\n" -"will return a new instance of the struct. These are often called `new`, but\n" -"`new` isn’t a special name and isn’t built into the language. For example, we\n" -"could choose to provide an associated function named `square` that would have\n" -"one dimension parameter and use that as both width and height, thus making it\n" -"easier to create a square `Rectangle` rather than having to specify the same\n" -"value twice:" -msgstr "" -"所有在`trait`和`impl` 块中定义的函数可以直接使用`::` 运算符在实现名称上进行访问。\n" -"在`trait`中的不是方法的函数通常用于构造函数,以返回一个结构体的新实例。\n" -"这些函数通常被称为`new`,但`new`不是一个特殊的名称,也不是内置到语言中的。\n" -"例如,我们可以选择提供一个名为`square` 的关联函数,它将具有一个维度参数,\n" -"并将其用作宽度和高度,从而更容易地创建一个正方形`Rectangle`,而不必指定两次相同的值:" - -#: src/ch04-03-method-syntax.md:233 +#: src/ch04-01-defining-and-instantiating-structs.md:28 msgid "" "```rust\n" -"trait RectangleTrait {\n" -" fn square(size: u64) -> Rectangle;\n" +"#[derive(Copy, Drop)]\n" +"struct User {\n" +" active: bool,\n" +" username: felt252,\n" +" email: felt252,\n" +" sign_in_count: u64,\n" "}\n" -"\n" -"impl RectangleImpl of RectangleTrait {\n" -" fn square(size: u64) -> Rectangle {\n" -" Rectangle { width: size, height: size }\n" -" }\n" +"fn main() {\n" +" let user1 = User {\n" +" active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" +" };\n" "}\n" +"\n" "```" msgstr "" "```rust\n" -"trait RectangleTrait {\n" -" fn square(size: u64) -> Rectangle;\n" +"#[derive(Copy, Drop)]\n" +"struct User {\n" +" active: bool,\n" +" username: felt252,\n" +" email: felt252,\n" +" sign_in_count: u64,\n" "}\n" -"\n" -"impl RectangleImpl of RectangleTrait {\n" -" fn square(size: u64) -> Rectangle {\n" -" Rectangle { width: size, height: size }\n" -" }\n" +"fn main() {\n" +" let user1 = User {\n" +" active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" +" };\n" "}\n" +"\n" "```" -#: src/ch04-03-method-syntax.md:245 +#: src/ch04-01-defining-and-instantiating-structs.md:44 +msgid "Listing 4-2: Creating an instance of the `User` struct" +msgstr "示例4-2:创建一个`User`结构的实例" + +#: src/ch04-01-defining-and-instantiating-structs.md:46 msgid "" -"To call this function, we use the `::` syntax with the implementation name;\n" -"`let square = RectangleImpl::square(10);` is an example. This function is namespaced by\n" -"the implementation; the `::` syntax is used for both trait functions and\n" -"namespaces created by modules. We’ll discuss modules in [Chapter 7][modules]." +"To get a specific value from a struct, we use dot notation. For example, to access this user’s email address, we use `user1.email`. If the instance is mutable, we can change a value " +"by using the dot notation and assigning into a particular field. Listing 4-3 shows how to change the value in the `email` field of a mutable `User` instance." msgstr "" -"为了调用这个函数,我们在实现的名称后面使用`::`语法;\n" -"比如`let square = RectangleImpl::square(10);` 这个例子。这个函数的位于其实现的命名空间中;`::`语法用于关联trait的函数和模块创建的命名空间。\n" -"我们将在 [Chapter 7][modules]<!--ignore-->中讲到模块。" +"为了从结构体中获取某个特定的值,可以使用点号。举个例子,想要用户的邮箱地址,可以用 `user1.email`。如果结构体的实例是可变的,我们可以使用点号并为对应的字段赋值。示例 4-3 展示了如何改变" +"一个可变的 `User` 实例中 `email` 字段的值。" -#: src/ch04-03-method-syntax.md:250 -msgid "> Note: It is also possible to call this function using the trait name, with `RectangleTrait::square(10)`." -msgstr "> 注意:也可以用trait名称 `RectangleTrait::square(10)` 来调用这个函数。" +#: src/ch04-01-defining-and-instantiating-structs.md:50 +msgid "" +"```rust\n" +"# #[derive(Copy, Drop)]\n" +"# struct User {\n" +"# active: bool,\n" +"# username: felt252,\n" +"# email: felt252,\n" +"# sign_in_count: u64,\n" +"# }\n" +"fn main() {\n" +" let mut user1 = User {\n" +" active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" +" };\n" +" user1.email = 'anotheremail@example.com';\n" +"}\n" +"# \n" +"# fn build_user(email: felt252, username: felt252) -> User {\n" +"# User { active: true, username: username, email: email, sign_in_count: 1, }\n" +"# }\n" +"# \n" +"# fn build_user_short(email: felt252, username: felt252) -> User {\n" +"# User { active: true, username, email, sign_in_count: 1, }\n" +"# }\n" +"# \n" +"# \n" +"```" +msgstr "" +"```rust\n" +"# #[derive(Copy, Drop)]\n" +"# struct User {\n" +"# active: bool,\n" +"# username: felt252,\n" +"# email: felt252,\n" +"# sign_in_count: u64,\n" +"# }\n" +"fn main() {\n" +" let mut user1 = User {\n" +" active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" +" };\n" +" user1.email = 'anotheremail@example.com';\n" +"}\n" +"# \n" +"# fn build_user(email: felt252, username: felt252) -> User {\n" +"# User { active: true, username: username, email: email, sign_in_count: 1, }\n" +"# }\n" +"# \n" +"# fn build_user_short(email: felt252, username: felt252) -> User {\n" +"# User { active: true, username, email, sign_in_count: 1, }\n" +"# }\n" +"# \n" +"# \n" +"```" -#: src/ch04-03-method-syntax.md:252 -msgid "### Multiple `impl` Blocks" -msgstr "### 多个`impl`块" +#: src/ch04-01-defining-and-instantiating-structs.md:76 +msgid "Listing 4-3: Changing the value in the email field of a `User` instance" +msgstr "示例4-3:改变`User`实例的电子邮件字段中的值" -#: src/ch04-03-method-syntax.md:254 +#: src/ch04-01-defining-and-instantiating-structs.md:78 +msgid "Note that the entire instance must be mutable; Cairo doesn’t allow us to mark only certain fields as mutable." +msgstr "注意,整个实例必须是可变的;Cairo不允许我们只把某些字段标记为可变的。" + +#: src/ch04-01-defining-and-instantiating-structs.md:80 +msgid "As with any expression, we can construct a new instance of the struct as the last expression in the function body to implicitly return that new instance." +msgstr "与任何表达式一样,我们可以在函数主体的最后一个表达式中构造一个新的结构体实例,以隐式返回该新实例。" + +#: src/ch04-01-defining-and-instantiating-structs.md:82 msgid "" -"Each struct is allowed to have multiple `trait` and `impl` blocks. For example, Listing\n" -"5-15 is equivalent to the code shown in Listing 4-16, which has each method in\n" -"its own `trait` and `impl` blocks." -msgstr "每个结构体都可以有多个`trait` 和`impl`块。例如,示例4-15等价于示例4-16中展示的代码,其中每个方法都有自己的`trait` 和`impl`块。" +"Listing 4-4 shows a `build_user` function that returns a `User` instance with the given email and username. The `active` field gets the value of `true`, and the `sign_in_count` gets " +"a value of `1`." +msgstr "示例4-4显示了一个`build_user`函数,该函数返回一个`User`实例,并给出了电子邮件和用户名。`active`字段的值为`true`,`sign_in_count`的值为`1`。" -#: src/ch04-03-method-syntax.md:258 +#: src/ch04-01-defining-and-instantiating-structs.md:86 msgid "" "```rust\n" -"trait RectangleCalc {\n" -" fn area(self: @Rectangle) -> u64;\n" -"}\n" -"impl RectangleCalcImpl of RectangleCalc {\n" -" fn area(self: @Rectangle) -> u64 {\n" -" (*self.width) * (*self.height)\n" -" }\n" -"}\n" -"\n" -"trait RectangleCmp {\n" -" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" -"}\n" -"\n" -"impl RectangleCmpImpl of RectangleCmp {\n" -" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" -" *self.width > *other.width & *self.height > *other.height\n" -" }\n" +"# #[derive(Copy, Drop)]\n" +"# struct User {\n" +"# active: bool,\n" +"# username: felt252,\n" +"# email: felt252,\n" +"# sign_in_count: u64,\n" +"# }\n" +"# fn main() {\n" +"# let mut user1 = User {\n" +"# active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" +"# };\n" +"# user1.email = 'anotheremail@example.com';\n" +"# }\n" +"# \n" +"fn build_user(email: felt252, username: felt252) -> User {\n" +" User { active: true, username: username, email: email, sign_in_count: 1, }\n" "}\n" +"# \n" +"# fn build_user_short(email: felt252, username: felt252) -> User {\n" +"# User { active: true, username, email, sign_in_count: 1, }\n" +"# }\n" +"# \n" +"# \n" "```" msgstr "" "```rust\n" -"trait RectangleCalc {\n" -" fn area(self: @Rectangle) -> u64;\n" -"}\n" -"impl RectangleCalcImpl of RectangleCalc {\n" -" fn area(self: @Rectangle) -> u64 {\n" -" (*self.width) * (*self.height)\n" -" }\n" -"}\n" -"\n" -"trait RectangleCmp {\n" -" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" -"}\n" -"\n" -"impl RectangleCmpImpl of RectangleCmp {\n" -" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" -" *self.width > *other.width & *self.height > *other.height\n" -" }\n" +"# #[derive(Copy, Drop)]\n" +"# struct User {\n" +"# active: bool,\n" +"# username: felt252,\n" +"# email: felt252,\n" +"# sign_in_count: u64,\n" +"# }\n" +"# fn main() {\n" +"# let mut user1 = User {\n" +"# active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" +"# };\n" +"# user1.email = 'anotheremail@example.com';\n" +"# }\n" +"# \n" +"fn build_user(email: felt252, username: felt252) -> User {\n" +" User { active: true, username: username, email: email, sign_in_count: 1, }\n" "}\n" +"# \n" +"# fn build_user_short(email: felt252, username: felt252) -> User {\n" +"# User { active: true, username, email, sign_in_count: 1, }\n" +"# }\n" +"# \n" +"# \n" "```" -#: src/ch04-03-method-syntax.md:279 -msgid "" -"Listing 4-16: Rewriting Listing 4-15 using multiple `impl`\n" -"blocks" -msgstr "" -"示例4-16:使用多个`impl`重写示例4-15\n" -"块" +#: src/ch04-01-defining-and-instantiating-structs.md:112 +msgid "Listing 4-4: A `build_user` function that takes an email and username and returns a `User` instance" +msgstr "示例4-4:一个`build_user`函数,接收电子邮件和用户名,并返回一个`User`实例" -#: src/ch04-03-method-syntax.md:282 +#: src/ch04-01-defining-and-instantiating-structs.md:114 msgid "" -"There’s no reason to separate these methods into multiple `trait` and `impl` blocks here,\n" -"but this is valid syntax. We’ll see a case in which multiple blocks are\n" -"useful in [Chapter 7](ch07-00-generic-types-and-traits.md), where we discuss generic types and traits." +"It makes sense to name the function parameters with the same name as the struct fields, but having to repeat the `email` and `username` field names and variables is a bit tedious. If " +"the struct had more fields, repeating each name would get even more annoying. Luckily, there’s a convenient shorthand!" msgstr "" -"这里没有理由把这些方法分成多个`trait`和`impl`块,\n" -"但这是有效的语法。我们将在[第7章](ch07-00-generic-types-and-traits.md)中看\n" -"到一个多块的情况,在那里我们讨论泛型和trait。" +"为函数参数起与结构体字段相同的名字是可以理解的,但必须重复`email`和`username`字段的名称和变量就有点乏味了。如果结构体有更多字段,重复每个名称就更加烦人了。幸运的是,有一个方便的简写语" +"法!" -#: src/ch04-03-method-syntax.md:288 +#: src/ch04-01-defining-and-instantiating-structs.md:116 +msgid "## Using the Field Init Shorthand" +msgstr "## 使用字段初始化简写语法" + +#: src/ch04-01-defining-and-instantiating-structs.md:118 msgid "" -"Structs let you create custom types that are meaningful for your domain. By\n" -"using structs, you can keep associated pieces of data connected to each other\n" -"and name each piece to make your code clear. In `trait` and `impl` blocks, you can define\n" -"methods, which are functions associated to a type and let you specify the behavior that instances of your\n" -"type have." +"Because the parameter names and the struct field names are exactly the same in Listing 4-4, we can use the field init shorthand syntax to rewrite `build_user` so it behaves exactly " +"the same but doesn’t have the repetition of `username` and `email`, as shown in Listing 4-5." msgstr "" -"结构体让你可以创建出在你的领域中有意义的自定义类型。\n" -"通过结构体,我们可以将相关联的数据片段联系起来并命名它们,这样可以使得代码更加清晰。\n" -"在`trait`和`impl`块中,你可以定义与你的类型相关联的方法,而方法是一种相关联的函数,让你指定结构体的实例所具有的行为。" +"因为示例 5-4 中的参数名与字段名都完全相同,我们可以使用字段初始化简写语法(field init shorthand)来重写 `build_user`,这样其行为与之前完全相同,不过无需重复 `username` 和 `email` 了," +"如示例 5-5 所示。" -#: src/ch04-03-method-syntax.md:294 +#: src/ch04-01-defining-and-instantiating-structs.md:122 msgid "" -"But structs aren’t the only way you can create custom types: let’s turn to\n" -"Cairo’s enum feature to add another tool to your toolbox." -msgstr "但结构体并不是创建自定义类型的唯一方法:让我们转向 Cairo 的枚举功能,为你的工具箱再添一个工具。" - -#: src/ch05-00-enums-and-pattern-matching.md:1 -msgid "# Enums and Pattern Matching" -msgstr "# 枚举和模式匹配" - -#: src/ch05-01-enums.md:1 -msgid "# Enums" -msgstr "# 枚举" +"```rust\n" +"# #[derive(Copy, Drop)]\n" +"# struct User {\n" +"# active: bool,\n" +"# username: felt252,\n" +"# email: felt252,\n" +"# sign_in_count: u64,\n" +"# }\n" +"# fn main() {\n" +"# let mut user1 = User {\n" +"# active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" +"# };\n" +"# user1.email = 'anotheremail@example.com';\n" +"# }\n" +"# \n" +"# fn build_user(email: felt252, username: felt252) -> User {\n" +"# User { active: true, username: username, email: email, sign_in_count: 1, }\n" +"# }\n" +"# \n" +"fn build_user_short(email: felt252, username: felt252) -> User {\n" +" User { active: true, username, email, sign_in_count: 1, }\n" +"}\n" +"# \n" +"# \n" +"```" +msgstr "" +"```rust\n" +"# #[derive(Copy, Drop)]\n" +"# struct User {\n" +"# active: bool,\n" +"# username: felt252,\n" +"# email: felt252,\n" +"# sign_in_count: u64,\n" +"# }\n" +"# fn main() {\n" +"# let mut user1 = User {\n" +"# active: true, username: 'someusername123', email: 'someone@example.com', sign_in_count: 1\n" +"# };\n" +"# user1.email = 'anotheremail@example.com';\n" +"# }\n" +"# \n" +"# fn build_user(email: felt252, username: felt252) -> User {\n" +"# User { active: true, username: username, email: email, sign_in_count: 1, }\n" +"# }\n" +"# \n" +"fn build_user_short(email: felt252, username: felt252) -> User {\n" +" User { active: true, username, email, sign_in_count: 1, }\n" +"}\n" +"# \n" +"# \n" +"```" -#: src/ch05-01-enums.md:3 +#: src/ch04-01-defining-and-instantiating-structs.md:148 msgid "" -"Enums, short for \"enumerations,\" are a way to define a custom data type that consists of a fixed set of named values, called _variants_. Enums are useful for representing a " -"collection of related values where each value is distinct and has a specific meaning." +"Listing 4-5: A `build_user` function that uses field init shorthand because the `username` and `email` parameters have the same name as struct fields" +msgstr "示例4-5: `build_user`函数使用了字段初始化简写语法,因为`username`和`email`参数与结构体字段同名," + +#: src/ch04-01-defining-and-instantiating-structs.md:150 +msgid "" +"Here, we’re creating a new instance of the `User` struct, which has a field named `email`. We want to set the `email` field’s value to the value in the `email` parameter of the " +"`build_user` function. Because the `email` field and the `email` parameter have the same name, we only need to write `email` rather than `email: email`." msgstr "" -"本章介绍 \"枚举\"(enumerations),也被称作 enums,是一种自定义数据类型的方式,它由一组固定的命名值成员组成,称为 _variants_ 。枚举对于表示相关值的集合非常有用,其中每个值都是不同的," -"并且有特定的含义。" +"这里,我们正在创建一个新的 `User` 结构体实例,它有一个名为 `email`的字段。我们希望将`email`字段的值设置为`build_user`函数的`email`参数中的值。因为`email`字段和`email`参数有相同的名" +"字,我们只需要写`email`而不是`email: email`。" -#: src/ch05-01-enums.md:5 -msgid "## Enum Variants and Values" -msgstr "## 枚举成员和值" +#: src/ch04-02-an-example-program-using-structs.md:1 +msgid "# An Example Program Using Structs" +msgstr "# 结构体示例程序" -#: src/ch05-01-enums.md:7 -msgid "Here's a simple example of an enum:" -msgstr "下面是一个枚举的简单例子:" +#: src/ch04-02-an-example-program-using-structs.md:3 +msgid "" +"To understand when we might want to use structs, let’s write a program that calculates the area of a rectangle. We’ll start by using single variables, and then refactor the program " +"until we’re using structs instead." +msgstr "为了理解何时会需要使用结构体,让我们编写一个计算长方形面积的程序。我们会从单独的变量开始,接着重构程序直到使用结构体替代他们为止。" -#: src/ch05-01-enums.md:9 +#: src/ch04-02-an-example-program-using-structs.md:5 msgid "" -"```rs\n" -"#[derive(Drop)]\n" -"enum Direction {\n" -" North: (),\n" -" East: (),\n" -" South: (),\n" -" West: (),\n" +"Let’s make a new project with Scarb called _rectangles_ that will take the width and height of a rectangle specified in pixels and calculate the area of the rectangle. Listing 4-6 " +"shows a short program with one way of doing exactly that in our project’s _src/lib.cairo_." +msgstr "" +"让我们用Scarb做一个名为 _rectangles_ 的新项目,它获取以像素为单位的长方形的宽度和高度,并计算出长方形的面积。示例4-6显示了位于项目中的 _src/lib.cairo_ 中的小程序,它刚刚好实现此功能。" + +#: src/ch04-02-an-example-program-using-structs.md:9 +msgid "" +"```rust\n" +"use debug::PrintTrait;\n" +"fn main() {\n" +" let width1 = 30;\n" +" let height1 = 10;\n" +" let area = area(width1, height1);\n" +" area.print();\n" "}\n" "\n" +"fn area(width: u64, height: u64) -> u64 {\n" +" width * height\n" +"}\n" "```" msgstr "" -"```rs\n" -"#[derive(Drop)]\n" -"enum Direction {\n" -" North: (),\n" -" East: (),\n" -" South: (),\n" -" West: (),\n" +"```rust\n" +"use debug::PrintTrait;\n" +"fn main() {\n" +" let width1 = 30;\n" +" let height1 = 10;\n" +" let area = area(width1, height1);\n" +" area.print();\n" "}\n" "\n" +"fn area(width: u64, height: u64) -> u64 {\n" +" width * height\n" +"}\n" "```" -#: src/ch05-01-enums.md:20 -msgid "" -"Unlike other languages like Rust, every variant has a type. In this example, we've defined an enum called `Direction` with four variants: `North`, `East`, `South`, and `West`. The " -"naming convention is to use PascalCase for enum variants. Each variant represents a distinct value of the Direction type and is associated with a unit type `()`. One variant can be " -"instantiated using this syntax:" -msgstr "" -"与Rust等其他语言不同,每个成员都有一个类型。在这个例子中,我们定义了一个叫做 `Direction`的枚举,有四个变量:`North`, `East`, `South`, 和 `West`。命名惯例是使用PascalCase来表示枚举成" -"员。每个成员代表方向类型的一个不同的值,并与一个unit类型`()`相关。一个成员可以使用这种语法进行实例化:" +#: src/ch04-02-an-example-program-using-structs.md:23 +msgid "Listing 4-6: Calculating the area of a rectangle specified by separate width and height variables" +msgstr "示例4-6:通过分别指定长方形的宽和高的变量来计算长方形面积" + +#: src/ch04-02-an-example-program-using-structs.md:25 +msgid "Now run the program with `scarb cairo-run`:" +msgstr "现在用`scarb cairo-run`运行该程序:" -#: src/ch05-01-enums.md:22 +#: src/ch04-02-an-example-program-using-structs.md:27 msgid "" -"```rs\n" -"let direction = Direction::North(());\n" +"```bash\n" +"$ scarb cairo-run\n" +"[DEBUG] , (raw: 300)\n" +"\n" +"Run completed successfully, returning []\n" "```" msgstr "" -"```rs\n" -"let direction = Direction::North(());\n" +"```bash\n" +"$ scarb cairo-run\n" +"[DEBUG] , (raw: 300)\n" +"\n" +"Run completed successfully, returning []\n" "```" -#: src/ch05-01-enums.md:26 -msgid "" -"It's easy to write code that acts differently depending on the variant of an enum instance, in this example to run specific code according to a Direction. You can learn more about it " -"on [The Match Control Flow Construct page](ch05-02-the-match-control-flow-construct.md)." -msgstr "" -"我们可以很轻易的写出根据枚举的成员运行不同的流程的代码,在上面这个例子中,是根据方向来运行特定的代码。你可以在 [Match 控制流结构](ch05-02-the-match-control-flow-construct.md)页面上了" -"解更多信息。" - -#: src/ch05-01-enums.md:28 -msgid "## Enums Combined with Custom Types" -msgstr "## 枚举与自定义类型相结合" +#: src/ch04-02-an-example-program-using-structs.md:34 +msgid "This code succeeds in figuring out the area of the rectangle by calling the `area` function with each dimension, but we can do more to make this code clear and readable." +msgstr "这段代码通过调用每个维度的`area`函数,成功地算出了矩形的面积,但我们仍然可以修改这段代码来使它的意义更加明确,并且增加可读性。" -#: src/ch05-01-enums.md:30 -msgid "Enums can also be used to store more interesting data associated with each variant. For example:" -msgstr "枚举也可以用来存储与每个成员相关的更有趣的数据。比如说:" +#: src/ch04-02-an-example-program-using-structs.md:36 +msgid "The issue with this code is evident in the signature of `area`:" +msgstr "这段代码的问题在 `area` 的签名中很明显:" -#: src/ch05-01-enums.md:32 +#: src/ch04-02-an-example-program-using-structs.md:38 msgid "" -"```rs\n" -"#[derive(Drop)]\n" -"enum Message {\n" -" Quit : (),\n" -" Echo : felt252,\n" -" Move : (u128, u128),\n" -"}\n" +"```rust,noplayground\n" +"fn area(width: u64, height: u64) -> u64 {\n" "```" msgstr "" -"```rs\n" -"#[derive(Drop)]\n" -"enum Message {\n" -" Quit : (),\n" -" Echo : felt252,\n" -" Move : (u128, u128),\n" -"}\n" +"```rust,noplayground\n" +"fn area(width: u64, height: u64) -> u64 {\n" "```" -#: src/ch05-01-enums.md:41 -msgid "In this example, the `Message` enum has three variants: `Quit`, `Echo` and `Move`, all with different types:" -msgstr "在这个例子中,`Message`枚举有三个成员:`Quit`、`Echo`和`Move`,都有不同的类型:" - -#: src/ch05-01-enums.md:43 +#: src/ch04-02-an-example-program-using-structs.md:42 msgid "" -"- `Quit` is the unit type - it has no data associated with it at all.\n" -"- `Echo` is a single felt.\n" -"- `Move` is a tuple of two u128 values." +"The `area` function is supposed to calculate the area of one rectangle, but the function we wrote has two parameters, and it’s not clear anywhere in our program that the parameters " +"are related. It would be more readable and more manageable to group width and height together. We’ve already discussed one way we might do that in [Chapter 3](ch02-02-data-types." +"html#the-tuple-type): using tuples." msgstr "" -"- `Quit`是unit类型 - 它完全没有与之相关的数据。\n" -"- `Echo'是一个单一的felt。\n" -"- `Move'是一个由两个u128值组成的tuple。" - -#: src/ch05-01-enums.md:47 -msgid "You could even use a Struct or another Enum you defined inside one of your Enum variants." -msgstr "你甚至可以在你的一个枚举成员中使用一个结构体或另一个你定义的枚举。" +"`area`函数应该是计算一个矩形的面积,但是我们写的函数有两个参数,而且在我们的程序中没有任何地方明确说明这些参数的关系。如果把宽度和高度放在一起,会更有可读性,也更容易管理。我们已经在" +"[第三章](ch02-02-data-types.html#the-tuple-type)中讨论了一种我们可以做到的方法:使用元组。" -#: src/ch05-01-enums.md:49 -msgid "## Trait Implementations for Enums" -msgstr "## 枚举的Trait实现" +#: src/ch04-02-an-example-program-using-structs.md:44 +msgid "## Refactoring with Tuples" +msgstr "## 使用元组重构" -#: src/ch05-01-enums.md:51 -msgid "" -"In Cairo, you can define traits and implement them for your custom enums. This allows you to define methods and behaviors associated with the enum. Here's an example of defining a " -"trait and implementing it for the previous `Message` enum:" -msgstr "在Cairo中,你可以为你的自定义枚举定义trait并实现它们。这允许你定义与枚举相关的方法和行为。下面是一个定义trait并为之前的 `Message` 枚举实现的例子:" +#: src/ch04-02-an-example-program-using-structs.md:46 +msgid "Listing 4-7 shows another version of our program that uses tuples." +msgstr "示例4-7显示了我们使用元组的另一个程序版本。" -#: src/ch05-01-enums.md:53 +#: src/ch04-02-an-example-program-using-structs.md:50 msgid "" -"```rs\n" -"trait Processing {\n" -" fn process(self: Message);\n" +"```rust\n" +"use debug::PrintTrait;\n" +"fn main() {\n" +" let rectangle = (30, 10);\n" +" let area = area(rectangle);\n" +" area.print(); // print out the area\n" "}\n" "\n" -"impl ProcessingImpl of Processing {\n" -" fn process(self: Message) {\n" -" match self {\n" -" Message::Quit(()) => {\n" -" 'quitting'.print();\n" -" },\n" -" Message::Echo(value) => {\n" -" value.print();\n" -" },\n" -" Message::Move((x, y)) => {\n" -" 'moving'.print();\n" -" },\n" -" }\n" -" }\n" +"fn area(dimension: (u64, u64)) -> u64 {\n" +" let (x, y) = dimension;\n" +" x * y\n" "}\n" "```" msgstr "" -"```rs\n" -"trait Processing {\n" -" fn process(self: Message);\n" +"```rust\n" +"use debug::PrintTrait;\n" +"fn main() {\n" +" let rectangle = (30, 10);\n" +" let area = area(rectangle);\n" +" area.print(); // print out the area\n" "}\n" "\n" -"impl ProcessingImpl of Processing {\n" -" fn process(self: Message) {\n" -" match self {\n" -" Message::Quit(()) => {\n" -" 'quitting'.print();\n" -" },\n" -" Message::Echo(value) => {\n" -" value.print();\n" -" },\n" -" Message::Move((x, y)) => {\n" -" 'moving'.print();\n" -" },\n" -" }\n" -" }\n" +"fn area(dimension: (u64, u64)) -> u64 {\n" +" let (x, y) = dimension;\n" +" x * y\n" "}\n" "```" -#: src/ch05-01-enums.md:75 -msgid "In this example, we implemented the `Processing` trait for `Message`. Here is how it could be used to process a Quit message:" -msgstr "在这个例子中,我们为`Message`实现了`Processing` trait。下面是如何用它来处理一条退出消息:" +#: src/ch04-02-an-example-program-using-structs.md:64 +msgid "Listing 4-7: Specifying the width and height of the rectangle with a tuple" +msgstr "示例4-7:用一个元组指定矩形的宽度和高度" -#: src/ch05-01-enums.md:77 +#: src/ch04-02-an-example-program-using-structs.md:66 msgid "" -"```rust\n" -"let msg: Message = Message::Quit(());\n" -"msg.process();\n" -"```" +"In one way, this program is better. Tuples let us add a bit of structure, and we’re now passing just one argument. But in another way, this version is less clear: tuples don’t name " +"their elements, so we have to index into the parts of the tuple, making our calculation less obvious." msgstr "" -"```rust\n" -"let msg: Message = Message::Quit(());\n" -"msg.process();\n" -"```" +"在某种程度上说,这个程序更好一点了。元组帮助我们增加了一些结构性,并且现在只需传一个参数。不过在另一方面,这个版本却有一点不明确了:元组并没有给出元素的名称,所以计算变得更费解了,因" +"为不得不使用索引来获取元组的每一部分。" -#: src/ch05-01-enums.md:82 -msgid "Running this code would print `quitting`." -msgstr "运行这段代码会打印出 `quitting`。" +#: src/ch04-02-an-example-program-using-structs.md:68 +msgid "" +"Mixing up the width and height wouldn’t matter for the area calculation, but if we want to calculate the difference, it would matter! We would have to keep in mind that `width` is " +"the tuple index `0` and `height` is the tuple index `1`. This would be even harder for someone else to figure out and keep in mind if they were to use our code. Because we haven’t " +"conveyed the meaning of our data in our code, it’s now easier to introduce errors." +msgstr "" +"混淆宽度和高度对于计算面积来说并不重要,但是如果我们想计算差值,那就很重要了。我们必须记住 `width` 是元组索引`0`, `height` 是元组索引`1`。如果其他人要使用这些代码,他们必须要搞清楚这" +"一点,并也要牢记于心。很容易忘记或者混淆这些值而造成错误,因为我们没有在代码中传达数据的意图。" -#: src/ch05-01-enums.md:84 -msgid "## The Option Enum and Its Advantages" -msgstr "## Option枚举及其优势" +#: src/ch04-02-an-example-program-using-structs.md:70 +msgid "## Refactoring with Structs: Adding More Meaning" +msgstr "## 使用结构体重构:赋予更多意义" -#: src/ch05-01-enums.md:86 -msgid "" -"The Option enum is a standard Cairo enum that represents the concept of an optional value. It has two variants: `Some: T` and `None: ()`. `Some: T ` indicates that there's a value of " -"type `T`, while `None` represents the absence of a value." -msgstr "Option枚举是一个标准的Cairo枚举,表示一个可选值的概念。它有两个变量:`Some: T` 和 `None: ()`。`Some:T`表示有一个`T`类型的值,而`None`表示没有值。" - -#: src/ch05-01-enums.md:88 -msgid "" -"```rs\n" -"enum Option {\n" -" Some: T,\n" -" None: (),\n" -"}\n" -"```" -msgstr "" -"```rs\n" -"enum Option {\n" -" Some: T,\n" -" None: (),\n" -"}\n" -"```" - -#: src/ch05-01-enums.md:95 -msgid "" -"The `Option` enum is helpful because it allows you to explicitly represent the possibility of a value being absent, making your code more expressive and easier to reason about. Using " -"`Option` can also help prevent bugs caused by using uninitialized or unexpected `null` values." -msgstr "`Option` 枚举很有用,因为它允许你明确地表示一个值不存在的可能性,使你的代码更具表现力,更容易推理。使用 `Option` 也可以帮助防止因使用未初始化的或意外的 `null` 值而引起的错误。" - -#: src/ch05-01-enums.md:97 -msgid "To give you an example, here is a function which returns the index of the first element of an array with a given value, or None if the element is not present." -msgstr "为了给你一个例子,这里有一个函数,它返回一个给定值的数组中第一个元素的索引,如果该元素不存在则返回None。" - -#: src/ch05-01-enums.md:99 -msgid "We are demonstrating two approaches for the above function:" -msgstr "我们为上述函数演示了两种方法:" - -#: src/ch05-01-enums.md:101 -msgid "" -"- Recursive Approach `find_value_recursive`\n" -"- Iterative Approach `find_value_iterative`" -msgstr "" -"- 递归法 `find_value_recursive`\n" -"- 迭代法 `find_value_iterative`" - -#: src/ch05-01-enums.md:104 -msgid "> Note: in the future it would be nice to replace this example by something simpler using a loop and without gas related code." -msgstr "> 注意:将来最好能用循环和无需 gas 的相关代码的简单示例替换此示例。" +#: src/ch04-02-an-example-program-using-structs.md:72 +msgid "We use structs to add meaning by labeling the data. We can transform the tuple we’re using into a struct with a name for the whole as well as names for the parts." +msgstr "我们使用结构体为数据命名来为其赋予意义。我们可以将我们正在使用的元组转换成一个有整体名称而且每个部分也有对应名字的结构体。" -#: src/ch05-01-enums.md:106 +#: src/ch04-02-an-example-program-using-structs.md:76 msgid "" "```rust\n" -"use array::ArrayTrait;\n" "use debug::PrintTrait;\n" -"fn find_value_recursive(arr: @Array, value: felt252, index: usize) -> Option {\n" -" if index >= arr.len() {\n" -" return Option::None(());\n" -" }\n" "\n" -" if *arr.at(index) == value {\n" -" return Option::Some(index);\n" -" }\n" -"\n" -" find_value_recursive(arr, value, index + 1)\n" +"struct Rectangle {\n" +" width: u64,\n" +" height: u64,\n" "}\n" "\n" -"fn find_value_iterative(arr: @Array, value: felt252) -> Option {\n" -" let length = arr.len();\n" -" let mut index = 0;\n" -" let mut found: Option = Option::None(());\n" -" loop {\n" -" if index < length {\n" -" if *arr.at(index) == value {\n" -" found = Option::Some(index);\n" -" break ();\n" -" }\n" -" } else {\n" -" break ();\n" -" }\n" -" index += 1;\n" -" };\n" -" return found;\n" +"fn main() {\n" +" let rectangle = Rectangle { width: 30, height: 10, };\n" +" let area = area(rectangle);\n" +" area.print(); // print out the area\n" "}\n" "\n" -"#[test]\n" -"#[available_gas(999999)]\n" -"fn test_increase_amount() {\n" -" let mut my_array = ArrayTrait::new();\n" -" my_array.append(3);\n" -" my_array.append(7);\n" -" my_array.append(2);\n" -" my_array.append(5);\n" -"\n" -" let value_to_find = 7;\n" -" let result = find_value_recursive(@my_array, value_to_find, 0);\n" -" let result_i = find_value_iterative(@my_array, value_to_find);\n" -"\n" -" match result {\n" -" Option::Some(index) => {\n" -" if index == 1{\n" -" 'it worked'.print();\n" -" }\n" -" },\n" -" Option::None(()) => {\n" -" 'not found'.print();\n" -" },\n" -" }\n" -" match result_i {\n" -" Option::Some(index) => {\n" -" if index == 1{\n" -" 'it worked'.print();\n" -" }\n" -" },\n" -" Option::None(()) => {\n" -" 'not found'.print();\n" -" },\n" -" }\n" +"fn area(rectangle: Rectangle) -> u64 {\n" +" rectangle.width * rectangle.height\n" "}\n" -"\n" "```" msgstr "" "```rust\n" -"use array::ArrayTrait;\n" "use debug::PrintTrait;\n" -"fn find_value_recursive(arr: @Array, value: felt252, index: usize) -> Option {\n" -" if index >= arr.len() {\n" -" return Option::None(());\n" -" }\n" -"\n" -" if *arr.at(index) == value {\n" -" return Option::Some(index);\n" -" }\n" "\n" -" find_value_recursive(arr, value, index + 1)\n" +"struct Rectangle {\n" +" width: u64,\n" +" height: u64,\n" "}\n" "\n" -"fn find_value_iterative(arr: @Array, value: felt252) -> Option {\n" -" let length = arr.len();\n" -" let mut index = 0;\n" -" let mut found: Option = Option::None(());\n" -" loop {\n" -" if index < length {\n" -" if *arr.at(index) == value {\n" -" found = Option::Some(index);\n" -" break ();\n" -" }\n" -" } else {\n" -" break ();\n" -" }\n" -" index += 1;\n" -" };\n" -" return found;\n" +"fn main() {\n" +" let rectangle = Rectangle { width: 30, height: 10, };\n" +" let area = area(rectangle);\n" +" area.print(); // print out the area\n" "}\n" "\n" -"#[test]\n" -"#[available_gas(999999)]\n" -"fn test_increase_amount() {\n" -" let mut my_array = ArrayTrait::new();\n" -" my_array.append(3);\n" -" my_array.append(7);\n" -" my_array.append(2);\n" -" my_array.append(5);\n" -"\n" -" let value_to_find = 7;\n" -" let result = find_value_recursive(@my_array, value_to_find, 0);\n" -" let result_i = find_value_iterative(@my_array, value_to_find);\n" -"\n" -" match result {\n" -" Option::Some(index) => {\n" -" if index == 1{\n" -" 'it worked'.print();\n" -" }\n" -" },\n" -" Option::None(()) => {\n" -" 'not found'.print();\n" -" },\n" -" }\n" -" match result_i {\n" -" Option::Some(index) => {\n" -" if index == 1{\n" -" 'it worked'.print();\n" -" }\n" -" },\n" -" Option::None(()) => {\n" -" 'not found'.print();\n" -" },\n" -" }\n" +"fn area(rectangle: Rectangle) -> u64 {\n" +" rectangle.width * rectangle.height\n" "}\n" -"\n" "```" -#: src/ch05-01-enums.md:176 -msgid "Running this code would print `it worked`." -msgstr "运行这段代码会打印出 `it worked`。" - -#: src/ch05-02-the-match-control-flow-construct.md:1 -msgid "# The Match Control Flow Construct" -msgstr "# match控制流结构" - -#: src/ch05-02-the-match-control-flow-construct.md:3 -msgid "" -msgstr "" +#: src/ch04-02-an-example-program-using-structs.md:95 +msgid "Listing 4-8: Defining a `Rectangle` struct" +msgstr "示例 4-8:定义一个`Rectangle`结构" -#: src/ch05-02-the-match-control-flow-construct.md:5 +#: src/ch04-02-an-example-program-using-structs.md:97 msgid "" -"Cairo has an extremely powerful control flow construct called `match` that allows you to compare a value against a series of patterns and then execute code based on which pattern " -"matches. Patterns can be made up of literal values, variable names, wildcards, and many other things. The power of match comes from the expressiveness of the patterns and the fact " -"that the compiler confirms that all possible cases are handled." +"Here we’ve defined a struct and named it `Rectangle`. Inside the curly brackets, we defined the fields as `width` and `height`, both of which have type `u64`. Then, in `main`, we " +"created a particular instance of `Rectangle` that has a width of `30` and a height of `10`. Our `area` function is now defined with one parameter, which we’ve named `rectangle` which " +"is of type `Rectangle` struct. We can then access the fields of the instance with dot notation, and it gives descriptive names to the values rather than using the tuple index values " +"of `0` and `1`." msgstr "" -"Cairo 有一个叫做 `match` 的极为强大的控制流运算符,它允许我们将一个值与一系列的模式相比较,并根据相匹配的模式执行相应代码。模式可由字面值、变量、通配符和许多其他内容构成;第十八章会涉" -"及到所有不同种类的模式以及它们的作用。`match` 的力量来源于模式的表现力以及编译器检查,它确保了所有可能的情况都得到处理。" +"这里我们定义了一个结构,并将其命名为 `Rectangle`。在大括号中,我们将字段定义为 `width` 和 `height`,它们的类型都是 `u64`。然后,在`main`中,我们创建了一个`Rectangle`的特殊实例,它的宽" +"度是`30`,高度是`10`。我们的 `area`函数现在定义了一个名为 `rectangle`参数,它是`Rectangle`结构类型。然后我们可以用点符号来访问实例的字段,它给这些值起了描述性的名字,而不是使用`0`和" +"`1`的元组索引值。结构体胜在更清晰明了。" -#: src/ch05-02-the-match-control-flow-construct.md:7 -msgid "" -"Think of a match expression as being like a coin-sorting machine: coins slide down a track with variously sized holes along it, and each coin falls through the first hole it " -"encounters that it fits into. In the same way, values go through each pattern in a match, and at the first pattern the value “fits”, the value falls into the associated code block to " -"be used during execution." -msgstr "" -"可以把 `match` 表达式想象成某种硬币分类器:硬币滑入有着不同大小孔洞的轨道,每一个硬币都会掉入符合它大小的孔洞。同样地,值也会通过 `match` 的每一个模式,并且在遇到第一个 “符合” 的模式" -"时,值会进入相关联的代码块并在执行中被使用。" +#: src/ch04-02-an-example-program-using-structs.md:99 +msgid "## Adding Useful Functionality with Trait" +msgstr "## 用Trait增加实用功能" -#: src/ch05-02-the-match-control-flow-construct.md:9 +#: src/ch04-02-an-example-program-using-structs.md:101 msgid "" -"Speaking of coins, let’s use them as an example using match! We can write a function that takes an unknown US coin and, in a similar way as the counting machine, determines which " -"coin it is and returns its value in cents, as shown in Listing 5-3." -msgstr "" -"因为刚刚提到了硬币,让我们用它们来作为一个使用 `match` 的例子!我们可以编写一个函数来获取一个未知的硬币,并以一种类似验钞机的方式,确定它是何种硬币,并返回其价值(美分),如示例5-3所" -"示。" +"It’d be useful to be able to print an instance of `Rectangle` while we’re debugging our program and see the values for all its fields. Listing 4-9 tries using the `print` as we have " +"used in previous chapters. This won’t work." +msgstr "在调试程序时打印出 `Rectangle` 实例来查看其所有字段的值非常有用。示例 4-9 像前面章节那样尝试使用 `print`。但这并不管用。" -#: src/ch05-02-the-match-control-flow-construct.md:11 +#: src/ch04-02-an-example-program-using-structs.md:105 msgid "" "```rust\n" -"enum Coin {\n" -" Penny: (),\n" -" Nickel: (),\n" -" Dime: (),\n" -" Quarter: (),\n" +"use debug::PrintTrait;\n" +"\n" +"struct Rectangle {\n" +" width: u64,\n" +" height: u64,\n" "}\n" "\n" -"fn value_in_cents(coin: Coin) -> felt252 {\n" -" match coin {\n" -" Coin::Penny(_) => 1,\n" -" Coin::Nickel(_) => 5,\n" -" Coin::Dime(_) => 10,\n" -" Coin::Quarter(_) => 25,\n" -" }\n" +"fn main() {\n" +" let rectangle = Rectangle { width: 30, height: 10, };\n" +" rectangle.print();\n" "}\n" "```" msgstr "" "```rust\n" -"enum Coin {\n" -" Penny: (),\n" -" Nickel: (),\n" -" Dime: (),\n" -" Quarter: (),\n" +"use debug::PrintTrait;\n" +"\n" +"struct Rectangle {\n" +" width: u64,\n" +" height: u64,\n" "}\n" "\n" -"fn value_in_cents(coin: Coin) -> felt252 {\n" -" match coin {\n" -" Coin::Penny(_) => 1,\n" -" Coin::Nickel(_) => 5,\n" -" Coin::Dime(_) => 10,\n" -" Coin::Quarter(_) => 25,\n" -" }\n" +"fn main() {\n" +" let rectangle = Rectangle { width: 30, height: 10, };\n" +" rectangle.print();\n" "}\n" "```" -#: src/ch05-02-the-match-control-flow-construct.md:29 -msgid "Listing 5-3: An enum and a match expression that has the variants of the enum as its patterns" -msgstr "示例5-3:一个枚举和一个将枚举成员作为其模式的 match 表达式" - -#: src/ch05-02-the-match-control-flow-construct.md:31 -msgid "" -"Let’s break down the `match` in the `value_in_cents` function. First we list the `match` keyword followed by an expression, which in this case is the value `coin`. This seems very " -"similar to a conditional expression used with if, but there’s a big difference: with if, the condition needs to evaluate to a Boolean value, but here it can be any type. The type of " -"coin in this example is the `Coin` enum that we defined on the first line." -msgstr "" -"拆开 `value_in_cents` 函数中的 `match` 来看。首先,我们列出 `match` 关键字后跟一个表达式,在这个例子中是 coin 的值。这看起来非常像 `if` 所使用的条件表达式,不过这里有一个非常大的区" -"别:对于 `if`,表达式必须返回一个布尔值,而这里它可以是任何类型的。本例中硬币的类型是我们在第一行定义的 `Coin` 枚举。" +#: src/ch04-02-an-example-program-using-structs.md:119 +msgid "Listing 4-9: Attempting to print a `Rectangle` instance" +msgstr "示例 4-9:试图打印一个 `Rectangle`实例" -#: src/ch05-02-the-match-control-flow-construct.md:33 -msgid "" -"Next are the `match` arms. An arm has two parts: a pattern and some code. The first arm here has a pattern that is the value `Coin::Penny(_)` and then the `=>` operator that " -"separates the pattern and the code to run. The code in this case is just the value `1`. Each arm is separated from the next with a comma." -msgstr "" -"接下来是 `match` 分支。一个分支有两个部分:一个模式和一些代码。这里的第一个分支有一个模式,就是值 `Coin::Penny(_)`,然后是`=>`操作符,把模式和要运行的代码分开。本例中的代码只是值 " -"`1`。每个分支都用逗号与下一个分支隔开。" +#: src/ch04-02-an-example-program-using-structs.md:121 +msgid "When we compile this code, we get an error with this message:" +msgstr "当我们编译这段代码时,我们得到了一个错误,有这样的信息:" -#: src/ch05-02-the-match-control-flow-construct.md:35 +#: src/ch04-02-an-example-program-using-structs.md:123 msgid "" -"When the `match` expression executes, it compares the resultant value against the pattern of each arm, in order. If a pattern matches the value, the code associated with that pattern " -"is executed. If that pattern doesn’t match the value, execution continues to the next arm, much as in a coin-sorting machine. We can have as many arms as we need: in the above " -"example, our match has four arms." +"```text\n" +"$ cairo-compile src/lib.cairo\n" +"error: Method `print` not found on type \"../src::Rectangle\". Did you import the correct trait and impl?\n" +" --> lib.cairo:16:15\n" +" rectangle.print();\n" +" ^***^\n" +"\n" +"Error: Compilation failed.\n" +"```" msgstr "" -"当 `match` 表达式执行时,它将结果值与每个分支的模式进行比较,依次进行。如果一个模式与值匹配,则执行与该模式相关的代码。如果该模式不匹配该值,则继续执行下一个分支,就像验钞机一样。我们" -"可以根据自己的需要有多少个分支:在上面的例子中,我们的匹配有四个分支。" - -#: src/ch05-02-the-match-control-flow-construct.md:37 -msgid "In Cairo, the order of the arms must follow the same order as the enum." -msgstr "在 Cairo,分支的顺序必须遵循与枚举相同的顺序。" - -#: src/ch05-02-the-match-control-flow-construct.md:39 -msgid "" -"The code associated with each arm is an expression, and the resultant value of the expression in the matching arm is the value that gets returned for the entire match expression." -msgstr "与每个 match 相关的代码是一个表达式,而 match 分支中表达式的结果值是整个 match 表达式被返回的值。" +"```text\n" +"$ cairo-compile src/lib.cairo\n" +"error: Method `print` not found on type \"../src::Rectangle\". Did you import the correct trait and impl?\n" +" --> lib.cairo:16:15\n" +" rectangle.print();\n" +" ^***^\n" +"\n" +"Error: Compilation failed.\n" +"```" -#: src/ch05-02-the-match-control-flow-construct.md:41 +#: src/ch04-02-an-example-program-using-structs.md:133 msgid "" -"We don’t typically use curly brackets if the match arm code is short, as it is in our example where each arm just returns a value. If you want to run multiple lines of code in a " -"match arm, you must use curly brackets, with a comma following the arm. For example, the following code prints “Lucky penny!” every time the method is called with a `Coin::" -"Penny(())`, but still returns the last value of the block, `1`:" +"The `print` trait is implemented for many data types, but not for the `Rectangle` struct. We can fix this by implementing the `PrintTrait` trait on `Rectangle` as shown in Listing " +"4-10.\n" +"To learn more about traits, see [Traits in Cairo](ch07-02-traits-in-cairo.md)." msgstr "" -"如果 match 分支的代码很短,我们通常不使用大括号,就像在我们的示例中一样,每个分支只是返回一个值。如果你想在一个 match 分支中运行多行代码,你必须使用大括号,在 match 分支后面加一个逗" -"号。例如,下面的代码在每次调用 `Coin::Penny(())` 方法时都会打印出 “Lucky penny!”,但仍然返回区块的最后一个值 `1`:" +"许多数据类型都实现了 `print` trait,但 `Rectangle` 结构没有。我们可以通过在`Rectangle`上实现`PrintTrait` trait来解决这个问题,如示例4-10所示。\n" +"要了解更多关于traits的信息,请参阅[Traits in Cairo](ch07-02-traits-in-cairo.md)。" -#: src/ch05-02-the-match-control-flow-construct.md:43 +#: src/ch04-02-an-example-program-using-structs.md:138 msgid "" "```rust\n" -"fn value_in_cents(coin: Coin) -> felt252 {\n" -" match coin {\n" -" Coin::Penny(_) => {\n" -" ('Lucky penny!').print();\n" -" 1\n" -" },\n" -" Coin::Nickel(_) => 5,\n" -" Coin::Dime(_) => 10,\n" -" Coin::Quarter(_)=> 25,\n" +"use debug::PrintTrait;\n" +"\n" +"struct Rectangle {\n" +" width: u64,\n" +" height: u64,\n" +"}\n" +"\n" +"fn main() {\n" +" let rectangle = Rectangle { width: 30, height: 10, };\n" +" rectangle.print();\n" +"}\n" +"\n" +"impl RectanglePrintImpl of PrintTrait {\n" +" fn print(self: Rectangle) {\n" +" self.width.print();\n" +" self.height.print();\n" " }\n" "}\n" "```" msgstr "" "```rust\n" -"fn value_in_cents(coin: Coin) -> felt252 {\n" -" match coin {\n" -" Coin::Penny(_) => {\n" -" ('Lucky penny!').print();\n" -" 1\n" -" },\n" -" Coin::Nickel(_) => 5,\n" -" Coin::Dime(_) => 10,\n" -" Coin::Quarter(_)=> 25,\n" +"use debug::PrintTrait;\n" +"\n" +"struct Rectangle {\n" +" width: u64,\n" +" height: u64,\n" +"}\n" +"\n" +"fn main() {\n" +" let rectangle = Rectangle { width: 30, height: 10, };\n" +" rectangle.print();\n" +"}\n" +"\n" +"impl RectanglePrintImpl of PrintTrait {\n" +" fn print(self: Rectangle) {\n" +" self.width.print();\n" +" self.height.print();\n" " }\n" "}\n" "```" -#: src/ch05-02-the-match-control-flow-construct.md:57 -msgid "## Patterns That Bind to Values" -msgstr "## 绑定值的模式" +#: src/ch04-02-an-example-program-using-structs.md:159 +msgid "Listing 4-10: Implementing the `PrintTrait` trait on `Rectangle`" +msgstr "示例4-10:在`Rectangle`上实现`PrintTrait` trait" -#: src/ch05-02-the-match-control-flow-construct.md:59 -msgid "Another useful feature of match arms is that they can bind to the parts of the values that match the pattern. This is how we can extract values out of enum variants." -msgstr "另一个match分支的有用的特点是它们可以绑定到值中与模式相匹配的部分。这就是如何从枚举成员中提取数值的方法。" +#: src/ch04-02-an-example-program-using-structs.md:161 +msgid "Nice! It’s not the prettiest output, but it shows the values of all the fields for this instance, which would definitely help during debugging." +msgstr "很好!这不是最漂亮的输出,但它显示了这个实例的所有字段的值,这在调试时肯定会有帮助。" -#: src/ch05-02-the-match-control-flow-construct.md:61 +#: src/ch04-03-method-syntax.md:1 +msgid "## Method Syntax" +msgstr "## 方法语法(Method Syntax)" + +#: src/ch04-03-method-syntax.md:3 msgid "" -"As an example, let’s change one of our enum variants to hold data inside it. From 1999 through 2008, the United States minted quarters with different designs for each of the 50 " -"states on one side. No other coins got state designs, so only quarters have this extra value. We can add this information to our `enum` by changing the `Quarter` variant to include a " -"`UsState` value stored inside it, which we’ve done in Listing 5-4." +"_Methods_ are similar to functions: we declare them with the `fn` keyword and a\n" +"name, they can have parameters and a return value, and they contain some code\n" +"that’s run when the method is called from somewhere else. Unlike functions,\n" +"methods are defined within the context of a type and their first parameter is\n" +"always `self`, which represents the instance of the type the method is being\n" +"called on. For those familiar with Rust, Cairo's approach might be confusing,\n" +"as methods cannot be defined directly on types. Instead, you must define a trait\n" +"and an implementation associated with the type for which the method is intended." msgstr "" -"作为一个例子,让我们修改枚举的一个成员来存放数据。1999 年到 2008 年间,美国在 25 美分的硬币的一侧为 50 个州的每一个都印刷了不同的设计。其他的硬币都没有这种区分州的设计,所以只有这些 " -"25 美分硬币有特殊的价值。我们可以通过改变 `Quarter` 变量,使其包含一个`UsState` 的值,从而将这个信息添加到我们的 `enum` 中,我们在示例5-4中已经这样做了。" +"_方法_(method)与函数类似:它们使用 `fn` 关键字和名称声明,可以拥有参数和返回值,同时包含在某处调用该方法时会执行的代码。不过方法与函数是不同的,因为它们在结构体的上下文中被定义,并" +"且它们第一个参数总是 `self`,它代表调用该方法的结构体实例。\n" +"对于那些熟悉Rust的人来说,Cairo的方法可能会令人困惑,因为方法不能被直接定义在类型上。\n" +"相反,你必须定义一个trait和一个与该方法所在类型相关的实现。" -#: src/ch05-02-the-match-control-flow-construct.md:63 +#: src/ch04-03-method-syntax.md:12 +msgid "### Defining Methods" +msgstr "### 定义方法" + +#: src/ch04-03-method-syntax.md:14 +msgid "" +"Let’s change the `area` function that has a `Rectangle` instance as a parameter\n" +"and instead make an `area` method defined on the `RectangleTrait` trait, as shown\n" +"in Listing 4-13." +msgstr "" +"让我们把前面实现的获取一个 `Rectangle` 实例作为参数的 `area` 函数,\n" +"改写成一个定义于 `RectangleTrait` trait 上的 `area` 方法,如示例4-13所示。" + +#: src/ch04-03-method-syntax.md:20 msgid "" "```rust\n" -"#[derive(Drop)]\n" -"enum UsState {\n" -" Alabama: (),\n" -" Alaska: (),\n" +"use debug::PrintTrait;\n" +"#[derive(Copy, Drop)]\n" +"struct Rectangle {\n" +" width: u64,\n" +" height: u64,\n" "}\n" "\n" -"#[derive(Drop)]\n" -"enum Coin {\n" -" Penny: (),\n" -" Nickel: (),\n" -" Dime: (),\n" -" Quarter: (UsState),\n" +"trait RectangleTrait {\n" +" fn area(self: @Rectangle) -> u64;\n" +"}\n" +"\n" +"impl RectangleImpl of RectangleTrait {\n" +" fn area(self: @Rectangle) -> u64 {\n" +" (*self.width) * (*self.height)\n" +" }\n" +"}\n" +"\n" +"fn main() {\n" +" let rect1 = Rectangle { width: 30, height: 50, };\n" +"\n" +" rect1.area().print();\n" "}\n" "```" msgstr "" "```rust\n" -"#[derive(Drop)]\n" -"enum UsState {\n" -" Alabama: (),\n" -" Alaska: (),\n" +"use debug::PrintTrait;\n" +"#[derive(Copy, Drop)]\n" +"struct Rectangle {\n" +" width: u64,\n" +" height: u64,\n" "}\n" "\n" -"#[derive(Drop)]\n" -"enum Coin {\n" -" Penny: (),\n" -" Nickel: (),\n" -" Dime: (),\n" -" Quarter: (UsState),\n" +"trait RectangleTrait {\n" +" fn area(self: @Rectangle) -> u64;\n" +"}\n" +"\n" +"impl RectangleImpl of RectangleTrait {\n" +" fn area(self: @Rectangle) -> u64 {\n" +" (*self.width) * (*self.height)\n" +" }\n" +"}\n" +"\n" +"fn main() {\n" +" let rect1 = Rectangle { width: 30, height: 50, };\n" +"\n" +" rect1.area().print();\n" "}\n" "```" -#: src/ch05-02-the-match-control-flow-construct.md:79 -msgid "Listing 5-4: A `Coin` enum in which the `Quarter` variant also holds a `UsState` value" -msgstr "列表5-4: 一个 `Coin` 枚举,其中 `Quarter` 变量也持有一个 `UsState` 值" - -#: src/ch05-02-the-match-control-flow-construct.md:81 +#: src/ch04-03-method-syntax.md:45 msgid "" -"Let’s imagine that a friend is trying to collect all 50 state quarters. While we sort our loose change by coin type, we’ll also call out the name of the state associated with each " -"quarter so that if it’s one our friend doesn’t have, they can add it to their collection." -msgstr "" -"想象一下我们的一个朋友尝试收集所有 50 个州的 25 美分硬币。在根据硬币类型分类零钱的同时,也可以报告出每个 25 美分硬币所对应的州名称,这样如果我们的朋友没有的话,他可以将其加入收藏。" +"Listing 4-13: Defining an `area` method to use on the\n" +"`Rectangle` " +msgstr "示例4-13:定义一个用在`Rectangle` 上的 `area` 方法 " -#: src/ch05-02-the-match-control-flow-construct.md:83 +#: src/ch04-03-method-syntax.md:48 msgid "" -"In the match expression for this code, we add a variable called `state` to the pattern that matches values of the variant `Coin::Quarter`. When a `Coin::Quarter` matches, the `state` " -"variable will bind to the value of that quarter’s state. Then we can use `state` in the code for that arm, like so:" +"To define the function within the context of `Rectangle`, we start by defining a `trait`\n" +"block with the signature of the method that we want to implement. Traits are not linked to\n" +"a specific type; only the `self` parameter of the method defines which type it can be used\n" +"with. Then, we define an `impl` (implementation) block for `RectangleTrait`, that defines\n" +"the behavior of the methods implemented. Everything within this `impl` block will be\n" +"associated with the type of the `self` parameter of the method called. While it is technically\n" +"possible to define methods for multiple types within the same `impl` block, it is not\n" +"a recommended practice, as it can lead to confusion. We recommend that the type of the `self` parameter\n" +"stays consistent within the same `impl` block.\n" +"Then we move the `area` function within the `impl` curly brackets and change the first (and in this case, only)\n" +"parameter to be `self` in the signature and everywhere within the body. In\n" +"`main`, where we called the `area` function and passed `rect1` as an argument,\n" +"we can instead use the _method syntax_ to call the `area` method on our `Rectangle`\n" +"instance. The method syntax goes after an instance: we add a dot followed by\n" +"the method name, parentheses, and any arguments." msgstr "" -"在这段代码的match表达式中,我们在模式中添加了一个叫做 `state` 的变量,用来匹配变量 `Coin::Quarter` 的值。当 `Coin::Quarter` 匹配时,`state` 变量将与该季度的状态值绑定。然后我们可以在" -"该分支的代码中使用 `state`,像这样:" - -#: src/ch05-02-the-match-control-flow-construct.md:85 -msgid "" -"```rust\n" -"fn value_in_cents(coin: Coin) -> felt252 {\n" -" match coin {\n" -" Coin::Penny(_) => 1,\n" -" Coin::Nickel(_) => 5,\n" -" Coin::Dime(_) => 10,\n" -" Coin::Quarter(state)=> {\n" -" state.print();\n" -" 25\n" -" },\n" -" }\n" -"}\n" -"```" -msgstr "" -"```rust\n" -"fn value_in_cents(coin: Coin) -> felt252 {\n" -" match coin {\n" -" Coin::Penny(_) => 1,\n" -" Coin::Nickel(_) => 5,\n" -" Coin::Dime(_) => 10,\n" -" Coin::Quarter(state)=> {\n" -" state.print();\n" -" 25\n" -" },\n" -" }\n" -"}\n" -"```" - -#: src/ch05-02-the-match-control-flow-construct.md:99 -msgid "To print the value of a variant of an enum in Cairo, we need to add an implementation for the `print` function for the `debug::PrintTrait`:" -msgstr "为了在 Cairo 打印一个枚举的变量的值,我们需要为`debug::PrintTrait` 添加一个 `print` 函数的实现:" +"为了使函数定义于 `Rectangle` 的上下文中,我们开始了一个 `trait` 块,其中包含我们想要实现的方法的签名。\n" +"Traits 并不与一个特定的类型所链接;只有方法的 `self` 参数定义了它可以用于哪种类型。然后,我们为 `RectangleTrait` 定义一个 `impl`(实现)块,它定义了实现的方法的行为。\n" +"这个 `impl` 块中的所有内容都将与被调用方法的 `self` 参数的类型相关。虽然在技术上可以在同一个 `impl` 块中定义多种类型的方法,但这并不是一个值得推荐的做法。\n" +"因为它可能会导致混乱。我们建议`self`参数的类型在同一个 `impl` 块中保持一致。\n" +"然后我们将`area`函数移到`impl`大括号内,并在签名和正文的所有地方将第一个(在本例中是唯一的)参数改为`self`。在`main`中,我们调用`area`函数并传递`rect1`作为参数、\n" +"\n" +"我们可以使用 _method syntax_ 在我们的`Rectangle`实例上调用`area`方法。\n" +"方法语法是:在一个实例的后面,加上一个点号,后跟方法名、圆括号以及任何参数。" -#: src/ch05-02-the-match-control-flow-construct.md:101 +#: src/ch04-03-method-syntax.md:64 msgid "" -"```rust\n" -"impl UsStatePrintImpl of PrintTrait:: {\n" -" fn print(self: UsState) {\n" -" match self {\n" -" UsState::Alabama(_) => ('Alabama').print(),\n" -" UsState::Alaska(_) => ('Alaska').print(),\n" -" }\n" -" }\n" -"}\n" -"```" +"Methods must have a parameter named `self` of the type they will be applied to for their first parameter.\n" +"Note that we used the `@` snapshot operator in front of the `Rectangle` type in the function signature.\n" +"By doing so, we indicate that this method takes an immutable snapshot of the `Rectangle` instance, which is\n" +"automatically created by the compiler when passing the instance to the method.\n" +"Methods can take ownership of `self`, use `self` with snapshots as we’ve done here, or use a mutable reference to `self`\n" +"using the `ref self: T` syntax." msgstr "" -"```rust\n" -"impl UsStatePrintImpl of PrintTrait:: {\n" -" fn print(self: UsState) {\n" -" match self {\n" -" UsState::Alabama(_) => ('Alabama').print(),\n" -" UsState::Alaska(_) => ('Alaska').print(),\n" -" }\n" -" }\n" -"}\n" -"```" +"方法必须有一个名为 `self` 的类型参数作为它们将要应用的类型的第一个参数。请注意,我们在函数签名中在 `Rectangle` 类型前面使用了 `@` 快照运算符。这样做,我们表示此方法获取 `Rectangle` 实" +"例的不可变快照,编译器在将实例传递给该方法时会自动创建。方法可以获取 `self` 实例的所有权,像我们在这里所做的那样使用快照的 `self`,或使用 `ref self: T` 语法使用 `self` 的可变引用。" -#: src/ch05-02-the-match-control-flow-construct.md:112 +#: src/ch04-03-method-syntax.md:71 msgid "" -"If we were to call `value_in_cents(Coin::Quarter(UsState::Alaska(())))`, `coin` would be `Coin::Quarter(UsState::Alaska())`. When we compare that value with each of the match arms, " -"none of them match until we reach `Coin::Quarter(state)`. At that point, the binding for state will be the value `UsState::Alaska()`. We can then use that binding in the " -"`PrintTrait`, thus getting the inner state value out of the `Coin` enum variant for `Quarter`." +"We chose `self: @Rectangle` here for the same reason we used `@Rectangle` in the function\n" +"version: we don’t want to take ownership, and we just want to read the data in\n" +"the struct, not write to it. If we wanted to change the instance that we’ve\n" +"called the method on as part of what the method does, we’d use `ref self: Rectangle` as\n" +"the first parameter. Having a method that takes ownership of the instance by\n" +"using just `self` as the first parameter is rare; this technique is usually\n" +"used when the method transforms `self` into something else and you want to\n" +"prevent the caller from using the original instance after the transformation." msgstr "" -"如果我们调用 `value_in_cents(Coin::quarter(UsState::Alaska(())))`,`coin` 将是 `Coin::quarter(UsState::Alaska())`。当我们将该值与每个匹配臂进行比较时,没有一个匹配,直到我们到达 " -"`Coin::Quarter(state)`。在这一点上,state 的绑定将是 `UsState::Alaska()` 的值。然后我们可以在 `PrintTrait` 中使用该绑定,从而从 `Coin` 枚举变量中获得 `Quarter` 的内部状态值。" - -#: src/ch05-02-the-match-control-flow-construct.md:114 -msgid "## Matching with Options" -msgstr "## 匹配 Option" +"我们在这里选择 `self: @Rectangle` 与函数版本中使用 `@Rectangle` 的原因相同:我们不想要所有权,只是想读取结构体中的数据,而不是对它进行写入。如果我们想要作为方法的一部分更改调用方法的" +"实例,我们将使用 `ref self: Rectangle` 作为第一个参数。通过仅使用 `self` 作为第一个参数来使方法获取实例的所有权是很少见的;这种技术通常用在当方法将 `self` 转换成别的实例的时候,这时我" +"们想要防止调用者在转换之后使用原始的实例。" -#: src/ch05-02-the-match-control-flow-construct.md:116 +#: src/ch04-03-method-syntax.md:80 msgid "" -"In the previous section, we wanted to get the inner `T` value out of the `Some` case when using `Option`; we can also handle `Option` using `match`, as we did with the `Coin` " -"enum! Instead of comparing coins, we’ll compare the variants of `Option`, but the way the `match` expression works remains the same. You can use Options by importing the `option::" -"OptionTrait` trait." +"Observe the use of the desnap operator `*` within the area method when accessing the struct's members.\n" +"This is necessary because the struct is passed as a snapshot, and all of its field values are of type `@T`,\n" +"requiring them to be desnapped in order to manipulate them." msgstr "" -"在上一节中,我们想在使用 `Option` 时从 `Some` 情况下得到内部的 `T` 值;我们也可以使用`match` 来处理 `Option`,就像我们对 `Coin` 枚举所做的那样! 只不过这回比较的不再是硬币,而是" -"比较 `Option` 的成员,但 `match` 表达式的工作方式保持不变。你可以通过导入 `option::OptionTrait` trait来使用Option。" +"在访问结构体的成员时,请注意在区域方法中使用 _desnap_ 操作符`*`。\n" +"这是必要的,因为该结构是以快照形式传递的,其所有字段值都是`@T`类型、\n" +"需要对它们进行解快照,以便对其进行操作。" -#: src/ch05-02-the-match-control-flow-construct.md:118 +#: src/ch04-03-method-syntax.md:84 msgid "" -"Let’s say we want to write a function that takes an `Option` and, if there’s a value inside, adds `1` to that value. If there isn’t a value inside, the function should return the " -"`None` value and not attempt to perform any operations." -msgstr "假设我们想写一个函数,接收一个 `Option`,如果里面有一个值,就把 `1` 加到这个值上。如果里面没有一个值,这个函数应该返回 `None` 值,并且不试图执行任何操作。" +"The main reason for using methods instead of functions is for organization and code clarity. We’ve put all the things we can do with an instance of a type in one combination of " +"`trait` & `impl` blocks, rather than making future users\n" +"of our code search for capabilities of `Rectangle` in various places in the\n" +"library we provide. However, we can define multiple combinations of `trait` & `impl` blocks for the same type at different places, which can be useful for a more granular code " +"organization. For example, you could implement\n" +"the `Add` trait for your type in one `impl` block, and the `Sub` trait in another block." +msgstr "" +"使用方法而不是函数的主要原因是为了组织和代码的清晰性。我们把所有我们能对一个类型的实例做的操作都放在一组`trait`和`impl`块的组合中,而不是让未来的用户在我们提供的库中的不同地方搜索 " +"`Rectangle`的函数。\n" +"然而,我们可以在不同的地方为同一类型定义多个`trait`和`impl`块的组合,这对更细化的代码组织很有用。例如,你可以在一个`impl`块中为你的类型实现 `impl` trait ,在另一个块中实现 `Sub` " +"trait 。" -#: src/ch05-02-the-match-control-flow-construct.md:120 -msgid "This function is very easy to write, thanks to match, and will look like Listing 5-5." -msgstr "这个函数非常容易编写,这要归功于 match,它看起来像示例5-5。" +#: src/ch04-03-method-syntax.md:89 +msgid "" +"Note that we can choose to give a method the same name as one of the struct’s\n" +"fields. For example, we can define a method on `Rectangle` that is also named\n" +"`width`:" +msgstr "请注意,我们可以选择将方法的名称与结构中的一个字段相同。例如,我们可以在 `Rectangle` 上定义一个方法,并命名为`width`:" -#: src/ch05-02-the-match-control-flow-construct.md:122 +#: src/ch04-03-method-syntax.md:95 msgid "" "```rust\n" -"use option::OptionTrait;\n" "use debug::PrintTrait;\n" +"#[derive(Copy, Drop)]\n" +"struct Rectangle {\n" +" width: u64,\n" +" height: u64,\n" +"}\n" "\n" -"fn plus_one(x: Option) -> Option {\n" -" match x {\n" -" Option::Some(val) => Option::Some(val + 1),\n" -" Option::None(_) => Option::None(()),\n" +"trait RectangleTrait {\n" +" fn width(self: @Rectangle) -> bool;\n" +"}\n" +"\n" +"impl RectangleImpl of RectangleTrait {\n" +" fn width(self: @Rectangle) -> bool {\n" +" (*self.width) > 0\n" " }\n" "}\n" "\n" "fn main() {\n" -" let five: Option = Option::Some(5);\n" -" let six: Option = plus_one(five);\n" -" six.unwrap().print();\n" -" let none = plus_one(Option::None(()));\n" -" none.unwrap().print();\n" +" let rect1 = Rectangle { width: 30, height: 50, };\n" +" rect1.width().print();\n" "}\n" "```" msgstr "" "```rust\n" -"use option::OptionTrait;\n" "use debug::PrintTrait;\n" +"#[derive(Copy, Drop)]\n" +"struct Rectangle {\n" +" width: u64,\n" +" height: u64,\n" +"}\n" "\n" -"fn plus_one(x: Option) -> Option {\n" -" match x {\n" -" Option::Some(val) => Option::Some(val + 1),\n" -" Option::None(_) => Option::None(()),\n" +"trait RectangleTrait {\n" +" fn width(self: @Rectangle) -> bool;\n" +"}\n" +"\n" +"impl RectangleImpl of RectangleTrait {\n" +" fn width(self: @Rectangle) -> bool {\n" +" (*self.width) > 0\n" " }\n" "}\n" "\n" "fn main() {\n" -" let five: Option = Option::Some(5);\n" -" let six: Option = plus_one(five);\n" -" six.unwrap().print();\n" -" let none = plus_one(Option::None(()));\n" -" none.unwrap().print();\n" +" let rect1 = Rectangle { width: 30, height: 50, };\n" +" rect1.width().print();\n" "}\n" "```" -#: src/ch05-02-the-match-control-flow-construct.md:142 -msgid "Listing 5-5: A function that uses a match expression on an `Option`" -msgstr "示例5-5:一个在`Option`上使用匹配表达式的函数" +#: src/ch04-03-method-syntax.md:119 +msgid "" +"Here, we’re choosing to make the `width` method return `true` if the value in\n" +"the instance’s `width` field is greater than `0` and `false` if the value is\n" +"`0`: we can use a field within a method of the same name for any purpose. In\n" +"`main`, when we follow `rect1.width` with parentheses, Cairo knows we mean the\n" +"method `width`. When we don’t use parentheses, Cairo knows we mean the field\n" +"`width`." +msgstr "" +"在这里,我们选择让`width`方法在实例的`width`字段中的值大于0时返回`true`,在值为0时返回`false` :我们可以在同名方法的字段内使用任何目的。在`main`中,当我们在`rect1.width`后面跟着括号" +"时,Cairo知道我们意思是`width`方法。当我们不使用括号时,Cairo知道我们指的是`width`字段。" -#: src/ch05-02-the-match-control-flow-construct.md:144 -msgid "Note that your arms must respect the same order as the enum defined in the `OptionTrait` of the core Cairo lib." -msgstr "注意,你的分支顺序与核心Cairo库的`OptionTrait`中定义的枚举顺序必须相同。" +#: src/ch04-03-method-syntax.md:126 +msgid "### Methods with More Parameters" +msgstr "### 带有更多参数的方法" -#: src/ch05-02-the-match-control-flow-construct.md:146 src/ch07-01-generic-data-types.md:176 +#: src/ch04-03-method-syntax.md:128 msgid "" -"```rust\n" -"enum Option {\n" -" Some: T,\n" -" None: (),\n" +"Let’s practice using methods by implementing a second method on the `Rectangle`\n" +"struct. This time we want an instance of `Rectangle` to take another instance\n" +"of `Rectangle` and return `true` if the second `Rectangle` can fit completely\n" +"within `self` (the first `Rectangle`); otherwise, it should return `false`.\n" +"That is, once we’ve defined the `can_hold` method, we want to be able to write\n" +"the program shown in Listing 4-14." +msgstr "" +"让我们通过在`Rectangle`结构体上实现第二个方法来练习使用方法。这次,我们希望让`Rectangle`的实例接收另一个`Rectangle`的实例。如果第二个`Rectangle`可以完全适应`self` (第一个" +"`Rectangle`)就返回 `true` ; 否则,它应该返回`false`。也就是说,一旦我们定义了`can_hold`方法,我们希望能够编写列表4-14中显示的程序。" + +#: src/ch04-03-method-syntax.md:137 +msgid "" +"```rust,does_not_compile\n" +"use debug::PrintTrait;\n" +"#[derive(Copy, Drop)]\n" +"struct Rectangle {\n" +" width: u64,\n" +" height: u64,\n" +"}\n" +"\n" +"fn main() {\n" +" let rect1 = Rectangle { width: 30, height: 50, };\n" +" let rect2 = Rectangle { width: 10, height: 40, };\n" +" let rect3 = Rectangle { width: 60, height: 45, };\n" +"\n" +" 'Can rect1 hold rect2?'.print();\n" +" rect1.can_hold(@rect2).print();\n" +"\n" +" 'Can rect1 hold rect3?'.print();\n" +" rect1.can_hold(@rect3).print();\n" "}\n" "```" msgstr "" -"```rust\n" -"enum Option {\n" -" Some: T,\n" -" None: (),\n" +"```rust,does_not_compile\n" +"use debug::PrintTrait;\n" +"#[derive(Copy, Drop)]\n" +"struct Rectangle {\n" +" width: u64,\n" +" height: u64,\n" +"}\n" +"\n" +"fn main() {\n" +" let rect1 = Rectangle { width: 30, height: 50, };\n" +" let rect2 = Rectangle { width: 10, height: 40, };\n" +" let rect3 = Rectangle { width: 60, height: 45, };\n" +"\n" +" 'Can rect1 hold rect2?'.print();\n" +" rect1.can_hold(@rect2).print();\n" +"\n" +" 'Can rect1 hold rect3?'.print();\n" +" rect1.can_hold(@rect3).print();\n" "}\n" "```" -#: src/ch05-02-the-match-control-flow-construct.md:153 +#: src/ch04-03-method-syntax.md:158 msgid "" -"Let’s examine the first execution of `plus_one` in more detail. When we call `plus_one(five)`, the variable `x` in the body of `plus_one` will have the value `Some(5)`. We then " -"compare that against each match arm:" -msgstr "让我们更详细地看一下 `plus_one` 的第一次执行。当我们调用 `plus_one(five)` 时,`plus_one` 函数体中的变量 `x` 的值是 `Some(5)`。然后我们将其与每个匹配分支进行比较:" +"Listing 4-14: Using the as-yet-unwritten `can_hold`\n" +"method" +msgstr "示例4-14:使用尚未编写的`can_hold`方法" -#: src/ch05-02-the-match-control-flow-construct.md:155 src/ch05-02-the-match-control-flow-construct.md:163 +#: src/ch04-03-method-syntax.md:161 msgid "" -"```rust\n" -" Option::Some(val) => Option::Some(val + 1),\n" -"```" +"The expected output would look like the following because both dimensions of\n" +"`rect2` are smaller than the dimensions of `rect1`, but `rect3` is wider than\n" +"`rect1`:" msgstr "" -"```rust\n" -" Option::Some(val) => Option::Some(val + 1),\n" -"```" - -#: src/ch05-02-the-match-control-flow-construct.md:159 +"预期的输出结果如下,因为`rect2`的两个尺寸都小于`rect1`的尺寸。\n" +"但`rect3`的宽度大于`rect1`:" + +#: src/ch04-03-method-syntax.md:165 msgid "" -"Does `Option::Some(5)` value match the pattern `Option::Some(val)`? It does! We have the same variant. The `val` binds to the value contained in `Option::Some`, so `val` takes the " -"value `5`. The code in the match arm is then executed, so we add `1` to the value of `val` and create a new `Option::Some` value with our total `6` inside. Because the first arm " -"matched, no other arms are compared." +"```text\n" +"$ scarb cairo-run\n" +"[DEBUG]\tCan rec1 hold rect2? \t(raw: 384675147322001379018464490539350216396261044799)\n" +"\n" +"[DEBUG]\ttrue \t(raw: 1953658213)\n" +"\n" +"[DEBUG]\tCan rect1 hold rect3? \t(raw: 384675147322001384331925548502381811111693612095)\n" +"\n" +"[DEBUG]\tfalse \t(raw: 439721161573)\n" +"\n" +"```" msgstr "" -"`Option::Some(5)` 和`Option::Some(val)`匹配吗?当然匹配!它们是相同的成员。`val` 与 `Option::Some` 中包含的值绑定,所以 `val` 取值为 `5` 。接着匹配分支的代码被执行,所以我们在 `val` " -"的值上加上 `1`,并创建一个新的 `Option::Some` 值,里面有我们的和 `6` 。因为第一个分支就匹配到了,其他的分支将不再进行比较。" - -#: src/ch05-02-the-match-control-flow-construct.md:161 -msgid "Now let’s consider the second call of `plus_one` in our main function, where `x` is `Option::None(())`. We enter the match and compare to the first arm:" -msgstr "现在让我们考虑在我们的主函数中对 `plus_one` 的第二次调用,其中 `x` 是`Option::None(())`。我们进入匹配,并与第一个分支进行比较:" +"```text\n" +"$ scarb cairo-run\n" +"[DEBUG]\tCan rec1 hold rect2? \t(raw: 384675147322001379018464490539350216396261044799)\n" +"\n" +"[DEBUG]\ttrue \t(raw: 1953658213)\n" +"\n" +"[DEBUG]\tCan rect1 hold rect3? \t(raw: 384675147322001384331925548502381811111693612095)\n" +"\n" +"[DEBUG]\tfalse \t(raw: 439721161573)\n" +"\n" +"```" -#: src/ch05-02-the-match-control-flow-construct.md:167 -msgid "The `Option::Some(val)` value doesn’t match the pattern `Option::None`, so we continue to the next arm:" -msgstr "`Option::Some(val)` 的值不匹配 `Option::None` ,所以我们继续到下一个分支:" +#: src/ch04-03-method-syntax.md:177 +msgid "" +"We know we want to define a method, so it will be within the `trait RectangleTrait`\n" +"and `impl RectangleImpl of RectangleTrait` blocks.\n" +"The method name will be `can_hold`, and it will take a snapshot\n" +"of another `Rectangle` as a parameter. We can tell what the type of the\n" +"parameter will be by looking at the code that calls the method:\n" +"`rect1.can_hold(@rect2)` passes in `@rect2`, which is a snapshot to\n" +"`rect2`, an instance of `Rectangle`. This makes sense because we only need to\n" +"read `rect2` (rather than write, which would mean we’d need a mutable borrow),\n" +"and we want `main` to retain ownership of `rect2` so we can use it again after\n" +"calling the `can_hold` method. The return value of `can_hold` will be a\n" +"Boolean, and the implementation will check whether the width and height of\n" +"`self` are greater than the width and height of the other `Rectangle`,\n" +"respectively. Let’s add the new `can_hold` method to the `trait` and `impl` blocks from\n" +"Listing 4-13, shown in Listing 4-15." +msgstr "" +"我们需要定义一个方法,将它放置在在`trait RectangleTrait`和`impl RectangleImpl of RectangleTrait` 块中。该方法名为 `can_hold`,它将接收另一个`Rectangle`的快照作为参数。我们可以通过查看" +"调用该方法的代码来确定参数的类型:`rect1.can_hold(@rect2)`将`@rect2`作为快照传递给`rect2`,它是`Rectangle`的一个实例。这是有意义的,因为我们只需要读取`rect2`(而不是写入,这意味着我们" +"需要一个可变借用),我们希望`main`保留对`rect2`的所有权,以便在调用`can_hold` 方法后再次使用它。`can_hold` 的返回值将是一个布尔值,实现将检查`self`的宽度和高度是否分别大于另一" +"`Rectangle`的宽度和高度。让我们将新的`can_hold`方法添加到示例4-13中的`trait`和`impl` 块中,如示例4-15所示。" -#: src/ch05-02-the-match-control-flow-construct.md:169 +#: src/ch04-03-method-syntax.md:194 msgid "" "```rust\n" -" Option::None(_) => Option::None(()),\n" +"trait RectangleTrait {\n" +" fn area(self: @Rectangle) -> u64;\n" +" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" +"}\n" +"\n" +"impl RectangleImpl of RectangleTrait {\n" +" fn area(self: @Rectangle) -> u64 {\n" +" *self.width * *self.height\n" +" }\n" +"\n" +" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +" *self.width > *other.width & *self.height > *other.height\n" +" }\n" +"}\n" "```" msgstr "" "```rust\n" -" Option::None(_) => Option::None(()),\n" +"trait RectangleTrait {\n" +" fn area(self: @Rectangle) -> u64;\n" +" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" +"}\n" +"\n" +"impl RectangleImpl of RectangleTrait {\n" +" fn area(self: @Rectangle) -> u64 {\n" +" *self.width * *self.height\n" +" }\n" +"\n" +" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +" *self.width > *other.width & *self.height > *other.height\n" +" }\n" +"}\n" "```" -#: src/ch05-02-the-match-control-flow-construct.md:173 -msgid "It matches! There’s no value to add to, so the program stops and returns the `Option::None(())` value on the right side of `=>`." -msgstr "它是匹配的!没有值可以添加,所以程序停止,并返回 `=>` 右边的 `Option::None(())` 值。" +#: src/ch04-03-method-syntax.md:211 +msgid "" +"Listing 4-15: Implementing the `can_hold` method on\n" +"`Rectangle` that takes another `Rectangle` instance as a parameter" +msgstr "示例4-15: 在`Rectangle`上实现`can_hold`方法,该方法接收另一个`Rectangle`实例作为参数" -#: src/ch05-02-the-match-control-flow-construct.md:175 +#: src/ch04-03-method-syntax.md:214 msgid "" -"Combining `match` and enums is useful in many situations. You’ll see this pattern a lot in Cairo code: `match` against an enum, bind a variable to the data inside, and then execute " -"code based on it. It’s a bit tricky at first, but once you get used to it, you’ll wish you had it in all languages. It’s consistently a user favorite." +"When we run this code with the `main` function in Listing 4-14, we’ll get our\n" +"desired output. Methods can take multiple parameters that we add to the\n" +"signature after the `self` parameter, and those parameters work just like\n" +"parameters in functions." msgstr "" -"将 `match` 与枚举相结合在很多场景中都是有用的。你会在 Cairo 代码中看到很多这样的模式:`match` 一个枚举,绑定其中的值到一个变量,接着根据其值执行代码。这在一开始有点复杂,不过一旦习惯" -"了,你会希望所有语言都拥有它!这一直是用户的最爱。" +"当我们在示例 4-14中的`main`函数中运行这段代码时,我们将得到我们想要的输出。\n" +"方法可以接收多个参数,我们可以在`self`参数之后在函数签名中添加这些参数,\n" +"这些参数与函数中的参数工作原理相同。" -#: src/ch05-02-the-match-control-flow-construct.md:177 -msgid "## Matches Are Exhaustive" -msgstr "## 匹配是穷尽的" +#: src/ch04-03-method-syntax.md:219 +msgid "### Accessing implementation functions" +msgstr "### 访问实现里的函数" -#: src/ch05-02-the-match-control-flow-construct.md:179 +#: src/ch04-03-method-syntax.md:221 msgid "" -"There’s one other aspect of match we need to discuss: the arms’ patterns must cover all possibilities. Consider this version of our `plus_one` function, which has a bug and won’t " -"compile:" -msgstr "还有另一方面需要讨论:这些分支必须覆盖了所有的可能性。考虑一下 `plus_one` 函数的这个版本,它有一个 bug 并不能编译:" +"All functions defined within a `trait` and `impl` block can be directly addressed\n" +"using the `::` operator on the implementation name.\n" +"Functions in traits that aren’t methods are often used for constructors that\n" +"will return a new instance of the struct. These are often called `new`, but\n" +"`new` isn’t a special name and isn’t built into the language. For example, we\n" +"could choose to provide an associated function named `square` that would have\n" +"one dimension parameter and use that as both width and height, thus making it\n" +"easier to create a square `Rectangle` rather than having to specify the same\n" +"value twice:" +msgstr "" +"所有在`trait`和`impl` 块中定义的函数可以直接使用`::` 运算符在实现名称上进行访问。\n" +"在`trait`中的不是方法的函数通常用于构造函数,以返回一个结构体的新实例。\n" +"这些函数通常被称为`new`,但`new`不是一个特殊的名称,也不是内置到语言中的。\n" +"例如,我们可以选择提供一个名为`square` 的关联函数,它将具有一个维度参数,\n" +"并将其用作宽度和高度,从而更容易地创建一个正方形`Rectangle`,而不必指定两次相同的值:" -#: src/ch05-02-the-match-control-flow-construct.md:181 +#: src/ch04-03-method-syntax.md:233 msgid "" -"```bash\n" -"$ cairo-run src/test.cairo\n" -" error: Unsupported match. Currently, matches require one arm per variant,\n" -" in the order of variant definition.\n" -" --> test.cairo:34:5\n" -" match x {\n" -" ^*******^\n" -" Error: failed to compile: ./src/test.cairo\n" +"```rust,noplayground\n" +"trait RectangleTrait {\n" +" fn square(size: u64) -> Rectangle;\n" +"}\n" +"\n" +"impl RectangleImpl of RectangleTrait {\n" +" fn square(size: u64) -> Rectangle {\n" +" Rectangle { width: size, height: size }\n" +" }\n" +"}\n" "```" msgstr "" -"```bash\n" -"$ cairo-run src/test.cairo\n" -" error: Unsupported match. Currently, matches require one arm per variant,\n" -" in the order of variant definition.\n" -" --> test.cairo:34:5\n" -" match x {\n" -" ^*******^\n" -" Error: failed to compile: ./src/test.cairo\n" +"```rust,noplayground\n" +"trait RectangleTrait {\n" +" fn square(size: u64) -> Rectangle;\n" +"}\n" +"\n" +"impl RectangleImpl of RectangleTrait {\n" +" fn square(size: u64) -> Rectangle {\n" +" Rectangle { width: size, height: size }\n" +" }\n" +"}\n" "```" -#: src/ch05-02-the-match-control-flow-construct.md:191 +#: src/ch04-03-method-syntax.md:245 msgid "" -"Cairo knows that we didn’t cover every possible case, and even knows which pattern we forgot! Matches in Cairo are exhaustive: we must exhaust every last possibility in order for the " -"code to be valid. Especially in the case of `Option`, when Cairo prevents us from forgetting to explicitly handle the `None` case, it protects us from assuming that we have a " -"value when we might have null, thus making the billion-dollar mistake discussed earlier impossible." +"To call this function, we use the `::` syntax with the implementation name;\n" +"`let square = RectangleImpl::square(10);` is an example. This function is namespaced by\n" +"the implementation; the `::` syntax is used for both trait functions and\n" +"namespaces created by modules. We’ll discuss modules in [Chapter 7][modules]." msgstr "" -"Rust 知道我们没有覆盖所有可能的情况甚至知道哪些模式被忘记了!Cairo 中的匹配是 穷尽的(exhaustive):必须穷举到最后的可能性来使代码有效。特别的在这个 `Option` 的例子中,Cairo 防止我" -"们忘记明确的处理 None 的情况,这让我们免于假设拥有一个实际上为空的值,从而使之前提到的价值亿万的错误不可能发生。" +"为了调用这个函数,我们在实现的名称后面使用`::`语法;\n" +"比如`let square = RectangleImpl::square(10);` 这个例子。这个函数的位于其实现的命名空间中;`::`语法用于关联trait的函数和模块创建的命名空间。\n" +"我们将在 [Chapter 7][modules]<!--ignore-->中讲到模块。" -#: src/ch05-02-the-match-control-flow-construct.md:193 -msgid "## Match 0 and the \\_ Placeholder" -msgstr "## Match 0 与 \\_ 占位符" +#: src/ch04-03-method-syntax.md:250 +msgid "> Note: It is also possible to call this function using the trait name, with `RectangleTrait::square(10)`." +msgstr "> 注意:也可以用trait名称 `RectangleTrait::square(10)` 来调用这个函数。" -#: src/ch05-02-the-match-control-flow-construct.md:195 -msgid "" -"Using enums, we can also take special actions for a few particular values, but for all other values take one default action. Currently only `0` and the `_`operator are supported." -msgstr "使用枚举,我们也可以对一些特定的值采取特殊的操作,但对所有其他的值采取一个默认的操作。目前只支持 `0` 和 `_` 操作符。" +#: src/ch04-03-method-syntax.md:252 +msgid "### Multiple `impl` Blocks" +msgstr "### 多个`impl`块" -#: src/ch05-02-the-match-control-flow-construct.md:197 +#: src/ch04-03-method-syntax.md:254 msgid "" -"Imagine we’re implementing a game where, you get a random number between 0 and 7. If you have 0, you win. For all other values you lose. Here's a match that implements that logic, " -"with the number hardcoded rather than a random value." -msgstr "" -"想象一下,我们正在实现一个游戏,你会获得一个 0 到 7 之间的随机数字。如果你有 0,你就赢了。若是任何其他的值,你就输了。这里有一个实现该逻辑的 match,数字是硬编码的,而不是随机值。" +"Each struct is allowed to have multiple `trait` and `impl` blocks. For example, Listing\n" +"5-15 is equivalent to the code shown in Listing 4-16, which has each method in\n" +"its own `trait` and `impl` blocks." +msgstr "每个结构体都可以有多个`trait` 和`impl`块。例如,示例4-15等价于示例4-16中展示的代码,其中每个方法都有自己的`trait` 和`impl`块。" -#: src/ch05-02-the-match-control-flow-construct.md:199 +#: src/ch04-03-method-syntax.md:258 msgid "" -"```rust\n" -"fn did_i_win(nb: felt252) {\n" -" match nb {\n" -" 0 => ('You won!').print(),\n" -" _ => ('You lost...').print(),\n" +"```rust,noplayground\n" +"trait RectangleCalc {\n" +" fn area(self: @Rectangle) -> u64;\n" +"}\n" +"impl RectangleCalcImpl of RectangleCalc {\n" +" fn area(self: @Rectangle) -> u64 {\n" +" (*self.width) * (*self.height)\n" +" }\n" +"}\n" +"\n" +"trait RectangleCmp {\n" +" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" +"}\n" +"\n" +"impl RectangleCmpImpl of RectangleCmp {\n" +" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +" *self.width > *other.width && *self.height > *other.height\n" " }\n" "}\n" "```" msgstr "" -"```rust\n" -"fn did_i_win(nb: felt252) {\n" -" match nb {\n" -" 0 => ('You won!').print(),\n" -" _ => ('You lost...').print(),\n" +"```rust,noplayground\n" +"trait RectangleCalc {\n" +" fn area(self: @Rectangle) -> u64;\n" +"}\n" +"impl RectangleCalcImpl of RectangleCalc {\n" +" fn area(self: @Rectangle) -> u64 {\n" +" (*self.width) * (*self.height)\n" +" }\n" +"}\n" +"\n" +"trait RectangleCmp {\n" +" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" +"}\n" +"\n" +"impl RectangleCmpImpl of RectangleCmp {\n" +" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +" *self.width > *other.width && *self.height > *other.height\n" " }\n" "}\n" "```" -#: src/ch05-02-the-match-control-flow-construct.md:208 +#: src/ch04-03-method-syntax.md:279 msgid "" -"The first arm, the pattern is the literal values 0. For the last arm that covers every other possible value, the pattern is the character `_`. This code compiles, even though we " -"haven’t listed all the possible values a `felt252` can have, because the last pattern will match all values not specifically listed. This catch-all pattern meets the requirement that " -"`match` must be exhaustive. Note that we have to put the catch-all arm last because the patterns are evaluated in order. If we put the catch-all arm earlier, the other arms would " -"never run, so Cairo will warn us if we add arms after a catch-all!" +"Listing 4-16: Rewriting Listing 4-15 using multiple `impl`\n" +"blocks" msgstr "" -"第一条分支,模式是字面值 0。对于涵盖了所有其他可能的值的最后一条分支,其模式是字符 `_`。尽管我们没有列出 `felt252` 可能具有的所有值,但这段代码仍然可以编译,因为最后一个模式将匹配所有" -"没有特别列出的值。这个通配模式满足了 `match` 必须被穷尽的要求。请注意,我们必须把通配分支放在最后,因为模式是按顺序评估的。如果我们把通配分支放在前面,其他的分支就不会运行,所以如果我" -"们在通配分支之后添加分支,Cairo 会警告我们!" +"示例4-16:使用多个`impl`重写示例4-15\n" +"块" -#: src/ch05-02-the-match-control-flow-construct.md:210 -msgid "" -msgstr "" - -#: src/ch06-00-managing-cairo-projects-with-packages-crates-and-modules.md:1 -msgid "# Managing Cairo Projects with Packages, Crates and Modules" -msgstr "# 使用包、Crate 和模块管理Cairo项目" - -#: src/ch06-00-managing-cairo-projects-with-packages-crates-and-modules.md:3 +#: src/ch04-03-method-syntax.md:282 msgid "" -"As you write large programs, organizing your code will become increasingly\n" -"important. By grouping related functionality and separating code with distinct\n" -"features, you’ll clarify where to find code that implements a particular\n" -"feature and where to go to change how a feature works." +"There’s no reason to separate these methods into multiple `trait` and `impl` blocks here,\n" +"but this is valid syntax. We’ll see a case in which multiple blocks are\n" +"useful in [Chapter 7](ch07-00-generic-types-and-traits.md), where we discuss generic types and traits." msgstr "" -"当你编写大型程序时,组织你的代码将变得越来越重要。\n" -"通过对相关的功能进行分组,并将具有不同功能的代码分开,你就可以清楚地知道在哪里可以找到实现某一特定的代码,以及到哪里去改变一个功能的工作方式。" +"这里没有理由把这些方法分成多个`trait`和`impl`块,\n" +"但这是有效的语法。我们将在[第7章](ch07-00-generic-types-and-traits.md)中看\n" +"到一个多块的情况,在那里我们讨论泛型和trait。" -#: src/ch06-00-managing-cairo-projects-with-packages-crates-and-modules.md:8 +#: src/ch04-03-method-syntax.md:288 msgid "" -"The programs we’ve written so far have been in one module in one file. As a\n" -"project grows, you should organize code by splitting it into multiple modules\n" -"and then multiple files. As a package grows, you can extract parts into\n" -"separate crates that become external dependencies. This chapter covers all\n" -"these techniques." +"Structs let you create custom types that are meaningful for your domain. By\n" +"using structs, you can keep associated pieces of data connected to each other\n" +"and name each piece to make your code clear. In `trait` and `impl` blocks, you can define\n" +"methods, which are functions associated to a type and let you specify the behavior that instances of your\n" +"type have." msgstr "" -"到目前为止,我们所写的程序都是在一个文件中的一个模块中。\n" -"伴随着项目的增长,你应该通过将代码分解为多个模块和多个文件来组织代码。\n" -"伴随着包的增长,你可以将包中的部分代码提取出来,做成独立的 crate,这些 crate 则作为外部依赖项。\n" -"本章将会涵盖所有这些概念。" +"结构体让你可以创建出在你的领域中有意义的自定义类型。\n" +"通过结构体,我们可以将相关联的数据片段联系起来并命名它们,这样可以使得代码更加清晰。\n" +"在`trait`和`impl`块中,你可以定义与你的类型相关联的方法,而方法是一种相关联的函数,让你指定结构体的实例所具有的行为。" -#: src/ch06-00-managing-cairo-projects-with-packages-crates-and-modules.md:14 +#: src/ch04-03-method-syntax.md:294 msgid "" -"We’ll also discuss encapsulating implementation details, which lets you reuse\n" -"code at a higher level: once you’ve implemented an operation, other code can\n" -"call your code without having to know how the\n" -"implementation works." -msgstr "我们也会讨论封装来实现细节,这可以使你更高级地重用代码:你实现了一个操作后,其他的代码可以通过该代码的公共接口来进行调用,而不需要知道它是如何实现的。" +"But structs aren’t the only way you can create custom types: let’s turn to\n" +"Cairo’s enum feature to add another tool to your toolbox." +msgstr "但结构体并不是创建自定义类型的唯一方法:让我们转向 Cairo 的枚举功能,为你的工具箱再添一个工具。" -#: src/ch06-00-managing-cairo-projects-with-packages-crates-and-modules.md:19 -msgid "" -"A related concept is scope: the nested context in which code is written has a\n" -"set of names that are defined as “in scope.” When reading, writing, and\n" -"compiling code, programmers and compilers need to know whether a particular\n" -"name at a particular spot refers to a variable, function, struct, enum, module,\n" -"constant, or other item and what that item means. You can create scopes and\n" -"change which names are in or out of scope. You can’t have two items with the\n" -"same name in the same scope." -msgstr "" -"这里有一个需要说明的概念 “作用域(scope)”:代码所在的嵌套上下文有一组定义为 “in scope” 的名称。当阅读、编写和编译代码时,程序员和编译器需要知道特定位置的特定名称是否引用了变量、函" -"数、结构体、枚举、模块、常量或者其他有意义的项。你可以创建作用域,以及改变哪些名称在作用域内还是作用域外。同一个作用域内不能拥有两个相同名称的项。" +#: src/ch05-00-enums-and-pattern-matching.md:1 +msgid "# Enums and Pattern Matching" +msgstr "# 枚举和模式匹配" -#: src/ch06-00-managing-cairo-projects-with-packages-crates-and-modules.md:27 -msgid "" -"Cairo has a number of features that allow you to manage your code’s\n" -"organization. These features, sometimes\n" -"collectively referred to as the _module system_, include:" -msgstr "Cairo有许多功能可以让你管理代码的组织。这些功能。这有时被称为 “模块系统(the module system)”,包括:" +#: src/ch05-01-enums.md:1 +msgid "# Enums" +msgstr "# 枚举" -#: src/ch06-00-managing-cairo-projects-with-packages-crates-and-modules.md:31 +#: src/ch05-01-enums.md:3 msgid "" -"- **Packages:** A Scarb feature that lets you build, test, and share crates\n" -"- **Crates:** A tree of modules that corresponds to a single compilation unit.\n" -" It has a root directory, and a root module defined at the file `lib.cairo` under this directory.\n" -"- **Modules** and **use:** Let you control the organization and scope of items.\n" -"- **Paths:** A way of naming an item, such as a struct, function, or module" +"Enums, short for \"enumerations,\" are a way to define a custom data type that consists of a fixed set of named values, called _variants_. Enums are useful for representing a " +"collection of related values where each value is distinct and has a specific meaning." msgstr "" -"- **Packages:** Scarb的一个功能,可以让你建立、测试和分享crates。\n" -"- **Crates:** 一个模块的树形结构,对应于一个单一的编译单元。\n" -" 它有一个根目录,并在该目录下的`lib.cairo`文件中定义了一个根模块。\n" -"- **Modules** 和 **use:** 允许你控制组织结构和作用域。\n" -"- **Paths:** 一个命名例如结构体、函数或模块等项的方式" - -#: src/ch06-00-managing-cairo-projects-with-packages-crates-and-modules.md:37 -msgid "" -"In this chapter, we’ll cover all these features, discuss how they interact, and\n" -"explain how to use them to manage scope. By the end, you should have a solid\n" -"understanding of the module system and be able to work with scopes like a pro!" -msgstr "在这一章中,我们将介绍所有这些特性,讨论它们如何相互作用,以及解释如何使用它们来管理作用域。到最后,你应该对模块系统有一个扎实的理解,并且能够像专家一样使用作用域了!" +"本章介绍 \"枚举\"(enumerations),也被称作 enums,是一种自定义数据类型的方式,它由一组固定的命名值成员组成,称为 _variants_ 。枚举对于表示相关值的集合非常有用,其中每个值都是不同的," +"并且有特定的含义。" -#: src/ch06-01-packages-and-crates.md:1 -msgid "# Packages and Crates" -msgstr "# 包和 Crate" +#: src/ch05-01-enums.md:5 +msgid "## Enum Variants and Values" +msgstr "## 枚举成员和值" -#: src/ch06-01-packages-and-crates.md:3 -msgid "## What is a crate?" -msgstr "## 什么是crate?" +#: src/ch05-01-enums.md:7 +msgid "Here's a simple example of an enum:" +msgstr "下面是一个枚举的简单例子:" -#: src/ch06-01-packages-and-crates.md:4 +#: src/ch05-01-enums.md:9 msgid "" -"A crate is the smallest amount of code that the Cairo compiler considers at a time. Even if you run `cairo-compile` rather than `scarb build` and pass a single source code file, the " -"compiler considers that file to be a crate. Crates can contain modules, and the modules may be defined in other files that get compiled with the crate, as will be discussed in the " -"subsequent sections." +"```rust,noplayground\n" +"#[derive(Drop)]\n" +"enum Direction {\n" +" North,\n" +" East,\n" +" South,\n" +" West,\n" +"}\n" +"```" msgstr "" -"Crate是Cairo在编译时最小的代码单位。即使你运行 `cairo-compile` 而不是 `scarb build` 并传递一个源代码文件,编译器还是会将那个文件认作一个 crate。Crate可以包含模块,这些模块可以在其他文" -"件中定义,并与Crate一起被编译,这将在后面的章节中讨论。" - -#: src/ch06-01-packages-and-crates.md:6 -msgid "## What is the crate root?" -msgstr "## 什么是crate root?" +"```rust,noplayground\n" +"#[derive(Drop)]\n" +"enum Direction {\n" +" North,\n" +" East,\n" +" South,\n" +" West,\n" +"}\n" +"```" -#: src/ch06-01-packages-and-crates.md:7 +#: src/ch05-01-enums.md:19 msgid "" -"The crate root is the `lib.cairo` source file that the Cairo compiler starts from and makes up the root module of your crate (we’ll explain modules in depth in the [“Defining Modules " -"to Control Scope”](./ch06-02-defining-modules-to-control-scope.md) section)." +"In this example, we've defined an enum called `Direction` with four variants: `North`, `East`, `South`, and `West`. The naming convention is to use PascalCase for enum variants. Each " +"variant represents a distinct value of the Direction type. In this particular example, variants don't have any associated value. One variant can be instantiated using this syntax:" msgstr "" -"Crate root根是`lib.cairo`源文件,Cairo编译器从该文件开始,并构成你的crate的根模块(我们将在[“定义模块来控制作用域”](./ch06-02-defining-modules-to-control-scope.md)部分深入解释模块)。" +"在本例中,我们定义了一个名为 `Direction` 的枚举,它有四个变量:`North`, `East`, `South` 和 `West`。命名惯例是使用 PascalCase 来命名枚举变量。每个变量代表 Direction 类型的一个不同值。" +"在本示例中,枚举成员没有任何关联值。使用此语法可以实例化一个变量:" -#: src/ch06-01-packages-and-crates.md:9 -msgid "## What is a package?" -msgstr "## 什么是包?" +#: src/ch05-01-enums.md:21 +msgid "" +"```rust\n" +"# #[derive(Drop)]\n" +"# enum Direction {\n" +"# North,\n" +"# East,\n" +"# South,\n" +"# West,\n" +"# }\n" +"# \n" +"# fn main() {\n" +" let direction = Direction::North;\n" +"# }\n" +"# \n" +"# \n" +"```" +msgstr "" +"```rust\n" +"# #[derive(Drop)]\n" +"# enum Direction {\n" +"# North,\n" +"# East,\n" +"# South,\n" +"# West,\n" +"# }\n" +"# \n" +"# fn main() {\n" +" let direction = Direction::North;\n" +"# }\n" +"# \n" +"# \n" +"```" -#: src/ch06-01-packages-and-crates.md:10 +#: src/ch05-01-enums.md:37 msgid "" -"A cairo package is a bundle of one or more crates with a Scarb.toml file that describes how to build those crates. This enables the splitting of code into smaller, reusable parts and " -"facilitates more structured dependency management." -msgstr "一个cairo包是一个由一个或多个crate组成的集合,其中的Scarb.toml文件描述如何构建这些板块。这使得代码被分割成更小的、可重复使用的部分,并有利于更有条理的依赖管理。" +"It's easy to write code that acts differently depending on the variant of an enum instance, in this example to run specific code according to a Direction. You can learn more about it " +"on [The Match Control Flow Construct page](ch05-02-the-match-control-flow-construct.md)." +msgstr "" +"我们可以很轻易的写出根据枚举的成员运行不同的流程的代码,在上面这个例子中,是根据方向来运行特定的代码。你可以在 [Match 控制流结构](ch05-02-the-match-control-flow-construct.md)页面上了" +"解更多信息。" -#: src/ch06-01-packages-and-crates.md:12 -msgid "## Creating a Package with Scarb" -msgstr "## 用Scarb创建一个包" +#: src/ch05-01-enums.md:39 +msgid "## Enums Combined with Custom Types" +msgstr "## 枚举与自定义类型相结合" -#: src/ch06-01-packages-and-crates.md:14 -msgid "You can create a new Cairo package using the scarb command-line tool. To create a new package, run the following command:" -msgstr "你可以使用scarb命令行工具创建一个新的Cairo包。要创建一个新的软件包,运行以下命令:" +#: src/ch05-01-enums.md:41 +msgid "Enums can also be used to store more interesting data associated with each variant. For example:" +msgstr "枚举也可以用来存储与每个成员相关的更有趣的数据。比如说:" -#: src/ch06-01-packages-and-crates.md:16 +#: src/ch05-01-enums.md:43 msgid "" -"```bash\n" -"scarb new my_package\n" +"```rust,noplayground\n" +"#[derive(Drop)]\n" +"enum Message {\n" +" Quit,\n" +" Echo: felt252,\n" +" Move: (u128, u128),\n" +"}\n" "```" msgstr "" -"```bash\n" -"scarb new my_package\n" +"```rust,noplayground\n" +"#[derive(Drop)]\n" +"enum Message {\n" +" Quit,\n" +" Echo: felt252,\n" +" Move: (u128, u128),\n" +"}\n" "```" -#: src/ch06-01-packages-and-crates.md:20 -msgid "This command will generate a new package directory named `my_package` with the following structure:" -msgstr "该命令将生成一个名为`my_package`的新软件包目录,其结构如下:" +#: src/ch05-01-enums.md:52 +msgid "In this example, the `Message` enum has three variants: `Quit`, `Echo` and `Move`, all with different types:" +msgstr "在这个例子中,`Message`枚举有三个成员:`Quit`、`Echo`和`Move`,都有不同的类型:" -#: src/ch06-01-packages-and-crates.md:22 +#: src/ch05-01-enums.md:54 msgid "" -"```\n" -"my_package/\n" -"├── Scarb.toml\n" -"└── src\n" -" └── lib.cairo\n" -"```" +"- `Quit` doesn't have any associated value.\n" +"- `Echo` is a single felt.\n" +"- `Move` is a tuple of two u128 values." msgstr "" -"```\n" -"my_package/\n" -"├── Scarb.toml\n" -"└── src\n" -" └── lib.cairo\n" -"```" +"- `Quit` 没有任何相关值。\n" +"- `Echo` 是一个单一的 felt。\n" +"- `Move`是两个 u128 值组成的的元组。" + +#: src/ch05-01-enums.md:58 +msgid "You could even use a Struct or another Enum you defined inside one of your Enum variants." +msgstr "你甚至可以在你的一个枚举成员中使用一个结构体或另一个你定义的枚举。" -#: src/ch06-01-packages-and-crates.md:29 +#: src/ch05-01-enums.md:60 +msgid "## Trait Implementations for Enums" +msgstr "## 枚举的Trait实现" + +#: src/ch05-01-enums.md:62 msgid "" -"- `src/` is the main directory where all the Cairo source files for the package will be stored.\n" -"- `lib.cairo` is the default root module of the crate, which is also the main entry point of the package. By default, it is empty.\n" -"- `Scarb.toml` is the package manifest file, which contains metadata and configuration options for the package, such as dependencies, package name, version, and authors. You can find " -"documentation about it on the [scarb reference](https://docs.swmansion.com/scarb/docs/reference/manifest)." -msgstr "" -"- `src/`是主目录,包的所有Cairo源文件将存放在这里。\n" -"- `lib.cairo`是crate的默认根模块,也是包的主要入口点。默认情况下,它是空的。\n" -"- `Scarb.toml`是包示例文件,它包含包的元数据和配置选项,如依赖关系、包名称、版本和作者。你可以在[scarb reference](https://docs.swmansion.com/scarb/docs/reference/manifest)上找到关于它" -"的文档。" +"In Cairo, you can define traits and implement them for your custom enums. This allows you to define methods and behaviors associated with the enum. Here's an example of defining a " +"trait and implementing it for the previous `Message` enum:" +msgstr "在Cairo中,你可以为你的自定义枚举定义trait并实现它们。这允许你定义与枚举相关的方法和行为。下面是一个定义trait并为之前的 `Message` 枚举实现的例子:" -#: src/ch06-01-packages-and-crates.md:33 +#: src/ch05-01-enums.md:64 msgid "" -"```toml\n" -"[package]\n" -"name = \"my_package\"\n" -"version = \"0.1.0\"\n" +"```rust,noplayground\n" +"trait Processing {\n" +" fn process(self: Message);\n" +"}\n" "\n" -"[dependencies]\n" -"# foo = { path = \"vendor/foo\" }\n" +"impl ProcessingImpl of Processing {\n" +" fn process(self: Message) {\n" +" match self {\n" +" Message::Quit => {\n" +" 'quitting'.print();\n" +" },\n" +" Message::Echo(value) => {\n" +" value.print();\n" +" },\n" +" Message::Move((x, y)) => {\n" +" 'moving'.print();\n" +" },\n" +" }\n" +" }\n" +"}\n" "```" msgstr "" -"```toml\n" -"[package]\n" -"name = \"my_package\"\n" -"version = \"0.1.0\"\n" +"```rust,noplayground\n" +"trait Processing {\n" +" fn process(self: Message);\n" +"}\n" "\n" -"[dependencies]\n" -"# foo = { path = \"vendor/foo\" }\n" +"impl ProcessingImpl of Processing {\n" +" fn process(self: Message) {\n" +" match self {\n" +" Message::Quit => {\n" +" 'quitting'.print();\n" +" },\n" +" Message::Echo(value) => {\n" +" value.print();\n" +" },\n" +" Message::Move((x, y)) => {\n" +" 'moving'.print();\n" +" },\n" +" }\n" +" }\n" +"}\n" "```" -#: src/ch06-01-packages-and-crates.md:42 -msgid "" -"As you develop your package, you may want to organize your code into multiple Cairo source files. You can do this by creating additional `.cairo` files within the `src` directory or " -"its subdirectories." -msgstr "当你开发你的包时,你可能想把你的代码组织成多个Cairo源文件。你可以通过在`src`目录或其子目录下创建额外的`.cairo`文件来做到这一点。" +#: src/ch05-01-enums.md:86 +msgid "In this example, we implemented the `Processing` trait for `Message`. Here is how it could be used to process a Quit message:" +msgstr "在这个例子中,我们为`Message`实现了`Processing` trait。下面是如何用它来处理一条退出消息:" -#: src/ch06-02-defining-modules-to-control-scope.md:1 -msgid "## Defining Modules to Control Scope" -msgstr "## 定义模块以控制作用域" +#: src/ch05-01-enums.md:88 +msgid "" +"```rust\n" +"# use debug::PrintTrait;\n" +"# #[derive(Drop)]\n" +"# enum Message {\n" +"# Quit,\n" +"# Echo: felt252,\n" +"# Move: (u128, u128),\n" +"# }\n" +"# \n" +"# trait Processing {\n" +"# fn process(self: Message);\n" +"# }\n" +"# \n" +"# impl ProcessingImpl of Processing {\n" +"# fn process(self: Message) {\n" +"# match self {\n" +"# Message::Quit => {\n" +"# 'quitting'.print();\n" +"# },\n" +"# Message::Echo(value) => {\n" +"# value.print();\n" +"# },\n" +"# Message::Move((x, y)) => {\n" +"# 'moving'.print();\n" +"# },\n" +"# }\n" +"# }\n" +"# }\n" +"# fn main() {\n" +" let msg: Message = Message::Quit;\n" +" msg.process();\n" +"# }\n" +"# \n" +"# \n" +"```" +msgstr "" +"```rust\n" +"# use debug::PrintTrait;\n" +"# #[derive(Drop)]\n" +"# enum Message {\n" +"# Quit,\n" +"# Echo: felt252,\n" +"# Move: (u128, u128),\n" +"# }\n" +"# \n" +"# trait Processing {\n" +"# fn process(self: Message);\n" +"# }\n" +"# \n" +"# impl ProcessingImpl of Processing {\n" +"# fn process(self: Message) {\n" +"# match self {\n" +"# Message::Quit => {\n" +"# 'quitting'.print();\n" +"# },\n" +"# Message::Echo(value) => {\n" +"# value.print();\n" +"# },\n" +"# Message::Move((x, y)) => {\n" +"# 'moving'.print();\n" +"# },\n" +"# }\n" +"# }\n" +"# }\n" +"# fn main() {\n" +" let msg: Message = Message::Quit;\n" +" msg.process();\n" +"# }\n" +"# \n" +"# \n" +"```" -#: src/ch06-02-defining-modules-to-control-scope.md:3 +#: src/ch05-01-enums.md:124 +msgid "Running this code would print `quitting`." +msgstr "运行这段代码会打印出 `quitting`。" + +#: src/ch05-01-enums.md:126 +msgid "## The Option Enum and Its Advantages" +msgstr "## Option枚举及其优势" + +#: src/ch05-01-enums.md:128 msgid "" -"In this section, we’ll talk about modules and other parts of the module system,\n" -"namely _paths_ that allow you to name items and the `use` keyword that brings a\n" -"path into scope." -msgstr "在本节,我们将讨论模块和其它一些关于模块系统的部分,如允许你命名项的 路径(_paths_);用来将路径引入作用域的`use`关键字。" +"The Option enum is a standard Cairo enum that represents the concept of an optional value. It has two variants: `Some: T` and `None: ()`. `Some: T ` indicates that there's a value of " +"type `T`, while `None` represents the absence of a value." +msgstr "Option枚举是一个标准的Cairo枚举,表示一个可选值的概念。它有两个变量:`Some: T` 和 `None: ()`。`Some:T`表示有一个`T`类型的值,而`None`表示没有值。" -#: src/ch06-02-defining-modules-to-control-scope.md:7 +#: src/ch05-01-enums.md:130 src/ch05-02-the-match-control-flow-construct.md:146 msgid "" -"First, we’re going to start with a list of rules for easy reference when you’re\n" -"organizing your code in the future. Then we’ll explain each of the rules in\n" -"detail." -msgstr "首先,我们将从一系列的规则开始,在你未来组织代码的时候,这些规则可被用作简单的参考。接下来我们将会详细的解释每条规则。" +"```rust,noplayground\n" +"enum Option {\n" +" Some: T,\n" +" None: (),\n" +"}\n" +"```" +msgstr "" +"```rust,noplayground\n" +"enum Option {\n" +" Some: T,\n" +" None: (),\n" +"}\n" +"```" -#: src/ch06-02-defining-modules-to-control-scope.md:11 -msgid "### Modules Cheat Sheet" -msgstr "### 模块小抄" +#: src/ch05-01-enums.md:137 +msgid "" +"The `Option` enum is helpful because it allows you to explicitly represent the possibility of a value being absent, making your code more expressive and easier to reason about. Using " +"`Option` can also help prevent bugs caused by using uninitialized or unexpected `null` values." +msgstr "`Option` 枚举很有用,因为它允许你明确地表示一个值不存在的可能性,使你的代码更具表现力,更容易推理。使用 `Option` 也可以帮助防止因使用未初始化的或意外的 `null` 值而引起的错误。" -#: src/ch06-02-defining-modules-to-control-scope.md:13 +#: src/ch05-01-enums.md:139 +msgid "To give you an example, here is a function which returns the index of the first element of an array with a given value, or None if the element is not present." +msgstr "为了给你一个例子,这里有一个函数,它返回一个给定值的数组中第一个元素的索引,如果该元素不存在则返回None。" + +#: src/ch05-01-enums.md:141 +msgid "We are demonstrating two approaches for the above function:" +msgstr "我们为上述函数演示了两种方法:" + +#: src/ch05-01-enums.md:143 msgid "" -"Here we provide a quick reference on how modules, paths and the `use` keyword\n" -"work in the compiler, and how most developers organize their\n" -"code. We’ll be going through examples of each of these rules throughout this\n" -"chapter, but this is a great place to refer to as a reminder of how modules\n" -"work. You can create a new Scarb project with `scarb new backyard` to follow along." +"- Recursive Approach `find_value_recursive`\n" +"- Iterative Approach `find_value_iterative`" msgstr "" -"这里我们提供一个简单的参考,用来解释模块、路径、 `use`关键词如何在编译器中工作,以及大部分开发者如何组织他们的代码。我们将在本章节中举例说明每条规则,不过这是一个解释模块工作方式的良" -"好参考。你可以用`scarb new backyard`创建一个新的Scarb项目来跟随。" +"- 递归法 `find_value_recursive`\n" +"- 迭代法 `find_value_iterative`" -#: src/ch06-02-defining-modules-to-control-scope.md:19 +#: src/ch05-01-enums.md:146 +msgid "> Note: in the future it would be nice to replace this example by something simpler using a loop and without gas related code." +msgstr "> 注意:将来最好能用循环和无需 gas 的相关代码的简单示例替换此示例。" + +#: src/ch05-01-enums.md:148 msgid "" -"- **Start from the crate root**: When compiling a crate, the compiler first\n" -" looks in the crate root file (_src/lib.cairo_) for code to compile.\n" -"- **Declaring modules**: In the crate root file, you can declare new modules;\n" -" say, you declare a “garden” module with `mod garden;`. The compiler will look\n" -" for the module’s code in these places:\n" +"```rust,noplayground\n" +"use debug::PrintTrait;\n" "\n" -" - Inline, within curly brackets that replace the semicolon following `mod garden;`.\n" +"fn find_value_recursive(arr: @Array, value: felt252, index: usize) -> Option {\n" +" if index >= arr.len() {\n" +" return Option::None;\n" +" }\n" "\n" -" ```rust\n" -" // crate root file (lib.cairo)\n" -" mod garden {\n" -" // code defining the garden module goes here\n" +" if *arr.at(index) == value {\n" +" return Option::Some(index);\n" +" }\n" +"\n" +" find_value_recursive(arr, value, index + 1)\n" +"}\n" +"\n" +"fn find_value_iterative(arr: @Array, value: felt252) -> Option {\n" +" let length = arr.len();\n" +" let mut index = 0;\n" +" let mut found: Option = Option::None;\n" +" loop {\n" +" if index < length {\n" +" if *arr.at(index) == value {\n" +" found = Option::Some(index);\n" +" break;\n" +" }\n" +" } else {\n" +" break;\n" " }\n" -" ```\n" +" index += 1;\n" +" };\n" +" return found;\n" +"}\n" "\n" -"- In the file _src/garden.cairo_\n" -"- **Declaring submodules**: In any file other than the crate root, you can\n" -" declare submodules. For example, you might declare `mod vegetables;` in\n" -" _src/garden.cairo_. The compiler will look for the submodule’s code within the\n" -" directory named for the parent module in these places:\n" +"#[test]\n" +"#[available_gas(999999)]\n" +"fn test_increase_amount() {\n" +" let mut my_array = ArrayTrait::new();\n" +" my_array.append(3);\n" +" my_array.append(7);\n" +" my_array.append(2);\n" +" my_array.append(5);\n" "\n" -" - Inline, directly following `mod vegetables`, within curly brackets instead\n" -" of the semicolon.\n" +" let value_to_find = 7;\n" +" let result = find_value_recursive(@my_array, value_to_find, 0);\n" +" let result_i = find_value_iterative(@my_array, value_to_find);\n" "\n" -" ```rust\n" -" // src/garden.cairo file\n" -" mod vegetables {\n" -" // code defining the vegetables submodule goes here\n" +" match result {\n" +" Option::Some(index) => {\n" +" if index == 1 {\n" +" 'it worked'.print();\n" +" }\n" +" },\n" +" Option::None => {\n" +" 'not found'.print();\n" +" },\n" " }\n" -" ```\n" -"\n" -" - In the file _src/garden/vegetables.cairo_\n" +" match result_i {\n" +" Option::Some(index) => {\n" +" if index == 1 {\n" +" 'it worked'.print();\n" +" }\n" +" },\n" +" Option::None => {\n" +" 'not found'.print();\n" +" },\n" +" }\n" +"}\n" "\n" -"- **Paths to code in modules**: Once a module is part of your crate, you can\n" -" refer to code in that module from anywhere else in that same crate, using the path\n" -" to the code. For example, an `Asparagus` type in the garden vegetables module would be found at\n" -" `backyard::garden::vegetables::Asparagus`.\n" -"- **The `use` keyword**: Within a scope, the `use` keyword creates shortcuts to\n" -" items to reduce repetition of long paths. In any scope that can refer to\n" -" `backyard::garden::vegetables::Asparagus`, you can create a shortcut with\n" -" `use backyard::garden::vegetables::Asparagus;` and from then on you only need to\n" -" write `Asparagus` to make use of that type in the scope." +"```" msgstr "" -"- **从 crate 根节点开始**:当编译一个 crate, 编译器首先在 crate 根文件(_src/lib.cairo_)中寻找要编译的代码。\n" -"- **声明模块:**:在 crate 根文件中,你可以声明新的模块;\n" -" 例如,你用`mod garden;`声明一个 “garden”模块。编译器会在下列路径中寻找模块代码:\n" +"```rust,noplayground\n" +"use debug::PrintTrait;\n" "\n" -" - 内联,在大括号中,当`mod garden`后方不是一个分号而是一个大括号\n" +"fn find_value_recursive(arr: @Array, value: felt252, index: usize) -> Option {\n" +" if index >= arr.len() {\n" +" return Option::None;\n" +" }\n" "\n" -" ```rust\n" -" // crate root file (lib.cairo)\n" -" mod garden {\n" -" // code defining the garden module goes here\n" +" if *arr.at(index) == value {\n" +" return Option::Some(index);\n" +" }\n" +"\n" +" find_value_recursive(arr, value, index + 1)\n" +"}\n" +"\n" +"fn find_value_iterative(arr: @Array, value: felt252) -> Option {\n" +" let length = arr.len();\n" +" let mut index = 0;\n" +" let mut found: Option = Option::None;\n" +" loop {\n" +" if index < length {\n" +" if *arr.at(index) == value {\n" +" found = Option::Some(index);\n" +" break;\n" +" }\n" +" } else {\n" +" break;\n" " }\n" -" ```\n" +" index += 1;\n" +" };\n" +" return found;\n" +"}\n" "\n" -"- 在文件 _src/garden.cairo_ 中\n" -"- **声明子模块**:在除了 crate 根节点以外的其他文件中,你可以定义子模块。例如,你可以在以下文件中声明 `mod vegetables;`。\n" -" _src/garden.cairo_ 。编译器会在以父模块命名的目录中寻找子模块代码: \n" +"#[test]\n" +"#[available_gas(999999)]\n" +"fn test_increase_amount() {\n" +" let mut my_array = ArrayTrait::new();\n" +" my_array.append(3);\n" +" my_array.append(7);\n" +" my_array.append(2);\n" +" my_array.append(5);\n" "\n" -" - 内联,直接跟在`mod vegetables`后面,用大括号代替分号\n" +" let value_to_find = 7;\n" +" let result = find_value_recursive(@my_array, value_to_find, 0);\n" +" let result_i = find_value_iterative(@my_array, value_to_find);\n" "\n" -" ```rust\n" -" // src/garden.cairo file\n" -" mod vegetables {\n" -" // code defining the vegetables submodule goes here\n" +" match result {\n" +" Option::Some(index) => {\n" +" if index == 1 {\n" +" 'it worked'.print();\n" +" }\n" +" },\n" +" Option::None => {\n" +" 'not found'.print();\n" +" },\n" " }\n" -" ```\n" -"\n" -" - 在文件 _src/garden/vegetables.cairo_ 中\n" +" match result_i {\n" +" Option::Some(index) => {\n" +" if index == 1 {\n" +" 'it worked'.print();\n" +" }\n" +" },\n" +" Option::None => {\n" +" 'not found'.print();\n" +" },\n" +" }\n" +"}\n" "\n" -"- **模块中的代码路径**:一旦一个模块是你 crate 的一部分,你可以在隐私规则允许的前提下,从同一个 crate 内的任意地方,通过代码路径引用该模块的代码。举例而言,一个 garden vegetables 模块" -"下的`Asparagus`类型可以在`backyard::garden::vegetables::Asparagus`被找到。\n" -"- **`use`关键字**:在一个作用域内,`use`关键字创建了一个成员的快捷方式,用来减少长路径的重复。在任何可以引用`backyard::garden::vegetables::Asparagus`的作用域,你可以通过 `use " -"backyard::garden::vegetables::Asparagus;`创建一个快捷方式,然后你就可以在作用域中只写`Asparagus`来使用该类型。" +"```" -#: src/ch06-02-defining-modules-to-control-scope.md:62 -msgid "" -"Here we create a crate named `backyard` that illustrates these rules. The\n" -"crate’s directory, also named `backyard`, contains these files and directories:" -msgstr "这里我们创建一个名为`backyard`的crate 来说明这些规则。该 crate 的路径同样命名为`backyard`,该路径包含了这些文件和目录:" +#: src/ch05-01-enums.md:218 +msgid "Running this code would print `it worked`." +msgstr "运行这段代码会打印出 `it worked`。" -#: src/ch06-02-defining-modules-to-control-scope.md:65 +#: src/ch05-02-the-match-control-flow-construct.md:1 +msgid "# The Match Control Flow Construct" +msgstr "# match控制流结构" + +#: src/ch05-02-the-match-control-flow-construct.md:3 +msgid "" +msgstr "" + +#: src/ch05-02-the-match-control-flow-construct.md:5 msgid "" -"```text\n" -"backyard/\n" -"├── Scarb.toml\n" -"├── cairo_project.toml\n" -"└── src\n" -" ├── garden\n" -" │   └── vegetables.cairo\n" -" ├── garden.cairo\n" -" └── lib.cairo\n" -"```" +"Cairo has an extremely powerful control flow construct called `match` that allows you to compare a value against a series of patterns and then execute code based on which pattern " +"matches. Patterns can be made up of literal values, variable names, wildcards, and many other things. The power of match comes from the expressiveness of the patterns and the fact " +"that the compiler confirms that all possible cases are handled." msgstr "" -"```text\n" -"backyard/\n" -"├── Scarb.toml\n" -"├── cairo_project.toml\n" -"└── src\n" -" ├── garden\n" -" │   └── vegetables.cairo\n" -" ├── garden.cairo\n" -" └── lib.cairo\n" -"```" +"Cairo 有一个叫做 `match` 的极为强大的控制流运算符,它允许我们将一个值与一系列的模式相比较,并根据相匹配的模式执行相应代码。模式可由字面值、变量、通配符和许多其他内容构成;第十八章会涉" +"及到所有不同种类的模式以及它们的作用。`match` 的力量来源于模式的表现力以及编译器检查,它确保了所有可能的情况都得到处理。" -#: src/ch06-02-defining-modules-to-control-scope.md:76 +#: src/ch05-02-the-match-control-flow-construct.md:7 msgid "" -"> Note: You will notice here a `cairo_project.toml` file.\n" -"> This is the configuration file for \"vanilla\" Cairo projects (i.e. not managed by Scarb),\n" -"> which is required to run the `cairo-run .` command to run the code of the crate.\n" -"> It is required until Scarb implements this feature. The content of the file is:\n" -">\n" -"> ```toml\n" -"> [crate_roots]\n" -"> backyard = \"src\"\n" -"> ```\n" -">\n" -"> and indicates that the crate named \"backyard\" is located in the `src` directory." +"Think of a match expression as being like a coin-sorting machine: coins slide down a track with variously sized holes along it, and each coin falls through the first hole it " +"encounters that it fits into. In the same way, values go through each pattern in a match, and at the first pattern the value “fits”, the value falls into the associated code block to " +"be used during execution." msgstr "" -"> 注意:你会注意到这里有一个`cairo_project.toml`文件。\n" -"> 这是 通常的Cairo项目的配置文件(即不由Scarb管理)、\n" -"> 这是运行`cairo-run .`命令来运行crate的代码所需要的。\n" -"> 在Scarb实现这一功能之前,它是必需的。该文件的内容是:\n" -">\n" -"> ```toml\n" -"> [crate_roots]\n" -"> backyard = “src”\n" -"> ```\n" -">\n" -"> 它表示名为 \"backyard \"的板块位于`src`目录下。" +"可以把 `match` 表达式想象成某种硬币分类器:硬币滑入有着不同大小孔洞的轨道,每一个硬币都会掉入符合它大小的孔洞。同样地,值也会通过 `match` 的每一个模式,并且在遇到第一个 “符合” 的模式" +"时,值会进入相关联的代码块并在执行中被使用。" -#: src/ch06-02-defining-modules-to-control-scope.md:88 -msgid "The crate root file in this case is _src/lib.cairo_, and it contains:" -msgstr "在这种情况下,crate根文件是 _src/lib.cairo_ ,它包含:" +#: src/ch05-02-the-match-control-flow-construct.md:9 +msgid "" +"Speaking of coins, let’s use them as an example using match! We can write a function that takes an unknown US coin and, in a similar way as the counting machine, determines which " +"coin it is and returns its value in cents, as shown in Listing 5-3." +msgstr "" +"因为刚刚提到了硬币,让我们用它们来作为一个使用 `match` 的例子!我们可以编写一个函数来获取一个未知的硬币,并以一种类似验钞机的方式,确定它是何种硬币,并返回其价值(美分),如示例5-3所" +"示。" -#: src/ch06-02-defining-modules-to-control-scope.md:92 +#: src/ch05-02-the-match-control-flow-construct.md:11 msgid "" -"```rust,does_not_compile\n" -"use garden::vegetables::Asparagus;\n" -"\n" -"mod garden;\n" -"\n" -"fn main() {\n" -" let Asparagus = Asparagus {};\n" +"```rust,noplayground\n" +"enum Coin {\n" +" Penny: (),\n" +" Nickel: (),\n" +" Dime: (),\n" +" Quarter: (),\n" "}\n" "\n" +"fn value_in_cents(coin: Coin) -> felt252 {\n" +" match coin {\n" +" Coin::Penny(_) => 1,\n" +" Coin::Nickel(_) => 5,\n" +" Coin::Dime(_) => 10,\n" +" Coin::Quarter(_) => 25,\n" +" }\n" +"}\n" "```" msgstr "" -"```rust,does_not_compile\n" -"use garden::vegetables::Asparagus;\n" -"\n" -"mod garden;\n" -"\n" -"fn main() {\n" -" let Asparagus = Asparagus {};\n" +"```rust,noplayground\n" +"enum Coin {\n" +" Penny: (),\n" +" Nickel: (),\n" +" Dime: (),\n" +" Quarter: (),\n" "}\n" "\n" +"fn value_in_cents(coin: Coin) -> felt252 {\n" +" match coin {\n" +" Coin::Penny(_) => 1,\n" +" Coin::Nickel(_) => 5,\n" +" Coin::Dime(_) => 10,\n" +" Coin::Quarter(_) => 25,\n" +" }\n" +"}\n" "```" -#: src/ch06-02-defining-modules-to-control-scope.md:103 -msgid "The `mod garden;` line tells the compiler to include the code it finds in _src/garden.cairo_, which is:" -msgstr "`mod garden;`行告诉编译器包括它在 _src/garden.cairo_ 中发现的代码是:" - -#: src/ch06-02-defining-modules-to-control-scope.md:105 -msgid "Filename: src/garden.cairo" -msgstr "文件名: src/garden.cairo" +#: src/ch05-02-the-match-control-flow-construct.md:29 +msgid "Listing 5-3: An enum and a match expression that has the variants of the enum as its patterns" +msgstr "示例5-3:一个枚举和一个将枚举成员作为其模式的 match 表达式" -#: src/ch06-02-defining-modules-to-control-scope.md:107 +#: src/ch05-02-the-match-control-flow-construct.md:31 msgid "" -"```rust\n" -"mod vegetables;\n" -"```" +"Let’s break down the `match` in the `value_in_cents` function. First we list the `match` keyword followed by an expression, which in this case is the value `coin`. This seems very " +"similar to a conditional expression used with if, but there’s a big difference: with if, the condition needs to evaluate to a Boolean value, but here it can be any type. The type of " +"coin in this example is the `Coin` enum that we defined on the first line." msgstr "" -"```rust\n" -"mod vegetables;\n" -"```" - -#: src/ch06-02-defining-modules-to-control-scope.md:111 -msgid "" -"Here, `mod vegetables;` means the code in _src/garden/vegetables.cairo_ is\n" -"included too. That code is:" -msgstr "这里,`mod vegetables;`意味着 _src/garden/vegetables.cairo_ 中的代码也被包括在内。这段代码是:" +"拆开 `value_in_cents` 函数中的 `match` 来看。首先,我们列出 `match` 关键字后跟一个表达式,在这个例子中是 coin 的值。这看起来非常像 `if` 所使用的条件表达式,不过这里有一个非常大的区" +"别:对于 `if`,表达式必须返回一个布尔值,而这里它可以是任何类型的。本例中硬币的类型是我们在第一行定义的 `Coin` 枚举。" -#: src/ch06-02-defining-modules-to-control-scope.md:114 +#: src/ch05-02-the-match-control-flow-construct.md:33 msgid "" -"```rust\n" -"#[derive(Copy,Drop)]\n" -"struct Asparagus{}\n" -"```" +"Next are the `match` arms. An arm has two parts: a pattern and some code. The first arm here has a pattern that is the value `Coin::Penny(_)` and then the `=>` operator that " +"separates the pattern and the code to run. The code in this case is just the value `1`. Each arm is separated from the next with a comma." msgstr "" -"```rust\n" -"#[derive(Copy,Drop)]\n" -"struct Asparagus{}\n" -"```" - -#: src/ch06-02-defining-modules-to-control-scope.md:119 -msgid "" -"The line `use garden::vegetables::Asparagus;` lets us use bring the `Asparagus` type into scope,\n" -"so we can use it in the `main` function." -msgstr "这行`use garden::vecants::Asparagus;`让我们把`Asparagus`类型带入作用域、所以我们可以在`main`函数中使用它。" - -#: src/ch06-02-defining-modules-to-control-scope.md:122 -msgid "Now let’s get into the details of these rules and demonstrate them in action!" -msgstr "现在让我们深入了解这些规则的细节并在实际中演示它们!" - -#: src/ch06-02-defining-modules-to-control-scope.md:124 -msgid "### Grouping Related Code in Modules" -msgstr "### 在模块中对相关代码进行分组" +"接下来是 `match` 分支。一个分支有两个部分:一个模式和一些代码。这里的第一个分支有一个模式,就是值 `Coin::Penny(_)`,然后是`=>`操作符,把模式和要运行的代码分开。本例中的代码只是值 " +"`1`。每个分支都用逗号与下一个分支隔开。" -#: src/ch06-02-defining-modules-to-control-scope.md:126 +#: src/ch05-02-the-match-control-flow-construct.md:35 msgid "" -"_Modules_ let us organize code within a crate for readability and easy reuse.\n" -"As an example, let’s write a library crate that provides the functionality of a\n" -"restaurant. We’ll define the signatures of functions but leave their bodies\n" -"empty to concentrate on the organization of the code, rather than the\n" -"implementation of a restaurant." +"When the `match` expression executes, it compares the resultant value against the pattern of each arm, in order. If a pattern matches the value, the code associated with that pattern " +"is executed. If that pattern doesn’t match the value, execution continues to the next arm, much as in a coin-sorting machine. We can have as many arms as we need: in the above " +"example, our match has four arms." msgstr "" -"_模块_ 让我们可以将一个 crate 中的代码进行分组,以提高可读性与重用性。\n" -"作为一个例子,让我们写一个crate,提供一个餐馆的机能。我们将定义函数的签名,但将其主体留空,以专注于代码的组织,而不是餐馆的实现。" +"当 `match` 表达式执行时,它将结果值与每个分支的模式进行比较,依次进行。如果一个模式与值匹配,则执行与该模式相关的代码。如果该模式不匹配该值,则继续执行下一个分支,就像验钞机一样。我们" +"可以根据自己的需要有多少个分支:在上面的例子中,我们的匹配有四个分支。" + +#: src/ch05-02-the-match-control-flow-construct.md:37 +msgid "In Cairo, the order of the arms must follow the same order as the enum." +msgstr "在 Cairo,分支的顺序必须遵循与枚举相同的顺序。" -#: src/ch06-02-defining-modules-to-control-scope.md:132 +#: src/ch05-02-the-match-control-flow-construct.md:39 msgid "" -"In the restaurant industry, some parts of a restaurant are referred to as\n" -"_front of house_ and others as _back of house_. Front of house is where\n" -"customers are; this encompasses where the hosts seat customers, servers take\n" -"orders and payment, and bartenders make drinks. Back of house is where the\n" -"chefs and cooks work in the kitchen, dishwashers clean up, and managers do\n" -"administrative work." -msgstr "" -"在餐饮业,餐馆中会有一些地方被称之为 前台(_front of house_),还有另外一些地方被称之为 后台(_back of house_)。\n" -"前台是招待顾客的地方,在这里,店主可以为顾客安排座位,服务员接受顾客下单和付款,调酒师会制作饮品。\n" -"后台则是由厨师工作的厨房,洗碗工的工作地点,以及经理做行政工作的地方组成。" +"The code associated with each arm is an expression, and the resultant value of the expression in the matching arm is the value that gets returned for the entire match expression." +msgstr "与每个 match 相关的代码是一个表达式,而 match 分支中表达式的结果值是整个 match 表达式被返回的值。" -#: src/ch06-02-defining-modules-to-control-scope.md:139 +#: src/ch05-02-the-match-control-flow-construct.md:41 msgid "" -"To structure our crate in this way, we can organize its functions into nested\n" -"modules. Create a new package named `restaurant` by running `scarb new restaurant`; then enter the code in Listing 6-1 into _src/lib.cairo_ to\n" -"define some modules and function signatures. Here’s the front of house section:" +"We don’t typically use curly brackets if the match arm code is short, as it is in our example where each arm just returns a value. If you want to run multiple lines of code in a " +"match arm, you must use curly brackets, with a comma following the arm. For example, the following code prints “Lucky penny!” every time the method is called with a `Coin::" +"Penny(())`, but still returns the last value of the block, `1`:" msgstr "" -"我们可以将函数放置到嵌套的模块中,来使我们的 crate 结构与实际的餐厅结构相同。\n" -"通过运行 `scarb new restaurant`创建一个名为 `restaurant`的新包;然后将示例6-1中的代码输入 _src/lib.cairo_ ,以定义一些模块和函数签名。这里是前台的部分:" +"如果 match 分支的代码很短,我们通常不使用大括号,就像在我们的示例中一样,每个分支只是返回一个值。如果你想在一个 match 分支中运行多行代码,你必须使用大括号,在 match 分支后面加一个逗" +"号。例如,下面的代码在每次调用 `Coin::Penny(())` 方法时都会打印出 “Lucky penny!”,但仍然返回区块的最后一个值 `1`:" -#: src/ch06-02-defining-modules-to-control-scope.md:145 +#: src/ch05-02-the-match-control-flow-construct.md:43 msgid "" -"```rust\n" -"mod front_of_house {\n" -" mod hosting {\n" -" fn add_to_waitlist() {}\n" -"\n" -" fn seat_at_table() {}\n" -" }\n" -"\n" -" mod serving {\n" -" fn take_order() {}\n" -"\n" -" fn serve_order() {}\n" -"\n" -" fn take_payment() {}\n" +"```rust,noplayground\n" +"fn value_in_cents(coin: Coin) -> felt252 {\n" +" match coin {\n" +" Coin::Penny(_) => {\n" +" ('Lucky penny!').print();\n" +" 1\n" +" },\n" +" Coin::Nickel(_) => 5,\n" +" Coin::Dime(_) => 10,\n" +" Coin::Quarter(_) => 25,\n" " }\n" "}\n" "```" msgstr "" -"```rust\n" -"mod front_of_house {\n" -" mod hosting {\n" -" fn add_to_waitlist() {}\n" -"\n" -" fn seat_at_table() {}\n" -" }\n" -"\n" -" mod serving {\n" -" fn take_order() {}\n" -"\n" -" fn serve_order() {}\n" -"\n" -" fn take_payment() {}\n" +"```rust,noplayground\n" +"fn value_in_cents(coin: Coin) -> felt252 {\n" +" match coin {\n" +" Coin::Penny(_) => {\n" +" ('Lucky penny!').print();\n" +" 1\n" +" },\n" +" Coin::Nickel(_) => 5,\n" +" Coin::Dime(_) => 10,\n" +" Coin::Quarter(_) => 25,\n" " }\n" "}\n" "```" -#: src/ch06-02-defining-modules-to-control-scope.md:163 -msgid "" -"Listing 6-1: A `front_of_house` module containing other\n" -"modules that then contain functions" -msgstr "示例6-1:一个 `front_of_house`模块包含其他的模块,而这些模块又包含了函数" +#: src/ch05-02-the-match-control-flow-construct.md:57 +msgid "## Patterns That Bind to Values" +msgstr "## 绑定值的模式" -#: src/ch06-02-defining-modules-to-control-scope.md:166 +#: src/ch05-02-the-match-control-flow-construct.md:59 +msgid "Another useful feature of match arms is that they can bind to the parts of the values that match the pattern. This is how we can extract values out of enum variants." +msgstr "另一个match分支的有用的特点是它们可以绑定到值中与模式相匹配的部分。这就是如何从枚举成员中提取数值的方法。" + +#: src/ch05-02-the-match-control-flow-construct.md:61 msgid "" -"We define a module with the `mod` keyword followed by the name of the module\n" -"(in this case, `front_of_house`). The body of the module then goes inside curly\n" -"brackets. Inside modules, we can place other modules, as in this case with the\n" -"modules `hosting` and `serving`. Modules can also hold definitions for other\n" -"items, such as structs, enums, constants, traits, and—as in Listing\n" -"6-1—functions." +"As an example, let’s change one of our enum variants to hold data inside it. From 1999 through 2008, the United States minted quarters with different designs for each of the 50 " +"states on one side. No other coins got state designs, so only quarters have this extra value. We can add this information to our `enum` by changing the `Quarter` variant to include a " +"`UsState` value stored inside it, which we’ve done in Listing 5-4." msgstr "" -"我们定义一个模块,是以 `mod`关键字为起始,然后指定模块的名字(本例中叫做 `front_of_house`),并且用花括号包围模块的主体。在模块内,我们还可以定义其他的模块,就像本例中的 `hosting` 和 " -"`serving` 模块。模块还可以保存一些定义的其他项,比如结构体、枚举、常量、特性、以及列表中6-1中展示的函数。" +"作为一个例子,让我们修改枚举的一个成员来存放数据。1999 年到 2008 年间,美国在 25 美分的硬币的一侧为 50 个州的每一个都印刷了不同的设计。其他的硬币都没有这种区分州的设计,所以只有这些 " +"25 美分硬币有特殊的价值。我们可以通过改变 `Quarter` 变量,使其包含一个`UsState` 的值,从而将这个信息添加到我们的 `enum` 中,我们在示例5-4中已经这样做了。" -#: src/ch06-02-defining-modules-to-control-scope.md:173 +#: src/ch05-02-the-match-control-flow-construct.md:63 msgid "" -"By using modules, we can group related definitions together and name why\n" -"they’re related. Programmers using this code can navigate the code based on the\n" -"groups rather than having to read through all the definitions, making it easier\n" -"to find the definitions relevant to them. Programmers adding new functionality\n" -"to this code would know where to place the code to keep the program organized." +"```rust,noplayground\n" +"#[derive(Drop)]\n" +"enum UsState {\n" +" Alabama: (),\n" +" Alaska: (),\n" +"}\n" +"\n" +"#[derive(Drop)]\n" +"enum Coin {\n" +" Penny: (),\n" +" Nickel: (),\n" +" Dime: (),\n" +" Quarter: (UsState,),\n" +"}\n" +"```" msgstr "" -"通过使用模块,我们可以将相关的定义分组到一起,并指出他们为什么相关。程序员可以通过使用这段代码,更加容易地找到他们想要的定义,因为他们可以基于分组来对代码进行导航,而不需要阅读所有的" -"定义。\n" -"程序员向这段代码中添加一个新的功能时,他们也会知道代码应该放置在何处,可以保持程序的组织性。" +"```rust,noplayground\n" +"#[derive(Drop)]\n" +"enum UsState {\n" +" Alabama: (),\n" +" Alaska: (),\n" +"}\n" +"\n" +"#[derive(Drop)]\n" +"enum Coin {\n" +" Penny: (),\n" +" Nickel: (),\n" +" Dime: (),\n" +" Quarter: (UsState,),\n" +"}\n" +"```" + +#: src/ch05-02-the-match-control-flow-construct.md:79 +msgid "Listing 5-4: A `Coin` enum in which the `Quarter` variant also holds a `UsState` value" +msgstr "列表5-4: 一个 `Coin` 枚举,其中 `Quarter` 变量也持有一个 `UsState` 值" -#: src/ch06-02-defining-modules-to-control-scope.md:179 +#: src/ch05-02-the-match-control-flow-construct.md:81 msgid "" -"Earlier, we mentioned that _src/lib.cairo_ is called the crate\n" -"root. The reason for this name is that the content of this file form a module named after the crate name at the root of the crate’s module structure,\n" -"known as the _module tree_." -msgstr "在前面我们提到了,_src/lib.cairo_ 叫做 crate 根。之所以这样叫它是因为这个文件的内容在 crate 模块结构的根组成了一个名为 crate 的模块,该结构被称为 模块树( _module tree_ )。" +"Let’s imagine that a friend is trying to collect all 50 state quarters. While we sort our loose change by coin type, we’ll also call out the name of the state associated with each " +"quarter so that if it’s one our friend doesn’t have, they can add it to their collection." +msgstr "" +"想象一下我们的一个朋友尝试收集所有 50 个州的 25 美分硬币。在根据硬币类型分类零钱的同时,也可以报告出每个 25 美分硬币所对应的州名称,这样如果我们的朋友没有的话,他可以将其加入收藏。" -#: src/ch06-02-defining-modules-to-control-scope.md:183 -msgid "Listing 6-2 shows the module tree for the structure in Listing 6-1." -msgstr "示例6-2显示了示例6-1中结构的模块树。" +#: src/ch05-02-the-match-control-flow-construct.md:83 +msgid "" +"In the match expression for this code, we add a variable called `state` to the pattern that matches values of the variant `Coin::Quarter`. When a `Coin::Quarter` matches, the `state` " +"variable will bind to the value of that quarter’s state. Then we can use `state` in the code for that arm, like so:" +msgstr "" +"在这段代码的match表达式中,我们在模式中添加了一个叫做 `state` 的变量,用来匹配变量 `Coin::Quarter` 的值。当 `Coin::Quarter` 匹配时,`state` 变量将与该季度的状态值绑定。然后我们可以在" +"该分支的代码中使用 `state`,像这样:" -#: src/ch06-02-defining-modules-to-control-scope.md:185 +#: src/ch05-02-the-match-control-flow-construct.md:85 msgid "" -"```text\n" -"restaurant\n" -" └── front_of_house\n" -" ├── hosting\n" -" │ ├── add_to_waitlist\n" -" │ └── seat_at_table\n" -" └── serving\n" -" ├── take_order\n" -" ├── serve_order\n" -" └── take_payment\n" +"```rust,noplayground\n" +"fn value_in_cents(coin: Coin) -> felt252 {\n" +" match coin {\n" +" Coin::Penny(_) => 1,\n" +" Coin::Nickel(_) => 5,\n" +" Coin::Dime(_) => 10,\n" +" Coin::Quarter(state) => {\n" +" state.print();\n" +" 25\n" +" },\n" +" }\n" +"}\n" "```" msgstr "" -"```text\n" -"restaurant\n" -" └── front_of_house\n" -" ├── hosting\n" -" │ ├── add_to_waitlist\n" -" │ └── seat_at_table\n" -" └── serving\n" -" ├── take_order\n" -" ├── serve_order\n" -" └── take_payment\n" +"```rust,noplayground\n" +"fn value_in_cents(coin: Coin) -> felt252 {\n" +" match coin {\n" +" Coin::Penny(_) => 1,\n" +" Coin::Nickel(_) => 5,\n" +" Coin::Dime(_) => 10,\n" +" Coin::Quarter(state) => {\n" +" state.print();\n" +" 25\n" +" },\n" +" }\n" +"}\n" "```" -#: src/ch06-02-defining-modules-to-control-scope.md:197 -msgid "" -"Listing 6-2: The module tree for the code in Listing\n" -"6-1" -msgstr "示例6-2:示例6-1中代码的模块树" +#: src/ch05-02-the-match-control-flow-construct.md:99 +msgid "To print the value of a variant of an enum in Cairo, we need to add an implementation for the `print` function for the `debug::PrintTrait`:" +msgstr "为了在 Cairo 打印一个枚举的变量的值,我们需要为`debug::PrintTrait` 添加一个 `print` 函数的实现:" -#: src/ch06-02-defining-modules-to-control-scope.md:200 +#: src/ch05-02-the-match-control-flow-construct.md:101 msgid "" -"This tree shows how some of the modules nest inside one another; for example,\n" -"`hosting` nests inside `front_of_house`. The tree also shows that some modules\n" -"are _siblings_ to each other, meaning they’re defined in the same module;\n" -"`hosting` and `serving` are siblings defined within `front_of_house`. If module\n" -"A is contained inside module B, we say that module A is the _child_ of module B\n" -"and that module B is the _parent_ of module A. Notice that the entire module\n" -"tree is rooted under the explicit name of the crate `restaurant`." +"```rust,noplayground\n" +"impl UsStatePrintImpl of PrintTrait {\n" +" fn print(self: UsState) {\n" +" match self {\n" +" UsState::Alabama(_) => ('Alabama').print(),\n" +" UsState::Alaska(_) => ('Alaska').print(),\n" +" }\n" +" }\n" +"}\n" +"```" msgstr "" -"这个树展示了一些模块是如何被嵌入到另一个模块的(例如,`hosting` 嵌套在 `front_of_house` 中)。这个树还展示了一些模块是互为 兄弟( _siblings_ )的,这意味着它们定义在同一模块中" -"( `hosting` 和 `serving` 被一起定义在 _front_of_house_ 中)。继续沿用家庭关系的比喻,如果一个模块 A 被包含在模块 B 中,我们将模块 A 称为模块 B 的 子( _child_ ),模块 B 则是模块 A " -"的 父( _parent_ )。注意,整个模块树都植根于名为 `restaurant` crate的隐式模块下。" +"```rust,noplayground\n" +"impl UsStatePrintImpl of PrintTrait {\n" +" fn print(self: UsState) {\n" +" match self {\n" +" UsState::Alabama(_) => ('Alabama').print(),\n" +" UsState::Alaska(_) => ('Alaska').print(),\n" +" }\n" +" }\n" +"}\n" +"```" -#: src/ch06-02-defining-modules-to-control-scope.md:208 +#: src/ch05-02-the-match-control-flow-construct.md:112 msgid "" -"The module tree might remind you of the filesystem’s directory tree on your\n" -"computer; this is a very apt comparison! Just like directories in a filesystem,\n" -"you use modules to organize your code. And just like files in a directory, we\n" -"need a way to find our modules." -msgstr "这个模块树可能会令你想起电脑上文件系统的目录树;这是一个非常恰当的类比!就像文件系统的目录,你可以使用模块来组织你的代码。并且,就像目录中的文件,我们需要一种方法来找到模块。" - -#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:1 -msgid "## Paths for Referring to an Item in the Module Tree" -msgstr "## 引用模块项目的路径" - -#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:3 -msgid "To show Cairo where to find an item in a module tree, we use a path in the same way we use a path when navigating a filesystem. To call a function, we need to know its path." -msgstr "为了告诉Cairo如何在模块树中找到一个项目,我们使用路径的方式,就像在文件系统使用路径一样。为了调用一个函数,我们需要知道它的路径。" +"If we were to call `value_in_cents(Coin::Quarter(UsState::Alaska(())))`, `coin` would be `Coin::Quarter(UsState::Alaska())`. When we compare that value with each of the match arms, " +"none of them match until we reach `Coin::Quarter(state)`. At that point, the binding for state will be the value `UsState::Alaska()`. We can then use that binding in the " +"`PrintTrait`, thus getting the inner state value out of the `Coin` enum variant for `Quarter`." +msgstr "" +"如果我们调用 `value_in_cents(Coin::quarter(UsState::Alaska(())))`,`coin` 将是 `Coin::quarter(UsState::Alaska())`。当我们将该值与每个匹配臂进行比较时,没有一个匹配,直到我们到达 " +"`Coin::Quarter(state)`。在这一点上,state 的绑定将是 `UsState::Alaska()` 的值。然后我们可以在 `PrintTrait` 中使用该绑定,从而从 `Coin` 枚举变量中获得 `Quarter` 的内部状态值。" -#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:5 -msgid "A path can take two forms:" -msgstr "路径可以有两种形式:" +#: src/ch05-02-the-match-control-flow-construct.md:114 +msgid "## Matching with Options" +msgstr "## 匹配 Option" -#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:7 +#: src/ch05-02-the-match-control-flow-construct.md:116 msgid "" -"- An _absolute path_ is the full path starting from a crate root. The absolute path begins with the crate name.\n" -"- A _relative path_ starts from the current module.\n" -"\n" -" Both absolute and relative paths are followed by one or more identifiers\n" -" separated by double colons (`::`)." +"In the previous section, we wanted to get the inner `T` value out of the `Some` case when using `Option`; we can also handle `Option` using `match`, as we did with the `Coin` " +"enum! Instead of comparing coins, we’ll compare the variants of `Option`, but the way the `match` expression works remains the same. You can use Options by importing the `option::" +"OptionTrait` trait." msgstr "" -"- 绝对路径( _absolute path_ )是以 crate 根(root)开头的全路径。绝对路径以 crate 名开头。\n" -"- 相对路径( _relative path_ )是从当前模块开始的。\n" -"\n" -"绝对路径和相对路径后面都有一个或多个标识符用双冒号(`::`)分开。" +"在上一节中,我们想在使用 `Option` 时从 `Some` 情况下得到内部的 `T` 值;我们也可以使用`match` 来处理 `Option`,就像我们对 `Coin` 枚举所做的那样! 只不过这回比较的不再是硬币,而是" +"比较 `Option` 的成员,但 `match` 表达式的工作方式保持不变。你可以通过导入 `option::OptionTrait` trait来使用Option。" -#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:13 +#: src/ch05-02-the-match-control-flow-construct.md:118 msgid "" -"To illustrate this notion let's take back our example Listing 6-1 for the restaurant we used in the last chapter. We have a crate named `restaurant` in which we have a module named " -"`front_of_house` that contains a module named `hosting`. The `hosting` module contains a function named `add_to_waitlist`. We want to call the `add_to_waitlist` function from the " -"`eat_at_restaurant` function. We need to tell Cairo the path to the `add_to_waitlist` function so it can find it." -msgstr "" -"为了说明这个概念,让我们回到我们在上一章使用的餐厅的例子示例6-1。我们有一个名为 `restaurant`的crate,其中有一个名为`front_of_house`的模块,包含一个名为 `hosting`的模块。`hosting`模块" -"包含一个名为 `add_to_waitlist`的函数。我们想从`eat_at_restaurant`函数中调用`add_to_waitlist`函数。我们需要告诉Cairo `add_to_waitlist`函数的路径,以便它能找到它。" +"Let’s say we want to write a function that takes an `Option` and, if there’s a value inside, adds `1` to that value. If there isn’t a value inside, the function should return the " +"`None` value and not attempt to perform any operations." +msgstr "假设我们想写一个函数,接收一个 `Option`,如果里面有一个值,就把 `1` 加到这个值上。如果里面没有一个值,这个函数应该返回 `None` 值,并且不试图执行任何操作。" -#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:17 +#: src/ch05-02-the-match-control-flow-construct.md:120 +msgid "This function is very easy to write, thanks to match, and will look like Listing 5-5." +msgstr "这个函数非常容易编写,这要归功于 match,它看起来像示例5-5。" + +#: src/ch05-02-the-match-control-flow-construct.md:122 msgid "" "```rust\n" -"mod front_of_house {\n" -" mod hosting {\n" -" fn add_to_waitlist() {}\n" -"\n" -" fn seat_at_table() {}\n" -" }\n" -"\n" -" mod serving {\n" -" fn take_order() {}\n" -"\n" -" fn serve_order() {}\n" +"use debug::PrintTrait;\n" "\n" -" fn take_payment() {}\n" +"fn plus_one(x: Option) -> Option {\n" +" match x {\n" +" Option::Some(val) => Option::Some(val + 1),\n" +" Option::None(_) => Option::None,\n" " }\n" "}\n" "\n" -"\n" -"pub fn eat_at_restaurant() {\n" -" // Absolute path\n" -" restaurant::front_of_house::hosting::add_to_waitlist(); // ✅ Compiles\n" -"\n" -" // Relative path\n" -" front_of_house::hosting::add_to_waitlist(); // ✅ Compiles\n" +"fn main() {\n" +" let five: Option = Option::Some(5);\n" +" let six: Option = plus_one(five);\n" +" six.unwrap().print();\n" +" let none = plus_one(Option::None);\n" +" none.unwrap().print();\n" "}\n" "```" msgstr "" "```rust\n" -"mod front_of_house {\n" -" mod hosting {\n" -" fn add_to_waitlist() {}\n" -"\n" -" fn seat_at_table() {}\n" -" }\n" -"\n" -" mod serving {\n" -" fn take_order() {}\n" -"\n" -" fn serve_order() {}\n" +"use debug::PrintTrait;\n" "\n" -" fn take_payment() {}\n" +"fn plus_one(x: Option) -> Option {\n" +" match x {\n" +" Option::Some(val) => Option::Some(val + 1),\n" +" Option::None(_) => Option::None,\n" " }\n" "}\n" "\n" -"\n" -"pub fn eat_at_restaurant() {\n" -" // Absolute path\n" -" restaurant::front_of_house::hosting::add_to_waitlist(); // ✅ Compiles\n" -"\n" -" // Relative path\n" -" front_of_house::hosting::add_to_waitlist(); // ✅ Compiles\n" -"}\n" -"```" - -#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:44 -msgid "Listing 6-3: Calling the `add_to_waitlist` function using absolute and relative paths" -msgstr "示例6-3:使用绝对和相对路径调用`add_to_waitlist`函数" +"fn main() {\n" +" let five: Option = Option::Some(5);\n" +" let six: Option = plus_one(five);\n" +" six.unwrap().print();\n" +" let none = plus_one(Option::None);\n" +" none.unwrap().print();\n" +"}\n" +"```" -#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:46 +#: src/ch05-02-the-match-control-flow-construct.md:141 msgid "" -"The first time we call the `add_to_waitlist` function in `eat_at_restaurant`,\n" -"we use an absolute path. The `add_to_waitlist` function is defined in the same\n" -"crate as `eat_at_restaurant`. In Cairo, absolute paths start from the crate root, which you need to refer to by using the crate name." -msgstr "" -"我们第一次调用`eat_at_restaurant`中的`add_to_waitlist`函数时、使用了一个绝对路径。`add_to_waitlist`函数与`eat_at_restaurant`定义在同一个crate中。在Cairo中,绝对路径从crate根开始,你需" -"要用crate的名字来引用它。" +"Listing 5-5: A function that uses a match\n" +"expression on an `Option`" +msgstr "示例5-5:一个在`Option`上使用匹配表达式的函数" + +#: src/ch05-02-the-match-control-flow-construct.md:144 +msgid "Note that your arms must respect the same order as the enum defined in the `OptionTrait` of the core Cairo lib." +msgstr "注意,你的分支顺序与核心Cairo库的`OptionTrait`中定义的枚举顺序必须相同。" -#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:50 +#: src/ch05-02-the-match-control-flow-construct.md:153 msgid "" -"The second time we call `add_to_waitlist`, we use a relative path. The path starts with `front_of_house`, the name of the module\n" -"defined at the same level of the module tree as `eat_at_restaurant`. Here the\n" -"filesystem equivalent would be using the path\n" -"`./front_of_house/hosting/add_to_waitlist`. Starting with a module name means\n" -"that the path is relative to the current module." -msgstr "" -"第二次我们调用 add_to_waitlist时,使用的是相对路径。这个路径以 `front_of_house` 为起始,这个模块在模块树中,与 `eat_at_restaurant` 定义在同一层级。\n" -"与之等价的文件系统路径就是 `./front_of_house/hosting/add_to_waitlist`。以模块名开头意味着该路径是相对路径。" +"Let’s examine the first execution of `plus_one` in more detail. When we call `plus_one(five)`, the variable `x` in the body of `plus_one` will have the value `Some(5)`. We then " +"compare that against each match arm:" +msgstr "让我们更详细地看一下 `plus_one` 的第一次执行。当我们调用 `plus_one(five)` 时,`plus_one` 函数体中的变量 `x` 的值是 `Some(5)`。然后我们将其与每个匹配分支进行比较:" -#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:56 -msgid "### Starting Relative Paths with `super`" -msgstr "### 使用 `super` 起始的相对路径" +#: src/ch05-02-the-match-control-flow-construct.md:155 src/ch05-02-the-match-control-flow-construct.md:163 +msgid "" +"```rust,noplayground\n" +" Option::None(_) => Option::None,\n" +"```" +msgstr "" +"```rust,noplayground\n" +" Option::None(_) => Option::None,\n" +"```" -#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:58 +#: src/ch05-02-the-match-control-flow-construct.md:159 msgid "" -"Choosing whether to use a `super` or not is a decision you’ll make\n" -"based on your project, and depends on whether you’re more likely to move item\n" -"definition code separately from or together with the code that uses the item." +"Does `Option::Some(5)` value match the pattern `Option::Some(val)`? It does! We have the same variant. The `val` binds to the value contained in `Option::Some`, so `val` takes the " +"value `5`. The code in the match arm is then executed, so we add `1` to the value of `val` and create a new `Option::Some` value with our total `6` inside. Because the first arm " +"matched, no other arms are compared." msgstr "" -"选择是否使用 `super`将根据你的项目具体情况来决定。\n" -"并取决于你是否更有可能将项目定义的代码是与使用该项目的代码分开还是放在一起。" +"`Option::Some(5)` 和`Option::Some(val)`匹配吗?当然匹配!它们是相同的成员。`val` 与 `Option::Some` 中包含的值绑定,所以 `val` 取值为 `5` 。接着匹配分支的代码被执行,所以我们在 `val` " +"的值上加上 `1`,并创建一个新的 `Option::Some` 值,里面有我们的和 `6` 。因为第一个分支就匹配到了,其他的分支将不再进行比较。" + +#: src/ch05-02-the-match-control-flow-construct.md:161 +msgid "Now let’s consider the second call of `plus_one` in our main function, where `x` is `Option::None(())`. We enter the match and compare to the first arm:" +msgstr "现在让我们考虑在我们的主函数中对 `plus_one` 的第二次调用,其中 `x` 是`Option::None(())`。我们进入匹配,并与第一个分支进行比较:" + +#: src/ch05-02-the-match-control-flow-construct.md:167 +msgid "The `Option::Some(val)` value doesn’t match the pattern `Option::None`, so we continue to the next arm:" +msgstr "`Option::Some(val)` 的值不匹配 `Option::None` ,所以我们继续到下一个分支:" -#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:64 +#: src/ch05-02-the-match-control-flow-construct.md:169 msgid "" "```rust\n" -"fn deliver_order() {}\n" -"\n" -"mod back_of_house {\n" -" fn fix_incorrect_order() {\n" -" cook_order();\n" -" super::deliver_order();\n" " }\n" -"\n" -" fn cook_order() {}\n" -"}\n" "```" msgstr "" "```rust\n" -"fn deliver_order() {}\n" -"\n" -"mod back_of_house {\n" -" fn fix_incorrect_order() {\n" -" cook_order();\n" -" super::deliver_order();\n" " }\n" -"\n" -" fn cook_order() {}\n" -"}\n" "```" -#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:77 -msgid "Listing 6-4: Calling a function using a relative path starting with super" -msgstr "示例6-4:使用以super开头的相对路径调用一个函数" - -#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:79 -msgid "Here you can see directly that you access a parent's module easily using `super`, which wasn't the case previously." -msgstr "在这里你可以直接看到,和之前的例子不同,在这你可以使用`super`轻松地访问父级的模块。" - -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:1 -msgid "# Bringing Paths into Scope with the `use` Keyword" -msgstr "# 使用 `use` 关键字将路径引入作用域" +#: src/ch05-02-the-match-control-flow-construct.md:173 +msgid "It matches! There’s no value to add to, so the program stops and returns the `Option::None(())` value on the right side of `=>`." +msgstr "它是匹配的!没有值可以添加,所以程序停止,并返回 `=>` 右边的 `Option::None(())` 值。" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:3 +#: src/ch05-02-the-match-control-flow-construct.md:175 msgid "" -"Having to write out the paths to call functions can feel inconvenient and repetitive. Fortunately, there’s a way to simplify this process: we can create a shortcut to a path with the " -"`use` keyword once, and then use the shorter name everywhere else in the scope." -msgstr "不得不编写路径来调用函数显得不便且重复。幸运的是,有一种方法可以简化这个过程:我们可以用`use`关键字创建一个路径的快捷方式,然后在作用域内的其他地方使用这个较短的名字。" +"Combining `match` and enums is useful in many situations. You’ll see this pattern a lot in Cairo code: `match` against an enum, bind a variable to the data inside, and then execute " +"code based on it. It’s a bit tricky at first, but once you get used to it, you’ll wish you had it in all languages. It’s consistently a user favorite." +msgstr "" +"将 `match` 与枚举相结合在很多场景中都是有用的。你会在 Cairo 代码中看到很多这样的模式:`match` 一个枚举,绑定其中的值到一个变量,接着根据其值执行代码。这在一开始有点复杂,不过一旦习惯" +"了,你会希望所有语言都拥有它!这一直是用户的最爱。" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:5 +#: src/ch05-02-the-match-control-flow-construct.md:177 +msgid "## Matches Are Exhaustive" +msgstr "## 匹配是穷尽的" + +#: src/ch05-02-the-match-control-flow-construct.md:179 msgid "" -"In Listing 6-5, we bring the `restaurant::front_of_house::hosting` module into the\n" -"scope of the `eat_at_restaurant` function so we only have to specify\n" -"`hosting::add_to_waitlist` to call the `add_to_waitlist` function in\n" -"`eat_at_restaurant`." -msgstr "在示例6-5中,我们把`restaurant::front_of_house::hosting`模块带入到作用域内,所以我们只需要指定 `hosting::add_to_waitlist` 来调用`eat_at_restaurant`中的`add_to_waitlist` 函数。" +"There’s one other aspect of match we need to discuss: the arms’ patterns must cover all possibilities. Consider this version of our `plus_one` function, which has a bug and won’t " +"compile:" +msgstr "还有另一方面需要讨论:这些分支必须覆盖了所有的可能性。考虑一下 `plus_one` 函数的这个版本,它有一个 bug 并不能编译:" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:12 +#: src/ch05-02-the-match-control-flow-construct.md:181 msgid "" -"```rust\n" -"mod front_of_house {\n" -" mod hosting {\n" -" fn add_to_waitlist() {}\n" +"```rust,noplayground\n" +"fn plus_one(x: Option) -> Option {\n" +" match x {\n" +" Option::Some(val) => Option::Some(val + 1),\n" " }\n" "}\n" -"\n" -"use restaurant::front_of_house::hosting;\n" -"\n" -"fn eat_at_restaurant() {\n" -" hosting::add_to_waitlist(); // ✅ Shorter path\n" -"}\n" "```" msgstr "" -"```rust\n" -"mod front_of_house {\n" -" mod hosting {\n" -" fn add_to_waitlist() {}\n" +"```rust,noplayground\n" +"fn plus_one(x: Option) -> Option {\n" +" match x {\n" +" Option::Some(val) => Option::Some(val + 1),\n" " }\n" "}\n" -"\n" -"use restaurant::front_of_house::hosting;\n" -"\n" -"fn eat_at_restaurant() {\n" -" hosting::add_to_waitlist(); // ✅ Shorter path\n" -"}\n" "```" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:26 +#: src/ch05-02-the-match-control-flow-construct.md:189 msgid "" -"Listing 6-5: Bringing a module into scope with\n" -"`use`" +"```bash\n" +"$ scarb cairo-run\n" +" error: Unsupported match. Currently, matches require one arm per variant,\n" +" in the order of variant definition.\n" +" --> test.cairo:34:5\n" +" match x {\n" +" ^*******^\n" +" Error: failed to compile: ./src/test.cairo\n" +"```" msgstr "" -"示例 6-5: 用 \"使用 \"将一个模块带入范围。\n" -"使用" +"```bash\n" +"$ scarb cairo-run\n" +" error: Unsupported match. Currently, matches require one arm per variant,\n" +" in the order of variant definition.\n" +" --> test.cairo:34:5\n" +" match x {\n" +" ^*******^\n" +" Error: failed to compile: ./src/test.cairo\n" +"```" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:29 +#: src/ch05-02-the-match-control-flow-construct.md:199 msgid "" -"Adding use and a path in a scope is similar to creating a symbolic link in the filesystem. By adding `use restaurant::front_of_house::hosting` in the crate root, hosting is now a " -"valid name in that scope, just as though the `hosting` module had been defined in the crate root." +"Cairo knows that we didn’t cover every possible case, and even knows which pattern we forgot! Matches in Cairo are exhaustive: we must exhaust every last possibility in order for the " +"code to be valid. Especially in the case of `Option`, when Cairo prevents us from forgetting to explicitly handle the `None` case, it protects us from assuming that we have a " +"value when we might have null, thus making the billion-dollar mistake discussed earlier impossible." msgstr "" -"在作用域中添加 use 和路径类似于在文件系统中创建一个软连接(符号连接,symbolic link)。通过在 crate 根中添加 `use restaurant::front_of_house::hosting`,hosting 现在是该作用域中的一个有" -"效名称,就像在 crate 根中定义了`hosting`模块一样。" +"Rust 知道我们没有覆盖所有可能的情况甚至知道哪些模式被忘记了!Cairo 中的匹配是 穷尽的(exhaustive):必须穷举到最后的可能性来使代码有效。特别的在这个 `Option` 的例子中,Cairo 防止我" +"们忘记明确的处理 None 的情况,这让我们免于假设拥有一个实际上为空的值,从而使之前提到的价值亿万的错误不可能发生。" + +#: src/ch05-02-the-match-control-flow-construct.md:201 +msgid "## Match 0 and the \\_ Placeholder" +msgstr "## Match 0 与 \\_ 占位符" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:31 +#: src/ch05-02-the-match-control-flow-construct.md:203 msgid "" -"Note that `use` only creates the shortcut for the particular scope in which the `use` occurs. Listing 6-6 moves the `eat_at_restaurant` function into a new\n" -"child module named `customer`, which is then a different scope than the `use`\n" -"statement, so the function body won’t compile:" -msgstr "注意 `use` 只能创建 `use` 所在的特定作用域内的短路径。示例 6-6 将 `eat_at_restaurant` 函数移到一个新的子模块中,这又是一个不同于 `use` 语句的作用域,所以函数体不能编译:" +"Using enums, we can also take special actions for a few particular values, but for all other values take one default action. Currently only `0` and the `_`operator are supported." +msgstr "使用枚举,我们也可以对一些特定的值采取特殊的操作,但对所有其他的值采取一个默认的操作。目前只支持 `0` 和 `_` 操作符。" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:37 +#: src/ch05-02-the-match-control-flow-construct.md:205 msgid "" -"```rust\n" -"mod front_of_house {\n" -" mod hosting {\n" -" fn add_to_waitlist() {}\n" -" }\n" -"}\n" -"\n" -"use restaurant::front_of_house::hosting;\n" -"\n" -"mod customer {\n" -" fn eat_at_restaurant() {\n" -" hosting::add_to_waitlist();\n" +"Imagine we’re implementing a game where, you get a random number between 0 and 7. If you have 0, you win. For all other values you lose. Here's a match that implements that logic, " +"with the number hardcoded rather than a random value." +msgstr "" +"想象一下,我们正在实现一个游戏,你会获得一个 0 到 7 之间的随机数字。如果你有 0,你就赢了。若是任何其他的值,你就输了。这里有一个实现该逻辑的 match,数字是硬编码的,而不是随机值。" + +#: src/ch05-02-the-match-control-flow-construct.md:207 +msgid "" +"```rust,noplayground\n" +"fn did_i_win(nb: felt252) {\n" +" match nb {\n" +" 0 => ('You won!').print(),\n" +" _ => ('You lost...').print(),\n" " }\n" "}\n" "```" msgstr "" -"```rust\n" -"mod front_of_house {\n" -" mod hosting {\n" -" fn add_to_waitlist() {}\n" -" }\n" -"}\n" -"\n" -"use restaurant::front_of_house::hosting;\n" -"\n" -"mod customer {\n" -" fn eat_at_restaurant() {\n" -" hosting::add_to_waitlist();\n" +"```rust,noplayground\n" +"fn did_i_win(nb: felt252) {\n" +" match nb {\n" +" 0 => ('You won!').print(),\n" +" _ => ('You lost...').print(),\n" " }\n" "}\n" "```" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:53 -msgid "" -"Listing 6-6: A `use` statement only applies in the scope\n" -"it’s in" -msgstr "示例6-6:一个 `use`语句只适用于它所在的作用域" - -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:56 -msgid "" -"The compiler error shows that the shortcut no longer applies within the\n" -"`customer` module:" -msgstr "编译器错误显示短路径不在适用于 `customer` 模块中:" - -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:59 +#: src/ch05-02-the-match-control-flow-construct.md:216 msgid "" -"```console\n" -"❯ scarb build\n" -"error: Identifier not found.\n" -" --> lib.cairo:11:9\n" -" hosting::add_to_waitlist();\n" -" ^*****^\n" -"```" +"The first arm, the pattern is the literal values 0. For the last arm that covers every other possible value, the pattern is the character `_`. This code compiles, even though we " +"haven’t listed all the possible values a `felt252` can have, because the last pattern will match all values not specifically listed. This catch-all pattern meets the requirement that " +"`match` must be exhaustive. Note that we have to put the catch-all arm last because the patterns are evaluated in order. If we put the catch-all arm earlier, the other arms would " +"never run, so Cairo will warn us if we add arms after a catch-all!" msgstr "" -"```console\n" -"❯ scarb build\n" -"error: Identifier not found.\n" -" --> lib.cairo:11:9\n" -" hosting::add_to_waitlist();\n" -" ^*****^\n" -"```" +"第一条分支,模式是字面值 0。对于涵盖了所有其他可能的值的最后一条分支,其模式是字符 `_`。尽管我们没有列出 `felt252` 可能具有的所有值,但这段代码仍然可以编译,因为最后一个模式将匹配所有" +"没有特别列出的值。这个通配模式满足了 `match` 必须被穷尽的要求。请注意,我们必须把通配分支放在最后,因为模式是按顺序评估的。如果我们把通配分支放在前面,其他的分支就不会运行,所以如果我" +"们在通配分支之后添加分支,Cairo 会警告我们!" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:67 -msgid "## Creating Idiomatic `use` Paths" -msgstr "## 创建惯用的 `use` 路径" +#: src/ch05-02-the-match-control-flow-construct.md:218 +msgid "" +msgstr "" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:69 +#: src/ch06-00-managing-cairo-projects-with-packages-crates-and-modules.md:1 +msgid "# Managing Cairo Projects with Packages, Crates and Modules" +msgstr "# 使用包、Crate 和模块管理Cairo项目" + +#: src/ch06-00-managing-cairo-projects-with-packages-crates-and-modules.md:3 msgid "" -"In Listing 6-5, you might have wondered why we specified `use\n" -"restaurant::front_of_house::hosting` and then called `hosting::add_to_waitlist` in\n" -"`eat_at_restaurant` rather than specifying the `use` path all the way out to\n" -"the `add_to_waitlist` function to achieve the same result, as in Listing 6-7." +"As you write large programs, organizing your code will become increasingly\n" +"important. By grouping related functionality and separating code with distinct\n" +"features, you’ll clarify where to find code that implements a particular\n" +"feature and where to go to change how a feature works." msgstr "" -"在示例6-5中,你可能想知道为什么我们指定`restaurant::front_of_house::hosting`,然后调用`eat_at_restaurant`中的`hosting::add_to_waitlist`,而不是通过指定一直到\n" -"`add_to_waitlist`函数的 `use` 路径来得到相同的结果,如示例6-7。" +"当你编写大型程序时,组织你的代码将变得越来越重要。\n" +"通过对相关的功能进行分组,并将具有不同功能的代码分开,你就可以清楚地知道在哪里可以找到实现某一特定的代码,以及到哪里去改变一个功能的工作方式。" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:76 +#: src/ch06-00-managing-cairo-projects-with-packages-crates-and-modules.md:8 msgid "" -"```rust\n" -"mod front_of_house {\n" -" pub mod hosting {\n" -" pub fn add_to_waitlist() {}\n" -" }\n" -"}\n" -"\n" -"use restaurant::front_of_house::hosting::add_to_waitlist;\n" -"\n" -"pub fn eat_at_restaurant() {\n" -" add_to_waitlist();\n" -"}\n" -"\n" -"```" +"The programs we’ve written so far have been in one module in one file. As a\n" +"project grows, you should organize code by splitting it into multiple modules\n" +"and then multiple files. As a package grows, you can extract parts into\n" +"separate crates that become external dependencies. This chapter covers all\n" +"these techniques." msgstr "" -"```rust\n" -"mod front_of_house {\n" -" pub mod hosting {\n" -" pub fn add_to_waitlist() {}\n" -" }\n" -"}\n" -"\n" -"use restaurant::front_of_house::hosting::add_to_waitlist;\n" -"\n" -"pub fn eat_at_restaurant() {\n" -" add_to_waitlist();\n" -"}\n" -"\n" -"```" +"到目前为止,我们所写的程序都是在一个文件中的一个模块中。\n" +"伴随着项目的增长,你应该通过将代码分解为多个模块和多个文件来组织代码。\n" +"伴随着包的增长,你可以将包中的部分代码提取出来,做成独立的 crate,这些 crate 则作为外部依赖项。\n" +"本章将会涵盖所有这些概念。" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:91 +#: src/ch06-00-managing-cairo-projects-with-packages-crates-and-modules.md:14 msgid "" -"Listing 6-7: Bringing the `add_to_waitlist` function\n" -"into scope with `use`, which is unidiomatic" -msgstr "示例6-7:使用 `use` 将 `add_to_waitlist` 函数引入作用域,这并不符合习惯" +"We’ll also discuss encapsulating implementation details, which lets you reuse\n" +"code at a higher level: once you’ve implemented an operation, other code can\n" +"call your code without having to know how the\n" +"implementation works." +msgstr "我们也会讨论封装来实现细节,这可以使你更高级地重用代码:你实现了一个操作后,其他的代码可以通过该代码的公共接口来进行调用,而不需要知道它是如何实现的。" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:94 +#: src/ch06-00-managing-cairo-projects-with-packages-crates-and-modules.md:19 msgid "" -"Although both Listing 6-5 and 6-7 accomplish the same task, Listing 6-5 is\n" -"the idiomatic way to bring a function into scope with `use`. Bringing the\n" -"function’s parent module into scope with `use` means we have to specify the\n" -"parent module when calling the function. Specifying the parent module when\n" -"calling the function makes it clear that the function isn’t locally defined\n" -"while still minimizing repetition of the full path. The code in Listing 6-7 is\n" -"unclear as to where `add_to_waitlist` is defined." +"A related concept is scope: the nested context in which code is written has a\n" +"set of names that are defined as “in scope.” When reading, writing, and\n" +"compiling code, programmers and compilers need to know whether a particular\n" +"name at a particular spot refers to a variable, function, struct, enum, module,\n" +"constant, or other item and what that item means. You can create scopes and\n" +"change which names are in or out of scope. You can’t have two items with the\n" +"same name in the same scope." msgstr "" -"尽管示例6-5和6-7都完成了相同的任务,但示例 6-5 是使用 use 将函数引入作用域的习惯用法。要想使用 `use` 将函数的父模块引入作用域,我们必须在调用函数时指定父模块,这样可以清晰地表明函数不" -"是在本地定义的,同时使完整路径的重复度最小化。示例 6-7 中的代码不清楚 `add_to_waitlist` 是在哪里被定义的。" +"这里有一个需要说明的概念 “作用域(scope)”:代码所在的嵌套上下文有一组定义为 “in scope” 的名称。当阅读、编写和编译代码时,程序员和编译器需要知道特定位置的特定名称是否引用了变量、函" +"数、结构体、枚举、模块、常量或者其他有意义的项。你可以创建作用域,以及改变哪些名称在作用域内还是作用域外。同一个作用域内不能拥有两个相同名称的项。" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:102 +#: src/ch06-00-managing-cairo-projects-with-packages-crates-and-modules.md:27 msgid "" -"On the other hand, when bringing in structs, enums, traits, and other items with `use`,\n" -"it’s idiomatic to specify the full path. Listing 6-8 shows the idiomatic way\n" -"to bring the core library’s `ArrayTrait` trait into the scope." -msgstr "另一方面,使用 `use` 引入结构体、枚举和其他项时,习惯是指定它们的完整路径。示例 6-8 展示了将核心库的 `ArrayTrait` 特质带入作用域。" +"Cairo has a number of features that allow you to manage your code’s\n" +"organization. These features, sometimes\n" +"collectively referred to as the _module system_, include:" +msgstr "Cairo有许多功能可以让你管理代码的组织。这些功能。这有时被称为 “模块系统(the module system)”,包括:" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:106 +#: src/ch06-00-managing-cairo-projects-with-packages-crates-and-modules.md:31 msgid "" -"```rust\n" -"use array::ArrayTrait;\n" -"\n" -"fn main() {\n" -" let mut arr = ArrayTrait::new();\n" -" arr.append(1);\n" -"}\n" -"```" +"- **Packages:** A Scarb feature that lets you build, test, and share crates\n" +"- **Crates:** A tree of modules that corresponds to a single compilation unit.\n" +" It has a root directory, and a root module defined at the file `lib.cairo` under this directory.\n" +"- **Modules** and **use:** Let you control the organization and scope of items.\n" +"- **Paths:** A way of naming an item, such as a struct, function, or module" msgstr "" -"```rust\n" -"use array::ArrayTrait;\n" -"\n" -"fn main() {\n" -" let mut arr = ArrayTrait::new();\n" -" arr.append(1);\n" -"}\n" -"```" - -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:115 -msgid "" -"Listing 6-8: Bringing `ArrayTrait` into scope in an\n" -"idiomatic way" -msgstr "示例6-8:将`ArrayTrait`引入作用域的习惯用法式" +"- **Packages:** Scarb的一个功能,可以让你建立、测试和分享crates。\n" +"- **Crates:** 一个模块的树形结构,对应于一个单一的编译单元。\n" +" 它有一个根目录,并在该目录下的`lib.cairo`文件中定义了一个根模块。\n" +"- **Modules** 和 **use:** 允许你控制组织结构和作用域。\n" +"- **Paths:** 一个命名例如结构体、函数或模块等项的方式" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:118 +#: src/ch06-00-managing-cairo-projects-with-packages-crates-and-modules.md:37 msgid "" -"There’s no strong reason behind this idiom: it’s just the convention that has\n" -"emerged in the Rust community, and folks have gotten used to reading and writing Rust code this way.\n" -"As Cairo shares many idioms with Rust, we follow this convention as well." -msgstr "" -"这种习惯用法背后没有什么硬性要求:它只是一种惯例,人们已经习惯了以这种方式阅读和编写 Rust 代码。它只是在Rust社区中出现的惯例。\n" -"由于Cairo与Rust共享许多惯例,我们也遵循这一惯例。" +"In this chapter, we’ll cover all these features, discuss how they interact, and\n" +"explain how to use them to manage scope. By the end, you should have a solid\n" +"understanding of the module system and be able to work with scopes like a pro!" +msgstr "在这一章中,我们将介绍所有这些特性,讨论它们如何相互作用,以及解释如何使用它们来管理作用域。到最后,你应该对模块系统有一个扎实的理解,并且能够像专家一样使用作用域了!" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:122 -msgid "" -"The exception to this idiom is if we’re bringing two items with the same name\n" -"into scope with `use` statements, because Cairo doesn’t allow that." -msgstr "这个习惯用法有一个例外,那就是我们想使用 `use` 语句将两个具有相同名称的项带入作用域,因为Cairo不允许这样做。" +#: src/ch06-01-packages-and-crates.md:1 +msgid "# Packages and Crates" +msgstr "# 包和 Crate" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:125 -msgid "### Providing New Names with the `as` Keyword" -msgstr "### 使用 as 关键字提供新的名称" +#: src/ch06-01-packages-and-crates.md:3 +msgid "## What is a crate?" +msgstr "## 什么是crate?" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:127 +#: src/ch06-01-packages-and-crates.md:5 msgid "" -"There’s another solution to the problem of bringing two types of the same name\n" -"into the same scope with `use`: after the path, we can specify `as` and a new\n" -"local name, or _alias_, for the type. Listing 6-9 shows how you can rename an import with `as`:" +"A crate is the smallest amount of code that the Cairo compiler considers at a time. Even if you run `cairo-compile` rather than `scarb build` and pass a single source code file, the " +"compiler considers that file to be a crate. Crates can contain modules, and the modules may be defined in other files that get compiled with the crate, as will be discussed in the " +"subsequent sections." msgstr "" -"使用 `use` 将两个同名类型引入同一作用域这个问题还有另一个解决办法:在这个类型的路径后面,我们使用 `as` 指定一个新的本地名称或者别名( _alias_ )。示例6-9显示了如何用`as`重命名一个导" -"入:" +"Crate是Cairo在编译时最小的代码单位。即使你运行 `cairo-compile` 而不是 `scarb build` 并传递一个源代码文件,编译器还是会将那个文件认作一个 crate。Crate可以包含模块,这些模块可以在其他文" +"件中定义,并与Crate一起被编译,这将在后面的章节中讨论。" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:133 +#: src/ch06-01-packages-and-crates.md:7 +msgid "## What is the crate root?" +msgstr "## 什么是crate root?" + +#: src/ch06-01-packages-and-crates.md:9 msgid "" -"```rust\n" -"use array::ArrayTrait as Arr;\n" -"\n" -"fn main() {\n" -" let mut arr = Arr::new(); // ArrayTrait was renamed to Arr\n" -" arr.append(1);\n" -"}\n" -"```" +"The crate root is the `lib.cairo` source file that the Cairo compiler starts from and makes up the root module of your crate (we’ll explain modules in depth in the [“Defining Modules " +"to Control Scope”](./ch06-02-defining-modules-to-control-scope.md) section)." msgstr "" -"```rust\n" -"use array::ArrayTrait as Arr;\n" -"\n" -"fn main() {\n" -" let mut arr = Arr::new(); // ArrayTrait was renamed to Arr\n" -" arr.append(1);\n" -"}\n" -"```" +"Crate root根是`lib.cairo`源文件,Cairo编译器从该文件开始,并构成你的crate的根模块(我们将在[“定义模块来控制作用域”](./ch06-02-defining-modules-to-control-scope.md)部分深入解释模块)。" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:142 +#: src/ch06-01-packages-and-crates.md:11 +msgid "## What is a package?" +msgstr "## 什么是包?" + +#: src/ch06-01-packages-and-crates.md:13 msgid "" -"Listing 6-9: Renaming a trait when it’s brought into\n" -"scope with the `as` keyword" -msgstr "示例 6-9:使用 `as` 关键字重命名引入作用域的类型" +"A cairo package is a bundle of one or more crates with a Scarb.toml file that describes how to build those crates. This enables the splitting of code into smaller, reusable parts and " +"facilitates more structured dependency management." +msgstr "一个cairo包是一个由一个或多个crate组成的集合,其中的Scarb.toml文件描述如何构建这些板块。这使得代码被分割成更小的、可重复使用的部分,并有利于更有条理的依赖管理。" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:145 -msgid "Here, we brought `ArrayTrait` into scope with the alias `Arr`. We can now access the trait's methods with the `Arr` identifier." -msgstr "在这里,我们用别名`Arr`将`ArrayTrait`带入作用域。现在我们可以用`Arr`标识符来访问该trait的方法。" +#: src/ch06-01-packages-and-crates.md:15 +msgid "## Creating a Package with Scarb" +msgstr "## 用Scarb创建一个包" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:147 -msgid "### Importing multiple items from the same module" -msgstr "###从同一模块中导入多个项" +#: src/ch06-01-packages-and-crates.md:17 +msgid "You can create a new Cairo package using the scarb command-line tool. To create a new package, run the following command:" +msgstr "你可以使用scarb命令行工具创建一个新的Cairo包。要创建一个新的软件包,运行以下命令:" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:149 +#: src/ch06-01-packages-and-crates.md:19 msgid "" -"When you want to import multiple items (like functions, structs or enums)\n" -"from the same module in Cairo, you can use curly braces `{}` to list all of\n" -"the items that you want to import. This helps to keep your code clean and easy\n" -"to read by avoiding a long list of individual use statements." +"```bash\n" +"scarb new my_package\n" +"```" msgstr "" -"当你想从同一个模块中导入多个项(如函数、结构体或枚举)时,\n" -"你可以使用大括号`{}`来列出所有你想导入的项目。\n" -"避免了一长串单独的`use`有助于保持你的代码整洁和便于阅读。" +"```bash\n" +"scarb new my_package\n" +"```" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:154 -msgid "The general syntax for importing multiple items from the same module is:" -msgstr "从同一模块导入多个项的常见语法是:" +#: src/ch06-01-packages-and-crates.md:23 +msgid "This command will generate a new package directory named `my_package` with the following structure:" +msgstr "该命令将生成一个名为`my_package`的新软件包目录,其结构如下:" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:156 +#: src/ch06-01-packages-and-crates.md:25 msgid "" -"```rust\n" -"use module::{item1, item2, item3};\n" +"```\n" +"my_package/\n" +"├── Scarb.toml\n" +"└── src\n" +" └── lib.cairo\n" "```" msgstr "" -"```rust\n" -"use module::{item1, item2, item3};\n" +"```\n" +"my_package/\n" +"├── Scarb.toml\n" +"└── src\n" +" └── lib.cairo\n" "```" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:160 -msgid "Here is an example where we import three structures from the same module:" -msgstr "下面是一个从同一个模块导入三个结构体的例子:" +#: src/ch06-01-packages-and-crates.md:32 +msgid "" +"- `src/` is the main directory where all the Cairo source files for the package will be stored.\n" +"- `lib.cairo` is the default root module of the crate, which is also the main entry point of the package.\n" +"- `Scarb.toml` is the package manifest file, which contains metadata and configuration options for the package, such as dependencies, package name, version, and authors. You can find " +"documentation about it on the [scarb reference](https://docs.swmansion.com/scarb/docs/reference/manifest.html)." +msgstr "" +"- `src/`是主目录,包的所有Cairo源代码文件将存放在这里。\n" +"- `lib.cairo`是crate的默认根模块,也是包的主要入口点。\n" +"- `Scarb.toml`是包示例文件,它包含包的元数据和配置选项,如依赖关系、包名称、版本和作者。你可以在[scarb reference](https://docs.swmansion.com/scarb/docs/reference/manifest.html)上找到" +"关于它的文档。" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:162 +#: src/ch06-01-packages-and-crates.md:36 msgid "" -"```rust\n" -"// Assuming we have a module called `shapes` with the structures `Square`, `Circle`, and `Triangle`.\n" -"mod shapes {\n" -" #[derive(Drop)]\n" -" struct Square {\n" -" side: u32\n" -" }\n" -"\n" -" #[derive(Drop)]\n" -" struct Circle {\n" -" radius: u32\n" -" }\n" +"```toml\n" +"[package]\n" +"name = \"my_package\"\n" +"version = \"0.1.0\"\n" "\n" -" #[derive(Drop)]\n" -" struct Triangle {\n" -" base: u32,\n" -" height: u32,\n" -" }\n" -"}\n" -"\n" -"// We can import the structures `Square`, `Circle`, and `Triangle` from the `shapes` module like this:\n" -"use shapes::{Square, Circle, Triangle};\n" +"[dependencies]\n" +"# foo = { path = \"vendor/foo\" }\n" +"```" +msgstr "" +"```toml\n" +"[package]\n" +"name = \"my_package\"\n" +"version = \"0.1.0\"\n" "\n" -"// Now we can directly use `Square`, `Circle`, and `Triangle` in our code.\n" -"fn main() {\n" -" let sq = Square { side: 5 };\n" -" let cr = Circle { radius: 3 };\n" -" let tr = Triangle { base: 5, height: 2 };\n" -"// ...\n" -"}\n" +"[dependencies]\n" +"# foo = { path = \"vendor/foo\" }\n" "```" + +#: src/ch06-01-packages-and-crates.md:45 +msgid "" +"As you develop your package, you may want to organize your code into multiple Cairo source files. You can do this by creating additional `.cairo` files within the `src` directory or " +"its subdirectories." +msgstr "当你开发你的包时,你可能想把你的代码组织成多个Cairo源文件。你可以通过在`src`目录或其子目录下创建额外的`.cairo`文件来做到这一点。" + +#: src/ch06-02-defining-modules-to-control-scope.md:1 +msgid "## Defining Modules to Control Scope" +msgstr "## 定义模块以控制作用域" + +#: src/ch06-02-defining-modules-to-control-scope.md:3 +msgid "" +"In this section, we’ll talk about modules and other parts of the module system,\n" +"namely _paths_ that allow you to name items and the `use` keyword that brings a\n" +"path into scope." +msgstr "在本节,我们将讨论模块和其它一些关于模块系统的部分,如允许你命名项的 路径(_paths_);用来将路径引入作用域的`use`关键字。" + +#: src/ch06-02-defining-modules-to-control-scope.md:7 +msgid "" +"First, we’re going to start with a list of rules for easy reference when you’re\n" +"organizing your code in the future. Then we’ll explain each of the rules in\n" +"detail." +msgstr "首先,我们将从一系列的规则开始,在你未来组织代码的时候,这些规则可被用作简单的参考。接下来我们将会详细的解释每条规则。" + +#: src/ch06-02-defining-modules-to-control-scope.md:11 +msgid "### Modules Cheat Sheet" +msgstr "### 模块小抄" + +#: src/ch06-02-defining-modules-to-control-scope.md:13 +msgid "" +"Here we provide a quick reference on how modules, paths and the `use` keyword\n" +"work in the compiler, and how most developers organize their\n" +"code. We’ll be going through examples of each of these rules throughout this\n" +"chapter, but this is a great place to refer to as a reminder of how modules\n" +"work. You can create a new Scarb project with `scarb new backyard` to follow along." msgstr "" -"```rust\n" -"// Assuming we have a module called `shapes` with the structures `Square`, `Circle`, and `Triangle`.\n" -"mod shapes {\n" -" #[derive(Drop)]\n" -" struct Square {\n" -" side: u32\n" -" }\n" +"这里我们提供一个简单的参考,用来解释模块、路径、 `use`关键词如何在编译器中工作,以及大部分开发者如何组织他们的代码。我们将在本章节中举例说明每条规则,不过这是一个解释模块工作方式的良" +"好参考。你可以用`scarb new backyard`创建一个新的Scarb项目来跟随。" + +#: src/ch06-02-defining-modules-to-control-scope.md:19 +msgid "" +"- **Start from the crate root**: When compiling a crate, the compiler first\n" +" looks in the crate root file (_src/lib.cairo_) for code to compile.\n" +"- **Declaring modules**: In the crate root file, you can declare new modules;\n" +" say, you declare a “garden” module with `mod garden;`. The compiler will look\n" +" for the module’s code in these places:\n" "\n" -" #[derive(Drop)]\n" -" struct Circle {\n" -" radius: u32\n" +" - Inline, within curly brackets that replace the semicolon following `mod garden;`.\n" +"\n" +" ```rust,noplayground\n" +" // crate root file (src/lib.cairo)\n" +" mod garden {\n" +" // code defining the garden module goes here\n" +" }\n" +" ```\n" +"\n" +" - In the file _src/garden.cairo_\n" +"\n" +"- **Declaring submodules**: In any file other than the crate root, you can\n" +" declare submodules. For example, you might declare `mod vegetables;` in\n" +" _src/garden.cairo_. The compiler will look for the submodule’s code within the\n" +" directory named for the parent module in these places:\n" +"\n" +" - Inline, directly following `mod vegetables`, within curly brackets instead\n" +" of the semicolon.\n" +"\n" +" ```rust,noplayground\n" +" // src/garden.cairo file\n" +" mod vegetables {\n" +" // code defining the vegetables submodule goes here\n" " }\n" +" ```\n" "\n" -" #[derive(Drop)]\n" -" struct Triangle {\n" -" base: u32,\n" -" height: u32,\n" +" - In the file _src/garden/vegetables.cairo_\n" +"\n" +"- **Paths to code in modules**: Once a module is part of your crate, you can\n" +" refer to code in that module from anywhere else in that same crate, using the path\n" +" to the code. For example, an `Asparagus` type in the garden vegetables module would be found at\n" +" `backyard::garden::vegetables::Asparagus`.\n" +"- **The `use` keyword**: Within a scope, the `use` keyword creates shortcuts to\n" +" items to reduce repetition of long paths. In any scope that can refer to\n" +" `backyard::garden::vegetables::Asparagus`, you can create a shortcut with\n" +" `use backyard::garden::vegetables::Asparagus;` and from then on you only need to\n" +" write `Asparagus` to make use of that type in the scope." +msgstr "" +"- **从 crate 根节点开始**:当编译一个 crate, 编译器首先在 crate 根文件(_src/lib.cairo_)中寻找要编译的代码。\n" +"- **声明模块:**:在 crate 根文件中,你可以声明新的模块;\n" +" 例如,你用`mod garden;`声明一个 “garden”模块。编译器会在下列路径中寻找模块代码:\n" +"\n" +" - 内联,在大括号中,当`mod garden`后方不是一个分号而是一个大括号\n" +"\n" +" ```rust,noplayground\n" +" // crate root file (src/lib.cairo)\n" +" mod garden {\n" +" // code defining the garden module goes here\n" +" }\n" +" ```\n" +"\n" +"- 在文件 _src/garden.cairo_ 中\n" +"- **声明子模块**:在除了 crate 根节点以外的其他文件中,你可以定义子模块。例如,你可以在以下文件中声明 `mod vegetables;`。\n" +" _src/garden.cairo_ 。编译器会在以父模块命名的目录中寻找子模块代码: \n" +"\n" +" - 内联,直接跟在`mod vegetables`后面,用大括号代替分号\n" +"\n" +" ```rust,noplayground\n" +" // src/garden.cairo file\n" +" mod vegetables {\n" +" // code defining the vegetables submodule goes here\n" " }\n" -"}\n" +" ```\n" "\n" -"// We can import the structures `Square`, `Circle`, and `Triangle` from the `shapes` module like this:\n" -"use shapes::{Square, Circle, Triangle};\n" +" - 在文件 _src/garden/vegetables.cairo_ 中\n" "\n" -"// Now we can directly use `Square`, `Circle`, and `Triangle` in our code.\n" -"fn main() {\n" -" let sq = Square { side: 5 };\n" -" let cr = Circle { radius: 3 };\n" -" let tr = Triangle { base: 5, height: 2 };\n" -"// ...\n" -"}\n" -"```" - -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:194 -msgid "Listing 6-10: Importing multiple items from the same module" -msgstr "示例 6-10:从同一模块导入多个项" +"- **模块中的代码路径**:一旦一个模块是你 crate 的一部分,你可以在隐私规则允许的前提下,从同一个 crate 内的任意地方,通过代码路径引用该模块的代码。举例而言,一个 garden vegetables 模块" +"下的`Asparagus`类型可以在`backyard::garden::vegetables::Asparagus`被找到。\n" +"- **`use`关键字**:在一个作用域内,`use`关键字创建了一个成员的快捷方式,用来减少长路径的重复。在任何可以引用`backyard::garden::vegetables::Asparagus`的作用域,你可以通过 `use " +"backyard::garden::vegetables::Asparagus;`创建一个快捷方式,然后你就可以在作用域中只写`Asparagus`来使用该类型。" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:196 -msgid "## Re-exporting Names in Module Files" -msgstr "## 在模块文件中重导出名称" +#: src/ch06-02-defining-modules-to-control-scope.md:63 +msgid "" +"Here we create a crate named `backyard` that illustrates these rules. The\n" +"crate’s directory, also named `backyard`, contains these files and directories:" +msgstr "这里我们创建一个名为`backyard`的crate 来说明这些规则。该 crate 的路径同样命名为`backyard`,该路径包含了这些文件和目录:" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:198 +#: src/ch06-02-defining-modules-to-control-scope.md:66 msgid "" -"When we bring a name into scope with the `use` keyword, the name available in\n" -"the new scope can be imported as if it had been defined in that code’s scope.\n" -"This technique is called _re-exporting_ because we’re bringing an item into scope,\n" -"but also making that item available for others to bring into their scope." +"```text\n" +"backyard/\n" +"├── Scarb.toml\n" +"└── src\n" +" ├── garden\n" +" │   └── vegetables.cairo\n" +" ├── garden.cairo\n" +" └── lib.cairo\n" +"```" msgstr "" -"当我们用`use`关键字将一个名字带入作用域时,在新的作用域中也能够正常使用这个名称,就好像它本来就在当前作用域一样。\n" -"这种技术被称为 重导出( _re-exporting_ ),因为我们将一个项目带入作用域、但同时也使这个项目可以被其他人带入他们的作用域。" +"```text\n" +"backyard/\n" +"├── Scarb.toml\n" +"└── src\n" +" ├── garden\n" +" │   └── vegetables.cairo\n" +" ├── garden.cairo\n" +" └── lib.cairo\n" +"```" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:203 -msgid "For example, let's re-export the `add_to_waitlist` function in the restaurant example:" -msgstr "下面这个例子,让我们重新导出餐厅例子中的`add_to_waitlist`函数:" +#: src/ch06-02-defining-modules-to-control-scope.md:76 +msgid "The crate root file in this case is _src/lib.cairo_, and it contains:" +msgstr "在这种情况下,crate根文件是 _src/lib.cairo_ ,它包含:" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:207 +#: src/ch06-02-defining-modules-to-control-scope.md:80 msgid "" -"```rs\n" -"mod front_of_house {\n" -" mod hosting {\n" -" fn add_to_waitlist() {}\n" -" }\n" -"}\n" +"```rust\n" +"//TAG: does_not_compile\n" +"use garden::vegetables::Asparagus;\n" "\n" -"use restaurant::front_of_house::hosting;\n" +"mod garden;\n" "\n" -"fn eat_at_restaurant() {\n" -" hosting::add_to_waitlist();\n" +"fn main() {\n" +" let Asparagus = Asparagus {};\n" "}\n" "```" msgstr "" -"```rs\n" -"mod front_of_house {\n" -" mod hosting {\n" -" fn add_to_waitlist() {}\n" -" }\n" -"}\n" +"```rust\n" +"//TAG: does_not_compile\n" +"use garden::vegetables::Asparagus;\n" "\n" -"use restaurant::front_of_house::hosting;\n" +"mod garden;\n" "\n" -"fn eat_at_restaurant() {\n" -" hosting::add_to_waitlist();\n" +"fn main() {\n" +" let Asparagus = Asparagus {};\n" "}\n" "```" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:221 -msgid "" -"Listing 6-11: Making a name available for any code to use\n" -"from a new scope with `pub use`" -msgstr "示例 6-11: 通过 `pub use` 使名称可在新作用域中被导入至任何代码" +#: src/ch06-02-defining-modules-to-control-scope.md:91 +msgid "The `mod garden;` line tells the compiler to include the code it finds in _src/garden.cairo_, which is:" +msgstr "`mod garden;`行告诉编译器包括它在 _src/garden.cairo_ 中发现的代码是:" + +#: src/ch06-02-defining-modules-to-control-scope.md:93 +msgid "Filename: src/garden.cairo" +msgstr "文件名: src/garden.cairo" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:224 +#: src/ch06-02-defining-modules-to-control-scope.md:95 msgid "" -"Before this change, external code would have to call the `add_to_waitlist`\n" -"function by using the path\n" -"`restaurant::front_of_house::hosting::add_to_waitlist()`. Now that this `use`\n" -"has re-exported the `hosting` module from the root module, external code\n" -"can now use the path `restaurant::hosting::add_to_waitlist()` instead." +"```rust,noplayground\n" +"mod vegetables;\n" +"```" msgstr "" -"在这个修改之前,外部代码需要使用路径 `restaurant::front_of_house::hosting::add_to_waitlist()` 来调用 `add_to_waitlist` 函数。\n" -"现在这个 `use` 从根模块重导出了 `hosting` 模块,外部代码现在可以使用路径 `restaurant::hosting::add_to_waitlist()` 。" +"```rust,noplayground\n" +"mod vegetables;\n" +"```" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:230 +#: src/ch06-02-defining-modules-to-control-scope.md:99 msgid "" -"Re-exporting is useful when the internal structure of your code is different\n" -"from how programmers calling your code would think about the domain. For\n" -"example, in this restaurant metaphor, the people running the restaurant think\n" -"about “front of house” and “back of house.” But customers visiting a restaurant\n" -"probably won’t think about the parts of the restaurant in those terms. With\n" -"`use`, we can write our code with one structure but expose a different\n" -"structure. Doing so makes our library well organized for programmers working on\n" -"the library and programmers calling the library." -msgstr "" -"当你代码的内部结构与调用你代码的程序员所想象的结构不同时,重导出会很有用。\n" -"例如,在这个餐馆的比喻中,经营餐馆的人会想到“前台”和“后台”。但顾客在光顾一家餐馆时,可能不会以这些术语来考虑餐馆的各个部分。\n" -"使用 `use`,我们可以使用一种结构编写代码,却将不同的结构形式暴露出来。这样做使我们的库井井有条,也使开发这个库的程序员和调用这个库的程序员都更加方便。" +"Here, `mod vegetables;` means the code in _src/garden/vegetables.cairo_ is\n" +"included too. That code is:" +msgstr "这里,`mod vegetables;`意味着 _src/garden/vegetables.cairo_ 中的代码也被包括在内。这段代码是:" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:239 -msgid "## Using External Packages in Cairo with Scarb" -msgstr "## 在Cairo使用外部包与Scarb" +#: src/ch06-02-defining-modules-to-control-scope.md:102 +msgid "" +"```rust,noplayground\n" +"#[derive(Copy, Drop)]\n" +"struct Asparagus {}\n" +"```" +msgstr "" +"```rust,noplayground\n" +"#[derive(Copy, Drop)]\n" +"struct Asparagus {}\n" +"```" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:241 -msgid "You might need to use external packages to leverage the functionality provided by the community. To use an external package in your project with Scarb, follow these steps:" -msgstr "你可能需要使用外部包来利用社区提供的功能。要在你的项目中使用Scarb的外部包,请遵循以下步骤:" +#: src/ch06-02-defining-modules-to-control-scope.md:107 +msgid "" +"The line `use garden::vegetables::Asparagus;` lets us use bring the `Asparagus` type into scope,\n" +"so we can use it in the `main` function." +msgstr "这行`use garden::vecants::Asparagus;`让我们把`Asparagus`类型带入作用域、所以我们可以在`main`函数中使用它。" -#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:243 -msgid "> The dependencies system is still a work in progress. You can check the official [documentation](https://docs.swmansion.com/scarb/docs/guides/dependencies)." -msgstr "> 依赖关系系统仍然是一项正在进行的工作。你可以查看官方的[文档](https://docs.swmansion.com/scarb/docs/guides/dependencies)。" +#: src/ch06-02-defining-modules-to-control-scope.md:110 +msgid "Now let’s get into the details of these rules and demonstrate them in action!" +msgstr "现在让我们深入了解这些规则的细节并在实际中演示它们!" -#: src/ch06-05-separating-modules-into-different-files.md:1 -msgid "## Separating Modules into Different Files" -msgstr "## 将模块拆分成多个文件" +#: src/ch06-02-defining-modules-to-control-scope.md:112 +msgid "### Grouping Related Code in Modules" +msgstr "### 在模块中对相关代码进行分组" -#: src/ch06-05-separating-modules-into-different-files.md:3 +#: src/ch06-02-defining-modules-to-control-scope.md:114 msgid "" -"So far, all the examples in this chapter defined multiple modules in one file.\n" -"When modules get large, you might want to move their definitions to a separate\n" -"file to make the code easier to navigate." -msgstr "到目前为止,本章所有的例子都在一个文件中定义多个模块。当模块变得更大时,你可能想要将它们的定义移动到单独的文件中,从而使代码更容易阅读。" +"_Modules_ let us organize code within a crate for readability and easy reuse.\n" +"As an example, let’s write a library crate that provides the functionality of a\n" +"restaurant. We’ll define the signatures of functions but leave their bodies\n" +"empty to concentrate on the organization of the code, rather than the\n" +"implementation of a restaurant." +msgstr "" +"_模块_ 让我们可以将一个 crate 中的代码进行分组,以提高可读性与重用性。\n" +"作为一个例子,让我们写一个crate,提供一个餐馆的机能。我们将定义函数的签名,但将其主体留空,以专注于代码的组织,而不是餐馆的实现。" -#: src/ch06-05-separating-modules-into-different-files.md:7 +#: src/ch06-02-defining-modules-to-control-scope.md:120 msgid "" -"For example, let’s start from the code in Listing 6-11 that had multiple\n" -"restaurant modules. We’ll extract modules into files instead of having all the\n" -"modules defined in the crate root file. In this case, the crate root file is\n" -"_src/lib.cairo_." -msgstr "例如,我们从示例6-11中的代码开始,我们会将模块的代码提取到各自的文件中,而不是将所有模块都定义到 crate 根文件中。在这里,crate 根文件是 _src/lib.cairo_ 。" +"In the restaurant industry, some parts of a restaurant are referred to as\n" +"_front of house_ and others as _back of house_. Front of house is where\n" +"customers are; this encompasses where the hosts seat customers, servers take\n" +"orders and payment, and bartenders make drinks. Back of house is where the\n" +"chefs and cooks work in the kitchen, dishwashers clean up, and managers do\n" +"administrative work." +msgstr "" +"在餐饮业,餐馆中会有一些地方被称之为 前台(_front of house_),还有另外一些地方被称之为 后台(_back of house_)。\n" +"前台是招待顾客的地方,在这里,店主可以为顾客安排座位,服务员接受顾客下单和付款,调酒师会制作饮品。\n" +"后台则是由厨师工作的厨房,洗碗工的工作地点,以及经理做行政工作的地方组成。" -#: src/ch06-05-separating-modules-into-different-files.md:12 +#: src/ch06-02-defining-modules-to-control-scope.md:127 msgid "" -"First, we’ll extract the `front_of_house` module to its own file. Remove the\n" -"code inside the curly brackets for the `front_of_house` module, leaving only\n" -"the `mod front_of_house;` declaration, so that _src/lib.cairo_ contains the code\n" -"shown in Listing 6-12. Note that this won’t compile until we create the\n" -"_src/front_of_house.cairo_ file in Listing 6-13." +"To structure our crate in this way, we can organize its functions into nested\n" +"modules. Create a new package named `restaurant` by running `scarb new restaurant`; then enter the code in Listing 6-1 into _src/lib.cairo_ to\n" +"define some modules and function signatures. Here’s the front of house section:" msgstr "" -"首先将 `front_of_house` 模块提取到其自己的文件中。删除 `front_of_house` 模块的大括号中的代码,只留下 `mod front_of_house;` 声明,这样 _src/lib.cairo_ 就包含了代码\n" -"如示例6-12所示。注意直到创建示例 6-13 中的 _src/front_of_house.cairo_ 文件之前代码都不能编译。" +"我们可以将函数放置到嵌套的模块中,来使我们的 crate 结构与实际的餐厅结构相同。\n" +"通过运行 `scarb new restaurant`创建一个名为 `restaurant`的新包;然后将示例6-1中的代码输入 _src/lib.cairo_ ,以定义一些模块和函数签名。这里是前台的部分:" -#: src/ch06-05-separating-modules-into-different-files.md:20 +#: src/ch06-02-defining-modules-to-control-scope.md:133 msgid "" -"```rust\n" -"mod front_of_house;\n" +"```rust,noplayground\n" +"mod front_of_house {\n" +" mod hosting {\n" +" fn add_to_waitlist() {}\n" "\n" -"use restaurant::front_of_house::hosting;\n" +" fn seat_at_table() {}\n" +" }\n" "\n" -"pub fn eat_at_restaurant() {\n" -" hosting::add_to_waitlist();\n" +" mod serving {\n" +" fn take_order() {}\n" +"\n" +" fn serve_order() {}\n" +"\n" +" fn take_payment() {}\n" +" }\n" "}\n" "```" msgstr "" -"```rust\n" -"mod front_of_house;\n" +"```rust,noplayground\n" +"mod front_of_house {\n" +" mod hosting {\n" +" fn add_to_waitlist() {}\n" "\n" -"use restaurant::front_of_house::hosting;\n" +" fn seat_at_table() {}\n" +" }\n" "\n" -"pub fn eat_at_restaurant() {\n" -" hosting::add_to_waitlist();\n" +" mod serving {\n" +" fn take_order() {}\n" +"\n" +" fn serve_order() {}\n" +"\n" +" fn take_payment() {}\n" +" }\n" "}\n" "```" -#: src/ch06-05-separating-modules-into-different-files.md:30 +#: src/ch06-02-defining-modules-to-control-scope.md:151 msgid "" -"Listing 6-12: Declaring the `front_of_house` module whose\n" -"body will be in _src/front_of_house.cairo_" -msgstr "示例6-12:声明`front_of_house` 模块,其主体代码将存放在 _src/front_of_house.cairo_ 中。" +"Listing 6-1: A `front_of_house` module containing other\n" +"modules that then contain functions" +msgstr "示例6-1:一个 `front_of_house`模块包含其他的模块,而这些模块又包含了函数" -#: src/ch06-05-separating-modules-into-different-files.md:33 +#: src/ch06-02-defining-modules-to-control-scope.md:154 msgid "" -"Next, place the code that was in the curly brackets into a new file named\n" -"_src/front_of_house.cairo_, as shown in Listing 6-13. The compiler knows to look\n" -"in this file because it came across the module declaration in the crate root\n" -"with the name `front_of_house`." +"We define a module with the `mod` keyword followed by the name of the module\n" +"(in this case, `front_of_house`). The body of the module then goes inside curly\n" +"brackets. Inside modules, we can place other modules, as in this case with the\n" +"modules `hosting` and `serving`. Modules can also hold definitions for other\n" +"items, such as structs, enums, constants, traits, and—as in Listing\n" +"6-1—functions." msgstr "" -"接下来将之前大括号内的代码放入一个名叫 _src/front_of_house.cairo_ 的新文件中,如示例 6-13所示。因为编译器找到了 crate 根中名叫 `front_of_house` 的模块声明,它就知道去查看这个文件。" - -#: src/ch06-05-separating-modules-into-different-files.md:38 src/ch06-05-separating-modules-into-different-files.md:66 -msgid "Filename: src/front_of_house.cairo" -msgstr "文件名: src/front_of_house.cairo" +"我们定义一个模块,是以 `mod`关键字为起始,然后指定模块的名字(本例中叫做 `front_of_house`),并且用花括号包围模块的主体。在模块内,我们还可以定义其他的模块,就像本例中的 `hosting` 和 " +"`serving` 模块。模块还可以保存一些定义的其他项,比如结构体、枚举、常量、特性、以及列表中6-1中展示的函数。" -#: src/ch06-05-separating-modules-into-different-files.md:40 +#: src/ch06-02-defining-modules-to-control-scope.md:161 msgid "" -"```rust,\n" -"mod hosting {\n" -" fn add_to_waitlist() {}\n" -"}\n" -"```" +"By using modules, we can group related definitions together and name why\n" +"they’re related. Programmers using this code can navigate the code based on the\n" +"groups rather than having to read through all the definitions, making it easier\n" +"to find the definitions relevant to them. Programmers adding new functionality\n" +"to this code would know where to place the code to keep the program organized." msgstr "" -"```rust,\n" -"mod hosting {\n" -" fn add_to_waitlist() {}\n" -"}\n" -"```" +"通过使用模块,我们可以将相关的定义分组到一起,并指出他们为什么相关。程序员可以通过使用这段代码,更加容易地找到他们想要的定义,因为他们可以基于分组来对代码进行导航,而不需要阅读所有的" +"定义。\n" +"程序员向这段代码中添加一个新的功能时,他们也会知道代码应该放置在何处,可以保持程序的组织性。" -#: src/ch06-05-separating-modules-into-different-files.md:46 +#: src/ch06-02-defining-modules-to-control-scope.md:167 msgid "" -"Listing 6-13: Definitions inside the `front_of_house`\n" -"module in _src/front_of_house.cairo_" -msgstr "示例 6-13:在 _src/front_of_house.cairo_ 中定义 `front_of_house` 模块。" +"Earlier, we mentioned that _src/lib.cairo_ is called the crate\n" +"root. The reason for this name is that the content of this file form a module named after the crate name at the root of the crate’s module structure,\n" +"known as the _module tree_." +msgstr "在前面我们提到了,_src/lib.cairo_ 叫做 crate 根。之所以这样叫它是因为这个文件的内容在 crate 模块结构的根组成了一个名为 crate 的模块,该结构被称为 模块树( _module tree_ )。" -#: src/ch06-05-separating-modules-into-different-files.md:49 -msgid "" -"Note that you only need to load a file using a `mod` declaration _once_ in your\n" -"module tree. Once the compiler knows the file is part of the project (and knows\n" -"where in the module tree the code resides because of where you’ve put the `mod`\n" -"statement), other files in your project should refer to the loaded file’s code\n" -"using a path to where it was declared, as covered in the [“Paths for Referring\n" -"to an Item in the Module Tree”][paths] section. In other words,\n" -"`mod` is _not_ an “include” operation that you may have seen in other\n" -"programming languages." -msgstr "" -"注意你只需在模块树中的某处使用一次 mod 声明就可以加载这个文件。\n" -"一旦编译器知道了这个文件是项目的一部分(并且通过 mod 语句的位置知道了代码在模块树中的位置),项目中的其他文件应该使用其所声明的位置的路径来引用那个文件的代码,\n" -"这在 [引用模块项目的路径](ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md)部分有讲到。\n" -"换句话说,mod 不是 你可能会在其他编程语言中看到的 “include” 操作。" +#: src/ch06-02-defining-modules-to-control-scope.md:171 +msgid "Listing 6-2 shows the module tree for the structure in Listing 6-1." +msgstr "示例6-2显示了示例6-1中结构的模块树。" -#: src/ch06-05-separating-modules-into-different-files.md:58 +#: src/ch06-02-defining-modules-to-control-scope.md:173 msgid "" -"Next, we’ll extract the `hosting` module to its own file. The process is a bit\n" -"different because `hosting` is a child module of `front_of_house`, not of the\n" -"root module. We’ll place the file for `hosting` in a new directory that will be\n" -"named for its ancestors in the module tree, in this case _src/front_of_house/_." +"```text\n" +"restaurant\n" +" └── front_of_house\n" +" ├── hosting\n" +" │ ├── add_to_waitlist\n" +" │ └── seat_at_table\n" +" └── serving\n" +" ├── take_order\n" +" ├── serve_order\n" +" └── take_payment\n" +"```" msgstr "" -"接下来我们同样将 `hosting` 模块提取到自己的文件中。这个过程会有所不同,因为 `hosting` 是 `front_of_house` 的子模块而不是根模块。我们将 `hosting` 的文件放在与模块树中它的父级模块同名的" -"目录中,在这里是 _src/front_of_house/_ 。" +"```text\n" +"restaurant\n" +" └── front_of_house\n" +" ├── hosting\n" +" │ ├── add_to_waitlist\n" +" │ └── seat_at_table\n" +" └── serving\n" +" ├── take_order\n" +" ├── serve_order\n" +" └── take_payment\n" +"```" -#: src/ch06-05-separating-modules-into-different-files.md:63 +#: src/ch06-02-defining-modules-to-control-scope.md:185 msgid "" -"To start moving `hosting`, we change _src/front_of_house.cairo_ to contain only the\n" -"declaration of the `hosting` module:" -msgstr "为了移动 `hosting`,修改 _src/front_of_house.cairo_ 使之仅包含 `hosting` 模块的声明:" +"Listing 6-2: The module tree for the code in Listing\n" +"6-1" +msgstr "示例6-2:示例6-1中代码的模块树" -#: src/ch06-05-separating-modules-into-different-files.md:68 +#: src/ch06-02-defining-modules-to-control-scope.md:188 msgid "" -"```rust\n" -"mod hosting;\n" -"```" +"This tree shows how some of the modules nest inside one another; for example,\n" +"`hosting` nests inside `front_of_house`. The tree also shows that some modules\n" +"are _siblings_ to each other, meaning they’re defined in the same module;\n" +"`hosting` and `serving` are siblings defined within `front_of_house`. If module\n" +"A is contained inside module B, we say that module A is the _child_ of module B\n" +"and that module B is the _parent_ of module A. Notice that the entire module\n" +"tree is rooted under the explicit name of the crate `restaurant`." msgstr "" -"```rust\n" -"mod hosting;\n" -"```" +"这个树展示了一些模块是如何被嵌入到另一个模块的(例如,`hosting` 嵌套在 `front_of_house` 中)。这个树还展示了一些模块是互为 兄弟( _siblings_ )的,这意味着它们定义在同一模块中" +"( `hosting` 和 `serving` 被一起定义在 _front_of_house_ 中)。继续沿用家庭关系的比喻,如果一个模块 A 被包含在模块 B 中,我们将模块 A 称为模块 B 的 子( _child_ ),模块 B 则是模块 A " +"的 父( _parent_ )。注意,整个模块树都植根于名为 `restaurant` crate的隐式模块下。" -#: src/ch06-05-separating-modules-into-different-files.md:72 +#: src/ch06-02-defining-modules-to-control-scope.md:196 msgid "" -"Then we create a _src/front_of_house_ directory and a file _hosting.cairo_ to\n" -"contain the definitions made in the `hosting` module:" -msgstr "接着我们创建一个 _src/front_of_house_ 目录和一个包含 `hosting` 模块定义的 _hosting.cairo_ 文件:" +"The module tree might remind you of the filesystem’s directory tree on your\n" +"computer; this is a very apt comparison! Just like directories in a filesystem,\n" +"you use modules to organize your code. And just like files in a directory, we\n" +"need a way to find our modules." +msgstr "这个模块树可能会令你想起电脑上文件系统的目录树;这是一个非常恰当的类比!就像文件系统的目录,你可以使用模块来组织你的代码。并且,就像目录中的文件,我们需要一种方法来找到模块。" -#: src/ch06-05-separating-modules-into-different-files.md:75 -msgid "Filename: src/front_of_house/hosting.cairo" -msgstr "文件名: src/front_of_house/hosting.cairo" +#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:1 +msgid "## Paths for Referring to an Item in the Module Tree" +msgstr "## 引用模块项目的路径" -#: src/ch06-05-separating-modules-into-different-files.md:77 -msgid "" -"```rust\n" -"pub fn add_to_waitlist() {}\n" -"```" -msgstr "" -"```rust\n" -"pub fn add_to_waitlist() {}\n" -"```" +#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:3 +msgid "To show Cairo where to find an item in a module tree, we use a path in the same way we use a path when navigating a filesystem. To call a function, we need to know its path." +msgstr "为了告诉Cairo如何在模块树中找到一个项目,我们使用路径的方式,就像在文件系统使用路径一样。为了调用一个函数,我们需要知道它的路径。" -#: src/ch06-05-separating-modules-into-different-files.md:81 +#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:5 +msgid "A path can take two forms:" +msgstr "路径可以有两种形式:" + +#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:7 msgid "" -"If we instead put _hosting.cairo_ in the _src_ directory, the compiler would\n" -"expect the _hosting.cairo_ code to be in a `hosting` module declared in the crate\n" -"root, and not declared as a child of the `front_of_house` module. The\n" -"compiler’s rules for which files to check for which modules’ code means the\n" -"directories and files more closely match the module tree." +"- An _absolute path_ is the full path starting from a crate root. The absolute path begins with the crate name.\n" +"- A _relative path_ starts from the current module.\n" +"\n" +" Both absolute and relative paths are followed by one or more identifiers\n" +" separated by double colons (`::`)." msgstr "" -"如果将 _hosting.cairo_ 放在 _src_ 目录,编译器会认为 `hosting` 模块中的 _hosting.cairo_ 的代码声明于 crate 根,而不是声明为 `front_of_house` 的子模块。\n" -"编译器所遵循的哪些文件对应哪些模块的代码的规则,意味着目录和文件更接近于模块树。" +"- 绝对路径( _absolute path_ )是以 crate 根(root)开头的全路径。绝对路径以 crate 名开头。\n" +"- 相对路径( _relative path_ )是从当前模块开始的。\n" +"\n" +"绝对路径和相对路径后面都有一个或多个标识符用双冒号(`::`)分开。" -#: src/ch06-05-separating-modules-into-different-files.md:87 +#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:13 msgid "" -"We’ve moved each module’s code to a separate file, and the module tree remains\n" -"the same. The function calls in `eat_at_restaurant` will work without any\n" -"modification, even though the definitions live in different files. This\n" -"technique lets you move modules to new files as they grow in size." -msgstr "" -"我们将各个模块的代码移动到独立文件了,同时模块树依旧相同。\n" -"`eat_at_restaurant` 中的函数调用也无需修改继续保持有效,即便其定义存在于不同的文件中。\n" -"这个技巧让你可以在模块代码增长时,将它们移动到新文件中。" - -#: src/ch06-05-separating-modules-into-different-files.md:92 -msgid "" -"Note that the `use restaurant::front_of_house::hosting` statement in\n" -"_src/lib.cairo_ also hasn’t changed, nor does `use` have any impact on what files\n" -"are compiled as part of the crate. The `mod` keyword declares modules, and Cairo\n" -"looks in a file with the same name as the module for the code that goes into\n" -"that module." -msgstr "" -"注意,_src/lib.cairo_中的 `use restaurant::front_of_house::hosting` 语句是没有改变的,在文件作为 crate 的一部分而编译时,`use` 不会有任何影响。\n" -"`mod` 关键字声明了模块,Cairo 会在与模块同名的文件中查找模块的代码。" - -#: src/ch06-05-separating-modules-into-different-files.md:100 -msgid "" -"Cairo lets you split a package into multiple crates and a crate into modules\n" -"so you can refer to items defined in one module from another module. You can do\n" -"this by specifying absolute or relative paths. These paths can be brought into\n" -"scope with a `use` statement so you can use a shorter path for multiple uses of\n" -"the item in that scope. Module code is public by default." -msgstr "" -"Cairo 提供了将包分成多个 crate,将 crate 分成模块,以及通过指定绝对或相对路径从一个模块引用另一个模块中定义的项的方式。\n" -"你可以通过使用 `use` 语句将路径引入作用域,这样在多次使用时可以使用更短的路径。模块定义的代码默认是公有的。" - -#: src/ch07-00-generic-types-and-traits.md:1 -msgid "# Generic Types and Traits" -msgstr "# 泛型和Trait" - -#: src/ch07-00-generic-types-and-traits.md:3 -msgid "" -"Every programming language has tools for effectively handling the duplication of concepts. In Cairo, one such tool is generics: abstract stand-ins for concrete types or other " -"properties. We can express the behaviour of generics or how they relate to other generics without knowing what will be in their place when compiling and running the code." -msgstr "" -"每一个编程语言都有高效处理重复概念的工具。在 Cairo 中其工具之一就是 泛型(generics)。泛型是具体类型或其他属性的抽象替代。我们可以表达泛型的属性,比如他们的行为或如何与其他泛型相关" -"联,而不需要在编写和编译代码时知道他们在这里实际上代表什么。" - -#: src/ch07-00-generic-types-and-traits.md:5 -msgid "Functions, structs, enums and traits can incorporate generic types as part of their definition instead of a concrete types like `u32` or `ContractAddress`." -msgstr "函数、结构体、枚举和特征可以将泛型作为其定义的一部分,而不是像`u32`或`ContractAddress`这样的具体类型。" - -#: src/ch07-00-generic-types-and-traits.md:7 -msgid "Generics allow us to replace specific types with a placeholder that represents multiple types to remove code duplication." -msgstr "泛型允许我们用一个代表多种类型的占位符来替换特定的类型,以消除代码的重复。" - -#: src/ch07-00-generic-types-and-traits.md:9 -msgid "" -"For each concrete type that replaces a generic type the compiler creates a new definition, reducing development time for the programmer, but code duplication at compile level still " -"exists. This may be of importance if you are writing Starknet contracts and using a generic for multiple types which will cause contract size to increment." -msgstr "" -"对于每一个取代泛型的具体类型,编译器都会创建一个新的定义,从而减少程序员的开发时间,但在编译层面上的代码重复仍然存在。如果你正在编写Starknet合约,并为多个类型使用一个泛型,这将导致合" -"约大小的增加,这可能是很重要的。" - -#: src/ch07-00-generic-types-and-traits.md:11 -msgid "" -"Then you’ll learn how to use traits to define behavior in a generic way. You can combine traits with generic types to constrain a generic type to accept only those types that have a " -"particular behavior, as opposed to just any type." -msgstr "之后你将学习 trait,这是一个定义泛型行为的方法。trait 可以与泛型结合来将泛型限制为只接受拥有特定行为的类型,而不是任意类型。" - -#: src/ch07-01-generic-data-types.md:1 -msgid "# Generic Data Types" -msgstr "# 泛型数据类型" - -#: src/ch07-01-generic-data-types.md:3 -msgid "" -"We use generics to create definitions for item declarations, such as structs and functions, which we can then use with many different concrete data types. In Cairo we can use " -"generics when defining functions, structs, enums, traits, implementations and methods! In this chapter we are going to take a look at how to effectively use generic types with all of " -"them." -msgstr "" -"我们可以使用泛型为像函数签名或结构体这样的项创建定义,这样它们就可以用于多种不同的具体数据类型。在Cairo中,我们可以在定义函数、结构、枚举、特征、实现和方法时使用泛型!在本章中,我们将" -"看看在这些被提到的领域中如何有效地使用泛型。" - -#: src/ch07-01-generic-data-types.md:5 -msgid "## Generic Functions" -msgstr "## 在函数定义中使用泛型" - -#: src/ch07-01-generic-data-types.md:7 -msgid "" -"When defining a function that uses generics, we place the generics in the function signature, where we would usually specify the data types of the parameter and return value. For " -"example, imagine we want to create a function which given two `Array` of items, will return the largest one. If we need to perform this operation for lists of different types, then " -"we would have to redefine the function each time. Luckily we can implement the function once using generics and move on to other tasks." +"To illustrate this notion let's take back our example Listing 6-1 for the restaurant we used in the last chapter. We have a crate named `restaurant` in which we have a module named " +"`front_of_house` that contains a module named `hosting`. The `hosting` module contains a function named `add_to_waitlist`. We want to call the `add_to_waitlist` function from the " +"`eat_at_restaurant` function. We need to tell Cairo the path to the `add_to_waitlist` function so it can find it." msgstr "" -"当定义一个使用泛型的函数时,本来在函数签名中指定参数和返回值的类型的地方,会改用泛型来表示。例如,假设我们想创建一个函数,给定两个 `Array` 项,函数将返回最大的一个。如果我们需要对不同" -"类型的列表进行这种操作,那么我们就必须每次都重新定义这个函数。幸运的是,我们可以使用泛型来实现这个函数,然后继续完成其他任务。" +"为了说明这个概念,让我们回到我们在上一章使用的餐厅的例子示例6-1。我们有一个名为 `restaurant`的crate,其中有一个名为`front_of_house`的模块,包含一个名为 `hosting`的模块。`hosting`模块" +"包含一个名为 `add_to_waitlist`的函数。我们想从`eat_at_restaurant`函数中调用`add_to_waitlist`函数。我们需要告诉Cairo `add_to_waitlist`函数的路径,以便它能找到它。" -#: src/ch07-01-generic-data-types.md:9 +#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:17 msgid "" -"```rust,does_not_compile\n" -"// This code does not compile!\n" +"```rust,noplayground\n" +"//TAG: does_not_compile\n" +"mod front_of_house {\n" +" mod hosting {\n" +" fn add_to_waitlist() {}\n" "\n" -"use array::ArrayTrait;\n" +" fn seat_at_table() {}\n" +" }\n" "\n" -"// Specify generic type T between the angulars\n" -"fn largest_list(l1: Array, l2: Array) -> Array {\n" -" if l1.len() > l2.len() {\n" -" l1\n" -" } else {\n" -" l2\n" +" mod serving {\n" +" fn take_order() {}\n" +"\n" +" fn serve_order() {}\n" +"\n" +" fn take_payment() {}\n" " }\n" "}\n" "\n" -"fn main() {\n" -" let mut l1 = ArrayTrait::new();\n" -" let mut l2 = ArrayTrait::new();\n" -"\n" -" l1.append(1);\n" -" l1.append(2);\n" "\n" -" l2.append(3);\n" -" l2.append(4);\n" -" l2.append(5);\n" +"fn eat_at_restaurant() {\n" +" // Absolute path\n" +" restaurant::front_of_house::hosting::add_to_waitlist(); // ✅ Compiles\n" "\n" -" // There is no need to specify the concrete type of T because\n" -" // it is inferred by the compiler\n" -" let l3 = largest_list(l1, l2);\n" +" // Relative path\n" +" front_of_house::hosting::add_to_waitlist(); // ✅ Compiles\n" "}\n" "```" msgstr "" -"```rust,does_not_compile\n" -"// This code does not compile!\n" +"```rust,noplayground\n" +"//TAG: does_not_compile\n" +"mod front_of_house {\n" +" mod hosting {\n" +" fn add_to_waitlist() {}\n" "\n" -"use array::ArrayTrait;\n" +" fn seat_at_table() {}\n" +" }\n" "\n" -"// Specify generic type T between the angulars\n" -"fn largest_list(l1: Array, l2: Array) -> Array {\n" -" if l1.len() > l2.len() {\n" -" l1\n" -" } else {\n" -" l2\n" +" mod serving {\n" +" fn take_order() {}\n" +"\n" +" fn serve_order() {}\n" +"\n" +" fn take_payment() {}\n" " }\n" "}\n" "\n" -"fn main() {\n" -" let mut l1 = ArrayTrait::new();\n" -" let mut l2 = ArrayTrait::new();\n" -"\n" -" l1.append(1);\n" -" l1.append(2);\n" "\n" -" l2.append(3);\n" -" l2.append(4);\n" -" l2.append(5);\n" +"fn eat_at_restaurant() {\n" +" // Absolute path\n" +" restaurant::front_of_house::hosting::add_to_waitlist(); // ✅ Compiles\n" "\n" -" // There is no need to specify the concrete type of T because\n" -" // it is inferred by the compiler\n" -" let l3 = largest_list(l1, l2);\n" +" // Relative path\n" +" front_of_house::hosting::add_to_waitlist(); // ✅ Compiles\n" "}\n" "```" -#: src/ch07-01-generic-data-types.md:40 +#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:45 +msgid "Listing 6-3: Calling the `add_to_waitlist` function using absolute and relative paths" +msgstr "示例6-3:使用绝对和相对路径调用`add_to_waitlist`函数" + +#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:47 msgid "" -"The `largest_list` function compares two lists of the same type and returns the one with more elements and drops the other. If you compile the previous code, you will notice that it " -"will fail with an error saying that there are no traits defined for dropping an array of a generic type. This happens because the compiler has no way to guarantee that an `Array` " -"is droppable when executing the `main` function. In order to drop an array of `T`, the compiler must first know how to drop `T`. This can be fixed by specifying in the function " -"signature of `largest_list` that `T` must implement the drop trait. The correct function definition of `largest_list` is as follows:" +"The first time we call the `add_to_waitlist` function in `eat_at_restaurant`,\n" +"we use an absolute path. The `add_to_waitlist` function is defined in the same\n" +"crate as `eat_at_restaurant`. In Cairo, absolute paths start from the crate root, which you need to refer to by using the crate name." msgstr "" -"名为`largest_list`函数比较了两个相同类型的列表,返回具有更多元素的那一个,并丢弃另一个。如果你编译前面的代码,你会注意到它会出错,说没有为丢弃一个泛型的数组定义trait。这是因为编译器没" -"有办法保证在执行`main`函数时,`Array`是可以丢弃的。为了丢弃一个`T`的数组,编译器必须首先知道如何丢弃`T`。可以通过在`largest_list`的函数签名中规定`T`必须实现drop trait来解决这个问" -"题。`largest_list`的正确函数定义如下:" +"我们第一次调用`eat_at_restaurant`中的`add_to_waitlist`函数时、使用了一个绝对路径。`add_to_waitlist`函数与`eat_at_restaurant`定义在同一个crate中。在Cairo中,绝对路径从crate根开始,你需" +"要用crate的名字来引用它。" -#: src/ch07-01-generic-data-types.md:42 +#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:51 msgid "" -"```rust\n" -"fn largest_list>(l1: Array, l2: Array) -> Array {\n" -" if l1.len() > l2.len() {\n" -" l1\n" -" } else {\n" -" l2\n" +"The second time we call `add_to_waitlist`, we use a relative path. The path starts with `front_of_house`, the name of the module\n" +"defined at the same level of the module tree as `eat_at_restaurant`. Here the\n" +"filesystem equivalent would be using the path\n" +"`./front_of_house/hosting/add_to_waitlist`. Starting with a module name means\n" +"that the path is relative to the current module." +msgstr "" +"第二次我们调用 add_to_waitlist时,使用的是相对路径。这个路径以 `front_of_house` 为起始,这个模块在模块树中,与 `eat_at_restaurant` 定义在同一层级。\n" +"与之等价的文件系统路径就是 `./front_of_house/hosting/add_to_waitlist`。以模块名开头意味着该路径是相对路径。" + +#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:57 +msgid "### Starting Relative Paths with `super`" +msgstr "### 使用 `super` 起始的相对路径" + +#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:59 +msgid "" +"Choosing whether to use a `super` or not is a decision you’ll make\n" +"based on your project, and depends on whether you’re more likely to move item\n" +"definition code separately from or together with the code that uses the item." +msgstr "" +"选择是否使用 `super`将根据你的项目具体情况来决定。\n" +"并取决于你是否更有可能将项目定义的代码是与使用该项目的代码分开还是放在一起。" + +#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:65 +msgid "" +"```rust,noplayground\n" +"fn deliver_order() {}\n" +"\n" +"mod back_of_house {\n" +" fn fix_incorrect_order() {\n" +" cook_order();\n" +" super::deliver_order();\n" " }\n" +"\n" +" fn cook_order() {}\n" "}\n" "```" msgstr "" -"```rust\n" -"fn largest_list>(l1: Array, l2: Array) -> Array {\n" -" if l1.len() > l2.len() {\n" -" l1\n" -" } else {\n" -" l2\n" +"```rust,noplayground\n" +"fn deliver_order() {}\n" +"\n" +"mod back_of_house {\n" +" fn fix_incorrect_order() {\n" +" cook_order();\n" +" super::deliver_order();\n" " }\n" +"\n" +" fn cook_order() {}\n" "}\n" "```" -#: src/ch07-01-generic-data-types.md:52 -msgid "" -"The new `largest_list` function includes in its definition the requirement that whatever generic type is placed there, it must be droppable. The `main` function remains unchanged, " -"the compiler is smart enough to deduct which concrete type is being used and if it implements the `Drop` trait." -msgstr "" -"新的`largest_list`函数在其定义中包含了一个要求,即无论什么泛型被放在那里,它都必须是可丢弃的。`main`函数保持不变,编译器足够聪明,可以得出正在使用的具体类型以及它是否实现了`Drop`这个" -"trait。" +#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:78 +msgid "Listing 6-4: Calling a function using a relative path starting with super" +msgstr "示例6-4:使用以super开头的相对路径调用一个函数" -#: src/ch07-01-generic-data-types.md:54 -msgid "### Constraints for Generic Types" -msgstr "### 范型的约束" +#: src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md:80 +msgid "Here you can see directly that you access a parent's module easily using `super`, which wasn't the case previously." +msgstr "在这里你可以直接看到,和之前的例子不同,在这你可以使用`super`轻松地访问父级的模块。" -#: src/ch07-01-generic-data-types.md:56 -msgid "" -"When defining generic types, it is useful to have information about them. Knowing which traits a generic type implements allow us to use them more effectively in a functions logic at " -"the cost of constraining the generic types that can be used with the function. We saw an example of this previously by adding the `TDrop` implementation as part of the generic " -"arguments of `largest_list`. While `TDrop` was added to satisfy the compilers requirements, we can also add constraints to benefit our function logic." -msgstr "" -"在定义泛型的时候,掌握关于它们的信息是很有用的。知道一个泛型实现了哪些trait,可以让我们在函数逻辑中更有效地使用它们,代价是限制了可以与函数一起使用的泛型。我们之前看到了一个例子,就是" -"将`TDrop`的实现作为`largest_list`的泛型参数的一部分。虽然 `TDrop`是为了满足编译器的要求而添加的,但我们也可以添加一些约束条件以有利于我们的函数逻辑。" +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:1 +msgid "# Bringing Paths into Scope with the `use` Keyword" +msgstr "# 使用 `use` 关键字将路径引入作用域" -#: src/ch07-01-generic-data-types.md:58 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:3 msgid "" -"Imagine that we want, given a list of elements of some generic type `T`, find the smallest element among them. Initially, we know that for an element of type `T` to be comparable, it " -"must implement the `PartialOrd` trait. The resulting function would be:" -msgstr "想象一下,我们想,给定一个通用类型`T`的元素列表,找到其中最小的元素。首先,我们知道要使一个`T`类型的元素具有可比性,它必须实现`PartialOrd`这个trait。由此产生的函数将是:" +"Having to write out the paths to call functions can feel inconvenient and repetitive. Fortunately, there’s a way to simplify this process: we can create a shortcut to a path with the " +"`use` keyword once, and then use the shorter name everywhere else in the scope." +msgstr "不得不编写路径来调用函数显得不便且重复。幸运的是,有一种方法可以简化这个过程:我们可以用`use`关键字创建一个路径的快捷方式,然后在作用域内的其他地方使用这个较短的名字。" -#: src/ch07-01-generic-data-types.md:60 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:5 msgid "" -"```rust,does_not_compile\n" -"// This code does not compile!\n" -"use array::ArrayTrait;\n" -"\n" -"// Given a list of T get the smallest one.\n" -"// The PartialOrd trait implements comparison operations for T\n" -"fn smallest_element>(list: @Array) -> T {\n" -" // This represents the smallest element through the iteration\n" -" // Notice that we use the desnap (*) operator\n" -" let mut smallest = *list[0];\n" -"\n" -" // The index we will use to move through the list\n" -" let mut index = 1;\n" -"\n" -" // Iterate through the whole list storing the smallest\n" -" loop {\n" -" if index >= list.len() {\n" -" break smallest;\n" -" }\n" -" if *list[index] < smallest {\n" -" smallest = *list[index];\n" -" }\n" -" index = index + 1;\n" +"In Listing 6-5, we bring the `restaurant::front_of_house::hosting` module into the\n" +"scope of the `eat_at_restaurant` function so we only have to specify\n" +"`hosting::add_to_waitlist` to call the `add_to_waitlist` function in\n" +"`eat_at_restaurant`." +msgstr "在示例6-5中,我们把`restaurant::front_of_house::hosting`模块带入到作用域内,所以我们只需要指定 `hosting::add_to_waitlist` 来调用`eat_at_restaurant`中的`add_to_waitlist` 函数。" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:12 +msgid "" +"```rust\n" +"//TAG: does_not_compile\n" +"mod front_of_house {\n" +" mod hosting {\n" +" fn add_to_waitlist() {}\n" " }\n" "}\n" "\n" -"fn main() {\n" -" let mut list: Array = ArrayTrait::new();\n" -" list.append(5);\n" -" list.append(3);\n" -" list.append(10);\n" +"use restaurant::front_of_house::hosting;\n" "\n" -" // We need to specify that we are passing a snapshot of `list` as an argument\n" -" let s = smallest_element(@list);\n" -" assert(s == 3, 0);\n" +"fn eat_at_restaurant() {\n" +" hosting::add_to_waitlist(); // ✅ Shorter path\n" "}\n" "```" msgstr "" -"```rust,does_not_compile\n" -"// This code does not compile!\n" -"use array::ArrayTrait;\n" -"\n" -"// Given a list of T get the smallest one.\n" -"// The PartialOrd trait implements comparison operations for T\n" -"fn smallest_element>(list: @Array) -> T {\n" -" // This represents the smallest element through the iteration\n" -" // Notice that we use the desnap (*) operator\n" -" let mut smallest = *list[0];\n" -"\n" -" // The index we will use to move through the list\n" -" let mut index = 1;\n" -"\n" -" // Iterate through the whole list storing the smallest\n" -" loop {\n" -" if index >= list.len() {\n" -" break smallest;\n" -" }\n" -" if *list[index] < smallest {\n" -" smallest = *list[index];\n" -" }\n" -" index = index + 1;\n" +"```rust\n" +"//TAG: does_not_compile\n" +"mod front_of_house {\n" +" mod hosting {\n" +" fn add_to_waitlist() {}\n" " }\n" "}\n" "\n" -"fn main() {\n" -" let mut list: Array = ArrayTrait::new();\n" -" list.append(5);\n" -" list.append(3);\n" -" list.append(10);\n" +"use restaurant::front_of_house::hosting;\n" "\n" -" // We need to specify that we are passing a snapshot of `list` as an argument\n" -" let s = smallest_element(@list);\n" -" assert(s == 3, 0);\n" +"fn eat_at_restaurant() {\n" +" hosting::add_to_waitlist(); // ✅ Shorter path\n" "}\n" "```" -#: src/ch07-01-generic-data-types.md:98 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:27 msgid "" -"The `smallest_element` function uses a generic type `T` that implements the `PartialOrd` trait, takes a snapshot of an `Array` as a parameter and returns a copy of the smallest " -"element. Because the parameter is of type `@Array`, we no longer need to drop it at the end of the execution and so we don't require to implement the `Drop` trait for `T` as well. " -"Why it does not compile then?" +"Listing 6-5: Bringing a module into scope with\n" +"`use`" msgstr "" -"名为`smallest_element`函数使用一个实现了`PartialOrd`的trait的通用类型`T`,接收一个`Array`的快照作为参数并返回其中最小元素的拷贝。因为参数是`@Array`的类型,我们不再需要在执行结束" -"时丢弃它,所以我们不需要为`T`实现`Drop`特性。那为什么它不能编译呢?" +"示例 6-5: 用 \"使用 \"将一个模块带入范围。\n" +"使用" -#: src/ch07-01-generic-data-types.md:100 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:30 msgid "" -"When indexing on `list`, the value results in a snap of the indexed element, unless `PartialOrd` is implemented for `@T` we need to desnap the element using `*`. The `*` operation " -"requires a copy from `@T` to`T`, which means that `T` needs to implement the `Copy` trait. After copying an element of type `@T` to `T`, there are now variables with type `T` that " -"need to be dropped, requiring for `T` to implement the `Drop` trait as well. We must then add both `Drop` and `Copy` traits implementation for the function to be correct. After " -"updating the`smallest_element` function the resulting code would be:" +"Adding use and a path in a scope is similar to creating a symbolic link in the filesystem. By adding `use restaurant::front_of_house::hosting` in the crate root, hosting is now a " +"valid name in that scope, just as though the `hosting` module had been defined in the crate root." msgstr "" -"当对`list`进行索引时,其结果是对被索引的元素进行快照,除非`@T`实现了`PartialOrd`,否则我们需要使用 `*` 对元素进行解快照。`*` 操作需要从`@T`复制到`T`,这意味着`T`需要实现`Copy`特性。在" -"复制了一个`@T`类型的元素到`T`之后,现在有`T`类型的变量需要被删除,这就要求`T`也要实现`Drop`特性。然后我们必须同时添加`Drop`和`Copy`特性的实现,以使该函数正确。在更新`smallest_element`" -"函数后,产生的代码将是:" +"在作用域中添加 use 和路径类似于在文件系统中创建一个软连接(符号连接,symbolic link)。通过在 crate 根中添加 `use restaurant::front_of_house::hosting`,hosting 现在是该作用域中的一个有" +"效名称,就像在 crate 根中定义了`hosting`模块一样。" -#: src/ch07-01-generic-data-types.md:102 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:32 msgid "" -"```rs\n" -"fn smallest_element, impl TCopy: Copy, impl TDrop: Drop>(list: @Array) -> T {\n" -" let mut smallest = *list[0];\n" -" let mut index = 1;\n" -" loop {\n" -" if index >= list.len() {\n" -" break smallest;\n" -" }\n" -" if *list[index] < smallest {\n" -" smallest = *list[index];\n" -" }\n" -" index = index + 1;\n" +"Note that `use` only creates the shortcut for the particular scope in which the `use` occurs. Listing 6-6 moves the `eat_at_restaurant` function into a new\n" +"child module named `customer`, which is then a different scope than the `use`\n" +"statement, so the function body won’t compile:" +msgstr "注意 `use` 只能创建 `use` 所在的特定作用域内的短路径。示例 6-6 将 `eat_at_restaurant` 函数移到一个新的子模块中,这又是一个不同于 `use` 语句的作用域,所以函数体不能编译:" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:38 +msgid "" +"```rust\n" +"//TAG: does_not_compile\n" +"mod front_of_house {\n" +" mod hosting {\n" +" fn add_to_waitlist() {}\n" +" }\n" +"}\n" +"\n" +"use restaurant::front_of_house::hosting;\n" +"\n" +"mod customer {\n" +" fn eat_at_restaurant() {\n" +" hosting::add_to_waitlist();\n" " }\n" "}\n" "```" msgstr "" -"```rs\n" -"fn smallest_element, impl TCopy: Copy, impl TDrop: Drop>(list: @Array) -> T {\n" -" let mut smallest = *list[0];\n" -" let mut index = 1;\n" -" loop {\n" -" if index >= list.len() {\n" -" break smallest;\n" -" }\n" -" if *list[index] < smallest {\n" -" smallest = *list[index];\n" -" }\n" -" index = index + 1;\n" +"```rust\n" +"//TAG: does_not_compile\n" +"mod front_of_house {\n" +" mod hosting {\n" +" fn add_to_waitlist() {}\n" +" }\n" +"}\n" +"\n" +"use restaurant::front_of_house::hosting;\n" +"\n" +"mod customer {\n" +" fn eat_at_restaurant() {\n" +" hosting::add_to_waitlist();\n" " }\n" "}\n" "```" -#: src/ch07-01-generic-data-types.md:118 -msgid "## Structs" -msgstr "## 结构体定义中的泛型" +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:55 +msgid "" +"Listing 6-6: A `use` statement only applies in the scope\n" +"it’s in" +msgstr "示例6-6:一个 `use`语句只适用于它所在的作用域" -#: src/ch07-01-generic-data-types.md:120 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:58 msgid "" -"We can also define structs to use a generic type parameter for one or more fields using the `<>` syntax, similar to function definitions. First we declare the name of the type " -"parameter inside the angle brackets just after the name of the struct. Then we use the generic type in the struct definition where we would otherwise specify concrete data types. The " -"next code example shows the definition `Wallet` which has a `balance` field of type `T`." -msgstr "" -"我们也可以使用类似于函数定义的`<>` 语法来定义结构,它包含一个或多个泛型参数类型字段。首先,必须在结构体名称后面的尖括号中声明泛型参数的名称,接着在结构体定义中可以指定具体数据类型的位" -"置使用泛型类型。下一个代码示例显示了 `Wallet` 的定义,它有一个 `balance`字段,类型为 `T`。" +"The compiler error shows that the shortcut no longer applies within the\n" +"`customer` module:" +msgstr "编译器错误显示短路径不在适用于 `customer` 模块中:" -#: src/ch07-01-generic-data-types.md:122 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:61 msgid "" -"```rust,does_not_compile\n" -"// This code does not compile!\n" -"\n" -"#[derive(Drop)]\n" -"struct Wallet {\n" -" balance: T\n" -"}\n" -"\n" -"\n" -"fn main() {\n" -" let w = Wallet { balance: 3 };\n" -"}\n" +"```shell\n" +"❯ scarb build\n" +"error: Identifier not found.\n" +" --> lib.cairo:11:9\n" +" hosting::add_to_waitlist();\n" +" ^*****^\n" "```" msgstr "" -"```rust,does_not_compile\n" -"// This code does not compile!\n" -"\n" -"#[derive(Drop)]\n" -"struct Wallet {\n" -" balance: T\n" -"}\n" -"\n" -"\n" -"fn main() {\n" -" let w = Wallet { balance: 3 };\n" -"}\n" +"```shell\n" +"❯ scarb build\n" +"error: Identifier not found.\n" +" --> lib.cairo:11:9\n" +" hosting::add_to_waitlist();\n" +" ^*****^\n" "```" -#: src/ch07-01-generic-data-types.md:136 -msgid "Compiling the above code would error due to the `derive` macro not working well with generics. When using generic types is best to directly write the traits you want to use:" -msgstr "由于`derive`宏在泛型中不能正常工作,编译上述代码会出错。当使用泛型时,最好直接编写你想使用的特性:" +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:69 +msgid "## Creating Idiomatic `use` Paths" +msgstr "## 创建惯用的 `use` 路径" -#: src/ch07-01-generic-data-types.md:138 -msgid "" -msgstr "" +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:71 +msgid "" +"In Listing 6-5, you might have wondered why we specified `use\n" +"restaurant::front_of_house::hosting` and then called `hosting::add_to_waitlist` in\n" +"`eat_at_restaurant` rather than specifying the `use` path all the way out to\n" +"the `add_to_waitlist` function to achieve the same result, as in Listing 6-7." +msgstr "" +"在示例6-5中,你可能想知道为什么我们指定`restaurant::front_of_house::hosting`,然后调用`eat_at_restaurant`中的`hosting::add_to_waitlist`,而不是通过指定一直到\n" +"`add_to_waitlist`函数的 `use` 路径来得到相同的结果,如示例6-7。" -#: src/ch07-01-generic-data-types.md:140 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:78 msgid "" "```rust\n" -"struct Wallet {\n" -" balance: T\n" +"//TAG: does_not_compile\n" +"mod front_of_house {\n" +" mod hosting {\n" +" fn add_to_waitlist() {}\n" +" }\n" "}\n" "\n" -"impl WalletDrop> of Drop>;\n" +"use restaurant::front_of_house::hosting::add_to_waitlist;\n" "\n" -"fn main() {\n" -" let w = Wallet { balance: 3 };\n" +"fn eat_at_restaurant() {\n" +" add_to_waitlist();\n" "}\n" "```" msgstr "" "```rust\n" -"struct Wallet {\n" -" balance: T\n" +"//TAG: does_not_compile\n" +"mod front_of_house {\n" +" mod hosting {\n" +" fn add_to_waitlist() {}\n" +" }\n" "}\n" "\n" -"impl WalletDrop> of Drop>;\n" +"use restaurant::front_of_house::hosting::add_to_waitlist;\n" "\n" -"fn main() {\n" -" let w = Wallet { balance: 3 };\n" +"fn eat_at_restaurant() {\n" +" add_to_waitlist();\n" "}\n" "```" -#: src/ch07-01-generic-data-types.md:152 -msgid "" -"We avoid using the `derive` macro for `Drop` implementation of `Wallet` and instead define our own `WalletDrop` implementation. Notice that we must define, just like functions, an " -"additional generic type for `WalletDrop` saying that `T` implements the `Drop` trait as well. We are basically saying that the struct `Wallet` is droppable as long as `T` is also " -"droppable." -msgstr "" -"应该避免使用`derive`宏来实现`Wallet`的`Drop`,而是定义我们自己的`WalletDrop`实现。注意,我们必须像定义函数一样,为`WalletDrop`定义一个额外的泛型`T`并且也实现了`Drop`特性。这基本上是在" -"说,只要`T`也是可丢弃的,那么`钱包`这个结构就是可丢弃的。" - -#: src/ch07-01-generic-data-types.md:154 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:93 msgid "" -"Finally, if we want to add a field to `Wallet` representing its Cairo address and we want that field to be different than `T` but generic as well, we can simply add another generic " -"type between the `<>`:" -msgstr "最后,如果我们想给`Wallet`添加一个代表其Cairo地址的字段,并且我们希望这个字段是与`T`不同的另一个泛型,我们可以简单地在`<>`之间添加另一个泛型:" +"Listing 6-7: Bringing the `add_to_waitlist` function\n" +"into scope with `use`, which is unidiomatic" +msgstr "示例6-7:使用 `use` 将 `add_to_waitlist` 函数引入作用域,这并不符合习惯" -#: src/ch07-01-generic-data-types.md:156 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:96 msgid "" -"```rust\n" -"struct Wallet {\n" -" balance: T,\n" -" address: U,\n" -"}\n" -"\n" -"impl WalletDrop, U, impl UDrop: Drop> of Drop>;\n" -"\n" +"Although both Listing 6-5 and 6-7 accomplish the same task, Listing 6-5 is\n" +"the idiomatic way to bring a function into scope with `use`. Bringing the\n" +"function’s parent module into scope with `use` means we have to specify the\n" +"parent module when calling the function. Specifying the parent module when\n" +"calling the function makes it clear that the function isn’t locally defined\n" +"while still minimizing repetition of the full path. The code in Listing 6-7 is\n" +"unclear as to where `add_to_waitlist` is defined." +msgstr "" +"尽管示例6-5和6-7都完成了相同的任务,但示例 6-5 是使用 use 将函数引入作用域的习惯用法。要想使用 `use` 将函数的父模块引入作用域,我们必须在调用函数时指定父模块,这样可以清晰地表明函数不" +"是在本地定义的,同时使完整路径的重复度最小化。示例 6-7 中的代码不清楚 `add_to_waitlist` 是在哪里被定义的。" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:104 +msgid "" +"On the other hand, when bringing in structs, enums, traits, and other items with `use`,\n" +"it’s idiomatic to specify the full path. Listing 6-8 shows the idiomatic way\n" +"to bring the core library’s `ArrayTrait` trait into the scope." +msgstr "另一方面,使用 `use` 引入结构体、枚举和其他项时,习惯是指定它们的完整路径。示例 6-8 展示了将核心库的 `ArrayTrait` 特质带入作用域。" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:108 +msgid "" +"```rust\n" "fn main() {\n" -" let w = Wallet { balance: 3, address: 14 };\n" +" let mut arr = ArrayTrait::new();\n" +" arr.append(1);\n" "}\n" "```" msgstr "" "```rust\n" -"struct Wallet {\n" -" balance: T,\n" -" address: U,\n" -"}\n" -"\n" -"impl WalletDrop, U, impl UDrop: Drop> of Drop>;\n" -"\n" "fn main() {\n" -" let w = Wallet { balance: 3, address: 14 };\n" +" let mut arr = ArrayTrait::new();\n" +" arr.append(1);\n" "}\n" "```" -#: src/ch07-01-generic-data-types.md:169 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:115 +msgid "" +"Listing 6-8: Bringing `ArrayTrait` into scope in an\n" +"idiomatic way" +msgstr "示例6-8:将`ArrayTrait`引入作用域的习惯用法式" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:118 msgid "" -"We add to `Wallet` struct definition a new generic type `U` and then assign this type to the new field member `address`.\n" -"Then we adapt the `WalletDrop` trait to work with the new generic type `U`. Notice that when initializing the struct inside `main` it automatically infers that `T` is a `u128` and " -"`U` is a `felt252` and since they are both droppable, `Wallet` is droppable as well!" +"There’s no strong reason behind this idiom: it’s just the convention that has\n" +"emerged in the Rust community, and folks have gotten used to reading and writing Rust code this way.\n" +"As Cairo shares many idioms with Rust, we follow this convention as well." msgstr "" -"我们在`Wallet`结构定义中添加一个新的泛型`U`,然后将这个类型分配给新的字段成员`address`。\n" -"然后我们调整 `WalletDrop`的trait,使其与新的泛型 \"U \"一起工作。注意,在初始化`main`中的结构时,它会自动推断出`T`是`u128`,`U`是`felt252`,由于它们都是可丢弃的,所以`Wallet`也是可丢" -"弃的!" +"这种习惯用法背后没有什么硬性要求:它只是一种惯例,人们已经习惯了以这种方式阅读和编写 Rust 代码。它只是在Rust社区中出现的惯例。\n" +"由于Cairo与Rust共享许多惯例,我们也遵循这一惯例。" -#: src/ch07-01-generic-data-types.md:172 -msgid "## Enums" -msgstr "## 枚举定义中的泛型" +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:122 +msgid "" +"The exception to this idiom is if we’re bringing two items with the same name\n" +"into scope with `use` statements, because Cairo doesn’t allow that." +msgstr "这个习惯用法有一个例外,那就是我们想使用 `use` 语句将两个具有相同名称的项带入作用域,因为Cairo不允许这样做。" -#: src/ch07-01-generic-data-types.md:174 -msgid "As we did with structs, we can define enums to hold generic data types in their variants. For example the `Option` enum provided by the Cairo core library:" -msgstr "和结构体类似,枚举也可以在成员中存放泛型数据类型。例如,Cairo核心库提供的`Option`枚举:" +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:125 +msgid "### Providing New Names with the `as` Keyword" +msgstr "### 使用 as 关键字提供新的名称" -#: src/ch07-01-generic-data-types.md:183 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:127 msgid "" -"The `Option` enum is generic over a type `T` and has two variants: `Some`, which holds one value of type `T` and `None` that doesn't hold any value. By using the `Option` enum, " -"it is possible for us to express the abstract concept of an optional value and because the value has a generic type `T` we can use this abstraction with any type." +"There’s another solution to the problem of bringing two types of the same name\n" +"into the same scope with `use`: after the path, we can specify `as` and a new\n" +"local name, or _alias_, for the type. Listing 6-9 shows how you can rename an import with `as`:" msgstr "" -"如你所见 `Option` 是一个拥有泛型 `T` 的枚举,它有两个成员:`Some`,它存放了一个类型 `T` 的值,和不存在任何值的`None`。通过 `Option` 枚举可以表达有一个可能的值的抽象概念,同时因" -"为 `Option` 是泛型的,无论这个可能的值是什么类型都可以使用这个抽象。" - -#: src/ch07-01-generic-data-types.md:185 -msgid "Enums can use multiple generic types as well, like definition of the `Result` enum that the core library provides:" -msgstr "枚举也可以拥有多个泛型类型,比如核心库提供的`Result`枚举的定义:" +"使用 `use` 将两个同名类型引入同一作用域这个问题还有另一个解决办法:在这个类型的路径后面,我们使用 `as` 指定一个新的本地名称或者别名( _alias_ )。示例6-9显示了如何用`as`重命名一个导" +"入:" -#: src/ch07-01-generic-data-types.md:187 src/ch09-02-error-handling.md:11 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:133 msgid "" "```rust\n" -"enum Result {\n" -" Ok: T,\n" -" Err: E,\n" +"use array::ArrayTrait as Arr;\n" +"\n" +"fn main() {\n" +" let mut arr = Arr::new(); // ArrayTrait was renamed to Arr\n" +" arr.append(1);\n" "}\n" "```" msgstr "" "```rust\n" -"enum Result {\n" -" Ok: T,\n" -" Err: E,\n" +"use array::ArrayTrait as Arr;\n" +"\n" +"fn main() {\n" +" let mut arr = Arr::new(); // ArrayTrait was renamed to Arr\n" +" arr.append(1);\n" "}\n" "```" -#: src/ch07-01-generic-data-types.md:194 src/ch09-02-error-handling.md:18 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:142 msgid "" -"The `Result` enum has two generic types, `T` and `E`, and two variants: `Ok` which holds the value of type `T` and `Err` which holds the value of type `E`. This definition " -"makes it convenient to use the `Result` enum anywhere we have an operation that might succeed (by returning a value of type `T`) or fail (by returning a value of type `E`)." +"Listing 6-9: Renaming a trait when it’s brought into\n" +"scope with the `as` keyword" +msgstr "示例 6-9:使用 `as` 关键字重命名引入作用域的类型" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:145 +msgid "Here, we brought `ArrayTrait` into scope with the alias `Arr`. We can now access the trait's methods with the `Arr` identifier." +msgstr "在这里,我们用别名`Arr`将`ArrayTrait`带入作用域。现在我们可以用`Arr`标识符来访问该trait的方法。" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:147 +msgid "### Importing multiple items from the same module" +msgstr "### 从同一模块中导入多个项" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:149 +msgid "" +"When you want to import multiple items (like functions, structs or enums)\n" +"from the same module in Cairo, you can use curly braces `{}` to list all of\n" +"the items that you want to import. This helps to keep your code clean and easy\n" +"to read by avoiding a long list of individual use statements." msgstr "" -"`Result`枚举有两个泛型类型,`T`和`E`,以及两个成员:`Ok`,存放`T`类型的值,`Err`,存放`E`类型的值。这个定义使得我们可以在任何地方使用`Result`枚举,该操作可能成功(返回`T`类型的" -"值)或失败(返回`E`类型的值)。" +"当你想从同一个模块中导入多个项(如函数、结构体或枚举)时,\n" +"你可以使用大括号`{}`来列出所有你想导入的项目。\n" +"避免了一长串单独的`use`有助于保持你的代码整洁和便于阅读。" -#: src/ch07-01-generic-data-types.md:196 -msgid "## Generic Methods" -msgstr "## 方法定义中的泛型" +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:154 +msgid "The general syntax for importing multiple items from the same module is:" +msgstr "从同一模块导入多个项的常见语法是:" -#: src/ch07-01-generic-data-types.md:198 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:156 msgid "" -"We can implement methods on structs and enums, and use the generic types in their definition, too. Using our previous definition of `Wallet` struct, we define a `balance` method " -"for it:" -msgstr "我们可以在结构和枚举上实现方法,也可以在其定义中使用泛型。在之前定义的`Wallet`结构体上为其定义一个`balance` 方法:" +"```rust\n" +"use module::{item1, item2, item3};\n" +"```" +msgstr "" +"```rust\n" +"use module::{item1, item2, item3};\n" +"```" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:160 +msgid "Here is an example where we import three structures from the same module:" +msgstr "下面是一个从同一个模块导入三个结构体的例子:" -#: src/ch07-01-generic-data-types.md:200 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:162 msgid "" "```rust\n" -"struct Wallet {\n" -" balance: T\n" -"}\n" -"\n" -"impl WalletDrop> of Drop>;\n" -"impl WalletCopy> of Copy>;\n" +"// Assuming we have a module called `shapes` with the structures `Square`, `Circle`, and `Triangle`.\n" +"mod shapes {\n" +" #[derive(Drop)]\n" +" struct Square {\n" +" side: u32\n" +" }\n" "\n" -"trait WalletTrait {\n" -" fn balance(self: @Wallet) -> T;\n" -"}\n" +" #[derive(Drop)]\n" +" struct Circle {\n" +" radius: u32\n" +" }\n" "\n" -"impl WalletImpl> of WalletTrait {\n" -" fn balance(self: @Wallet) -> T {\n" -" return *self.balance;\n" +" #[derive(Drop)]\n" +" struct Triangle {\n" +" base: u32,\n" +" height: u32,\n" " }\n" "}\n" "\n" +"// We can import the structures `Square`, `Circle`, and `Triangle` from the `shapes` module like this:\n" +"use shapes::{Square, Circle, Triangle};\n" +"\n" +"// Now we can directly use `Square`, `Circle`, and `Triangle` in our code.\n" "fn main() {\n" -" let w = Wallet { balance: 50 };\n" -" assert(w.balance() == 50, 0);\n" +" let sq = Square { side: 5 };\n" +" let cr = Circle { radius: 3 };\n" +" let tr = Triangle { base: 5, height: 2 };\n" +"// ...\n" "}\n" "```" msgstr "" "```rust\n" -"struct Wallet {\n" -" balance: T\n" -"}\n" -"\n" -"impl WalletDrop> of Drop>;\n" -"impl WalletCopy> of Copy>;\n" +"// Assuming we have a module called `shapes` with the structures `Square`, `Circle`, and `Triangle`.\n" +"mod shapes {\n" +" #[derive(Drop)]\n" +" struct Square {\n" +" side: u32\n" +" }\n" "\n" -"trait WalletTrait {\n" -" fn balance(self: @Wallet) -> T;\n" -"}\n" +" #[derive(Drop)]\n" +" struct Circle {\n" +" radius: u32\n" +" }\n" "\n" -"impl WalletImpl> of WalletTrait {\n" -" fn balance(self: @Wallet) -> T {\n" -" return *self.balance;\n" +" #[derive(Drop)]\n" +" struct Triangle {\n" +" base: u32,\n" +" height: u32,\n" " }\n" "}\n" "\n" +"// We can import the structures `Square`, `Circle`, and `Triangle` from the `shapes` module like this:\n" +"use shapes::{Square, Circle, Triangle};\n" +"\n" +"// Now we can directly use `Square`, `Circle`, and `Triangle` in our code.\n" "fn main() {\n" -" let w = Wallet { balance: 50 };\n" -" assert(w.balance() == 50, 0);\n" +" let sq = Square { side: 5 };\n" +" let cr = Circle { radius: 3 };\n" +" let tr = Triangle { base: 5, height: 2 };\n" +"// ...\n" "}\n" "```" -#: src/ch07-01-generic-data-types.md:224 -msgid "" -"We first define `WalletTrait` trait using a generic type `T` which defines a method that returns a snapshot of the field `address` from `Wallet`. Then we give an implementation " -"for the trait in `WalletImpl`. Note that you need to include a generic type in both definitions of the trait and the implementation." -msgstr "" -"我们首先定义了`WalletTrait`trait,使用一个泛型`T`,它定义了一个方法,从`Wallet`中返回字段`address`的快照。然后我们在`WalletImpl`中给出该trait的实现。请注意,你需要在trait的定义" -"和实现中都包含一个泛型。" +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:194 +msgid "Listing 6-10: Importing multiple items from the same module" +msgstr "示例 6-10:从同一模块导入多个项" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:196 +msgid "## Re-exporting Names in Module Files" +msgstr "## 在模块文件中重导出名称" -#: src/ch07-01-generic-data-types.md:226 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:198 msgid "" -"We can also specify constraints on generic types when defining methods on the type. We could, for example, implement methods only for `Wallet` instances rather than " -"`Wallet`. In the code example we define an implementation for wallets which have a concrete type of `u128` for the `balance` field." +"When we bring a name into scope with the `use` keyword, the name available in\n" +"the new scope can be imported as if it had been defined in that code’s scope.\n" +"This technique is called _re-exporting_ because we’re bringing an item into scope,\n" +"but also making that item available for others to bring into their scope." msgstr "" -"在定义类型上的方法时,我们也可以指定对泛型的约束。例如,我们可以只为`Wallet`实例而不是`Wallet`实现方法。在代码示例中,我们为钱包定义了一个实现,这些钱包的`balance`字段的具体" -"类型为`u128`。" +"当我们用`use`关键字将一个名字带入作用域时,在新的作用域中也能够正常使用这个名称,就好像它本来就在当前作用域一样。\n" +"这种技术被称为 重导出( _re-exporting_ ),因为我们将一个项目带入作用域、但同时也使这个项目可以被其他人带入他们的作用域。" -#: src/ch07-01-generic-data-types.md:228 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:203 +msgid "For example, let's re-export the `add_to_waitlist` function in the restaurant example:" +msgstr "下面这个例子,让我们重新导出餐厅例子中的`add_to_waitlist`函数:" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:207 msgid "" "```rust\n" -"struct Wallet {\n" -" balance: T\n" +"//TAG: does_not_compile\n" +"mod front_of_house {\n" +" mod hosting {\n" +" fn add_to_waitlist() {}\n" +" }\n" "}\n" "\n" -"impl WalletDrop> of Drop>;\n" -"impl WalletCopy> of Copy>;\n" -"/// Generic trait for wallets\n" -"trait WalletTrait {\n" -" fn balance(self: @Wallet) -> T;\n" -"}\n" +"use restaurant::front_of_house::hosting;\n" "\n" -"impl WalletImpl> of WalletTrait {\n" -" fn balance(self: @Wallet) -> T {\n" -" return *self.balance;\n" -" }\n" -"}\n" -"\n" -"/// Trait for wallets of type u128\n" -"trait WalletReceiveTrait {\n" -" fn receive(ref self: Wallet, value: u128);\n" -"}\n" -"\n" -"impl WalletReceiveImpl of WalletReceiveTrait {\n" -" fn receive(ref self: Wallet, value: u128) {\n" -" self.balance += value;\n" -" }\n" -"}\n" -"\n" -"fn main() {\n" -" let mut w = Wallet { balance: 50 };\n" -" assert(w.balance() == 50, 0);\n" -"\n" -" w.receive(100);\n" -" assert(w.balance() == 150, 0);\n" +"fn eat_at_restaurant() {\n" +" hosting::add_to_waitlist();\n" "}\n" "```" msgstr "" "```rust\n" -"struct Wallet {\n" -" balance: T\n" -"}\n" -"\n" -"impl WalletDrop> of Drop>;\n" -"impl WalletCopy> of Copy>;\n" -"/// Generic trait for wallets\n" -"trait WalletTrait {\n" -" fn balance(self: @Wallet) -> T;\n" -"}\n" -"\n" -"impl WalletImpl> of WalletTrait {\n" -" fn balance(self: @Wallet) -> T {\n" -" return *self.balance;\n" -" }\n" -"}\n" -"\n" -"/// Trait for wallets of type u128\n" -"trait WalletReceiveTrait {\n" -" fn receive(ref self: Wallet, value: u128);\n" -"}\n" -"\n" -"impl WalletReceiveImpl of WalletReceiveTrait {\n" -" fn receive(ref self: Wallet, value: u128) {\n" -" self.balance += value;\n" +"//TAG: does_not_compile\n" +"mod front_of_house {\n" +" mod hosting {\n" +" fn add_to_waitlist() {}\n" " }\n" "}\n" "\n" -"fn main() {\n" -" let mut w = Wallet { balance: 50 };\n" -" assert(w.balance() == 50, 0);\n" +"use restaurant::front_of_house::hosting;\n" "\n" -" w.receive(100);\n" -" assert(w.balance() == 150, 0);\n" +"fn eat_at_restaurant() {\n" +" hosting::add_to_waitlist();\n" "}\n" "```" -#: src/ch07-01-generic-data-types.md:266 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:222 msgid "" -"The new method `receive` increments the size of the balance of any instance of a `Wallet`. Notice that we changed the `main` function making `w` a mutable variable in order for " -"it to be able to update its balance. If we were to change the initialization of `w` by changing the type of `balance` the previous code wouldn't compile." -msgstr "" -"新的方法`receive`增加了`Wallet`的实例的余额大小。请注意,我们改变了`main`函数,使`w`成为一个可变的变量,以便它能够更新其余额。如果我们通过改变`balance`的类型来改变`w`的初始化," -"那么之前的代码就不能编译了。" +"Listing 6-11: Making a name available for any code to use\n" +"from a new scope with `pub use`" +msgstr "示例 6-11: 通过 `pub use` 使名称可在新作用域中被导入至任何代码" -#: src/ch07-01-generic-data-types.md:268 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:225 msgid "" -"Cairo allows us to define generic methods inside generic traits as well. Using the past implementation from `Wallet` we are going to define a trait that picks two wallets of " -"different generic types and create a new one with a generic type of each. First, let's rewrite the struct definition:" -msgstr "Cairo也允许我们在泛型trait中定义泛型方法。在之前的 `Wallet`的实现上定义一个trait,用来选取两个不同泛型的钱包,并创建一个拥有两者泛型新的钱包。首先,让我们重写结构体定义:" +"Before this change, external code would have to call the `add_to_waitlist`\n" +"function by using the path\n" +"`restaurant::front_of_house::hosting::add_to_waitlist()`. Now that this `use`\n" +"has re-exported the `hosting` module from the root module, external code\n" +"can now use the path `restaurant::hosting::add_to_waitlist()` instead." +msgstr "" +"在这个修改之前,外部代码需要使用路径 `restaurant::front_of_house::hosting::add_to_waitlist()` 来调用 `add_to_waitlist` 函数。\n" +"现在这个 `use` 从根模块重导出了 `hosting` 模块,外部代码现在可以使用路径 `restaurant::hosting::add_to_waitlist()` 。" -#: src/ch07-01-generic-data-types.md:270 +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:231 msgid "" -"```rust\n" -"struct Wallet {\n" -" balance: T,\n" -" address: U,\n" -"}\n" -"```" +"Re-exporting is useful when the internal structure of your code is different\n" +"from how programmers calling your code would think about the domain. For\n" +"example, in this restaurant metaphor, the people running the restaurant think\n" +"about “front of house” and “back of house.” But customers visiting a restaurant\n" +"probably won’t think about the parts of the restaurant in those terms. With\n" +"`use`, we can write our code with one structure but expose a different\n" +"structure. Doing so makes our library well organized for programmers working on\n" +"the library and programmers calling the library." msgstr "" -"```rust\n" -"struct Wallet {\n" -" balance: T,\n" -" address: U,\n" -"}\n" -"```" +"当你代码的内部结构与调用你代码的程序员所想象的结构不同时,重导出会很有用。\n" +"例如,在这个餐馆的比喻中,经营餐馆的人会想到“前台”和“后台”。但顾客在光顾一家餐馆时,可能不会以这些术语来考虑餐馆的各个部分。\n" +"使用 `use`,我们可以使用一种结构编写代码,却将不同的结构形式暴露出来。这样做使我们的库井井有条,也使开发这个库的程序员和调用这个库的程序员都更加方便。" -#: src/ch07-01-generic-data-types.md:277 -msgid "Next we are going to naively define the mixup trait and implementation:" -msgstr "接下来,我们将初步地定义混合trait和其实现:" +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:240 +msgid "## Using External Packages in Cairo with Scarb" +msgstr "## 在Cairo使用外部包与Scarb" -#: src/ch07-01-generic-data-types.md:279 -msgid "" -"```rust\n" -"// This does not compile!\n" -"trait WalletMixTrait {\n" -" fn mixup(self: Wallet, other: Wallet) -> Wallet;\n" -"}\n" -"\n" -"impl WalletMixImpl of WalletMixTrait {\n" -" fn mixup(self: Wallet, other: Wallet) -> Wallet {\n" -" Wallet { balance: self.balance, address: other.address }\n" -" }\n" -"}\n" -"```" -msgstr "" -"```rust\n" -"// This does not compile!\n" -"trait WalletMixTrait {\n" -" fn mixup(self: Wallet, other: Wallet) -> Wallet;\n" -"}\n" -"\n" -"impl WalletMixImpl of WalletMixTrait {\n" -" fn mixup(self: Wallet, other: Wallet) -> Wallet {\n" -" Wallet { balance: self.balance, address: other.address }\n" -" }\n" -"}\n" -"```" +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:242 +msgid "You might need to use external packages to leverage the functionality provided by the community. To use an external package in your project with Scarb, follow these steps:" +msgstr "你可能需要使用外部包来利用社区提供的功能。要在你的项目中使用Scarb的外部包,请遵循以下步骤:" + +#: src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md:244 +msgid "> The dependencies system is still a work in progress. You can check the official [documentation](https://docs.swmansion.com/scarb/docs/guides/dependencies.html)." +msgstr "> 依赖关系系统仍然是一项正在进行的工作。你可以查看官方的[文档](https://docs.swmansion.com/scarb/docs/guides/dependencies.html)。" -#: src/ch07-01-generic-data-types.md:292 +#: src/ch06-05-separating-modules-into-different-files.md:1 +msgid "## Separating Modules into Different Files" +msgstr "## 将模块拆分成多个文件" + +#: src/ch06-05-separating-modules-into-different-files.md:3 msgid "" -"We are creating a trait `WalletMixTrait` with the `mixup` methods which given an instance of `Wallet` and `Wallet` creates a new `Wallet`. As " -"`mixup` signature specify, both `self` and `other` are getting dropped at the end of the function, which is the reason for this code not to compile. If you have been following from " -"the start until now you would know that we must add a requirement for all the generic types specifying that they will implement the `Drop` trait in order for the compiler to know how " -"to drop instances of `Wallet`. The updated implementation is as follow:" -msgstr "" -"我们正在创建一个trait`WalletMixTrait`,其中有`mixup`方法,给定一个`Wallet`和`Wallet`的实例,创建一个新的`Wallet。正如`mixup`签名所指定的," -"`self`和`other`都在函数的结尾处被丢弃,这就是这段代码不能编译的原因。如果你从开始到现在都跟上了课程,你会知道我们必须为所有的泛型添加一个`Drop` trait的实现,以便编译器知道如何丢弃" -"`Wallet`的实例。更新后的实现如下:" +"So far, all the examples in this chapter defined multiple modules in one file.\n" +"When modules get large, you might want to move their definitions to a separate\n" +"file to make the code easier to navigate." +msgstr "到目前为止,本章所有的例子都在一个文件中定义多个模块。当模块变得更大时,你可能想要将它们的定义移动到单独的文件中,从而使代码更容易阅读。" -#: src/ch07-01-generic-data-types.md:294 +#: src/ch06-05-separating-modules-into-different-files.md:7 msgid "" -"```rust\n" -"trait WalletMixTrait {\n" -" fn mixup, U2, impl U2Drop: Drop>(\n" -" self: Wallet, other: Wallet\n" -" ) -> Wallet;\n" -"}\n" -"\n" -"impl WalletMixImpl, U1, impl U1Drop: Drop> of WalletMixTrait {\n" -" fn mixup, U2, impl U2Drop: Drop>(\n" -" self: Wallet, other: Wallet\n" -" ) -> Wallet {\n" -" Wallet { balance: self.balance, address: other.address }\n" -" }\n" -"}\n" -"```" -msgstr "" -"```rust\n" -"trait WalletMixTrait {\n" -" fn mixup, U2, impl U2Drop: Drop>(\n" -" self: Wallet, other: Wallet\n" -" ) -> Wallet;\n" -"}\n" -"\n" -"impl WalletMixImpl, U1, impl U1Drop: Drop> of WalletMixTrait {\n" -" fn mixup, U2, impl U2Drop: Drop>(\n" -" self: Wallet, other: Wallet\n" -" ) -> Wallet {\n" -" Wallet { balance: self.balance, address: other.address }\n" -" }\n" -"}\n" -"```" +"For example, let’s start from the code in Listing 6-11 that had multiple\n" +"restaurant modules. We’ll extract modules into files instead of having all the\n" +"modules defined in the crate root file. In this case, the crate root file is\n" +"_src/lib.cairo_." +msgstr "例如,我们从示例6-11中的代码开始,我们会将模块的代码提取到各自的文件中,而不是将所有模块都定义到 crate 根文件中。在这里,crate 根文件是 _src/lib.cairo_ 。" -#: src/ch07-01-generic-data-types.md:310 +#: src/ch06-05-separating-modules-into-different-files.md:12 msgid "" -"We add the requirements for `T1` and `U1` to be droppable on `WalletMixImpl` declaration. Then we do the same for `T2` and `U2`, this time as part of `mixup` signature. We can now " -"try the `mixup` function:" -msgstr "我们在 `WalletMixImpl`\"的声明中添加了 `T1`和 `U1`的可丢弃trait。然后我们对`T2`和`U2`做同样的处理,这次是作为`mixup`签名的一部分。现在我们可以尝试使用`mixup` 函数了:" +"First, we’ll extract the `front_of_house` module to its own file. Remove the\n" +"code inside the curly brackets for the `front_of_house` module, leaving only\n" +"the `mod front_of_house;` declaration, so that _src/lib.cairo_ contains the code\n" +"shown in Listing 6-12. Note that this won’t compile until we create the\n" +"_src/front_of_house.cairo_ file in Listing 6-13." +msgstr "" +"首先将 `front_of_house` 模块提取到其自己的文件中。删除 `front_of_house` 模块的大括号中的代码,只留下 `mod front_of_house;` 声明,这样 _src/lib.cairo_ 就包含了代码\n" +"如示例6-12所示。注意直到创建示例 6-13 中的 _src/front_of_house.cairo_ 文件之前代码都不能编译。" -#: src/ch07-01-generic-data-types.md:312 +#: src/ch06-05-separating-modules-into-different-files.md:20 msgid "" -"```rs, does_not_compile\n" -"fn main() {\n" -" let w1 = Wallet { balance: true, address: 10 };\n" -" let w2 = Wallet { balance: 32, address: 100 };\n" +"```rust,noplayground\n" +"//TAG: does_not_compile\n" +"mod front_of_house;\n" "\n" -" let w3 = w1.mixup(w2);\n" +"use restaurant::front_of_house::hosting;\n" "\n" -" assert(w3.balance == true, 0);\n" -" assert(w3.address == 100, 0);\n" +"fn eat_at_restaurant() {\n" +" hosting::add_to_waitlist();\n" "}\n" "```" msgstr "" -"```rs, does_not_compile\n" -"fn main() {\n" -" let w1 = Wallet { balance: true, address: 10 };\n" -" let w2 = Wallet { balance: 32, address: 100 };\n" +"```rust,noplayground\n" +"//TAG: does_not_compile\n" +"mod front_of_house;\n" "\n" -" let w3 = w1.mixup(w2);\n" +"use restaurant::front_of_house::hosting;\n" "\n" -" assert(w3.balance == true, 0);\n" -" assert(w3.address == 100, 0);\n" +"fn eat_at_restaurant() {\n" +" hosting::add_to_waitlist();\n" "}\n" "```" -#: src/ch07-01-generic-data-types.md:324 -msgid "We first create two instances: one of `Wallet` and the other of `Wallet`. Then, we call `mixup` and create a new `Wallet` instance." -msgstr "我们首先创建两个实例:一个是 `Wallet`,另一个是`Wallet`。然后,我们调用`mixup`并创建一个新的`Wallet`实例。" - -#: src/ch07-02-traits-in-cairo.md:1 -msgid "# Traits in Cairo" -msgstr "# Cairo中的Trait" +#: src/ch06-05-separating-modules-into-different-files.md:31 +msgid "" +"Listing 6-12: Declaring the `front_of_house` module whose\n" +"body will be in _src/front_of_house.cairo_" +msgstr "示例6-12:声明`front_of_house` 模块,其主体代码将存放在 _src/front_of_house.cairo_ 中。" -#: src/ch07-02-traits-in-cairo.md:3 +#: src/ch06-05-separating-modules-into-different-files.md:34 msgid "" -"Traits specify functionality blueprints that can be implemented. The blueprint specification includes a set of function signatures containing type annotations for the parameters and " -"return value. This sets a standard to implement the specific functionality." +"Next, place the code that was in the curly brackets into a new file named\n" +"_src/front_of_house.cairo_, as shown in Listing 6-13. The compiler knows to look\n" +"in this file because it came across the module declaration in the crate root\n" +"with the name `front_of_house`." msgstr "" -"Trait(译注:也被称为特性,但本译文中将跟随rust中文的习惯,直接使用英文原单词)定义了可以实现的功能蓝图的规范。蓝图规范包括一组包含参数和返回值类型注释的函数签名。这为实现特定的功能设" -"定了一个标准。(译注:trait 类似于其他语言中的常被称为 接口(interfaces)的功能,虽然有一些不同。)" - -#: src/ch07-02-traits-in-cairo.md:5 -msgid "## Defining a Trait" -msgstr "## 定义一个Trait" - -#: src/ch07-02-traits-in-cairo.md:7 -msgid "To define a trait, you use the keyword `trait` followed by the name of the trait in `PascalCase` then the function signatures in a pair of curly braces." -msgstr "要定义一个Trait,你可以使用关键字`trait`,后面是以`PascalCase`书写的trait名称,然后是一对大括号内的函数签名。" +"接下来将之前大括号内的代码放入一个名叫 _src/front_of_house.cairo_ 的新文件中,如示例 6-13所示。因为编译器找到了 crate 根中名叫 `front_of_house` 的模块声明,它就知道去查看这个文件。" -#: src/ch07-02-traits-in-cairo.md:9 -msgid "" -"For example, let's say that we have multiple structs representing shapes. We want our application to be able to perform geometry operations on these shapes, So we define a trait " -"`ShapeGeometry` that contains a blueprint to implement geometry operations on a shape like this:" -msgstr "例如,假设我们有多个代表形状的结构体。我们希望我们的应用程序能够对这些形状进行几何操作,所以我们定义了一个trait`ShapeGeometry`,它包含一个蓝图来实现对形状的几何操作:" +#: src/ch06-05-separating-modules-into-different-files.md:39 src/ch06-05-separating-modules-into-different-files.md:67 +msgid "Filename: src/front_of_house.cairo" +msgstr "文件名: src/front_of_house.cairo" -#: src/ch07-02-traits-in-cairo.md:11 +#: src/ch06-05-separating-modules-into-different-files.md:41 msgid "" -"```rust\n" -"trait ShapeGeometry {\n" -" fn boundary(self: Rectangle) -> u64;\n" -" fn area(self: Rectangle) -> u64;\n" +"```rust,noplayground\n" +"mod hosting {\n" +" fn add_to_waitlist() {}\n" "}\n" "```" msgstr "" -"```rust\n" -"trait ShapeGeometry {\n" -" fn boundary(self: Rectangle) -> u64;\n" -" fn area(self: Rectangle) -> u64;\n" +"```rust,noplayground\n" +"mod hosting {\n" +" fn add_to_waitlist() {}\n" "}\n" "```" -#: src/ch07-02-traits-in-cairo.md:18 +#: src/ch06-05-separating-modules-into-different-files.md:47 msgid "" -"Here our trait `ShapeGeometry` declares signatures for two methods `boundary` and `area`. When implemented, both these functions should return a `u64` and accept parameters as " -"specified by the trait." -msgstr "这里我们的trait `ShapeGeometry`声明了两个方法的签名`boundary`和`area`。当编写实现时,这两个函数都应该返回一个`u64`,并接受trait所规定的参数。" +"Listing 6-13: Definitions inside the `front_of_house`\n" +"module in _src/front_of_house.cairo_" +msgstr "示例 6-13:在 _src/front_of_house.cairo_ 中定义 `front_of_house` 模块。" -#: src/ch07-02-traits-in-cairo.md:20 -msgid "## Implementing a Trait" -msgstr "## 实现一个trait" +#: src/ch06-05-separating-modules-into-different-files.md:50 +msgid "" +"Note that you only need to load a file using a `mod` declaration _once_ in your\n" +"module tree. Once the compiler knows the file is part of the project (and knows\n" +"where in the module tree the code resides because of where you’ve put the `mod`\n" +"statement), other files in your project should refer to the loaded file’s code\n" +"using a path to where it was declared, as covered in the [“Paths for Referring\n" +"to an Item in the Module Tree”][paths] section. In other words,\n" +"`mod` is _not_ an “include” operation that you may have seen in other\n" +"programming languages." +msgstr "" +"注意你只需在模块树中的某处使用一次 mod 声明就可以加载这个文件。\n" +"一旦编译器知道了这个文件是项目的一部分(并且通过 mod 语句的位置知道了代码在模块树中的位置),项目中的其他文件应该使用其所声明的位置的路径来引用那个文件的代码,\n" +"这在 [引用模块项目的路径](ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md)部分有讲到。\n" +"换句话说,mod 不是 你可能会在其他编程语言中看到的 “include” 操作。" -#: src/ch07-02-traits-in-cairo.md:22 +#: src/ch06-05-separating-modules-into-different-files.md:59 msgid "" -"A trait can be implemented using `impl` keyword with the name of your implementation followed by `of` then the name of trait being implemented. Here's an example implementing " -"`ShapeGeometry` trait." -msgstr "一个trait可以用`impl`关键字来实现,在你的实现名称后面加上`of`,然后是被实现的trait的名称。下面是一个实现`ShapeGeometry`trait的例子。" +"Next, we’ll extract the `hosting` module to its own file. The process is a bit\n" +"different because `hosting` is a child module of `front_of_house`, not of the\n" +"root module. We’ll place the file for `hosting` in a new directory that will be\n" +"named for its ancestors in the module tree, in this case _src/front_of_house/_." +msgstr "" +"接下来我们同样将 `hosting` 模块提取到自己的文件中。这个过程会有所不同,因为 `hosting` 是 `front_of_house` 的子模块而不是根模块。我们将 `hosting` 的文件放在与模块树中它的父级模块同名的" +"目录中,在这里是 _src/front_of_house/_ 。" -#: src/ch07-02-traits-in-cairo.md:24 +#: src/ch06-05-separating-modules-into-different-files.md:64 msgid "" -"```rust\n" -"impl RectangleGeometry of ShapeGeometry {\n" -"\tfn boundary(self: Rectangle) -> u64 {\n" -" 2 * (self.height + self.width)\n" -" }\n" -"\tfn area(self: Rectangle) -> u64 {\n" -"\t\tself.height * self.width\n" -"\t}\n" -"}\n" +"To start moving `hosting`, we change _src/front_of_house.cairo_ to contain only the\n" +"declaration of the `hosting` module:" +msgstr "为了移动 `hosting`,修改 _src/front_of_house.cairo_ 使之仅包含 `hosting` 模块的声明:" + +#: src/ch06-05-separating-modules-into-different-files.md:69 +msgid "" +"```rust,noplayground\n" +"mod hosting;\n" "```" msgstr "" -"```rust\n" -"impl RectangleGeometry of ShapeGeometry {\n" -"\tfn boundary(self: Rectangle) -> u64 {\n" -" 2 * (self.height + self.width)\n" -" }\n" -"\tfn area(self: Rectangle) -> u64 {\n" -"\t\tself.height * self.width\n" -"\t}\n" -"}\n" +"```rust,noplayground\n" +"mod hosting;\n" "```" -#: src/ch07-02-traits-in-cairo.md:35 +#: src/ch06-05-separating-modules-into-different-files.md:73 msgid "" -"In the code above, `RectangleGeometry` implements the trait `ShapeGeometry` defining what the methods `boundary` and `area` should do. Note that the function parameters and return " -"value types are identical to the trait specification." -msgstr "在上面的代码中,`RectangleGeometry`实现了`ShapeGeometry`的trait,定义了`boundary`和`area`方法应该做什么。请注意,函数参数和返回值的类型与trait所定义的规范是相同的。" +"Then we create a _src/front_of_house_ directory and a file _hosting.cairo_ to\n" +"contain the definitions made in the `hosting` module:" +msgstr "接着我们创建一个 _src/front_of_house_ 目录和一个包含 `hosting` 模块定义的 _hosting.cairo_ 文件:" -#: src/ch07-02-traits-in-cairo.md:37 -msgid "## Parameter `self`" -msgstr "## 参数 `self`" +#: src/ch06-05-separating-modules-into-different-files.md:76 +msgid "Filename: src/front_of_house/hosting.cairo" +msgstr "文件名: src/front_of_house/hosting.cairo" -#: src/ch07-02-traits-in-cairo.md:39 +#: src/ch06-05-separating-modules-into-different-files.md:78 msgid "" -"In the example above, `self` is a special parameter. When a parameter with name `self` is used, the implemented functions are also [attached to the instances of the type as methods]" -"(ch04-03-method-syntax.md#defining-methods). Here's an illustration," -msgstr "在上面的例子中,`self`是一个特殊参数。当使用名称为`self`的参数时,实现的函数也会[作为方法附加到类型的实例上](ch04-03-method-syntax.md#defining-methods)。下面是一个演示、" +"```rust,noplayground\n" +"fn add_to_waitlist() {}\n" +"```" +msgstr "" +"```rust,noplayground\n" +"fn add_to_waitlist() {}\n" +"```" -#: src/ch07-02-traits-in-cairo.md:41 -msgid "When the `ShapeGeometry` trait is implemented, the function `area` from the `ShapeGeometry` trait can be called in two ways:" -msgstr "当 \"ShapeGeometry \"特质被实现时,\"ShapeGeometry \"特质中的函数 \"area \"可以通过两种方式被调用:" +#: src/ch06-05-separating-modules-into-different-files.md:82 +msgid "" +"If we instead put _hosting.cairo_ in the _src_ directory, the compiler would\n" +"expect the _hosting.cairo_ code to be in a `hosting` module declared in the crate\n" +"root, and not declared as a child of the `front_of_house` module. The\n" +"compiler’s rules for which files to check for which modules’ code means the\n" +"directories and files more closely match the module tree." +msgstr "" +"如果将 _hosting.cairo_ 放在 _src_ 目录,编译器会认为 `hosting` 模块中的 _hosting.cairo_ 的代码声明于 crate 根,而不是声明为 `front_of_house` 的子模块。\n" +"编译器所遵循的哪些文件对应哪些模块的代码的规则,意味着目录和文件更接近于模块树。" -#: src/ch07-02-traits-in-cairo.md:43 +#: src/ch06-05-separating-modules-into-different-files.md:88 msgid "" -"```rust\n" -"let rect = Rectangle { ... }; // Rectangle instantiation\n" -"\n" -"// First way, as a method on the struct instance\n" -"let area1 = rect.area();\n" -"// Second way, from the implementation\n" -"let area2 = RectangleGeometry::area(rect);\n" -"// `area1` has same value as `area2`\n" -"area1.print();\n" -"area2.print();\n" -"```" +"We’ve moved each module’s code to a separate file, and the module tree remains\n" +"the same. The function calls in `eat_at_restaurant` will work without any\n" +"modification, even though the definitions live in different files. This\n" +"technique lets you move modules to new files as they grow in size." msgstr "" -"```rust\n" -"let rect = Rectangle { ... }; // Rectangle instantiation\n" -"\n" -"// First way, as a method on the struct instance\n" -"let area1 = rect.area();\n" -"// Second way, from the implementation\n" -"let area2 = RectangleGeometry::area(rect);\n" -"// `area1` has same value as `area2`\n" -"area1.print();\n" -"area2.print();\n" -"```" +"我们将各个模块的代码移动到独立文件了,同时模块树依旧相同。\n" +"`eat_at_restaurant` 中的函数调用也无需修改继续保持有效,即便其定义存在于不同的文件中。\n" +"这个技巧让你可以在模块代码增长时,将它们移动到新文件中。" -#: src/ch07-02-traits-in-cairo.md:55 -msgid "And the implementation of the `area` method will be accessed via the `self` parameter." -msgstr "之后我们可以通过 `self`参数访问`area`方法的实现。" +#: src/ch06-05-separating-modules-into-different-files.md:93 +msgid "" +"Note that the `use restaurant::front_of_house::hosting` statement in\n" +"_src/lib.cairo_ also hasn’t changed, nor does `use` have any impact on what files\n" +"are compiled as part of the crate. The `mod` keyword declares modules, and Cairo\n" +"looks in a file with the same name as the module for the code that goes into\n" +"that module." +msgstr "" +"注意,_src/lib.cairo_中的 `use restaurant::front_of_house::hosting` 语句是没有改变的,在文件作为 crate 的一部分而编译时,`use` 不会有任何影响。\n" +"`mod` 关键字声明了模块,Cairo 会在与模块同名的文件中查找模块的代码。" -#: src/ch07-02-traits-in-cairo.md:57 -msgid "## Generic Traits" -msgstr "## 泛型Traits" +#: src/ch06-05-separating-modules-into-different-files.md:101 +msgid "" +"Cairo lets you split a package into multiple crates and a crate into modules\n" +"so you can refer to items defined in one module from another module. You can do\n" +"this by specifying absolute or relative paths. These paths can be brought into\n" +"scope with a `use` statement so you can use a shorter path for multiple uses of\n" +"the item in that scope. Module code is public by default." +msgstr "" +"Cairo 提供了将包分成多个 crate,将 crate 分成模块,以及通过指定绝对或相对路径从一个模块引用另一个模块中定义的项的方式。\n" +"你可以通过使用 `use` 语句将路径引入作用域,这样在多次使用时可以使用更短的路径。模块定义的代码默认是公有的。" + +#: src/ch07-00-generic-types-and-traits.md:1 +msgid "# Generic Types and Traits" +msgstr "# 泛型和Trait" -#: src/ch07-02-traits-in-cairo.md:59 +#: src/ch07-00-generic-types-and-traits.md:3 msgid "" -"Usually we want to write a trait when we want multiple types to implement a functionality in a standard way. However, in the example above the signatures are static and cannot be " -"used for multiple types. To do this, we use generic types when defining traits." -msgstr "通常情况下,当我们希望多个类型以标准的方式实现一个功能时,我们要写一个trait。然而,在上面的例子中,签名是静态的,不能用于多种类型。为了做到这一点,我们在定义特质时使用泛型。" +"Every programming language has tools for effectively handling the duplication of concepts. In Cairo, one such tool is generics: abstract stand-ins for concrete types or other " +"properties. We can express the behaviour of generics or how they relate to other generics without knowing what will be in their place when compiling and running the code." +msgstr "" +"每一个编程语言都有高效处理重复概念的工具。在 Cairo 中其工具之一就是 泛型(generics)。泛型是具体类型或其他属性的抽象替代。我们可以表达泛型的属性,比如他们的行为或如何与其他泛型相关" +"联,而不需要在编写和编译代码时知道他们在这里实际上代表什么。" -#: src/ch07-02-traits-in-cairo.md:61 -msgid "In the example below, we use generic type `T` and our method signatures can use this alias which can be provided during implementation." -msgstr "在下面的例子中,我们使用泛型`T`,我们的方法签名可以使用由实现提供这个别名。" +#: src/ch07-00-generic-types-and-traits.md:5 +msgid "Functions, structs, enums and traits can incorporate generic types as part of their definition instead of a concrete types like `u32` or `ContractAddress`." +msgstr "函数、结构体、枚举和特征可以将泛型作为其定义的一部分,而不是像`u32`或`ContractAddress`这样的具体类型。" + +#: src/ch07-00-generic-types-and-traits.md:7 +msgid "Generics allow us to replace specific types with a placeholder that represents multiple types to remove code duplication." +msgstr "泛型允许我们用一个代表多种类型的占位符来替换特定的类型,以消除代码的重复。" + +#: src/ch07-00-generic-types-and-traits.md:9 +msgid "" +"For each concrete type that replaces a generic type the compiler creates a new definition, reducing development time for the programmer, but code duplication at compile level still " +"exists. This may be of importance if you are writing Starknet contracts and using a generic for multiple types which will cause contract size to increment." +msgstr "" +"对于每一个取代泛型的具体类型,编译器都会创建一个新的定义,从而减少程序员的开发时间,但在编译层面上的代码重复仍然存在。如果你正在编写Starknet合约,并为多个类型使用一个泛型,这将导致合" +"约大小的增加,这可能是很重要的。" + +#: src/ch07-00-generic-types-and-traits.md:11 +msgid "" +"Then you’ll learn how to use traits to define behavior in a generic way. You can combine traits with generic types to constrain a generic type to accept only those types that have a " +"particular behavior, as opposed to just any type." +msgstr "之后你将学习 trait,这是一个定义泛型行为的方法。trait 可以与泛型结合来将泛型限制为只接受拥有特定行为的类型,而不是任意类型。" + +#: src/ch07-01-generic-data-types.md:1 +msgid "# Generic Data Types" +msgstr "# 泛型数据类型" + +#: src/ch07-01-generic-data-types.md:3 +msgid "" +"We use generics to create definitions for item declarations, such as structs and functions, which we can then use with many different concrete data types. In Cairo we can use " +"generics when defining functions, structs, enums, traits, implementations and methods! In this chapter we are going to take a look at how to effectively use generic types with all of " +"them." +msgstr "" +"我们可以使用泛型为像函数签名或结构体这样的项创建定义,这样它们就可以用于多种不同的具体数据类型。在Cairo中,我们可以在定义函数、结构、枚举、特征、实现和方法时使用泛型!在本章中,我们将" +"看看在这些被提到的领域中如何有效地使用泛型。" + +#: src/ch07-01-generic-data-types.md:5 +msgid "## Generic Functions" +msgstr "## 在函数定义中使用泛型" + +#: src/ch07-01-generic-data-types.md:7 +msgid "" +"When defining a function that uses generics, we place the generics in the function signature, where we would usually specify the data types of the parameter and return value. For " +"example, imagine we want to create a function which given two `Array` of items, will return the largest one. If we need to perform this operation for lists of different types, then " +"we would have to redefine the function each time. Luckily we can implement the function once using generics and move on to other tasks." +msgstr "" +"当定义一个使用泛型的函数时,本来在函数签名中指定参数和返回值的类型的地方,会改用泛型来表示。例如,假设我们想创建一个函数,给定两个 `Array` 项,函数将返回最大的一个。如果我们需要对不同" +"类型的列表进行这种操作,那么我们就必须每次都重新定义这个函数。幸运的是,我们可以使用泛型来实现这个函数,然后继续完成其他任务。" -#: src/ch07-02-traits-in-cairo.md:63 +#: src/ch07-01-generic-data-types.md:9 msgid "" "```rust\n" -"use debug::PrintTrait;\n" +"//TAG: does_not_compile\n" "\n" -"#[derive(Copy, Drop)]\n" -"struct Rectangle {\n" -" height: u64,\n" -" width: u64,\n" +"// Specify generic type T between the angulars\n" +"fn largest_list(l1: Array, l2: Array) -> Array {\n" +" if l1.len() > l2.len() {\n" +" l1\n" +" } else {\n" +" l2\n" +" }\n" "}\n" "\n" -"#[derive(Copy, Drop)]\n" -"struct Circle {\n" -" radius: u64\n" -"}\n" +"fn main() {\n" +" let mut l1 = ArrayTrait::new();\n" +" let mut l2 = ArrayTrait::new();\n" "\n" -"// Here T is an alias type which will be provided during implementation\n" -"trait ShapeGeometry {\n" -" fn boundary(self: T) -> u64;\n" -" fn area(self: T) -> u64;\n" -"}\n" +" l1.append(1);\n" +" l1.append(2);\n" "\n" -"// Implementation RectangleGeometry passes in \n" -"// to implement the trait for that type\n" -"impl RectangleGeometry of ShapeGeometry {\n" -" fn boundary(self: Rectangle) -> u64 {\n" -" 2 * (self.height + self.width)\n" -" }\n" -" fn area(self: Rectangle) -> u64 {\n" -" self.height * self.width\n" -" }\n" +" l2.append(3);\n" +" l2.append(4);\n" +" l2.append(5);\n" +"\n" +" // There is no need to specify the concrete type of T because\n" +" // it is inferred by the compiler\n" +" let l3 = largest_list(l1, l2);\n" "}\n" +"```" +msgstr "" +"```rust\n" +"//TAG: does_not_compile\n" "\n" -"// We might have another struct Circle\n" -"// which can use the same trait spec\n" -"impl CircleGeometry of ShapeGeometry {\n" -" fn boundary(self: Circle) -> u64 {\n" -" (2 * 314 * self.radius) / 100\n" -" }\n" -" fn area(self: Circle) -> u64 {\n" -" (314 * self.radius * self.radius) / 100\n" +"// Specify generic type T between the angulars\n" +"fn largest_list(l1: Array, l2: Array) -> Array {\n" +" if l1.len() > l2.len() {\n" +" l1\n" +" } else {\n" +" l2\n" " }\n" "}\n" "\n" "fn main() {\n" -" let rect = Rectangle { height: 5, width: 7 };\n" -" rect.area().print(); // 35\n" -" rect.boundary().print(); // 24\n" +" let mut l1 = ArrayTrait::new();\n" +" let mut l2 = ArrayTrait::new();\n" "\n" -" let circ = Circle { radius: 5 };\n" -" circ.area().print(); // 78\n" -" circ.boundary().print(); // 31\n" -"}\n" -"```" -msgstr "" -"```rust\n" -"use debug::PrintTrait;\n" -"\n" -"#[derive(Copy, Drop)]\n" -"struct Rectangle {\n" -" height: u64,\n" -" width: u64,\n" -"}\n" +" l1.append(1);\n" +" l1.append(2);\n" "\n" -"#[derive(Copy, Drop)]\n" -"struct Circle {\n" -" radius: u64\n" -"}\n" +" l2.append(3);\n" +" l2.append(4);\n" +" l2.append(5);\n" "\n" -"// Here T is an alias type which will be provided during implementation\n" -"trait ShapeGeometry {\n" -" fn boundary(self: T) -> u64;\n" -" fn area(self: T) -> u64;\n" +" // There is no need to specify the concrete type of T because\n" +" // it is inferred by the compiler\n" +" let l3 = largest_list(l1, l2);\n" "}\n" -"\n" -"// Implementation RectangleGeometry passes in \n" -"// to implement the trait for that type\n" -"impl RectangleGeometry of ShapeGeometry {\n" -" fn boundary(self: Rectangle) -> u64 {\n" -" 2 * (self.height + self.width)\n" -" }\n" -" fn area(self: Rectangle) -> u64 {\n" -" self.height * self.width\n" +"```" + +#: src/ch07-01-generic-data-types.md:38 +msgid "" +"The `largest_list` function compares two lists of the same type and returns the one with more elements and drops the other. If you compile the previous code, you will notice that it " +"will fail with an error saying that there are no traits defined for dropping an array of a generic type. This happens because the compiler has no way to guarantee that an `Array` " +"is droppable when executing the `main` function. In order to drop an array of `T`, the compiler must first know how to drop `T`. This can be fixed by specifying in the function " +"signature of `largest_list` that `T` must implement the drop trait. The correct function definition of `largest_list` is as follows:" +msgstr "" +"名为`largest_list`函数比较了两个相同类型的列表,返回具有更多元素的那一个,并丢弃另一个。如果你编译前面的代码,你会注意到它会出错,说没有为丢弃一个泛型的数组定义trait。这是因为编译器没" +"有办法保证在执行`main`函数时,`Array`是可以丢弃的。为了丢弃一个`T`的数组,编译器必须首先知道如何丢弃`T`。可以通过在`largest_list`的函数签名中规定`T`必须实现drop trait来解决这个问" +"题。`largest_list`的正确函数定义如下:" + +#: src/ch07-01-generic-data-types.md:40 +msgid "" +"```rust\n" +"fn largest_list>(l1: Array, l2: Array) -> Array {\n" +" if l1.len() > l2.len() {\n" +" l1\n" +" } else {\n" +" l2\n" " }\n" "}\n" -"\n" -"// We might have another struct Circle\n" -"// which can use the same trait spec\n" -"impl CircleGeometry of ShapeGeometry {\n" -" fn boundary(self: Circle) -> u64 {\n" -" (2 * 314 * self.radius) / 100\n" -" }\n" -" fn area(self: Circle) -> u64 {\n" -" (314 * self.radius * self.radius) / 100\n" +"```" +msgstr "" +"```rust\n" +"fn largest_list>(l1: Array, l2: Array) -> Array {\n" +" if l1.len() > l2.len() {\n" +" l1\n" +" } else {\n" +" l2\n" " }\n" "}\n" -"\n" -"fn main() {\n" -" let rect = Rectangle { height: 5, width: 7 };\n" -" rect.area().print(); // 35\n" -" rect.boundary().print(); // 24\n" -"\n" -" let circ = Circle { radius: 5 };\n" -" circ.area().print(); // 78\n" -" circ.boundary().print(); // 31\n" -"}\n" "```" -#: src/ch07-02-traits-in-cairo.md:116 -msgid "## Managing and using external trait implementations" -msgstr "## 管理和使用外部trait的实现" - -#: src/ch07-02-traits-in-cairo.md:118 +#: src/ch07-01-generic-data-types.md:50 msgid "" -"To use traits methods, you need to make sure the correct traits/implementation(s) are imported. In the code above we imported `PrintTrait` from `debug` with `use debug::PrintTrait;` " -"to use the `print()` methods on supported types." +"The new `largest_list` function includes in its definition the requirement that whatever generic type is placed there, it must be droppable. The `main` function remains unchanged, " +"the compiler is smart enough to deduct which concrete type is being used and if it implements the `Drop` trait." msgstr "" -"要使用trait的方法,你需要确保导入了正确的 traits以及它的实现。在上面的代码中,我们从`debug`中导入了`PrintTrait`,并使用`use debug::PrintTrait;`以在支持的类型上使用`print()`方法。" +"新的`largest_list`函数在其定义中包含了一个要求,即无论什么泛型被放在那里,它都必须是可丢弃的。`main`函数保持不变,编译器足够聪明,可以得出正在使用的具体类型以及它是否实现了`Drop`这个" +"trait。" + +#: src/ch07-01-generic-data-types.md:52 +msgid "### Constraints for Generic Types" +msgstr "### 范型的约束" -#: src/ch07-02-traits-in-cairo.md:120 +#: src/ch07-01-generic-data-types.md:54 msgid "" -"In some cases you might need to import not only the trait but also the implementation if they are declared in separate modules.\n" -"If `CircleGeometry` was in a separate module/file `circle` then to use `boundary` on `circ: Circle`, we'd need to import `CircleGeometry` in addition to `ShapeGeometry`." +"When defining generic types, it is useful to have information about them. Knowing which traits a generic type implements allow us to use them more effectively in a functions logic at " +"the cost of constraining the generic types that can be used with the function. We saw an example of this previously by adding the `TDrop` implementation as part of the generic " +"arguments of `largest_list`. While `TDrop` was added to satisfy the compilers requirements, we can also add constraints to benefit our function logic." msgstr "" -"在某些情况下,如果它们被声明在不同的模块中,你可能不仅需要导入trait,还需要导入实现。\n" -"如果`CircleGeometry`是在一个单独的模块/文件`circle`中,那么要在`circ: Circle`上使用`boundary`,我们就需要在 `ShapeGeometry`之外再导入 `CircleGeometry`。" +"在定义泛型的时候,掌握关于它们的信息是很有用的。知道一个泛型实现了哪些trait,可以让我们在函数逻辑中更有效地使用它们,代价是限制了可以与函数一起使用的泛型。我们之前看到了一个例子,就是" +"将`TDrop`的实现作为`largest_list`的泛型参数的一部分。虽然 `TDrop`是为了满足编译器的要求而添加的,但我们也可以添加一些约束条件以有利于我们的函数逻辑。" -#: src/ch07-02-traits-in-cairo.md:123 -msgid "If the code was organised into modules like this," -msgstr "如果代码被如下般组织成模块," +#: src/ch07-01-generic-data-types.md:56 +msgid "" +"Imagine that we want, given a list of elements of some generic type `T`, find the smallest element among them. Initially, we know that for an element of type `T` to be comparable, it " +"must implement the `PartialOrd` trait. The resulting function would be:" +msgstr "想象一下,我们想,给定一个通用类型`T`的元素列表,找到其中最小的元素。首先,我们知道要使一个`T`类型的元素具有可比性,它必须实现`PartialOrd`这个trait。由此产生的函数将是:" -#: src/ch07-02-traits-in-cairo.md:125 +#: src/ch07-01-generic-data-types.md:58 msgid "" -"```rust,does_not_compile,ignore_format\n" -"use debug::PrintTrait;\n" -"\n" -"// struct Circle { ... } and struct Rectangle { ... }\n" +"```rust\n" +"//TAG: does_not_compile\n" "\n" -"mod geometry {\n" -" use super::Rectangle;\n" -" trait ShapeGeometry {\n" -" // ...\n" -" }\n" +"// Given a list of T get the smallest one.\n" +"// The PartialOrd trait implements comparison operations for T\n" +"fn smallest_element>(list: @Array) -> T {\n" +" // This represents the smallest element through the iteration\n" +" // Notice that we use the desnap (*) operator\n" +" let mut smallest = *list[0];\n" "\n" -" impl RectangleGeometry of ShapeGeometry:: {\n" -" // ...\n" -" }\n" -"}\n" +" // The index we will use to move through the list\n" +" let mut index = 1;\n" "\n" -"// Could be in a different file\n" -"mod circle {\n" -" use super::geometry::ShapeGeometry;\n" -" use super::Circle;\n" -" impl CircleGeometry of ShapeGeometry {\n" -" // ...\n" +" // Iterate through the whole list storing the smallest\n" +" loop {\n" +" if index >= list.len() {\n" +" break smallest;\n" +" }\n" +" if *list[index] < smallest {\n" +" smallest = *list[index];\n" +" }\n" +" index = index + 1;\n" " }\n" "}\n" "\n" "fn main() {\n" -" let rect = Rectangle { height: 5, width: 7 };\n" -" let circ = Circle { radius: 5 };\n" -" // Fails with this error\n" -" // Method `area` not found on... Did you import the correct trait and impl?\n" -" rect.area().print();\n" -" circ.area().print();\n" +" let mut list: Array = ArrayTrait::new();\n" +" list.append(5);\n" +" list.append(3);\n" +" list.append(10);\n" +"\n" +" // We need to specify that we are passing a snapshot of `list` as an argument\n" +" let s = smallest_element(@list);\n" +" assert(s == 3, 0);\n" "}\n" "```" msgstr "" -"```rust,does_not_compile,ignore_format\n" -"use debug::PrintTrait;\n" -"\n" -"// struct Circle { ... } and struct Rectangle { ... }\n" +"```rust\n" +"//TAG: does_not_compile\n" "\n" -"mod geometry {\n" -" use super::Rectangle;\n" -" trait ShapeGeometry {\n" -" // ...\n" -" }\n" +"// Given a list of T get the smallest one.\n" +"// The PartialOrd trait implements comparison operations for T\n" +"fn smallest_element>(list: @Array) -> T {\n" +" // This represents the smallest element through the iteration\n" +" // Notice that we use the desnap (*) operator\n" +" let mut smallest = *list[0];\n" "\n" -" impl RectangleGeometry of ShapeGeometry:: {\n" -" // ...\n" -" }\n" -"}\n" +" // The index we will use to move through the list\n" +" let mut index = 1;\n" "\n" -"// Could be in a different file\n" -"mod circle {\n" -" use super::geometry::ShapeGeometry;\n" -" use super::Circle;\n" -" impl CircleGeometry of ShapeGeometry {\n" -" // ...\n" +" // Iterate through the whole list storing the smallest\n" +" loop {\n" +" if index >= list.len() {\n" +" break smallest;\n" +" }\n" +" if *list[index] < smallest {\n" +" smallest = *list[index];\n" +" }\n" +" index = index + 1;\n" " }\n" "}\n" "\n" "fn main() {\n" -" let rect = Rectangle { height: 5, width: 7 };\n" -" let circ = Circle { radius: 5 };\n" -" // Fails with this error\n" -" // Method `area` not found on... Did you import the correct trait and impl?\n" -" rect.area().print();\n" -" circ.area().print();\n" +" let mut list: Array = ArrayTrait::new();\n" +" list.append(5);\n" +" list.append(3);\n" +" list.append(10);\n" +"\n" +" // We need to specify that we are passing a snapshot of `list` as an argument\n" +" let s = smallest_element(@list);\n" +" assert(s == 3, 0);\n" "}\n" "```" -#: src/ch07-02-traits-in-cairo.md:160 -msgid "To make it work, in addition to," -msgstr "为了使其发挥作用,除此之外、" - -#: src/ch07-02-traits-in-cairo.md:162 +#: src/ch07-01-generic-data-types.md:95 msgid "" -"```rust\n" -"use geometry::ShapeGeometry;\n" -"```" +"The `smallest_element` function uses a generic type `T` that implements the `PartialOrd` trait, takes a snapshot of an `Array` as a parameter and returns a copy of the smallest " +"element. Because the parameter is of type `@Array`, we no longer need to drop it at the end of the execution and so we don't require to implement the `Drop` trait for `T` as well. " +"Why it does not compile then?" msgstr "" -"```rust\n" -"use geometry::ShapeGeometry;\n" -"```" +"名为`smallest_element`函数使用一个实现了`PartialOrd`的trait的通用类型`T`,接收一个`Array`的快照作为参数并返回其中最小元素的拷贝。因为参数是`@Array`的类型,我们不再需要在执行结束" +"时丢弃它,所以我们不需要为`T`实现`Drop`特性。那为什么它不能编译呢?" -#: src/ch07-02-traits-in-cairo.md:166 -msgid "you might also need to use `CircleGeometry`," -msgstr "你可能还需要使用`CircleGeometry`、" +#: src/ch07-01-generic-data-types.md:97 +msgid "" +"When indexing on `list`, the value results in a snap of the indexed element, unless `PartialOrd` is implemented for `@T` we need to desnap the element using `*`. The `*` operation " +"requires a copy from `@T` to`T`, which means that `T` needs to implement the `Copy` trait. After copying an element of type `@T` to `T`, there are now variables with type `T` that " +"need to be dropped, requiring for `T` to implement the `Drop` trait as well. We must then add both `Drop` and `Copy` traits implementation for the function to be correct. After " +"updating the`smallest_element` function the resulting code would be:" +msgstr "" +"当对`list`进行索引时,其结果是对被索引的元素进行快照,除非`@T`实现了`PartialOrd`,否则我们需要使用 `*` 对元素进行解快照。`*` 操作需要从`@T`复制到`T`,这意味着`T`需要实现`Copy`特性。在" +"复制了一个`@T`类型的元素到`T`之后,现在有`T`类型的变量需要被删除,这就要求`T`也要实现`Drop`特性。然后我们必须同时添加`Drop`和`Copy`特性的实现,以使该函数正确。在更新`smallest_element`" +"函数后,产生的代码将是:" -#: src/ch07-02-traits-in-cairo.md:168 +#: src/ch07-01-generic-data-types.md:99 msgid "" "```rust\n" -"use circle::CircleGeometry\n" +"fn smallest_element, impl TCopy: Copy, impl TDrop: Drop>(\n" +" list: @Array\n" +") -> T {\n" +" let mut smallest = *list[0];\n" +" let mut index = 1;\n" +" loop {\n" +" if index >= list.len() {\n" +" break smallest;\n" +" }\n" +" if *list[index] < smallest {\n" +" smallest = *list[index];\n" +" }\n" +" index = index + 1;\n" +" }\n" +"}\n" "```" msgstr "" "```rust\n" -"use circle::CircleGeometry;\n" -"```" - -#: src/ch08-00-testing-cairo-programs.md:1 -msgid "# Testing Cairo Programs" -msgstr "# 测试Cairo 程序" - -#: src/ch08-01-how-to-write-tests.md:1 -msgid "# How To Write Tests" -msgstr "# 如何编写测试" - -#: src/ch08-01-how-to-write-tests.md:3 -msgid "## The Anatomy of a Test Function" -msgstr "## 测试函数的剖析" +"fn smallest_element, impl TCopy: Copy, impl TDrop: Drop>(\n" +" list: @Array\n" +") -> T {\n" +" let mut smallest = *list[0];\n" +" let mut index = 1;\n" +" loop {\n" +" if index >= list.len() {\n" +" break smallest;\n" +" }\n" +" if *list[index] < smallest {\n" +" smallest = *list[index];\n" +" }\n" +" index = index + 1;\n" +" }\n" +"}\n" +"```" -#: src/ch08-01-how-to-write-tests.md:5 -msgid "Tests are Cairo functions that verify that the non-test code is functioning in the expected manner. The bodies of test functions typically perform these three actions:" -msgstr "测试是Cairo函数,用于验证非测试代码是否以预期方式运行。测试函数的主体通常执行这三个动作:" +#: src/ch07-01-generic-data-types.md:117 +msgid "## Structs" +msgstr "## 结构体定义中的泛型" -#: src/ch08-01-how-to-write-tests.md:7 +#: src/ch07-01-generic-data-types.md:119 msgid "" -"- Set up any needed data or state.\n" -"- Run the code you want to test.\n" -"- Assert the results are what you expect." +"We can also define structs to use a generic type parameter for one or more fields using the `<>` syntax, similar to function definitions. First we declare the name of the type " +"parameter inside the angle brackets just after the name of the struct. Then we use the generic type in the struct definition where we would otherwise specify concrete data types. The " +"next code example shows the definition `Wallet` which has a `balance` field of type `T`." msgstr "" -"- 设置任何需要的数据或状态。\n" -"- 运行你想测试的代码。\n" -"- 断言结果与你期望的一样。" - -#: src/ch08-01-how-to-write-tests.md:11 -msgid "" -"Let’s look at the features Cairo provides specifically for writing tests that take these actions, which include the `test` attribute, the `assert` function, and the `should_panic` " -"attribute." -msgstr "让我们看看Cairo专门为编写执行这些动作的测试所提供的功能,其中包括`test`属性、`assert`函数和`should_panic`属性。" - -#: src/ch08-01-how-to-write-tests.md:13 -msgid "### The Anatomy of a Test Function" -msgstr "### 一个测试函数的剖析" +"我们也可以使用类似于函数定义的`<>` 语法来定义结构,它包含一个或多个泛型参数类型字段。首先,必须在结构体名称后面的尖括号中声明泛型参数的名称,接着在结构体定义中可以指定具体数据类型的位" +"置使用泛型类型。下一个代码示例显示了 `Wallet` 的定义,它有一个 `balance`字段,类型为 `T`。" -#: src/ch08-01-how-to-write-tests.md:15 +#: src/ch07-01-generic-data-types.md:121 msgid "" -"At its simplest, a test in Cairo is a function that’s annotated with the `test` attribute. Attributes are metadata about pieces of Cairo code; one example is the derive attribute we " -"used with structs in Chapter 4. To change a function into a test function, add `#[test]` on the line before `fn`. When you run your tests with the `cairo-test` command, Cairo builds " -"a test runner binary that runs the annotated functions and reports on whether each test function passes or fails." +"```rust\n" +"#[derive(Drop)]\n" +"struct Wallet {\n" +" balance: T\n" +"}\n" +"\n" +"\n" +"fn main() {\n" +" let w = Wallet { balance: 3 };\n" +"}\n" +"```" msgstr "" -"最简单的Cairo中的测试是一个带有`test`属性注释的函数。属性是关于Cairo代码片段的元数据;一个例子是我们在第4章中对结构体使用的derive属性。要把一个函数变成测试函数,在 `fn`前的一行加上 " -"`#[test]`。当你用`cairo-test`命令运行你的测试时,Cairo会建立一个测试运行器的二进制文件,运行被标注了的函数,并报告每个测试函数的通过或失败。" +"```rust\n" +"#[derive(Drop)]\n" +"struct Wallet {\n" +" balance: T\n" +"}\n" +"\n" +"\n" +"fn main() {\n" +" let w = Wallet { balance: 3 };\n" +"}\n" +"```" -#: src/ch08-01-how-to-write-tests.md:17 -msgid "Let's create a new project called `adder` that will add two numbers using Scarb with the command `scarb new adder`:" -msgstr "让我们创建一个名为 `adder`的将两个数字相加的新项目,用`scarb new adder`”命令:" +#: src/ch07-01-generic-data-types.md:133 +msgid "The above code derives the `Drop` trait for the `Wallet` type automatically. It is equivalent to writing the following code:" +msgstr "上述代码自动为`Wallet`类型派生`Drop` trait。这效果等同于手动编写以下代码:" -#: src/ch08-01-how-to-write-tests.md:19 +#: src/ch07-01-generic-data-types.md:135 msgid "" -"```shell\n" -"adder\n" -"├── cairo_project.toml\n" -"├── Scarb.toml\n" -"└── src\n" -" └── lib.cairo\n" +"```rust\n" +"struct Wallet {\n" +" balance: T\n" +"}\n" +"\n" +"impl WalletDrop> of Drop>;\n" +"\n" +"fn main() {\n" +" let w = Wallet { balance: 3 };\n" +"}\n" "```" msgstr "" -"```shell\n" -"adder\n" -"├── cairo_project.toml\n" -"├── Scarb.toml\n" -"└── src\n" -" └── lib.cairo\n" +"```rust\n" +"struct Wallet {\n" +" balance: T\n" +"}\n" +"\n" +"impl WalletDrop> of Drop>;\n" +"\n" +"fn main() {\n" +" let w = Wallet { balance: 3 };\n" +"}\n" "```" -#: src/ch08-01-how-to-write-tests.md:27 src/ch08-02-test-organization.md:51 -msgid "" -msgstr "" - -#: src/ch08-01-how-to-write-tests.md:29 +#: src/ch07-01-generic-data-types.md:147 msgid "" -"> Note: You will notice here a `cairo_project.toml` file.\n" -"> This is the configuration file for \"vanilla\" Cairo projects (i.e. not managed by Scarb),\n" -"> which is required to run the `cairo-test .` command to run the code of the crate.\n" -"> It is required until Scarb implements this feature. The content of the file is:\n" -">\n" -"> ```toml\n" -"> [crate_roots]\n" -"> adder = \"src\"\n" -"> ```\n" -">\n" -"> and indicates that the crate named \"adder\" is located in the `src` directory." +"We avoid using the `derive` macro for `Drop` implementation of `Wallet` and instead define our own `WalletDrop` implementation. Notice that we must define, just like functions, an " +"additional generic type for `WalletDrop` saying that `T` implements the `Drop` trait as well. We are basically saying that the struct `Wallet` is droppable as long as `T` is also " +"droppable." msgstr "" -"> 注意:你会注意到这里有一个`cairo_project.toml`文件。\n" -"> 这是 普通的Cairo项目的配置文件(即不由Scarb管理)、\n" -"> 在运行`cairo-test .`命令来运行crate的代码需要这个文件。\n" -"> 在Scarb实现这一功能之前,它是必需的。该文件的内容是:\n" -">\n" -"> ```toml\n" -"> [crate_roots]\n" -"> adder = “src”\n" -"> ```\n" -">\n" -"> 该文件指出,名为 \"adder \"的crate位于`src`目录下。" - -#: src/ch08-01-how-to-write-tests.md:41 -msgid "In _lib.cairo_, let's add a first test, as shown in Listing 8-1." -msgstr "在 _lib.cairo_ 中,让我们添加第一个测试,如示例8-1所示。" +"应该避免使用`derive`宏来实现`Wallet`的`Drop`,而是定义我们自己的`WalletDrop`实现。注意,我们必须像定义函数一样,为`WalletDrop`定义一个额外的泛型`T`并且也实现了`Drop`特性。这基本上是在" +"说,只要`T`也是可丢弃的,那么`钱包`这个结构就是可丢弃的。" -#: src/ch08-01-how-to-write-tests.md:43 src/ch08-01-how-to-write-tests.md:79 src/ch08-01-how-to-write-tests.md:140 src/ch08-01-how-to-write-tests.md:162 -#: src/ch08-01-how-to-write-tests.md:201 src/ch08-01-how-to-write-tests.md:274 src/ch08-01-how-to-write-tests.md:355 src/ch08-02-test-organization.md:19 -#: src/ch09-01-unrecoverable-errors-with-panic.md:9 -msgid "Filename: lib.cairo" -msgstr "文件名:lib.cairo" +#: src/ch07-01-generic-data-types.md:149 +msgid "" +"Finally, if we want to add a field to `Wallet` representing its address and we want that field to be different than `T` but generic as well, we can simply add another generic type " +"between the `<>`:" +msgstr "最后,如果我们想给`Wallet`添加一个代表其Cairo地址的字段,并且我们希望这个字段是与`T`不同的另一个泛型,我们可以简单地通过在`<>`之间添加另一个泛型来实现:" -#: src/ch08-01-how-to-write-tests.md:45 src/ch08-02-test-organization.md:21 +#: src/ch07-01-generic-data-types.md:151 msgid "" "```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" -" #[test]\n" -" fn it_works() {\n" -" let result = 2 + 2;\n" -" assert(result == 4, 'result is not 4');\n" -" }\n" +"#[derive(Drop)]\n" +"struct Wallet {\n" +" balance: T,\n" +" address: U,\n" +"}\n" +"\n" +"fn main() {\n" +" let w = Wallet { balance: 3, address: 14 };\n" "}\n" "```" msgstr "" "```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" -" #[test]\n" -" fn it_works() {\n" -" let result = 2 + 2;\n" -" assert(result == 4, ‘result is not 4’);\n" -" }\n" +"#[derive(Drop)]\n" +"struct Wallet {\n" +" balance: T,\n" +" address: U,\n" +"}\n" +"\n" +"fn main() {\n" +" let w = Wallet { balance: 3, address: 14 };\n" "}\n" "```" -#: src/ch08-01-how-to-write-tests.md:56 -msgid "Listing 8-1: A test module and function" -msgstr "示例8-1:一个测试模块和函数" - -#: src/ch08-01-how-to-write-tests.md:58 +#: src/ch07-01-generic-data-types.md:163 msgid "" -"For now, let’s ignore the top two lines and focus on the function. Note the `#[test]` annotation: this attribute indicates this is a test function, so the test runner knows to treat " -"this function as a test. We might also have non-test functions in the tests module to help set up common scenarios or perform common operations, so we always need to indicate which " -"functions are tests." +"We add to `Wallet` struct definition a new generic type `U` and then assign this type to the new field member `address`. Notice that the derive attribute for the `Drop` trait works " +"for `U` as well." msgstr "" -"现在,让我们忽略最上面的两行,专注于这个函数。注意`#[test]`标注:这个属性表明这是一个测试函数,所以测试运行器知道要把这个函数当作一个测试。我们可能在测试模块中也有非测试函数,以帮助设" -"置常见的场景或执行常见的操作,所以我们总是需要指出哪些函数是测试的。" +"我们在`Wallet`结构定义中添加一个新的泛型`U`,然后将这个类型分配给新的字段成员`address`。\n" +"注意派生属性的 `Drop`的trait在新的泛型 `U `上同样起作用。" -#: src/ch08-01-how-to-write-tests.md:60 -msgid "" -"The example function body uses the `assert` function, which contains the result of adding 2 and 2, equals 4. This assertion serves as an example of the format for a typical test. " -"Let’s run it to see that this test passes." -msgstr "这个例子的函数体使用了`assert`函数,它包含了2和2相加的结果,等于4。这个断言是一个典型测试格式范例。让我们运行它,看看这个测试是否通过。" +#: src/ch07-01-generic-data-types.md:165 +msgid "## Enums" +msgstr "## 枚举定义中的泛型" -#: src/ch08-01-how-to-write-tests.md:62 -msgid "The `cairo-test .` command runs all tests in our project, as shown in Listing 8-2." -msgstr "用`cairo-test .`命令运行我们项目中的所有测试,如示例8-2所示。" +#: src/ch07-01-generic-data-types.md:167 +msgid "As we did with structs, we can define enums to hold generic data types in their variants. For example the `Option` enum provided by the Cairo core library:" +msgstr "和结构体类似,枚举也可以在成员中存放泛型数据类型。例如,Cairo核心库提供的`Option`枚举:" -#: src/ch08-01-how-to-write-tests.md:64 +#: src/ch07-01-generic-data-types.md:169 msgid "" -"```shell\n" -"$ cairo-test .\n" -"running 1 tests\n" -"test adder::lib::tests::it_works ... ok\n" -"test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" +"```rust,noplayground\n" +"enum Option {\n" +" Some: T,\n" +" None,\n" +"}\n" "```" msgstr "" -"```shell\n" -"$ cairo-test .\n" -"running 1 tests\n" -"test adder::lib::tests::it_works … ok\n" -"test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" +"```rust,noplayground\n" +"enum Option {\n" +" Some: T,\n" +" None,\n" +"}\n" "```" -#: src/ch08-01-how-to-write-tests.md:71 -msgid "Listing 8-2: The output from running a test" -msgstr "示例8-2:运行一个测试的输出结果" +#: src/ch07-01-generic-data-types.md:176 +msgid "" +"The `Option` enum is generic over a type `T` and has two variants: `Some`, which holds one value of type `T` and `None` that doesn't hold any value. By using the `Option` enum, " +"it is possible for us to express the abstract concept of an optional value and because the value has a generic type `T` we can use this abstraction with any type." +msgstr "" +"如你所见 `Option` 是一个拥有泛型 `T` 的枚举,它有两个成员:`Some`,它存放了一个类型 `T` 的值,和不存在任何值的`None`。通过 `Option` 枚举可以表达有一个可能的值的抽象概念,同时因" +"为 `Option` 是泛型的,无论这个可能的值是什么类型都可以使用这个抽象。" + +#: src/ch07-01-generic-data-types.md:178 +msgid "Enums can use multiple generic types as well, like definition of the `Result` enum that the core library provides:" +msgstr "枚举也可以拥有多个泛型类型,比如核心库提供的`Result`枚举的定义:" -#: src/ch08-01-how-to-write-tests.md:73 +#: src/ch07-01-generic-data-types.md:180 src/ch09-02-recoverable-errors.md:11 msgid "" -"`cairo-test` compiled and ran the test. We see the line `running 1 tests`. The next line shows the name of the generated test function, called `it_works`, and that the result of " -"running that test is `ok`. The overall summary `test result: ok.` means that all the tests passed, and the portion that reads `1 passed; 0 failed` totals the number of tests that " -"passed or failed." +"```rust,noplayground\n" +"enum Result {\n" +" Ok: T,\n" +" Err: E,\n" +"}\n" +"```" msgstr "" -"`cairo-test`编译并运行了测试。我们看到一行`running 1 tests`。下一行显示了生成的测试函数的名称,叫做`it_works`,运行该测试的结果是`ok`。总体摘要`test result: ok.`意味着所有的测试都通过" -"了,`1 passed; 0 failed` 的部分展示了通过或失败的测试的总数。" +"```rust,noplayground\n" +"enum Result {\n" +" Ok: T,\n" +" Err: E,\n" +"}\n" +"```" -#: src/ch08-01-how-to-write-tests.md:75 +#: src/ch07-01-generic-data-types.md:187 src/ch09-02-recoverable-errors.md:18 msgid "" -"It’s possible to mark a test as ignored so it doesn’t run in a particular instance; we’ll cover that in the [Ignoring Some Tests Unless Specifically Requested](#ignoring-some-tests-" -"unless-specifically-requested) section later in this chapter. Because we haven’t done that here, the summary shows `0 ignored`. We can also pass an argument to the `cairo-test` " -"command to run only a test whose name matches a string; this is called filtering and we’ll cover that in the [Running Single Tests](#running-single-tests) section. We also haven’t " -"filtered the tests being run, so the end of the summary shows `0 filtered out`." +"The `Result` enum has two generic types, `T` and `E`, and two variants: `Ok` which holds the value of type `T` and `Err` which holds the value of type `E`. This definition " +"makes it convenient to use the `Result` enum anywhere we have an operation that might succeed (by returning a value of type `T`) or fail (by returning a value of type `E`)." msgstr "" -"我们可以把一个测试标记为忽略,这样它就不会在一个特定的实例中运行;我们将在本章后面的[忽略一些测试,除非特别要求](#ignoring-some-tests-unless-specifically-requested)一节中介绍。因为我" -"们在这里没有这样做,所以摘要中显示 `0 ignored`。我们也可以给`cairo-test`命令传递一个参数,只运行名称与某个字符串相匹配的测试;这叫做过滤,我们将在[运行单个测试](#running-single-test)" -"一节中介绍。我们也没有对正在运行的测试进行过滤,所以总结的最后显示`0 filtered out`。" +"`Result`枚举有两个泛型类型,`T`和`E`,以及两个成员:`Ok`,存放`T`类型的值,`Err`,存放`E`类型的值。这个定义使得我们可以在任何地方使用`Result`枚举,该操作可能成功(返回`T`类型的" +"值)或失败(返回`E`类型的值)。" -#: src/ch08-01-how-to-write-tests.md:77 -msgid "Let’s start to customize the test to our own needs. First change the name of the `it_works` function to a different name, such as `exploration`, like so:" -msgstr "让我们开始根据我们自己的需要定制测试。首先将`it_works`函数的名称改为不同的名称,例如`exploration`,像这样:" +#: src/ch07-01-generic-data-types.md:189 +msgid "## Generic Methods" +msgstr "## 方法定义中的泛型" + +#: src/ch07-01-generic-data-types.md:191 +msgid "" +"We can implement methods on structs and enums, and use the generic types in their definition, too. Using our previous definition of `Wallet` struct, we define a `balance` method " +"for it:" +msgstr "我们可以在结构和枚举上实现方法,也可以在其定义中使用泛型。在之前定义的`Wallet`结构体上为其定义一个`balance` 方法:" -#: src/ch08-01-how-to-write-tests.md:81 +#: src/ch07-01-generic-data-types.md:193 msgid "" "```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" -" #[test]\n" -" fn exploration() {\n" -" let result = 2 + 2;\n" -" assert(result == 4, 'result is not 4');\n" +"#[derive(Copy, Drop)]\n" +"struct Wallet {\n" +" balance: T\n" +"}\n" +"\n" +"trait WalletTrait {\n" +" fn balance(self: @Wallet) -> T;\n" +"}\n" +"\n" +"impl WalletImpl> of WalletTrait {\n" +" fn balance(self: @Wallet) -> T {\n" +" return *self.balance;\n" " }\n" "}\n" +"\n" +"fn main() {\n" +" let w = Wallet { balance: 50 };\n" +" assert(w.balance() == 50, 0);\n" +"}\n" "```" msgstr "" "```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" -" #[test]\n" -" fn exploration() {\n" -" let result = 2 + 2;\n" -" assert(result == 4, ‘result is not 4’);\n" +"#[derive(Copy, Drop)]\n" +"struct Wallet {\n" +" balance: T\n" +"}\n" +"\n" +"trait WalletTrait {\n" +" fn balance(self: @Wallet) -> T;\n" +"}\n" +"\n" +"impl WalletImpl> of WalletTrait {\n" +" fn balance(self: @Wallet) -> T {\n" +" return *self.balance;\n" " }\n" "}\n" +"\n" +"fn main() {\n" +" let w = Wallet { balance: 50 };\n" +" assert(w.balance() == 50, 0);\n" +"}\n" "```" -#: src/ch08-01-how-to-write-tests.md:92 -msgid "Then run `cairo-test -- --path src` again. The output now shows `exploration` instead of `it_works`:" -msgstr "然后再次运行`cairo-test -- --path src`。现在输出显示的是 `exploration`而不是`it_works`:" - -#: src/ch08-01-how-to-write-tests.md:94 +#: src/ch07-01-generic-data-types.md:215 msgid "" -"```shell\n" -"$ cairo-test .\n" -"running 1 tests\n" -"test adder::lib::tests::exploration ... ok\n" -"test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" -"```" +"We first define `WalletTrait` trait using a generic type `T` which defines a method that returns a snapshot of the field `address` from `Wallet`. Then we give an implementation " +"for the trait in `WalletImpl`. Note that you need to include a generic type in both definitions of the trait and the implementation." msgstr "" -"```shell\n" -"$ cairo-test .\n" -"running 1 tests\n" -"test adder::lib::tests::exploration … ok\n" -"test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" -"```" +"我们首先定义了`WalletTrait`trait,使用一个泛型`T`,它定义了一个方法,从`Wallet`中返回字段`address`的快照。然后我们在`WalletImpl`中给出该trait的实现。请注意,你需要在trait的定义" +"和实现中都包含一个泛型。" -#: src/ch08-01-how-to-write-tests.md:101 +#: src/ch07-01-generic-data-types.md:217 msgid "" -"Now we’ll add another test, but this time we’ll make a test that fails! Tests fail when something in the test function panics. Each test is run in a new thread, and when the main " -"thread sees that a test thread has died, the test is marked as failed. Enter the new test as a function named `another`, so your _src/lib.cairo_ file looks like Listing 8-3." +"We can also specify constraints on generic types when defining methods on the type. We could, for example, implement methods only for `Wallet` instances rather than " +"`Wallet`. In the code example we define an implementation for wallets which have a concrete type of `u128` for the `balance` field." msgstr "" -"现在我们将添加另一个测试,但这次我们要做一个失败的测试! 当测试函数中的某些东西发生panic时,测试就会失败。每个测试都在一个新的线程中运行,当主线程看到一个测试线程死亡时,该测试被标记为" -"失败。将新的测试作为一个名为`another`的函数输入,因此你的 _src/lib.cairo_ 文件看起来像示例8-3里一样。" +"在定义类型上的方法时,我们也可以指定对泛型的约束。例如,我们可以只为`Wallet`实例而不是`Wallet`实现方法。在代码示例中,我们为钱包定义了一个实现,这些钱包的`balance`字段的具体" +"类型为`u128`。" -#: src/ch08-01-how-to-write-tests.md:103 +#: src/ch07-01-generic-data-types.md:219 msgid "" "```rust\n" -"#[cfg(test)]\n" -"mod tests{\n" -" #[test]\n" -" fn another() {\n" -" let result = 2 + 2;\n" -" assert(result == 6, 'Make this test fail');\n" +"#[derive(Copy, Drop)]\n" +"struct Wallet {\n" +" balance: T\n" +"}\n" +"\n" +"/// Generic trait for wallets\n" +"trait WalletTrait {\n" +" fn balance(self: @Wallet) -> T;\n" +"}\n" +"\n" +"impl WalletImpl> of WalletTrait {\n" +" fn balance(self: @Wallet) -> T {\n" +" return *self.balance;\n" +" }\n" +"}\n" +"\n" +"/// Trait for wallets of type u128\n" +"trait WalletReceiveTrait {\n" +" fn receive(ref self: Wallet, value: u128);\n" +"}\n" +"\n" +"impl WalletReceiveImpl of WalletReceiveTrait {\n" +" fn receive(ref self: Wallet, value: u128) {\n" +" self.balance += value;\n" " }\n" "}\n" +"\n" +"fn main() {\n" +" let mut w = Wallet { balance: 50 };\n" +" assert(w.balance() == 50, 0);\n" +"\n" +" w.receive(100);\n" +" assert(w.balance() == 150, 0);\n" +"}\n" "```" msgstr "" "```rust\n" -"#[cfg(test)]\n" -"mod tests{\n" -" #[test]\n" -" fn another() {\n" -" let result = 2 + 2;\n" -" assert(result == 6, ‘Make this test fail’);\n" +"#[derive(Copy, Drop)]\n" +"struct Wallet {\n" +" balance: T\n" +"}\n" +"\n" +"/// Generic trait for wallets\n" +"trait WalletTrait {\n" +" fn balance(self: @Wallet) -> T;\n" +"}\n" +"\n" +"impl WalletImpl> of WalletTrait {\n" +" fn balance(self: @Wallet) -> T {\n" +" return *self.balance;\n" +" }\n" +"}\n" +"\n" +"/// Trait for wallets of type u128\n" +"trait WalletReceiveTrait {\n" +" fn receive(ref self: Wallet, value: u128);\n" +"}\n" +"\n" +"impl WalletReceiveImpl of WalletReceiveTrait {\n" +" fn receive(ref self: Wallet, value: u128) {\n" +" self.balance += value;\n" " }\n" "}\n" +"\n" +"fn main() {\n" +" let mut w = Wallet { balance: 50 };\n" +" assert(w.balance() == 50, 0);\n" +"\n" +" w.receive(100);\n" +" assert(w.balance() == 150, 0);\n" +"}\n" "```" -#: src/ch08-01-how-to-write-tests.md:114 -msgid "Listing 8-3: Adding a second test that will fail" -msgstr "示例8-3:添加第二个测试(会失败的测试)" - -#: src/ch08-01-how-to-write-tests.md:116 +#: src/ch07-01-generic-data-types.md:256 msgid "" -"```shell\n" -"$ cairo-test .\n" -"running 2 tests\n" -"test adder::lib::tests::exploration ... ok\n" -"test adder::lib::tests::another ... fail\n" -"failures:\n" -" adder::lib::tests::another - panicked with [1725643816656041371866211894343434536761780588 ('Make this test fail'), ].\n" -"Error: test result: FAILED. 1 passed; 1 failed; 0 ignored\n" -"```" +"The new method `receive` increments the size of the balance of any instance of a `Wallet`. Notice that we changed the `main` function making `w` a mutable variable in order for " +"it to be able to update its balance. If we were to change the initialization of `w` by changing the type of `balance` the previous code wouldn't compile." msgstr "" -"```shell\n" -"$ cairo-test .\n" -"running 2 tests\n" -"test adder::lib::tests::exploration … ok\n" -"test adder::lib::tests::another … fail\n" -"failures:\n" -" adder::lib::tests::another - panicked with [1725643816656041371866211894343434536761780588 (‘Make this test fail’), ].\n" -"Error: test result: FAILED. 1 passed; 1 failed; 0 ignored\n" -"```" - -#: src/ch08-01-how-to-write-tests.md:126 -msgid "Listing 8-4: Test results when one test passes and one test fails" -msgstr "示例8-4:一个测试通过,一个测试失败时的测试结果" +"新的方法`receive`增加了`Wallet`的实例的余额大小。请注意,我们改变了`main`函数,使`w`成为一个可变的变量,以便它能够更新其余额。如果我们通过改变`balance`的类型来改变`w`的初始化," +"那么之前的代码就不能编译了。" -#: src/ch08-01-how-to-write-tests.md:128 +#: src/ch07-01-generic-data-types.md:258 msgid "" -"Instead of `ok`, the line `adder::lib::tests::another` shows `fail`. A new section appears between the individual results and the summary. It displays the detailed reason for each " -"test failure. In this case, we get the details that `another` failed because it panicked with `[1725643816656041371866211894343434536761780588 ('Make this test fail'), ]` in the _src/" -"lib.cairo_ file." -msgstr "" -"`adder::lib::test::another`这一行没有显示`ok`,而是显示`fail`。在单个结果和摘要之间出现了一个新的部分。它显示了每个测试失败的详细原因。在这个例子中,我们得到的细节在是 _src/lib.cairo_" -"文件中`another`失败了,因为它发生了panic `[1725643816656041371866211894343434536761780588 (‘Make this test fail’), ]`。" - -#: src/ch08-01-how-to-write-tests.md:130 -msgid "The summary line displays at the end: overall, our test result is `FAILED`. We had one test pass and one test fail." -msgstr "摘要行显示在最后:总的来说,我们的测试结果是`FAILED`。我们有一个测试通过,一个测试失败。" - -#: src/ch08-01-how-to-write-tests.md:132 -msgid "Now that you’ve seen what the test results look like in different scenarios, let’s look at some functions that are useful in tests." -msgstr "现在你已经看到了不同场景下的测试结果,让我们看看一些在测试中有用的函数。" - -#: src/ch08-01-how-to-write-tests.md:134 -msgid "## Checking Results with the assert function" -msgstr "## 用断言函数检查结果" +"Cairo allows us to define generic methods inside generic traits as well. Using the past implementation from `Wallet` we are going to define a trait that picks two wallets of " +"different generic types and create a new one with a generic type of each. First, let's rewrite the struct definition:" +msgstr "Cairo也允许我们在泛型trait中定义泛型方法。在之前的 `Wallet`的实现上定义一个trait,用来选取两个不同泛型的钱包,并创建一个拥有两者泛型新的钱包。首先,让我们重写结构体定义:" -#: src/ch08-01-how-to-write-tests.md:136 +#: src/ch07-01-generic-data-types.md:260 msgid "" -"The `assert` function, provided by Cairo, is useful when you want to ensure that some condition in a test evaluates to `true`. We give the `assert` function a first argument that " -"evaluates to a Boolean. If the value is `true`, nothing happens and the test passes. If the value is `false`, the assert function calls `panic()` to cause the test to fail with a " -"message we defined as the second argument of the `assert` function. Using the `assert` function helps us check that our code is functioning in the way we intend." +"```rust,noplayground\n" +"//TAG: does_not_compile\n" +"struct Wallet {\n" +" balance: T,\n" +" address: U,\n" +"```" msgstr "" -"Cairo提供的`assert`函数,在你想确保测试中的某些条件一定为`true`时非常有用。我们给`assert`函数的第一个参数是一个布尔值。如果该值为`true`,则不会发生任何事情,测试通过。如果值是 " -"`false`,assert函数调用 `panic()`,导致测试失败,我们定义的信息是 `assert`函数的第二个参数。使用`assert`函数可以帮助我们检查我们的代码是否按照我们的意图运行。" +"```rust,noplayground\n" +"//TAG: does_not_compile\n" +"struct Wallet {\n" +" balance: T,\n" +" address: U,\n" +"```" -#: src/ch08-01-how-to-write-tests.md:138 -msgid "" -"In [Chapter 4, Listing 5-15](ch04-03-method-syntax.md#multiple-impl-blocks), we used a `Rectangle` struct and a `can_hold` method, which are repeated here in Listing 8-5. Let’s put " -"this code in the _src/lib.cairo_ file, then write some tests for it using the `assert` function." -msgstr "" -"在[第4章,示例5-15](ch04-03-method-syntax.md#multiple-impl-blocks)中,我们使用了一个`Rectangle`结构和一个`can_hold`方法,在示例8-5中重复了这些。让我们把这段代码放在_src/lib.cairo_文件" -"中,然后用`assert`函数为它写一些测试。" +#: src/ch07-01-generic-data-types.md:267 +msgid "Next we are going to naively define the mixup trait and implementation:" +msgstr "接下来,我们将初步地定义混合trait和其实现:" -#: src/ch08-01-how-to-write-tests.md:142 +#: src/ch07-01-generic-data-types.md:269 msgid "" -"```rust\n" -"trait RectangleTrait {\n" -" fn area(self: @Rectangle) -> u64;\n" -" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" +"```rust,noplayground\n" +"\n" +"// This does not compile!\n" +"trait WalletMixTrait {\n" +" fn mixup(self: Wallet, other: Wallet) -> Wallet;\n" "}\n" "\n" -"impl RectangleImpl of RectangleTrait {\n" -" fn area(self: @Rectangle) -> u64 {\n" -" *self.width * *self.height\n" -" }\n" -" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" -" *self.width > *other.width & *self.height > *other.height\n" +"impl WalletMixImpl of WalletMixTrait {\n" +" fn mixup(self: Wallet, other: Wallet) -> Wallet {\n" +" Wallet { balance: self.balance, address: other.address }\n" " }\n" -"}\n" +"\n" "```" msgstr "" -"```rust\n" -"trait RectangleTrait {\n" -" fn area(self: @Rectangle) -> u64;\n" -" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" +"```rust,noplayground\n" +"\n" +"// This does not compile!\n" +"trait WalletMixTrait {\n" +" fn mixup(self: Wallet, other: Wallet) -> Wallet;\n" "}\n" "\n" -"impl RectangleImpl of RectangleTrait {\n" -" fn area(self: @Rectangle) -> u64 {\n" -" *self.width * *self.height\n" -" }\n" -" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" -" *self.width > *other.width & *self.height > *other.height\n" +"impl WalletMixImpl of WalletMixTrait {\n" +" fn mixup(self: Wallet, other: Wallet) -> Wallet {\n" +" Wallet { balance: self.balance, address: other.address }\n" " }\n" -"}\n" +"\n" "```" -#: src/ch08-01-how-to-write-tests.md:158 -msgid "Listing 8-5: Using the `Rectangle` struct and its `can_hold` method from Chapter 5" -msgstr "示例8-5:使用第五章中的 `Rectangle`结构及其`can_hold`方法" - -#: src/ch08-01-how-to-write-tests.md:160 +#: src/ch07-01-generic-data-types.md:283 msgid "" -"The `can_hold` method returns a `Boolean`, which means it’s a perfect use case for the assert function. In Listing 8-6, we write a test that exercises the `can_hold` method by " -"creating a `Rectangle` instance that has a width of `8` and a height of `7` and asserting that it can hold another `Rectangle` instance that has a width of `5` and a height of `1`." +"We are creating a trait `WalletMixTrait` with the `mixup` methods which given an instance of `Wallet` and `Wallet` creates a new `Wallet`. As " +"`mixup` signature specify, both `self` and `other` are getting dropped at the end of the function, which is the reason for this code not to compile. If you have been following from " +"the start until now you would know that we must add a requirement for all the generic types specifying that they will implement the `Drop` trait in order for the compiler to know how " +"to drop instances of `Wallet`. The updated implementation is as follow:" msgstr "" -"会返回`Boolean`的`can_hold`方法是assert函数的一个完美用例。在示例8-6中,我们写了一个测试,通过创建一个宽度为`8`、高度为`7`的`Rectangle`实例,并断言它可以容纳另一个宽度为`5`、高度为`1`" -"的`Rectangle`实例,来测试`can_hold`方法。" +"我们正在创建一个trait`WalletMixTrait`,其中有`mixup`方法,给定一个`Wallet`和`Wallet`的实例,创建一个新的`Wallet`。正如`mixup`签名所指定的," +"`self`和`other`都在函数的结尾处被丢弃,这就是这段代码不能编译的原因。如果你从开始到现在都跟上了课程,你会知道我们必须为所有的泛型添加一个`Drop` trait的实现,以便编译器知道如何丢弃" +"`Wallet`的实例。更新后的实现如下:" -#: src/ch08-01-how-to-write-tests.md:164 +#: src/ch07-01-generic-data-types.md:285 msgid "" "```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" -" use super::Rectangle;\n" -" use super::RectangleTrait;\n" -"\n" -" #[test]\n" -" fn larger_can_hold_smaller() {\n" -" let larger = Rectangle {\n" -" height: 7,\n" -" width: 8,\n" -" };\n" -" let smaller = Rectangle {\n" -" height: 1,\n" -" width: 5,\n" -" };\n" +"trait WalletMixTrait {\n" +" fn mixup, U2, impl U2Drop: Drop>(\n" +" self: Wallet, other: Wallet\n" +" ) -> Wallet;\n" +"}\n" "\n" -" assert(larger.can_hold(@smaller), 'rectangle cannot hold');\n" +"impl WalletMixImpl, U1, impl U1Drop: Drop> of WalletMixTrait {\n" +" fn mixup, U2, impl U2Drop: Drop>(\n" +" self: Wallet, other: Wallet\n" +" ) -> Wallet {\n" +" Wallet { balance: self.balance, address: other.address }\n" " }\n" "}\n" "```" msgstr "" "```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" -" use super::Rectangle;\n" -" use super::RectangleTrait;\n" -"\n" -" #[test]\n" -" fn larger_can_hold_smaller() {\n" -" let larger = Rectangle {\n" -" height: 7,\n" -" width: 8,\n" -" };\n" -" let smaller = Rectangle {\n" -" height: 1,\n" -" width: 5,\n" -" };\n" +"trait WalletMixTrait {\n" +" fn mixup, U2, impl U2Drop: Drop>(\n" +" self: Wallet, other: Wallet\n" +" ) -> Wallet;\n" +"}\n" "\n" -" assert(larger.can_hold(@smaller), 'rectangle cannot hold');\n" +"impl WalletMixImpl, U1, impl U1Drop: Drop> of WalletMixTrait {\n" +" fn mixup, U2, impl U2Drop: Drop>(\n" +" self: Wallet, other: Wallet\n" +" ) -> Wallet {\n" +" Wallet { balance: self.balance, address: other.address }\n" " }\n" "}\n" "```" -#: src/ch08-01-how-to-write-tests.md:186 -msgid "Listing 8-6: A test for `can_hold` that checks whether a larger rectangle can indeed hold a smaller rectangle" -msgstr "示例 8-6: `can_hold`的测试,检查一个较大的矩形是否真的可以容纳一个较小的矩形" - -#: src/ch08-01-how-to-write-tests.md:188 -msgid "" -"Note that we’ve added two new lines inside the tests module: `use super::Rectangle;` and `use super::RectangleTrait;`. The tests module is a regular module that follows the usual " -"visibility rules. Because the tests module is an inner module, we need to bring the code under test in the outer module into the scope of the inner module." -msgstr "" -"注意,我们在测试模块中加入了两行新的内容:`use super::Rectangle;`和`use super::RectangleTrait;`。测试模块是一个常规模块,遵循通常的可见性规则。因为测试模块是一个内部模块,我们需要将外" -"部模块中的被测代码引入内部模块的范围。" - -#: src/ch08-01-how-to-write-tests.md:190 -msgid "" -"We’ve named our test `larger_can_hold_smaller`, and we’ve created the two `Rectangle` instances that we need. Then we called the assert function and passed it the result of calling " -"`larger.can_hold(@smaller)`. This expression is supposed to return `true`, so our test should pass. Let’s find out!" -msgstr "" -"我们将我们的测试命名为`larger_can_hold_smaller`,并且创建了我们需要的两个`Rectangle`实例。然后我们调用了assert函数,并将调用`larger.can_hold(@smaller)`的结果传给它。这个表达式应该返" -"回 `true`,所以我们的测试应该通过。让我们拭目以待吧!" - -#: src/ch08-01-how-to-write-tests.md:192 +#: src/ch07-01-generic-data-types.md:301 msgid "" -"```shell\n" -"$ cairo-test .\n" -"running 1 tests\n" -"test adder::lib::tests::larger_can_hold_smaller ... ok\n" -"test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" -"```" -msgstr "" -"```shell\n" -"$ cairo-test .\n" -"running 1 tests\n" -"test adder::lib::tests::larger_can_hold_smaller ... ok\n" -"test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" -"```" - -#: src/ch08-01-how-to-write-tests.md:199 -msgid "It does pass! Let’s add another test, this time asserting that a smaller rectangle cannot hold a larger rectangle:" -msgstr "它确实通过了!让我们再增加一个测试,这次是断言一个较小的矩形不能容纳一个较大的矩形:" +"We add the requirements for `T1` and `U1` to be droppable on `WalletMixImpl` declaration. Then we do the same for `T2` and `U2`, this time as part of `mixup` signature. We can now " +"try the `mixup` function:" +msgstr "我们在 `WalletMixImpl`\"的声明中添加了 `T1`和 `U1`的可丢弃trait。然后我们对`T2`和`U2`做同样的处理,这次是作为`mixup`签名的一部分。现在我们可以尝试使用`mixup` 函数了:" -#: src/ch08-01-how-to-write-tests.md:203 +#: src/ch07-01-generic-data-types.md:303 msgid "" -"```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" -" use super::Rectangle;\n" -" use super::RectangleTrait;\n" -"\n" -" #[test]\n" -" fn larger_can_hold_smaller() {\n" -" // --snip--\n" -" }\n" +"```rust,noplayground\n" +"fn main() {\n" +" let w1 = Wallet { balance: true, address: 10 };\n" +" let w2 = Wallet { balance: 32, address: 100 };\n" "\n" -" #[test]\n" -" fn smaller_cannot_hold_larger() {\n" -" let larger = Rectangle {\n" -" height: 7,\n" -" width: 8,\n" -" };\n" -" let smaller = Rectangle {\n" -" height: 1,\n" -" width: 5,\n" -" };\n" +" let w3 = w1.mixup(w2);\n" "\n" -" assert(!smaller.can_hold(@larger), 'rectangle cannot hold');\n" -" }\n" +" assert(w3.balance == true, 0);\n" +" assert(w3.address == 100, 0);\n" "}\n" "```" msgstr "" -"```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" -" use super::Rectangle;\n" -" use super::RectangleTrait;\n" -"\n" -" #[test]\n" -" fn larger_can_hold_smaller() {\n" -" // --snip--\n" -" }\n" +"```rust,noplayground\n" +"fn main() {\n" +" let w1 = Wallet { balance: true, address: 10 };\n" +" let w2 = Wallet { balance: 32, address: 100 };\n" "\n" -" #[test]\n" -" fn smaller_cannot_hold_larger() {\n" -" let larger = Rectangle {\n" -" height: 7,\n" -" width: 8,\n" -" };\n" -" let smaller = Rectangle {\n" -" height: 1,\n" -" width: 5,\n" -" };\n" +" let w3 = w1.mixup(w2);\n" "\n" -" assert(!smaller.can_hold(@larger), 'rectangle cannot hold');\n" -" }\n" +" assert(w3.balance == true, 0);\n" +" assert(w3.address == 100, 0);\n" "}\n" "```" -#: src/ch08-01-how-to-write-tests.md:230 +#: src/ch07-01-generic-data-types.md:315 +msgid "We first create two instances: one of `Wallet` and the other of `Wallet`. Then, we call `mixup` and create a new `Wallet` instance." +msgstr "我们首先创建两个实例:一个是 `Wallet`,另一个是`Wallet`。然后,我们调用`mixup`并创建一个新的`Wallet`实例。" + +#: src/ch07-02-traits-in-cairo.md:1 +msgid "# Traits in Cairo" +msgstr "# Cairo中的Trait" + +#: src/ch07-02-traits-in-cairo.md:3 msgid "" -"Because the correct result of the `can_hold` function in this case is `false`, we need to negate that result before we pass it to the assert function. As a result, our test will pass " -"if `can_hold` returns false:" -msgstr "因为在这种情况下,`can_hold`函数的正确结果是`false`,我们需要在传递给assert函数之前否定这个结果。因此,如果`can_hold`返回false,我们的测试将通过:" +"Traits specify functionality blueprints that can be implemented. The blueprint specification includes a set of function signatures containing type annotations for the parameters and " +"return value. This sets a standard to implement the specific functionality." +msgstr "" +"Trait(译注:也被称为特性,但本译文中将跟随rust中文的习惯,直接使用英文原单词)定义了可以实现的功能蓝图的规范。蓝图规范包括一组包含参数和返回值类型注释的函数签名。这为实现特定的功能设" +"定了一个标准。(译注:trait 类似于其他语言中的常被称为 接口(interfaces)的功能,虽然有一些不同。)" + +#: src/ch07-02-traits-in-cairo.md:5 +msgid "## Defining a Trait" +msgstr "## 定义一个Trait" + +#: src/ch07-02-traits-in-cairo.md:7 +msgid "To define a trait, you use the keyword `trait` followed by the name of the trait in `PascalCase` then the function signatures in a pair of curly braces." +msgstr "要定义一个Trait,你可以使用关键字`trait`,后面是以`PascalCase`书写的trait名称,然后是一对大括号内的函数签名。" -#: src/ch08-01-how-to-write-tests.md:232 +#: src/ch07-02-traits-in-cairo.md:9 msgid "" -"```shell\n" -"$ cairo-test .\n" -" running 2 tests\n" -" test adder::lib::tests::smaller_cannot_hold_larger ... ok\n" -" test adder::lib::tests::larger_can_hold_smaller ... ok\n" -" test result: ok. 2 passed; 0 failed; 0 ignored; 0 filtered out;\n" +"For example, let's say that we have multiple structs representing shapes. We want our application to be able to perform geometry operations on these shapes, So we define a trait " +"`ShapeGeometry` that contains a blueprint to implement geometry operations on a shape like this:" +msgstr "例如,假设我们有多个代表形状的结构体。我们希望我们的应用程序能够对这些形状进行几何操作,所以我们定义了一个trait`ShapeGeometry`,它包含一个蓝图来实现对形状的几何操作:" + +#: src/ch07-02-traits-in-cairo.md:11 +msgid "" +"```rust,noplayground\n" +"trait ShapeGeometry {\n" +" fn boundary(self: Rectangle) -> u64;\n" +" fn area(self: Rectangle) -> u64;\n" +"}\n" "```" msgstr "" -"```shell\n" -"$ cairo-test .\n" -" running 2 tests\n" -" test adder::lib::tests::smaller_cannot_hold_larger … ok\n" -" test adder::lib::tests::larger_can_hold_smaller … ok\n" -" test result: ok. 2 passed; 0 failed; 0 ignored; 0 filtered out;\n" +"```rust,noplayground\n" +"trait ShapeGeometry {\n" +" fn boundary(self: Rectangle) -> u64;\n" +" fn area(self: Rectangle) -> u64;\n" +"}\n" "```" -#: src/ch08-01-how-to-write-tests.md:240 +#: src/ch07-02-traits-in-cairo.md:18 msgid "" -"Two tests that pass! Now let’s see what happens to our test results when we introduce a bug in our code. We’ll change the implementation of the `can_hold` method by replacing the " -"greater-than sign with a less-than sign when it compares the widths:" -msgstr "两个测试都通过了!现在让我们看看当我们在代码中引入一个错误时,我们的测试结果会怎样。我们将改变`can_hold`方法的实现,当它比较宽度时,将大于号替换为小于号:" +"Here our trait `ShapeGeometry` declares signatures for two methods `boundary` and `area`. When implemented, both these functions should return a `u64` and accept parameters as " +"specified by the trait." +msgstr "这里我们的trait `ShapeGeometry`声明了两个方法的签名`boundary`和`area`。当编写实现时,这两个函数都应该返回一个`u64`,并接受trait所规定的参数。" + +#: src/ch07-02-traits-in-cairo.md:20 +msgid "## Implementing a Trait" +msgstr "## 实现一个trait" -#: src/ch08-01-how-to-write-tests.md:242 +#: src/ch07-02-traits-in-cairo.md:22 msgid "" -"```rust\n" -"// --snip--\n" -"impl RectangleImpl of RectangleTrait {\n" -" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" -" *self.width < *other.width & *self.height > *other.height\n" +"A trait can be implemented using `impl` keyword with the name of your implementation followed by `of` then the name of trait being implemented. Here's an example implementing " +"`ShapeGeometry` trait." +msgstr "一个trait可以用`impl`关键字来实现,在你的实现名称后面加上`of`,然后是被实现的trait的名称。下面是一个实现`ShapeGeometry`trait的例子。" + +#: src/ch07-02-traits-in-cairo.md:24 +msgid "" +"```rust,noplayground\n" +"impl RectangleGeometry of ShapeGeometry {\n" +" fn boundary(self: Rectangle) -> u64 {\n" +" 2 * (self.height + self.width)\n" +" }\n" +" fn area(self: Rectangle) -> u64 {\n" +" self.height * self.width\n" " }\n" "}\n" "```" msgstr "" -"```rust\n" -"// —snip—\n" -"impl RectangleImpl of RectangleTrait {\n" -" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" -" *self.width < *other.width & *self.height > *other.height\n" +"```rust,noplayground\n" +"impl RectangleGeometry of ShapeGeometry {\n" +" fn boundary(self: Rectangle) -> u64 {\n" +" 2 * (self.height + self.width)\n" +" }\n" +" fn area(self: Rectangle) -> u64 {\n" +" self.height * self.width\n" " }\n" "}\n" "```" -#: src/ch08-01-how-to-write-tests.md:251 -msgid "Running the tests now produces the following:" -msgstr "现在运行测试产生以下结果:" +#: src/ch07-02-traits-in-cairo.md:35 +msgid "" +"In the code above, `RectangleGeometry` implements the trait `ShapeGeometry` defining what the methods `boundary` and `area` should do. Note that the function parameters and return " +"value types are identical to the trait specification." +msgstr "在上面的代码中,`RectangleGeometry`实现了`ShapeGeometry`的trait,定义了`boundary`和`area`方法应该做什么。请注意,函数参数和返回值的类型与trait所定义的规范是相同的。" + +#: src/ch07-02-traits-in-cairo.md:37 +msgid "## Implementing a trait, without writing its declaration." +msgstr "## trait的无声明实现。" -#: src/ch08-01-how-to-write-tests.md:253 +#: src/ch07-02-traits-in-cairo.md:39 msgid "" -"```shell\n" -"$ cairo-test .\n" -"running 2 tests\n" -"test adder::lib::tests::smaller_cannot_hold_larger ... ok\n" -"test adder::lib::tests::larger_can_hold_smaller ... fail\n" -"failures:\n" -" adder::lib::tests::larger_can_hold_smaller - panicked with [167190012635530104759003347567405866263038433127524 ('rectangle cannot hold'), ].\n" +"You can write implementations directly without definining the corresponding trait. This is made possible by using the `#[generate_trait]` attribute with on the implementation, which " +"will make the compiler generate the trait corresponding to the implementation automatically. Remember to add `Trait` as a suffix to your trait name, as the compiler will create the " +"trait by adding a `Trait` suffix to the implementation name." +msgstr "" +"你可以直接编写实现而不需要定义相应的trait。这可以通过在实现上使用 `#[generate_trait]`属性来实现,它将使编译器自动生成与实现相对应的trait。记住在你的 trait 的名称后添加 `Trait` 作为后" +"缀,因为编译器会通过在实现名称后添加 `Trait` 后缀来创建 trait。" + +#: src/ch07-02-traits-in-cairo.md:41 +msgid "" +"```rust,noplayground\n" +"struct Rectangle {\n" +" height: u64,\n" +" width: u64,\n" +"}\n" "\n" -"Error: test result: FAILED. 1 passed; 1 failed; 0 ignored\n" +"#[generate_trait]\n" +"impl RectangleGeometry of RectangleGeometryTrait {\n" +" fn boundary(self: Rectangle) -> u64 {\n" +" 2 * (self.height + self.width)\n" +" }\n" +" fn area(self: Rectangle) -> u64 {\n" +" self.height * self.width\n" +" }\n" +"}\n" "```" msgstr "" -"```shell\n" -"$ cairo-test .\n" -"running 2 tests\n" -"test adder::lib::tests::smaller_cannot_hold_larger … ok\n" -"test adder::lib::tests::larger_can_hold_smaller … fail\n" -"failures:\n" -" adder::lib::tests::larger_can_hold_smaller - panicked with [167190012635530104759003347567405866263038433127524 (‘rectangle cannot hold’), ].\n" +"```rust,noplayground\n" +"struct Rectangle {\n" +" height: u64,\n" +" width: u64,\n" +"}\n" "\n" -"Error: test result: FAILED. 1 passed; 1 failed; 0 ignored\n" +"#[generate_trait]\n" +"impl RectangleGeometry of RectangleGeometryTrait {\n" +" fn boundary(self: Rectangle) -> u64 {\n" +" 2 * (self.height + self.width)\n" +" }\n" +" fn area(self: Rectangle) -> u64 {\n" +" self.height * self.width\n" +" }\n" +"}\n" "```" -#: src/ch08-01-how-to-write-tests.md:264 -msgid "Our tests caught the bug! Because `larger.width` is `8` and `smaller.width` is `5`, the comparison of the widths in `can_hold` now returns `false`: `8` is not less than `5`." -msgstr "我们的测试发现了这个错误! 因为`larger.width`是`8`,`smaller.width`是`5`,`can_hold`中的宽度比较现在返回`false`:因为`8`不比`5`小。" +#: src/ch07-02-traits-in-cairo.md:58 +msgid "" +"In the aforementioned code, there is no need to manually define the trait. The compiler will automatically handle its definition, dynamically generating and updating it as new " +"functions are introduced." +msgstr "在上述代码中,无需手动定义trait。编译器将自动处理它的定义,在引入新函数时动态生成和更新它。" -#: src/ch08-01-how-to-write-tests.md:266 -msgid "## Checking for Panics with `should_panic`" -msgstr "## 用`should_panic`检查panic情况" +#: src/ch07-02-traits-in-cairo.md:60 +msgid "## Parameter `self`" +msgstr "## 参数 `self`" -#: src/ch08-01-how-to-write-tests.md:268 +#: src/ch07-02-traits-in-cairo.md:62 msgid "" -"In addition to checking return values, it’s important to check that our code handles error conditions as we expect. For example, consider the Guess type in Listing 8-8. Other code " -"that uses `Guess` depends on the guarantee that `Guess` instances will contain only values between `1` and `100`. We can write a test that ensures that attempting to create a `Guess` " -"instance with a value outside that range panics." +"In the example above, `self` is a special parameter. When a parameter with name `self` is used, the implemented functions are also [attached to the instances of the type as methods]" +"(ch04-03-method-syntax.md#defining-methods). Here's an illustration," +msgstr "在上面的例子中,`self`是一个特殊参数。当使用名称为`self`的参数时,实现的函数也会[作为方法附加到类型的实例上](ch04-03-method-syntax.md#defining-methods)。下面是一个演示、" + +#: src/ch07-02-traits-in-cairo.md:64 +msgid "When the `ShapeGeometry` trait is implemented, the function `area` from the `ShapeGeometry` trait can be called in two ways:" +msgstr "当 \"ShapeGeometry \"特质被实现时,\"ShapeGeometry \"特质中的函数 \"area \"可以通过两种方式被调用:" + +#: src/ch07-02-traits-in-cairo.md:66 +msgid "" +"```rust\n" +"# use debug::PrintTrait;\n" +"# \n" +"# #[derive(Drop, Copy)]\n" +"# struct Rectangle {\n" +"# height: u64,\n" +"# width: u64,\n" +"# }\n" +"# \n" +"# trait ShapeGeometry {\n" +"# fn boundary(self: Rectangle) -> u64;\n" +"# fn area(self: Rectangle) -> u64;\n" +"# }\n" +"# \n" +"# impl RectangleGeometry of ShapeGeometry {\n" +"# fn boundary(self: Rectangle) -> u64 {\n" +"# 2 * (self.height + self.width)\n" +"# }\n" +"# fn area(self: Rectangle) -> u64 {\n" +"# self.height * self.width\n" +"# }\n" +"# }\n" +"# \n" +"fn main() {\n" +" let rect = Rectangle { height: 5, width: 10 }; // Rectangle instantiation\n" +"\n" +" // First way, as a method on the struct instance\n" +" let area1 = rect.area();\n" +" // Second way, from the implementation\n" +" let area2 = RectangleGeometry::area(rect);\n" +" // Third way, from the trait\n" +" let area3 = ShapeGeometry::area(rect);\n" +"\n" +" // `area1` has same value as `area2` and `area3`\n" +" area1.print();\n" +" area2.print();\n" +" area3.print();\n" +"}\n" +"# \n" +"# \n" +"```" msgstr "" -"除了检查返回值之外,检查我们的代码是否按照我们所期望的那样处理错误条件也很重要。例如,考虑示例8-8中的Guess类型。其他使用`Guess`的代码依赖于保证`Guess`实例只包含`1`和`100`之间的值。我" -"们可以写一个测试,以确保试图创建的`Guess`实例的值不在这个范围内时,会发生panic。" +"```rust\n" +"# use debug::PrintTrait;\n" +"# \n" +"# #[derive(Drop, Copy)]\n" +"# struct Rectangle {\n" +"# height: u64,\n" +"# width: u64,\n" +"# }\n" +"# \n" +"# trait ShapeGeometry {\n" +"# fn boundary(self: Rectangle) -> u64;\n" +"# fn area(self: Rectangle) -> u64;\n" +"# }\n" +"# \n" +"# impl RectangleGeometry of ShapeGeometry {\n" +"# fn boundary(self: Rectangle) -> u64 {\n" +"# 2 * (self.height + self.width)\n" +"# }\n" +"# fn area(self: Rectangle) -> u64 {\n" +"# self.height * self.width\n" +"# }\n" +"# }\n" +"# \n" +"fn main() {\n" +" let rect = Rectangle { height: 5, width: 10 }; // Rectangle instantiation\n" +"\n" +" // First way, as a method on the struct instance\n" +" let area1 = rect.area();\n" +" // Second way, from the implementation\n" +" let area2 = RectangleGeometry::area(rect);\n" +" // Third way, from the trait\n" +" let area3 = ShapeGeometry::area(rect);\n" +"\n" +" // `area1` has same value as `area2` and `area3`\n" +" area1.print();\n" +" area2.print();\n" +" area3.print();\n" +"}\n" +"# \n" +"# \n" +"```" + +#: src/ch07-02-traits-in-cairo.md:108 +msgid "And the implementation of the `area` method will be accessed via the `self` parameter." +msgstr "之后我们可以通过 `self`参数访问`area`方法的实现。" + +#: src/ch07-02-traits-in-cairo.md:110 +msgid "## Generic Traits" +msgstr "## 泛型Traits" -#: src/ch08-01-how-to-write-tests.md:270 +#: src/ch07-02-traits-in-cairo.md:112 msgid "" -"We do this by adding the attribute `should_panic` to our test function. The test passes if the code inside the function panics; the test fails if the code inside the function doesn’t " -"panic." -msgstr "我们通过在我们的测试函数中添加属性`should_panic`来做到这一点。如果函数中的代码出现panic,则测试通过;如果函数中的代码没有出现panic,则测试失败。" +"Usually we want to write a trait when we want multiple types to implement a functionality in a standard way. However, in the example above the signatures are static and cannot be " +"used for multiple types. To do this, we use generic types when defining traits." +msgstr "通常情况下,当我们希望多个类型以标准的方式实现一个功能时,我们要写一个trait。然而,在上面的例子中,签名是静态的,不能用于多种类型。为了做到这一点,我们在定义特质时使用泛型。" -#: src/ch08-01-how-to-write-tests.md:272 -msgid "Listing 8-8 shows a test that checks that the error conditions of `GuessTrait::new` happen when we expect them to." -msgstr "示例8-8显示了一个测试,检查`GuessTrait::new`的错误条件是否在我们期望的时候发生。" +#: src/ch07-02-traits-in-cairo.md:114 +msgid "In the example below, we use generic type `T` and our method signatures can use this alias which can be provided during implementation." +msgstr "在下面的例子中,我们使用泛型`T`,我们的方法签名可以使用由实现提供这个别名。" -#: src/ch08-01-how-to-write-tests.md:276 +#: src/ch07-02-traits-in-cairo.md:116 msgid "" "```rust\n" -"use array::ArrayTrait;\n" +"use debug::PrintTrait;\n" "\n" "#[derive(Copy, Drop)]\n" -"struct Guess {\n" -" value: u64,\n" +"struct Rectangle {\n" +" height: u64,\n" +" width: u64,\n" "}\n" "\n" -"trait GuessTrait {\n" -" fn new(value: u64) -> Guess;\n" +"#[derive(Copy, Drop)]\n" +"struct Circle {\n" +" radius: u64\n" "}\n" "\n" -"impl GuessImpl of GuessTrait {\n" -" fn new(value: u64) -> Guess {\n" -" if value < 1 | value > 100 {\n" -" let mut data = ArrayTrait::new();\n" -" data.append('Guess must be >= 1 and <= 100');\n" -" panic(data);\n" -" }\n" -" Guess { value }\n" -" }\n" +"// Here T is an alias type which will be provided during implementation\n" +"trait ShapeGeometry {\n" +" fn boundary(self: T) -> u64;\n" +" fn area(self: T) -> u64;\n" "}\n" "\n" -"#[cfg(test)]\n" -"mod tests {\n" -" use super::Guess;\n" -" use super::GuessTrait;\n" +"// Implementation RectangleGeometry passes in \n" +"// to implement the trait for that type\n" +"impl RectangleGeometry of ShapeGeometry {\n" +" fn boundary(self: Rectangle) -> u64 {\n" +" 2 * (self.height + self.width)\n" +" }\n" +" fn area(self: Rectangle) -> u64 {\n" +" self.height * self.width\n" +" }\n" +"}\n" "\n" -" #[test]\n" -" #[should_panic]\n" -" fn greater_than_100() {\n" -" GuessTrait::new(200);\n" +"// We might have another struct Circle\n" +"// which can use the same trait spec\n" +"impl CircleGeometry of ShapeGeometry {\n" +" fn boundary(self: Circle) -> u64 {\n" +" (2 * 314 * self.radius) / 100\n" +" }\n" +" fn area(self: Circle) -> u64 {\n" +" (314 * self.radius * self.radius) / 100\n" " }\n" "}\n" +"\n" +"fn main() {\n" +" let rect = Rectangle { height: 5, width: 7 };\n" +" rect.area().print(); // 35\n" +" rect.boundary().print(); // 24\n" +"\n" +" let circ = Circle { radius: 5 };\n" +" circ.area().print(); // 78\n" +" circ.boundary().print(); // 31\n" +"}\n" "```" msgstr "" "```rust\n" -"use array::ArrayTrait;\n" +"use debug::PrintTrait;\n" "\n" "#[derive(Copy, Drop)]\n" -"struct Guess {\n" -" value: u64,\n" +"struct Rectangle {\n" +" height: u64,\n" +" width: u64,\n" "}\n" "\n" -"trait GuessTrait {\n" -" fn new(value: u64) -> Guess;\n" +"#[derive(Copy, Drop)]\n" +"struct Circle {\n" +" radius: u64\n" "}\n" "\n" -"impl GuessImpl of GuessTrait {\n" -" fn new(value: u64) -> Guess {\n" -" if value < 1 | value > 100 {\n" -" let mut data = ArrayTrait::new();\n" -" data.append('Guess must be >= 1 and <= 100');\n" -" panic(data);\n" -" }\n" -" Guess { value }\n" -" }\n" +"// Here T is an alias type which will be provided during implementation\n" +"trait ShapeGeometry {\n" +" fn boundary(self: T) -> u64;\n" +" fn area(self: T) -> u64;\n" "}\n" "\n" -"#[cfg(test)]\n" -"mod tests {\n" -" use super::Guess;\n" -" use super::GuessTrait;\n" +"// Implementation RectangleGeometry passes in \n" +"// to implement the trait for that type\n" +"impl RectangleGeometry of ShapeGeometry {\n" +" fn boundary(self: Rectangle) -> u64 {\n" +" 2 * (self.height + self.width)\n" +" }\n" +" fn area(self: Rectangle) -> u64 {\n" +" self.height * self.width\n" +" }\n" +"}\n" "\n" -" #[test]\n" -" #[should_panic]\n" -" fn greater_than_100() {\n" -" GuessTrait::new(200);\n" +"// We might have another struct Circle\n" +"// which can use the same trait spec\n" +"impl CircleGeometry of ShapeGeometry {\n" +" fn boundary(self: Circle) -> u64 {\n" +" (2 * 314 * self.radius) / 100\n" +" }\n" +" fn area(self: Circle) -> u64 {\n" +" (314 * self.radius * self.radius) / 100\n" " }\n" "}\n" +"\n" +"fn main() {\n" +" let rect = Rectangle { height: 5, width: 7 };\n" +" rect.area().print(); // 35\n" +" rect.boundary().print(); // 24\n" +"\n" +" let circ = Circle { radius: 5 };\n" +" circ.area().print(); // 78\n" +" circ.boundary().print(); // 31\n" +"}\n" "```" -#: src/ch08-01-how-to-write-tests.md:312 -msgid "Listing 8-8: Testing that a condition will cause a panic" -msgstr "示例8-8:测试一个条件是否会导致panic" +#: src/ch07-02-traits-in-cairo.md:169 +msgid "## Managing and using external trait implementations" +msgstr "## 管理和使用外部trait的实现" -#: src/ch08-01-how-to-write-tests.md:314 -msgid "We place the `#[should_panic]` attribute after the `#[test]` attribute and before the test function it applies to. Let’s look at the result when this test passes:" -msgstr "我们把`#[should_panic]`属性放在`#[test]`属性之后和它适用的测试函数之前。让我们看一下这个测试通过后的结果:" +#: src/ch07-02-traits-in-cairo.md:171 +msgid "" +"To use traits methods, you need to make sure the correct traits/implementation(s) are imported. In the code above we imported `PrintTrait` from `debug` with `use debug::PrintTrait;` " +"to use the `print()` methods on supported types." +msgstr "" +"要使用trait的方法,你需要确保导入了正确的 traits以及它的实现。在上面的代码中,我们从`debug`中导入了`PrintTrait`,并使用`use debug::PrintTrait;`以在支持的类型上使用`print()`方法。" -#: src/ch08-01-how-to-write-tests.md:316 +#: src/ch07-02-traits-in-cairo.md:173 msgid "" -"```shell\n" -"$ cairo-test .\n" -"running 1 tests\n" -"test adder::lib::tests::greater_than_100 ... ok\n" -"test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" -"```" +"In some cases you might need to import not only the trait but also the implementation if they are declared in separate modules.\n" +"If `CircleGeometry` was in a separate module/file `circle` then to use `boundary` on `circ: Circle`, we'd need to import `CircleGeometry` in addition to `ShapeGeometry`." msgstr "" -"```shell\n" -"$ cairo-test .\n" -"running 1 tests\n" -"test adder::lib::tests::greater_than_100 … ok\n" -"test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" -"```" +"在某些情况下,如果它们被声明在不同的模块中,你可能不仅需要导入trait,还需要导入实现。\n" +"如果`CircleGeometry`是在一个单独的模块/文件`circle`中,那么要在`circ: Circle`上使用`boundary`,我们就需要在 `ShapeGeometry`之外再导入 `CircleGeometry`。" -#: src/ch08-01-how-to-write-tests.md:323 -msgid "Looks good! Now let’s introduce a bug in our code by removing the condition that the new function will panic if the value is greater than `100`:" -msgstr "看起来不错! 现在让我们在代码中引入一个错误,删除新函数在值大于`100`时将发生panic的条件:" +#: src/ch07-02-traits-in-cairo.md:176 +msgid "" +"If the code was organised into modules like this, where the implementation of a trait was defined in a different module than the trait itself, explicitly importing the relevant " +"implementation is required." +msgstr "如果代码被组织成类似这样的模块,其中trait的实现被定义在与trait本身不同的模块中时,则需要显式导入相关的实现。" -#: src/ch08-01-how-to-write-tests.md:325 +#: src/ch07-02-traits-in-cairo.md:178 msgid "" -"```rust\n" -"// --snip--\n" -"impl GuessImpl of GuessTrait {\n" -" fn new(value: u64) -> Guess {\n" -" if value < 1{\n" -" let mut data = ArrayTrait::new();\n" -" data.append('Guess must be >= 1 and <= 100');\n" -" panic(data);\n" -" }\n" +"```rust,noplayground\n" +"use debug::PrintTrait;\n" "\n" -" Guess { value, }\n" +"// struct Circle { ... } and struct Rectangle { ... }\n" +"\n" +"mod geometry {\n" +" use super::Rectangle;\n" +" trait ShapeGeometry {\n" +" // ...\n" +" }\n" +"\n" +" impl RectangleGeometry of ShapeGeometry:: {\n" +" // ...\n" " }\n" "}\n" -"```" -msgstr "" -"```rust\n" -"// --snip--\n" -"impl GuessImpl of GuessTrait {\n" -" fn new(value: u64) -> Guess {\n" -" if value < 1{\n" -" let mut data = ArrayTrait::new();\n" -" data.append('Guess must be >= 1 and <= 100');\n" -" panic(data);\n" -" }\n" "\n" -" Guess { value, }\n" +"// Could be in a different file\n" +"mod circle {\n" +" use super::geometry::ShapeGeometry;\n" +" use super::Circle;\n" +" impl CircleGeometry of ShapeGeometry {\n" +" // ...\n" " }\n" "}\n" +"\n" +"fn main() {\n" +" let rect = Rectangle { height: 5, width: 7 };\n" +" let circ = Circle { radius: 5 };\n" +" // Fails with this error\n" +" // Method `area` not found on... Did you import the correct trait and impl?\n" +" rect.area().print();\n" +" circ.area().print();\n" +"}\n" "```" - -#: src/ch08-01-how-to-write-tests.md:340 -msgid "When we run the test in Listing 8-8, it will fail:" -msgstr "当我们运行示例8-8中的测试时,它将失败:" - -#: src/ch08-01-how-to-write-tests.md:342 -msgid "" -"```shell\n" -"$ cairo-test .\n" -"running 1 tests\n" -"test adder::lib::tests::greater_than_100 ... fail\n" -"failures:\n" -" adder::lib::tests::greater_than_100 - expected panic but finished successfully.\n" -"Error: test result: FAILED. 0 passed; 1 failed; 0 ignored\n" -"```" -msgstr "" -"```shell\n" -"$ cairo-test .\n" -"running 1 tests\n" -"test adder::lib::tests::greater_than_100 ... fail\n" -"failures:\n" -" adder::lib::tests::greater_than_100 - expected panic but finished successfully.\n" -"Error: test result: FAILED. 0 passed; 1 failed; 0 ignored\n" -"```" - -#: src/ch08-01-how-to-write-tests.md:351 -msgid "" -"We don’t get a very helpful message in this case, but when we look at the test function, we see that it’s annotated with `#[should_panic]`. The failure we got means that the code in " -"the test function did not cause a panic." -msgstr "在这种情况下,我们没有得到一个非常有用的消息,但是当我们看测试函数时,我们看到它被注解为`#[should_panic]`。我们得到的失败意味着测试函数中的代码并没有引起panic。" - -#: src/ch08-01-how-to-write-tests.md:353 -msgid "" -"Tests that use `should_panic` can be imprecise. A `should_panic` test would pass even if the test panics for a different reason from the one we were expecting. To make `should_panic` " -"tests more precise, we can add an optional expected parameter to the `should_panic` attribute. The test harness will make sure that the failure message contains the provided text. " -"For example, consider the modified code for `Guess` in Listing 8-9 where the new function panics with different messages depending on whether the value is too small or too large." msgstr "" -"使用`should_panic`的测试可能是不精确的。即使测试的panic原因与我们所期望的不同, 但只要发生了panic,一个`should_panic`测试就一定会通过。为了使`should_panic`测试更加精确,我们可以在" -"`should_panic`属性中添加一个可选的预期参数。该测试限制将确保故障信息包含所提供的文本。例如,考虑示例8-9中`Guess`的修改后的代码,新函数根据数值过小或过大的情况,以不同的消息进行恐慌。" - -#: src/ch08-01-how-to-write-tests.md:357 -msgid "" -"```rust\n" -"// --snip--\n" -"impl GuessImpl of GuessTrait {\n" -" fn new(value: u64) -> Guess {\n" -" if value < 1{\n" -" let mut data = ArrayTrait::new();\n" -" data.append('Guess must be >= 1');\n" -" panic(data);\n" -" } else if value > 100{\n" -" let mut data = ArrayTrait::new();\n" -" data.append('Guess must be <= 100');\n" -" panic(data);\n" -" }\n" +"```rust,noplayground\n" +"use debug::PrintTrait;\n" "\n" -" Guess { value, }\n" -" }\n" -"}\n" +"// struct Circle { ... } and struct Rectangle { ... }\n" "\n" -"#[cfg(test)]\n" -"mod tests {\n" -" use super::Guess;\n" -" use super::GuessTrait;\n" +"mod geometry {\n" +" use super::Rectangle;\n" +" trait ShapeGeometry {\n" +" // ...\n" +" }\n" "\n" -" #[test]\n" -" #[should_panic(expected: ('Guess must be <= 100', ))]\n" -" fn greater_than_100() {\n" -" GuessTrait::new(200);\n" +" impl RectangleGeometry of ShapeGeometry:: {\n" +" // ...\n" " }\n" "}\n" -"```" -msgstr "" -"```rust\n" -"// --snip--\n" -"impl GuessImpl of GuessTrait {\n" -" fn new(value: u64) -> Guess {\n" -" if value < 1{\n" -" let mut data = ArrayTrait::new();\n" -" data.append('Guess must be >= 1');\n" -" panic(data);\n" -" } else if value > 100{\n" -" let mut data = ArrayTrait::new();\n" -" data.append('Guess must be <= 100');\n" -" panic(data);\n" -" }\n" "\n" -" Guess { value, }\n" +"// Could be in a different file\n" +"mod circle {\n" +" use super::geometry::ShapeGeometry;\n" +" use super::Circle;\n" +" impl CircleGeometry of ShapeGeometry {\n" +" // ...\n" " }\n" "}\n" "\n" -"#[cfg(test)]\n" -"mod tests {\n" -" use super::Guess;\n" -" use super::GuessTrait;\n" -"\n" -" #[test]\n" -" #[should_panic(expected: ('Guess must be <= 100', ))]\n" -" fn greater_than_100() {\n" -" GuessTrait::new(200);\n" -" }\n" +"fn main() {\n" +" let rect = Rectangle { height: 5, width: 7 };\n" +" let circ = Circle { radius: 5 };\n" +" // Fails with this error\n" +" // Method `area` not found on... Did you import the correct trait and impl?\n" +" rect.area().print();\n" +" circ.area().print();\n" "}\n" "```" -#: src/ch08-01-how-to-write-tests.md:388 -msgid "Listing 8-9: Testing for a panic with a panic message containing the error message string" -msgstr "示例8-9:用包含错误信息字符串的恐慌信息来测试panic" +#: src/ch07-02-traits-in-cairo.md:213 +msgid "To make it work, in addition to," +msgstr "为了使其发挥作用,除此之外、" -#: src/ch08-01-how-to-write-tests.md:390 +#: src/ch07-02-traits-in-cairo.md:215 msgid "" -"This test will pass because the value we put in the `should_panic` attribute’s expected parameter is the array of string of the message that the `Guess::new` function panics with. We " -"need to specify the entire panic message that we expect." -msgstr "这个测试将通过,因为我们放在`should_panic`属性的预期参数中的值是`Guess::new`函数panic信息的字符串阵列。我们需要指定我们期望的整个panic信息。" +"```rust\n" +"use geometry::ShapeGeometry;\n" +"```" +msgstr "" +"```rust\n" +"use geometry::ShapeGeometry;\n" +"```" -#: src/ch08-01-how-to-write-tests.md:392 +#: src/ch07-02-traits-in-cairo.md:219 msgid "" -"To see what happens when a `should_panic` test with an expected message fails, let’s again introduce a bug into our code by swapping the bodies of the if `value < 1` and the else if " -"`value > 100` blocks:" -msgstr "为了看看当一个带有预期信息的 `should_panic` 测试失败时会发生什么,让我们再次把if `value < 1`和else if `value > 100`块的主体互换,从而在我们的代码中引入一个错误:" +"you will need to import `CircleGeometry` explicitly. Note that you do not need to import `RectangleGeometry`, as it is defined in the same module as the imported trait, and thus is " +"automatically resolved." +msgstr "您需要明确地导入 `CircleGeometry`。请注意,您不需要导入 `RectangleGeometry`,因为它与导入的 trait 定义在同一个模块中,因此会自动解析。" -#: src/ch08-01-how-to-write-tests.md:394 +#: src/ch07-02-traits-in-cairo.md:221 msgid "" "```rust\n" -"if value < 1{\n" -" let mut data = ArrayTrait::new();\n" -" data.append('Guess must be <= 100');\n" -" panic(data);\n" -"} else if value > 100{\n" -" let mut data = ArrayTrait::new();\n" -" data.append('Guess must be >= 1');\n" -" panic(data);\n" -"}\n" +"use circle::CircleGeometry\n" "```" msgstr "" "```rust\n" -"if value < 1{\n" -" let mut data = ArrayTrait::new();\n" -" data.append('Guess must be <= 100');\n" -" panic(data);\n" -"} else if value > 100{\n" -" let mut data = ArrayTrait::new();\n" -" data.append('Guess must be >= 1');\n" -" panic(data);\n" -"}\n" +"use circle::CircleGeometry;\n" "```" -#: src/ch08-01-how-to-write-tests.md:406 -msgid "This time when we run the `should_panic` test, it will fail:" -msgstr "这一次,当我们运行`should_panic`测试时,它将失败:" +#: src/ch08-00-testing-cairo-programs.md:1 +msgid "# Testing Cairo Programs" +msgstr "# 测试Cairo 程序" + +#: src/ch08-01-how-to-write-tests.md:1 +msgid "# How To Write Tests" +msgstr "# 如何编写测试" + +#: src/ch08-01-how-to-write-tests.md:3 +msgid "## The Anatomy of a Test Function" +msgstr "## 测试函数的剖析" + +#: src/ch08-01-how-to-write-tests.md:5 +msgid "Tests are Cairo functions that verify that the non-test code is functioning in the expected manner. The bodies of test functions typically perform these three actions:" +msgstr "测试是Cairo函数,用于验证非测试代码是否以预期方式运行。测试函数的主体通常执行这三个动作:" + +#: src/ch08-01-how-to-write-tests.md:7 +msgid "" +"- Set up any needed data or state.\n" +"- Run the code you want to test.\n" +"- Assert the results are what you expect." +msgstr "" +"- 设置任何需要的数据或状态。\n" +"- 运行你想测试的代码。\n" +"- 断言结果与你期望的一样。" + +#: src/ch08-01-how-to-write-tests.md:11 +msgid "" +"Let’s look at the features Cairo provides specifically for writing tests that take these actions, which include the `test` attribute, the `assert` function, and the `should_panic` " +"attribute." +msgstr "让我们看看Cairo专门为编写执行这些动作的测试所提供的功能,其中包括`test`属性、`assert`函数和`should_panic`属性。" + +#: src/ch08-01-how-to-write-tests.md:13 +msgid "### The Anatomy of a Test Function" +msgstr "### 一个测试函数的剖析" + +#: src/ch08-01-how-to-write-tests.md:15 +msgid "" +"At its simplest, a test in Cairo is a function that’s annotated with the `test` attribute. Attributes are metadata about pieces of Cairo code; one example is the derive attribute we " +"used with structs in Chapter 4. To change a function into a test function, add `#[test]` on the line before `fn`. When you run your tests with the `cairo-test` command, Cairo builds " +"a test runner binary that runs the annotated functions and reports on whether each test function passes or fails." +msgstr "" +"最简单的Cairo中的测试是一个带有`test`属性注释的函数。属性是关于Cairo代码片段的元数据;一个例子是我们在第4章中对结构体使用的derive属性。要把一个函数变成测试函数,在 `fn`前的一行加上 " +"`#[test]`。当你用`cairo-test`命令运行你的测试时,Cairo会建立一个测试运行器的二进制文件,运行被标注了的函数,并报告每个测试函数的通过或失败。" + +#: src/ch08-01-how-to-write-tests.md:17 +msgid "Let's create a new project called `adder` that will add two numbers using Scarb with the command `scarb new adder`:" +msgstr "让我们创建一个名为 `adder`的将两个数字相加的新项目,用`scarb new adder`”命令:" -#: src/ch08-01-how-to-write-tests.md:408 +#: src/ch08-01-how-to-write-tests.md:19 msgid "" "```shell\n" -"$ cairo-test .\n" -"running 1 tests\n" -"test adder::lib::tests::greater_than_100 ... fail\n" -"failures:\n" -" adder::lib::tests::greater_than_100 - panicked with [6224920189561486601619856539731839409791025 ('Guess must be >= 1'), ].\n" -"\n" -"Error: test result: FAILED. 0 passed; 1 failed; 0 ignored\n" +"adder\n" +"├── cairo_project.toml\n" +"├── Scarb.toml\n" +"└── src\n" +" └── lib.cairo\n" "```" msgstr "" "```shell\n" -"$ cairo-test .\n" -"running 1 tests\n" -"test adder::lib::tests::greater_than_100 … fail\n" -"failures:\n" -" adder::lib::tests::greater_than_100 - panicked with [6224920189561486601619856539731839409791025 (‘Guess must be >= 1’), ].\n" -"\n" -"Error: test result: FAILED. 0 passed; 1 failed; 0 ignored\n" +"adder\n" +"├── cairo_project.toml\n" +"├── Scarb.toml\n" +"└── src\n" +" └── lib.cairo\n" "```" -#: src/ch08-01-how-to-write-tests.md:418 -msgid "" -"The failure message indicates that this test did indeed panic as we expected, but the panic message did not include the expected string. The panic message that we did get in this " -"case was `Guess must be >= 1`. Now we can start figuring out where our bug is!" -msgstr "" -"失败信息表明,这个测试确实像我们预期的那样发生了panic,但是panic信息不包括预期的字符串。在这种情况下,我们得到的panic信息是 `Guess must be >= 1`。现在我们可以开始找出我们的错误所在了!" - -#: src/ch08-01-how-to-write-tests.md:420 -msgid "## Running Single Tests" -msgstr "## 运行单一测试" +#: src/ch08-01-how-to-write-tests.md:27 src/ch08-02-test-organization.md:51 +msgid "" +msgstr "" -#: src/ch08-01-how-to-write-tests.md:422 +#: src/ch08-01-how-to-write-tests.md:29 msgid "" -"Sometimes, running a full test suite can take a long time. If you’re working on code in a particular area, you might want to run only the tests pertaining to that code. You can " -"choose which tests to run by passing `cairo-test` the name of the test you want to run as an argument." +"> Note: You will notice here a `cairo_project.toml` file.\n" +"> This is the configuration file for \"vanilla\" Cairo projects (i.e. not managed by Scarb),\n" +"> which is required to run the `cairo-test .` command to run the code of the crate.\n" +"> It is required until Scarb implements this feature. The content of the file is:\n" +">\n" +"> ```toml\n" +"> [crate_roots]\n" +"> adder = \"src\"\n" +"> ```\n" +">\n" +"> and indicates that the crate named \"adder\" is located in the `src` directory." msgstr "" -"有时,运行一个完整的测试套件可能需要很长的时间。如果你正在处理某个特定领域的代码,你可能只想运行与该代码有关的测试。你可以通过传递`cairo-test`你想运行的测试名称作为参数来选择运行哪些" -"测试。" +"> 注意:你会注意到这里有一个`cairo_project.toml`文件。\n" +"> 这是 普通的Cairo项目的配置文件(即不由Scarb管理)、\n" +"> 在运行`cairo-test .`命令来运行crate的代码需要这个文件。\n" +"> 在Scarb实现这一功能之前,它是必需的。该文件的内容是:\n" +">\n" +"> ```toml\n" +"> [crate_roots]\n" +"> adder = “src”\n" +"> ```\n" +">\n" +"> 该文件指出,名为 \"adder \"的crate位于`src`目录下。" -#: src/ch08-01-how-to-write-tests.md:424 -msgid "To demonstrate how to run a single test, we’ll first create two tests functions, as shown in Listing 8-10, and choose which ones to run." -msgstr "为了演示如何运行一个测试,我们将首先创建两个测试函数,如示例8-10所示,并选择运行哪一个。" +#: src/ch08-01-how-to-write-tests.md:41 +msgid "In _lib.cairo_, let's add a first test, as shown in Listing 8-1." +msgstr "在 _lib.cairo_ 中,让我们添加第一个测试,如示例8-1所示。" -#: src/ch08-01-how-to-write-tests.md:428 +#: src/ch08-01-how-to-write-tests.md:45 msgid "" "```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" " #[test]\n" -" fn add_two_and_two() {\n" +" fn it_works() {\n" " let result = 2 + 2;\n" " assert(result == 4, 'result is not 4');\n" " }\n" -"\n" -" #[test]\n" -" fn add_three_and_two() {\n" -" let result = 3 + 2;\n" -" assert(result == 5, 'result is not 5');\n" -" }\n" -"}\n" "```" msgstr "" "```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" " #[test]\n" -" fn add_two_and_two() {\n" +" fn it_works() {\n" " let result = 2 + 2;\n" -" assert(result == 4, ‘result is not 4’);\n" +" assert(result == 4, 'result is not 4');\n" " }\n" -"\n" -" #[test]\n" -" fn add_three_and_two() {\n" -" let result = 3 + 2;\n" -" assert(result == 5, ‘result is not 5’);\n" -" }\n" -"}\n" "```" -#: src/ch08-01-how-to-write-tests.md:445 -msgid "Listing 8-10: Two tests with two different names" -msgstr "示例8-10:两个不同名称的测试" +#: src/ch08-01-how-to-write-tests.md:53 +msgid "Listing 8-1: A test module and function" +msgstr "示例8-1:一个测试模块和其函数" -#: src/ch08-01-how-to-write-tests.md:447 -msgid "We can pass the name of any test function to `cairo-test` to run only that test using the `-f` flag:" -msgstr "我们可以将任何测试函数的名称传递给`cairo-test`,以使用`-f` 标志只运行该测试:" +#: src/ch08-01-how-to-write-tests.md:55 +msgid "" +"For now, let’s ignore the top two lines and focus on the function. Note the `#[test]` annotation: this attribute indicates this is a test function, so the test runner knows to treat " +"this function as a test. We might also have non-test functions in the tests module to help set up common scenarios or perform common operations, so we always need to indicate which " +"functions are tests." +msgstr "" +"现在,让我们忽略最上面的两行,专注于这个函数。注意`#[test]`标注:这个属性表明这是一个测试函数,所以测试运行器知道要把这个函数当作一个测试。我们可能在测试模块中也有非测试函数,以帮助设" +"置常见的场景或执行常见的操作,所以我们总是需要指出哪些函数是测试的。" -#: src/ch08-01-how-to-write-tests.md:449 +#: src/ch08-01-how-to-write-tests.md:57 +msgid "" +"The example function body uses the `assert` function, which contains the result of adding 2 and 2, equals 4. This assertion serves as an example of the format for a typical test. " +"Let’s run it to see that this test passes." +msgstr "这个例子的函数体使用了`assert`函数,它包含了2和2相加的结果,等于4。这个断言是一个典型测试格式范例。让我们运行它,看看这个测试是否通过。" + +#: src/ch08-01-how-to-write-tests.md:59 +msgid "The `cairo-test .` command runs all tests in our project, as shown in Listing 8-2." +msgstr "用`cairo-test .`命令运行我们项目中的所有测试,如示例8-2所示。" + +#: src/ch08-01-how-to-write-tests.md:61 msgid "" "```shell\n" -"$ cairo-test . -f add_two_and_two\n" +"$ cairo-test .\n" "running 1 tests\n" -"test adder::lib::tests::add_two_and_two ... ok\n" -"test result: ok. 1 passed; 0 failed; 0 ignored; 1 filtered out;\n" +"test adder::lib::tests::it_works ... ok\n" +"test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" "```" msgstr "" "```shell\n" -"$ cairo-test . -f add_two_and_two\n" +"$ cairo-test .\n" "running 1 tests\n" -"test adder::lib::tests::add_two_and_two ... ok\n" -"test result: ok. 1 passed; 0 failed; 0 ignored; 1 filtered out;\n" +"test adder::lib::tests::it_works … ok\n" +"test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" "```" -#: src/ch08-01-how-to-write-tests.md:456 -msgid "" -"Only the test with the name `add_two_and_two` ran; the other test didn’t match that name. The test output lets us know we had one more test that didn’t run by displaying 1 filtered " -"out at the end." -msgstr "只有名称为`add_two_and_two` 的测试被运行了,其他的测试不符合这个名称。测试输出最后显示了1个测试被过滤掉,让我们知道我们还有一个测试没有运行。" - -#: src/ch08-01-how-to-write-tests.md:458 -msgid "We can also specify part of a test name, and any test whose name contains that value will be run." -msgstr "我们还可以指定测试名称的一部分,任何名称包含该值的测试都将被运行。" +#: src/ch08-01-how-to-write-tests.md:68 +msgid "Listing 8-2: The output from running a test" +msgstr "示例8-2:运行测试后的输出" -#: src/ch08-01-how-to-write-tests.md:460 -msgid "## Ignoring Some Tests Unless Specifically Requested" -msgstr "## 在非特别指定时,忽略一些测试" +#: src/ch08-01-how-to-write-tests.md:70 +msgid "" +"`cairo-test` compiled and ran the test. We see the line `running 1 tests`. The next line shows the name of the generated test function, called `it_works`, and that the result of " +"running that test is `ok`. The overall summary `test result: ok.` means that all the tests passed, and the portion that reads `1 passed; 0 failed` totals the number of tests that " +"passed or failed." +msgstr "" +"`cairo-test`编译并运行了测试。我们看到一行`running 1 tests`。下一行显示了生成的测试函数的名称,叫做`it_works`,运行该测试的结果是`ok`。总体摘要`test result: ok.`意味着所有的测试都通过" +"了,`1 passed; 0 failed` 的部分展示了通过或失败的测试的总数。" -#: src/ch08-01-how-to-write-tests.md:462 +#: src/ch08-01-how-to-write-tests.md:72 msgid "" -"Sometimes a few specific tests can be very time-consuming to execute, so you might want to exclude them during most runs of `cairo-test`. Rather than listing as arguments all tests " -"you do want to run, you can instead annotate the time-consuming tests using the `ignore` attribute to exclude them, as shown here:" +"It’s possible to mark a test as ignored so it doesn’t run in a particular instance; we’ll cover that in the [Ignoring Some Tests Unless Specifically Requested](#ignoring-some-tests-" +"unless-specifically-requested) section later in this chapter. Because we haven’t done that here, the summary shows `0 ignored`. We can also pass an argument to the `cairo-test` " +"command to run only a test whose name matches a string; this is called filtering and we’ll cover that in the [Running Single Tests](#running-single-tests) section. We also haven’t " +"filtered the tests being run, so the end of the summary shows `0 filtered out`." msgstr "" -"有时一些特定的测试执行起来非常耗时,所以你可能想在大多数`cairo-test`的运行中排除它们。与其将所有你想运行的测试列为参数,不如使用`ignore` 属性对耗时的测试进行注释,将其排除在外,如图所" -"示:" +"我们可以把一个测试标记为忽略,这样它就不会在一个特定的实例中运行;我们将在本章后面的[忽略一些测试,除非特别要求](#ignoring-some-tests-unless-specifically-requested)一节中介绍。因为我" +"们在这里没有这样做,所以摘要中显示 `0 ignored`。我们也可以给`cairo-test`命令传递一个参数,只运行名称与某个字符串相匹配的测试;这叫做过滤,我们将在[运行单个测试](#running-single-test)" +"一节中介绍。我们也没有对正在运行的测试进行过滤,所以总结的最后显示`0 filtered out`。" + +#: src/ch08-01-how-to-write-tests.md:74 +msgid "Let’s start to customize the test to our own needs. First change the name of the `it_works` function to a different name, such as `exploration`, like so:" +msgstr "让我们开始根据我们自己的需要定制测试。首先将`it_works`函数的名称改为不同的名称,例如`exploration`,像这样:" -#: src/ch08-01-how-to-write-tests.md:466 +#: src/ch08-01-how-to-write-tests.md:78 msgid "" "```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" " #[test]\n" -" fn it_works() {\n" +" fn exploration() {\n" " let result = 2 + 2;\n" " assert(result == 4, 'result is not 4');\n" " }\n" -"\n" +"```" +msgstr "" +"```rust\n" " #[test]\n" -" #[ignore]\n" -" fn expensive_test() {\n" -" // code that takes an hour to run\n" +" fn exploration() {\n" +" let result = 2 + 2;\n" +" assert(result == 4, 'result is not 4');\n" " }\n" -"}\n" "```" + +#: src/ch08-01-how-to-write-tests.md:86 +msgid "Then run `cairo-test -- --path src` again. The output now shows `exploration` instead of `it_works`:" +msgstr "然后再次运行`cairo-test -- --path src`。现在输出显示的是 `exploration`而不是`it_works`:" + +#: src/ch08-01-how-to-write-tests.md:88 +msgid "" +"```shell\n" +"$ cairo-test .\n" +"running 1 tests\n" +"test adder::lib::tests::exploration ... ok\n" +"test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" +"```" +msgstr "" +"```shell\n" +"$ cairo-test .\n" +"running 1 tests\n" +"test adder::lib::tests::exploration … ok\n" +"test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" +"```" + +#: src/ch08-01-how-to-write-tests.md:95 +msgid "" +"Now we’ll add another test, but this time we’ll make a test that fails! Tests fail when something in the test function panics. Each test is run in a new thread, and when the main " +"thread sees that a test thread has died, the test is marked as failed. Enter the new test as a function named `another`, so your _src/lib.cairo_ file looks like Listing 8-3." msgstr "" +"现在我们将添加另一个测试,但这次我们要做一个失败的测试! 当测试函数中的某些东西发生panic时,测试就会失败。每个测试都在一个新的线程中运行,当主线程看到一个测试线程死亡时,该测试被标记为" +"失败。将新的测试作为一个名为`another`的函数输入,因此你的 _src/lib.cairo_ 文件看起来像示例8-3里一样。" + +#: src/ch08-01-how-to-write-tests.md:97 +msgid "" "```rust\n" -"#[cfg(test)]\n" -"mod tests {\n" " #[test]\n" -" fn it_works() {\n" +" fn another() {\n" " let result = 2 + 2;\n" -" assert(result == 4, ‘result is not 4’);\n" +" assert(result == 6, 'Make this test fail');\n" " }\n" "\n" +"```" +msgstr "" +"```rust\n" " #[test]\n" -" #[ignore]\n" -" fn expensive_test() {\n" -" // code that takes an hour to run\n" +" fn another() {\n" +" let result = 2 + 2;\n" +" assert(result == 6, 'Make this test fail');\n" " }\n" -"}\n" +"\n" "```" -#: src/ch08-01-how-to-write-tests.md:483 -msgid "After `#[test]` we add the `#[ignore]` line to the test we want to exclude. Now when we run our tests, `it_works` runs, but `expensive_test` doesn’t:" -msgstr "对于想要排除的测试,我们在 `#[test]`之后,添加了 `#[ignore]`行。现在,当我们运行我们的测试时,`it_works`会运行,但`expensive_test`不会:" +#: src/ch08-01-how-to-write-tests.md:106 +msgid "Listing 8-3: Adding a second test that will fail" +msgstr "示例8-3:添加第二个测试(会失败的测试)" -#: src/ch08-01-how-to-write-tests.md:485 +#: src/ch08-01-how-to-write-tests.md:108 msgid "" "```shell\n" "$ cairo-test .\n" "running 2 tests\n" -"test adder::lib::tests::expensive_test ... ignored\n" -"test adder::lib::tests::it_works ... ok\n" -"test result: ok. 1 passed; 0 failed; 1 ignored; 0 filtered out;\n" +"test adder::lib::tests::exploration ... ok\n" +"test adder::lib::tests::another ... fail\n" +"failures:\n" +" adder::lib::tests::another - panicked with [1725643816656041371866211894343434536761780588 ('Make this test fail'), ].\n" +"Error: test result: FAILED. 1 passed; 1 failed; 0 ignored\n" "```" msgstr "" "```shell\n" "$ cairo-test .\n" "running 2 tests\n" -"test adder::lib::tests::expensive_test ... ignored\n" -"test adder::lib::tests::it_works ... ok\n" -"test result: ok. 1 passed; 0 failed; 1 ignored; 0 filtered out;\n" +"test adder::lib::tests::exploration … ok\n" +"test adder::lib::tests::another … fail\n" +"failures:\n" +" adder::lib::tests::another - panicked with [1725643816656041371866211894343434536761780588 (‘Make this test fail’), ].\n" +"Error: test result: FAILED. 1 passed; 1 failed; 0 ignored\n" "```" -#: src/ch08-01-how-to-write-tests.md:493 -msgid "The `expensive_test` function is listed as ignored." -msgstr "`expensive_test`函数被列为`ignored`。" - -#: src/ch08-01-how-to-write-tests.md:495 -msgid "" -"When you’re at a point where it makes sense to check the results of the ignored tests and you have time to wait for the results, you can run `cairo-test --include-ignored` to run all " -"tests whether they’re ignored or not." -msgstr "当你到了需要检查被忽略的测试结果的时候,而且你有时间等待测试结果,你可以运行`cairo-test --include-ignored`来运行所有的测试,无论它们是否被标记忽略。" - -#: src/ch08-02-test-organization.md:1 -msgid "# Testing Organization" -msgstr "# 测试的组织结构" +#: src/ch08-01-how-to-write-tests.md:118 +msgid "Listing 8-4: Test results when one test passes and one test fails" +msgstr "示例8-4:一个测试通过,一个测试失败时的测试结果" -#: src/ch08-02-test-organization.md:3 +#: src/ch08-01-how-to-write-tests.md:120 msgid "" -"We'll think about tests in terms of two main categories: unit tests and integration tests. Unit tests are small and more focused, testing one module in isolation at a time, and can " -"test private functions. Integration tests use your code in the same way any other external code would, using only the public interface and potentially exercising multiple modules per " -"test." +"Instead of `ok`, the line `adder::lib::tests::another` shows `fail`. A new section appears between the individual results and the summary. It displays the detailed reason for each " +"test failure. In this case, we get the details that `another` failed because it panicked with `[1725643816656041371866211894343434536761780588 ('Make this test fail'), ]` in the _src/" +"lib.cairo_ file." msgstr "" -"我们倾向于根据测试的两个主要分类来考虑问题:单元测试和集成测试。单元测试(unit tests)与 集成测试(integration tests)。单元测试倾向于更小而更集中,在隔离的环境中一次测试一个模块,或" -"者是测试私有接口。而集成测试对于你的代码来说则完全是外部的。它们与其他外部代码一样,通过相同的方式使用你的代码,只测试公有接口而且每个测试都有可能会测试多个模块。" +"`adder::lib::test::another`这一行没有显示`ok`,而是显示`fail`。在单个结果和摘要之间出现了一个新的部分。它显示了每个测试失败的详细原因。在这个例子中,我们得到的细节在是 _src/lib.cairo_" +"文件中`another`失败了,因为它发生了panic `[1725643816656041371866211894343434536761780588 (‘Make this test fail’), ]`。" -#: src/ch08-02-test-organization.md:5 -msgid "Writing both kinds of tests is important to ensure that the pieces of your library are doing what you expect them to, separately and together." -msgstr "为了保证你的库能够按照你的预期运行,从独立和整体的角度编写这两类测试都是非常重要的。" +#: src/ch08-01-how-to-write-tests.md:122 +msgid "The summary line displays at the end: overall, our test result is `FAILED`. We had one test pass and one test fail." +msgstr "摘要行显示在最后:总的来说,我们的测试结果是`FAILED`。我们有一个测试通过,一个测试失败。" -#: src/ch08-02-test-organization.md:7 -msgid "## Unit Tests" -msgstr "## 单元测试" +#: src/ch08-01-how-to-write-tests.md:124 +msgid "Now that you’ve seen what the test results look like in different scenarios, let’s look at some functions that are useful in tests." +msgstr "现在你已经看到了不同场景下的测试结果,让我们看看一些在测试中有用的函数。" -#: src/ch08-02-test-organization.md:9 +#: src/ch08-01-how-to-write-tests.md:126 +msgid "## Checking Results with the assert function" +msgstr "## 用断言函数检查结果" + +#: src/ch08-01-how-to-write-tests.md:128 msgid "" -"The purpose of unit tests is to test each unit of code in isolation from the rest of the code to quickly pinpoint where code is and isn’t working as expected. You’ll put unit tests " -"in the `src` directory in each file with the code that they’re testing." +"The `assert` function, provided by Cairo, is useful when you want to ensure that some condition in a test evaluates to `true`. We give the `assert` function a first argument that " +"evaluates to a Boolean. If the value is `true`, nothing happens and the test passes. If the value is `false`, the assert function calls `panic()` to cause the test to fail with a " +"message we defined as the second argument of the `assert` function. Using the `assert` function helps us check that our code is functioning in the way we intend." msgstr "" -"单元测试的目的是在与其他部分隔离的环境中测试每一个单元的代码,以便于快速而准确地验证某个单元的代码功能是否符合预期。单元测试与他们要测试的代码共同存放在位于 src 目录下相同的文件中。" - -#: src/ch08-02-test-organization.md:11 -msgid "The convention is to create a module named tests in each file to contain the test functions and to annotate the module with `cfg(test)`." -msgstr "规范是在每个文件中创建包含测试函数的 tests 模块,并使用 `cfg(test)` 标注模块。" - -#: src/ch08-02-test-organization.md:13 -msgid "### The Tests Module and `#[cfg(test)]`" -msgstr "### 测试模块和`#[cfg(test)]`" +"Cairo提供的`assert`函数,在你想确保测试中的某些条件一定为`true`时非常有用。我们给`assert`函数的第一个参数是一个布尔值。如果该值为`true`,则不会发生任何事情,测试通过。如果值是 " +"`false`,assert函数调用 `panic()`,导致测试失败,我们定义的信息是 `assert`函数的第二个参数。使用`assert`函数可以帮助我们检查我们的代码是否按照我们的意图运行。" -#: src/ch08-02-test-organization.md:15 +#: src/ch08-01-how-to-write-tests.md:130 msgid "" -"The `#[cfg(test)]` annotation on the tests module tells Cairo to compile and run the test code only when you run `cairo-test`, not when you run `cairo-run`. This saves compile time " -"when you only want to build the library and saves space in the resulting compiled artifact because the tests are not included. You’ll see that because integration tests go in a " -"different directory, they don’t need the `#[cfg(test)]` annotation. However, because unit tests go in the same files as the code, you’ll use `#[cfg(test)]` to specify that they " -"shouldn’t be included in the compiled result." +"In [Chapter 4, Listing 5-15](ch04-03-method-syntax.md#multiple-impl-blocks), we used a `Rectangle` struct and a `can_hold` method, which are repeated here in Listing 8-5. Let’s put " +"this code in the _src/lib.cairo_ file, then write some tests for it using the `assert` function." msgstr "" -"测试模块的 `#[cfg(test)]`注解告诉 Cairo 只在执行`cairo-test` 时才编译和运行测试代码,而在运行 `cairo-run` 时不这么做。这在只希望构建库的时候可以节省编译时间,并且因为它们并没有包含测" -"试,所以能减少编译产生的文件的大小。与之对应的集成测试因为位于另一个文件夹,所以它们并不需要 `#[cfg(test)]`注解。然而单元测试位于与源码相同的文件中,所以你需要使用 `#[cfg(test)]` 来指" -"定他们不应该被包含进编译结果中。" - -#: src/ch08-02-test-organization.md:17 -msgid "Recall that when we created the new `adder` project in the first section of this chapter, we wrote this first test:" -msgstr "回顾一下,当我们在本章第一节创建新的`adder`项目时,我们写了这个测试:" +"在[第4章,示例5-15](ch04-03-method-syntax.md#multiple-impl-blocks)中,我们使用了一个`Rectangle`结构和一个`can_hold`方法,在示例8-5中重复了这些。让我们把这段代码放在_src/lib.cairo_文件" +"中,然后用`assert`函数为它写一些测试。" -#: src/ch08-02-test-organization.md:32 +#: src/ch08-01-how-to-write-tests.md:134 msgid "" -"The attribute `cfg` stands for configuration and tells Cairo that the following item should only be included given a certain configuration option. In this case, the configuration " -"option is `test`, which is provided by Cairo for compiling and running tests. By using the `cfg` attribute, Cairo compiles our test code only if we actively run the tests with `cairo-" -"test`. This includes any helper functions that might be within this module, in addition to the functions annotated with `#[test]`." +"```rust\n" +"trait RectangleTrait {\n" +" fn area(self: @Rectangle) -> u64;\n" +" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" +"}\n" +"\n" +"impl RectangleImpl of RectangleTrait {\n" +" fn area(self: @Rectangle) -> u64 {\n" +" *self.width * *self.height\n" +" }\n" +"\n" +" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +" *self.width > *other.width && *self.height > *other.height\n" +" }\n" +"}\n" +"```" msgstr "" -"属性`cfg`代表配置,告诉Cairo只有在给定的配置选项的情况下才应该包含下面的项目。在本例中,配置选项是`test`,它由Cairo提供,用于编译和运行测试。通过使用`cfg`属性,Cairo只有在我们用" -"`cairo-test`主动运行测试时才会编译我们的测试代码。这包括任何可能在这个模块中的辅助函数,以及用`#[test]`标注的函数。" +"```rust\n" +"trait RectangleTrait {\n" +" fn area(self: @Rectangle) -> u64;\n" +" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" +"}\n" +"\n" +"impl RectangleImpl of RectangleTrait {\n" +" fn area(self: @Rectangle) -> u64 {\n" +" *self.width * *self.height\n" +" }\n" +"\n" +" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +" *self.width > *other.width && *self.height > *other.height\n" +" }\n" +"}\n" +"```" -#: src/ch08-02-test-organization.md:34 -msgid "## Integration Tests" -msgstr "## 集成测试" +#: src/ch08-01-how-to-write-tests.md:151 +msgid "Listing 8-5: Using the `Rectangle` struct and its `can_hold` method from Chapter 5" +msgstr "示例8-5:使用第五章中的 `Rectangle`结构及其`can_hold`方法" -#: src/ch08-02-test-organization.md:36 +#: src/ch08-01-how-to-write-tests.md:153 msgid "" -"Integration tests use your library in the same way any other code would. Their purpose is to test whether many parts of your library work together correctly. Units of code that work " -"correctly on their own could have problems when integrated, so test coverage of the integrated code is important as well. To create integration tests, you first need a `tests` " -"directory." +"The `can_hold` method returns a `bool`, which means it’s a perfect use case for the assert function. In Listing 8-6, we write a test that exercises the `can_hold` method by creating " +"a `Rectangle` instance that has a width of `8` and a height of `7` and asserting that it can hold another `Rectangle` instance that has a width of `5` and a height of `1`." msgstr "" -"集成测试对于你需要测试的库来说完全是外部的。同其他使用库的代码一样使用库文件,也就是说它们只能调用一部分库中的公有 API。集成测试的目的是测试库的多个部分能否一起正常工作。一些单独能正" -"确运行的代码单元集成在一起也可能会出现问题,所以集成测试的覆盖率也是很重要的。为了创建集成测试,你需要先创建一个 `tests` 目录。" - -#: src/ch08-02-test-organization.md:38 -msgid "### The `tests` Directory" -msgstr "### `tests`目录" +"返回值为`bool`的`can_hold`方法是assert函数的一个完美用例。在示例8-6中,我们写了一个测试,通过创建一个宽度为`8`、高度为`7`的`Rectangle`实例,并断言它可以容纳另一个宽度为`5`、高度为`1`" +"的`Rectangle`实例,来测试`can_hold`方法。" -#: src/ch08-02-test-organization.md:40 +#: src/ch08-01-how-to-write-tests.md:157 msgid "" -"```shell\n" -"adder\n" -"├── cairo_project.toml\n" -"├── src\n" -" ├── lib.cairo\n" -"│ └── main.cairo\n" -"└── tests\n" -" ├── lib.cairo\n" -" └── integration_test.cairo\n" +"```rust\n" +"# use debug::PrintTrait;\n" +"# #[derive(Copy, Drop)]\n" +"# struct Rectangle {\n" +"# width: u64,\n" +"# height: u64,\n" +"# }\n" +"# \n" +"# trait RectangleTrait {\n" +"# fn area(self: @Rectangle) -> u64;\n" +"# fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" +"# }\n" +"# \n" +"# impl RectangleImpl of RectangleTrait {\n" +"# fn area(self: @Rectangle) -> u64 {\n" +"# *self.width * *self.height\n" +"# }\n" +"# \n" +"# fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +"# *self.width > *other.width && *self.height > *other.height\n" +"# }\n" +"# }\n" +"# \n" +"# #[cfg(test)]\n" +"# mod tests {\n" +"# use super::Rectangle;\n" +"# use super::RectangleTrait;\n" +"# \n" +"# \n" +" #[test]\n" +" fn larger_can_hold_smaller() {\n" +" let larger = Rectangle { height: 7, width: 8, };\n" +" let smaller = Rectangle { height: 1, width: 5, };\n" +"\n" +" assert(larger.can_hold(@smaller), 'rectangle cannot hold');\n" +" }\n" +"# \n" +"# #[test]\n" +"# fn smaller_cannot_hold_larger() {\n" +"# let larger = Rectangle { height: 7, width: 8, };\n" +"# let smaller = Rectangle { height: 1, width: 5, };\n" +"# \n" +"# assert(!smaller.can_hold(@larger), 'rectangle cannot hold');\n" +"# }\n" +"# }\n" +"# \n" +"# \n" "```" msgstr "" -"```shell\n" -"adder\n" -"├── cairo_project.toml\n" -"├── src\n" -" ├── lib.cairo\n" -"│ └── main.cairo\n" -"└── tests\n" -" ├── lib.cairo\n" -" └── integration_test.cairo\n" +"```rust\n" +"# use debug::PrintTrait;\n" +"# #[derive(Copy, Drop)]\n" +"# struct Rectangle {\n" +"# width: u64,\n" +"# height: u64,\n" +"# }\n" +"# \n" +"# trait RectangleTrait {\n" +"# fn area(self: @Rectangle) -> u64;\n" +"# fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" +"# }\n" +"# \n" +"# impl RectangleImpl of RectangleTrait {\n" +"# fn area(self: @Rectangle) -> u64 {\n" +"# *self.width * *self.height\n" +"# }\n" +"# \n" +"# fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +"# *self.width > *other.width && *self.height > *other.height\n" +"# }\n" +"# }\n" +"# \n" +"# #[cfg(test)]\n" +"# mod tests {\n" +"# use super::Rectangle;\n" +"# use super::RectangleTrait;\n" +"# \n" +"# \n" +" #[test]\n" +" fn larger_can_hold_smaller() {\n" +" let larger = Rectangle { height: 7, width: 8, };\n" +" let smaller = Rectangle { height: 1, width: 5, };\n" +"\n" +" assert(larger.can_hold(@smaller), 'rectangle cannot hold');\n" +" }\n" +"# \n" +"# #[test]\n" +"# fn smaller_cannot_hold_larger() {\n" +"# let larger = Rectangle { height: 7, width: 8, };\n" +"# let smaller = Rectangle { height: 1, width: 5, };\n" +"# \n" +"# assert(!smaller.can_hold(@larger), 'rectangle cannot hold');\n" +"# }\n" +"# }\n" +"# \n" +"# \n" "```" -#: src/ch08-02-test-organization.md:53 +#: src/ch08-01-how-to-write-tests.md:206 +msgid "Listing 8-6: A test for `can_hold` that checks whether a larger rectangle can indeed hold a smaller rectangle" +msgstr "示例 8-6: `can_hold`的测试,检查一个较大的矩形是否真的可以容纳一个较小的矩形" + +#: src/ch08-01-how-to-write-tests.md:208 msgid "" -"> To successfully run your tests with `cairo-test` you will need to update your `cairo_project.toml` file to add the declaration of your `tests` crate.\n" -">\n" -"> ```rust\n" -"> [crate_roots]\n" -"> adder = \"src\"\n" -"> tests = \"tests\"\n" -"> ```" +"Note that we’ve added two new lines inside the tests module: `use super::Rectangle;` and `use super::RectangleTrait;`. The tests module is a regular module that follows the usual " +"visibility rules. Because the tests module is an inner module, we need to bring the code under test in the outer module into the scope of the inner module." msgstr "" -"> 为了成功地用`cairo-test`运行你的测试,你需要更新你的`cairo_project.toml`文件,添加你的`tests`crate的声明。\n" -">\n" -"> ```rust\n" -"> [crate_roots]\n" -"> adder = “src”\n" -"> tests = “tests”\n" -"> ```" - -#: src/ch08-02-test-organization.md:61 -msgid "Each test file is compiled as its own separate crate, that's why whenever you add a new test file you must add it to your _tests/lib.cairo_." -msgstr "每个测试文件都被编译为它自己独立的crate,这就是为什么每当你添加一个新的测试文件,你必须把它添加到你的 _tests/lib.cairo_ 文件中。" +"注意,我们在测试模块中加入了两行新的内容:`use super::Rectangle;`和`use super::RectangleTrait;`。测试模块是一个常规模块,遵循通常的可见性规则。因为测试模块是一个内部模块,我们需要将外" +"部模块中的被测代码引入内部模块的范围。" -#: src/ch08-02-test-organization.md:63 -msgid "Filename: tests/lib.cairo" -msgstr "文件名:test/lib.cairo" +#: src/ch08-01-how-to-write-tests.md:210 +msgid "" +"We’ve named our test `larger_can_hold_smaller`, and we’ve created the two `Rectangle` instances that we need. Then we called the assert function and passed it the result of calling " +"`larger.can_hold(@smaller)`. This expression is supposed to return `true`, so our test should pass. Let’s find out!" +msgstr "" +"我们将我们的测试命名为`larger_can_hold_smaller`,并且创建了我们需要的两个`Rectangle`实例。然后我们调用了assert函数,并将调用`larger.can_hold(@smaller)`的结果传给它。这个表达式应该返" +"回 `true`,所以我们的测试应该通过。让我们拭目以待吧!" -#: src/ch08-02-test-organization.md:65 +#: src/ch08-01-how-to-write-tests.md:212 msgid "" -"```rust\n" -"#[cfg(tests)]\n" -"mod integration_tests;\n" +"```shell\n" +"$ cairo-test .\n" +"running 1 tests\n" +"test adder::lib::tests::larger_can_hold_smaller ... ok\n" +"test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" "```" msgstr "" -"```rust\n" -"#[cfg(tests)]\n" -"mod integration_tests;\n" +"```shell\n" +"$ cairo-test .\n" +"running 1 tests\n" +"test adder::lib::tests::larger_can_hold_smaller ... ok\n" +"test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" "```" -#: src/ch08-02-test-organization.md:70 -msgid "Enter the code in Listing 11-13 into the _tests/integration_test.cairo_ file:" -msgstr "将示例11-13中的代码输入到 _tests/integration_test.cairo_ 文件:" - -#: src/ch08-02-test-organization.md:72 -msgid "Filename: tests/integration_test.cairo" -msgstr "文件名:test/integration_test.cairo" +#: src/ch08-01-how-to-write-tests.md:219 +msgid "It does pass! Let’s add another test, this time asserting that a smaller rectangle cannot hold a larger rectangle:" +msgstr "它确实通过了!让我们再增加一个测试,这次是断言一个较小的矩形不能容纳一个较大的矩形:" -#: src/ch08-02-test-organization.md:74 +#: src/ch08-01-how-to-write-tests.md:223 msgid "" "```rust\n" -"use adder::main;\n" +"# use debug::PrintTrait;\n" +"# #[derive(Copy, Drop)]\n" +"# struct Rectangle {\n" +"# width: u64,\n" +"# height: u64,\n" +"# }\n" +"# \n" +"# trait RectangleTrait {\n" +"# fn area(self: @Rectangle) -> u64;\n" +"# fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" +"# }\n" +"# \n" +"# impl RectangleImpl of RectangleTrait {\n" +"# fn area(self: @Rectangle) -> u64 {\n" +"# *self.width * *self.height\n" +"# }\n" +"# \n" +"# fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +"# *self.width > *other.width && *self.height > *other.height\n" +"# }\n" +"# }\n" +"# \n" +"# #[cfg(test)]\n" +"# mod tests {\n" +"# use super::Rectangle;\n" +"# use super::RectangleTrait;\n" +"# \n" +"# \n" +"# #[test]\n" +"# fn larger_can_hold_smaller() {\n" +"# let larger = Rectangle { height: 7, width: 8, };\n" +"# let smaller = Rectangle { height: 1, width: 5, };\n" +"# \n" +"# assert(larger.can_hold(@smaller), 'rectangle cannot hold');\n" +"# }\n" +"# \n" +" #[test]\n" +" fn smaller_cannot_hold_larger() {\n" +" let larger = Rectangle { height: 7, width: 8, };\n" +" let smaller = Rectangle { height: 1, width: 5, };\n" "\n" -"#[test]\n" -"fn internal() {\n" -" assert(main::internal_adder(2, 2) == 4, 'internal_adder failed');\n" -"}\n" +" assert(!smaller.can_hold(@larger), 'rectangle cannot hold');\n" +" }\n" +"# }\n" +"# \n" +"# \n" "```" msgstr "" "```rust\n" -"use adder::main;\n" +"# use debug::PrintTrait;\n" +"# #[derive(Copy, Drop)]\n" +"# struct Rectangle {\n" +"# width: u64,\n" +"# height: u64,\n" +"# }\n" +"# \n" +"# trait RectangleTrait {\n" +"# fn area(self: @Rectangle) -> u64;\n" +"# fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" +"# }\n" +"# \n" +"# impl RectangleImpl of RectangleTrait {\n" +"# fn area(self: @Rectangle) -> u64 {\n" +"# *self.width * *self.height\n" +"# }\n" +"# \n" +"# fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +"# *self.width > *other.width && *self.height > *other.height\n" +"# }\n" +"# }\n" +"# \n" +"# #[cfg(test)]\n" +"# mod tests {\n" +"# use super::Rectangle;\n" +"# use super::RectangleTrait;\n" +"# \n" +"# \n" +"# #[test]\n" +"# fn larger_can_hold_smaller() {\n" +"# let larger = Rectangle { height: 7, width: 8, };\n" +"# let smaller = Rectangle { height: 1, width: 5, };\n" +"# \n" +"# assert(larger.can_hold(@smaller), 'rectangle cannot hold');\n" +"# }\n" +"# \n" +" #[test]\n" +" fn smaller_cannot_hold_larger() {\n" +" let larger = Rectangle { height: 7, width: 8, };\n" +" let smaller = Rectangle { height: 1, width: 5, };\n" "\n" -"#[test]\n" -"fn internal() {\n" -" assert(main::internal_adder(2, 2) == 4, 'internal_adder failed');\n" -"}\n" +" assert(!smaller.can_hold(@larger), 'rectangle cannot hold');\n" +" }\n" +"# }\n" +"# \n" +"# \n" "```" -#: src/ch08-02-test-organization.md:83 +#: src/ch08-01-how-to-write-tests.md:272 msgid "" -"Each file in the tests directory is a separate crate, so we need to bring our library into each test crate’s scope. For that reason we add `use adder::main` at the top of the code, " -"which we didn’t need in the unit tests." -msgstr "测试目录中的每个文件都是一个独立的crate,所以我们需要将我们的库引入每个测试crate的范围。出于这个原因,我们在代码的顶部添加了`use adder::main`,在单元测试中我们不需要这个。" +"Because the correct result of the `can_hold` function in this case is `false`, we need to negate that result before we pass it to the assert function. As a result, our test will pass " +"if `can_hold` returns false:" +msgstr "因为在这种情况下,`can_hold`函数的正确结果是`false`,我们需要在传递给assert函数之前否定这个结果。因此,如果`can_hold`返回false,我们的测试将通过:" -#: src/ch08-02-test-organization.md:85 +#: src/ch08-01-how-to-write-tests.md:274 msgid "" "```shell\n" -"$ cairo-test tests/\n" -"running 1 tests\n" -"test tests::tests_integration::it_adds_two ... ok\n" -"test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" +"$ cairo-test .\n" +" running 2 tests\n" +" test adder::lib::tests::smaller_cannot_hold_larger ... ok\n" +" test adder::lib::tests::larger_can_hold_smaller ... ok\n" +" test result: ok. 2 passed; 0 failed; 0 ignored; 0 filtered out;\n" "```" msgstr "" "```shell\n" -"$ cairo-test tests/\n" -"running 1 tests\n" -"test tests::tests_integration::it_adds_two ... ok\n" -"test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" +"$ cairo-test .\n" +" running 2 tests\n" +" test adder::lib::tests::smaller_cannot_hold_larger … ok\n" +" test adder::lib::tests::larger_can_hold_smaller … ok\n" +" test result: ok. 2 passed; 0 failed; 0 ignored; 0 filtered out;\n" "```" -#: src/ch08-02-test-organization.md:92 -msgid "The result of the tests is the same as what we've been seeing: one line for each test." -msgstr "测试的结果与我们之前看到的相同:每个测试一行。" - -#: src/ch09-00-error-handling.md:1 -msgid "# Error handling" -msgstr "# 错误处理" +#: src/ch08-01-how-to-write-tests.md:282 +msgid "" +"Two tests that pass! Now let’s see what happens to our test results when we introduce a bug in our code. We’ll change the implementation of the `can_hold` method by replacing the " +"greater-than sign with a less-than sign when it compares the widths:" +msgstr "两个测试都通过了!现在让我们看看当我们在代码中引入一个错误时,我们的测试结果会怎样。我们将改变`can_hold`方法的实现,当它比较宽度时,将大于号替换为小于号:" -#: src/ch09-00-error-handling.md:3 +#: src/ch08-01-how-to-write-tests.md:284 msgid "" -"In this chapter, we will explore various error handling techniques provided by Cairo, which not only allow you to address potential issues in your code, but also make it easier to " -"create programs that are adaptable and maintainable. By examining different approaches to managing errors, such as pattern matching with the Result enum, using the ? operator for " -"more ergonomic error propagation, and employing the unwrap or expect methods for handling recoverable errors, you'll gain a deeper understanding of Cairo's error handling features. " -"These concepts are crucial for building robust applications that can effectively handle unexpected situations, ensuring your code is ready for production." +"```rust\n" +"impl RectangleImpl of RectangleTrait {\n" +" fn area(self: @Rectangle) -> u64 {\n" +" *self.width * *self.height\n" +" }\n" +"\n" +" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +" *self.width < *other.width && *self.height > *other.height\n" +" }\n" +"}\n" +"```" msgstr "" -"在本章中,我们将探讨Cairo提供的各种错误处理技术,这些技术不仅能让你解决代码中的潜在问题,还能让你更容易创建易适应和易维护的程序。通过研究管理错误的不同方法,如用Result枚举进行模式匹" -"配,使用 ? 操作符进行更人性化的错误传播,以及采用unwrap或expect方法来处理可恢复的错误,你将对Cairo的错误处理功能有更深入的了解。这些概念对于构建强大的应用程序至关重要,它可以有效地处" -"理意外情况,确保你的代码可以用于生产环境。" +"```rust\n" +"impl RectangleImpl of RectangleTrait {\n" +" fn area(self: @Rectangle) -> u64 {\n" +" *self.width * *self.height\n" +" }\n" +"\n" +" fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +" *self.width < *other.width && *self.height > *other.height\n" +" }\n" +"}\n" +"```" -#: src/ch09-01-unrecoverable-errors-with-panic.md:1 -msgid "# Unrecoverable Errors with panic" -msgstr "# 无法恢复的错误与恐慌(panic)" +#: src/ch08-01-how-to-write-tests.md:296 +msgid "Running the tests now produces the following:" +msgstr "现在运行测试产生以下结果:" -#: src/ch09-01-unrecoverable-errors-with-panic.md:3 +#: src/ch08-01-how-to-write-tests.md:298 msgid "" -"In Cairo, unexpected issues may arise during program execution, resulting in runtime errors. While the panic function from the core library doesn't provide a resolution for these " -"errors, it does acknowledge their occurrence and terminates the program. There are two primary ways that a panic can be triggered in Cairo: inadvertently, through actions causing the " -"code to panic (e.g., accessing an array beyond its bounds), or deliberately, by invoking the panic function." -msgstr "" -"在Cairo中,程序执行过程中可能会出现意外问题,导致运行时错误。虽然核心库中的panic函数并没有为这些错误提供解决方案,但它确实承认这些错误的发生并终止程序。在Cairo中,有两种主要的方式可以" -"触发panic:无意地通过导致代码panic的行为(例如,访问一个超出其界限的数组),或故意地,通过调用panic函数。" - -#: src/ch09-01-unrecoverable-errors-with-panic.md:5 -msgid "" -"When a panic occurs, it leads to an abrupt termination of the program. The `panic` function takes an array as argument, which can be used to provide an error message and performs an " -"unwind process where all variables are dropped and dictionaries squashed to ensure the soundness of the program to safely terminate the execution." -msgstr "" -"当panic发生时,它会导致程序的突然终止。`panic` 函数接受一个数组作为参数,可以用来提供一个错误信息,并执行一个展开(unwind)过程--所有的变量被丢弃,字典被压缩(squash),以确保程序的合理" -"地,安全地终止执行。" - -#: src/ch09-01-unrecoverable-errors-with-panic.md:7 -msgid "Here is how we can `panic` from inside a program and return the error code `2`:" -msgstr "下面是我们如何在一个程序中`panic`并返回错误代码`2`:" - -#: src/ch09-01-unrecoverable-errors-with-panic.md:11 -msgid "" -"```rust,does_not_compile\n" -"use array::ArrayTrait;\n" -"use debug::PrintTrait;\n" +"```shell\n" +"$ cairo-test .\n" +"running 2 tests\n" +"test adder::lib::tests::smaller_cannot_hold_larger ... ok\n" +"test adder::lib::tests::larger_can_hold_smaller ... fail\n" +"failures:\n" +" adder::lib::tests::larger_can_hold_smaller - panicked with [167190012635530104759003347567405866263038433127524 ('rectangle cannot hold'), ].\n" "\n" -"fn main() {\n" -" let mut data = ArrayTrait::new();\n" -" data.append(2);\n" -" panic(data);\n" -" 'This line isn\\'t reached'.print();\n" -"}\n" +"Error: test result: FAILED. 1 passed; 1 failed; 0 ignored\n" "```" msgstr "" -"```rust,does_not_compile\n" -"use array::ArrayTrait;\n" -"use debug::PrintTrait;\n" +"```shell\n" +"$ cairo-test .\n" +"running 2 tests\n" +"test adder::lib::tests::smaller_cannot_hold_larger … ok\n" +"test adder::lib::tests::larger_can_hold_smaller … fail\n" +"failures:\n" +" adder::lib::tests::larger_can_hold_smaller - panicked with [167190012635530104759003347567405866263038433127524 (‘rectangle cannot hold’), ].\n" "\n" -"fn main() {\n" -" let mut data = ArrayTrait::new();\n" -" data.append(2);\n" -" panic(data);\n" -" 'This line isn\\'t reached'.print();\n" -"}\n" +"Error: test result: FAILED. 1 passed; 1 failed; 0 ignored\n" "```" -#: src/ch09-01-unrecoverable-errors-with-panic.md:23 -msgid "Running the program will produce the following output:" -msgstr "运行该程序将产生以下输出:" +#: src/ch08-01-how-to-write-tests.md:309 +msgid "Our tests caught the bug! Because `larger.width` is `8` and `smaller.width` is `5`, the comparison of the widths in `can_hold` now returns `false`: `8` is not less than `5`." +msgstr "我们的测试发现了这个错误! 因为`larger.width`是`8`,`smaller.width`是`5`,`can_hold`中的宽度比较现在返回`false`:因为`8`不比`5`小。" + +#: src/ch08-01-how-to-write-tests.md:311 +msgid "## Checking for Panics with `should_panic`" +msgstr "## 用`should_panic`检查panic情况" -#: src/ch09-01-unrecoverable-errors-with-panic.md:25 +#: src/ch08-01-how-to-write-tests.md:313 msgid "" -"```console\n" -"$ cairo-run test.cairo\n" -"Run panicked with err values: [2]\n" -"```" +"In addition to checking return values, it’s important to check that our code handles error conditions as we expect. For example, consider the Guess type in Listing 8-8. Other code " +"that uses `Guess` depends on the guarantee that `Guess` instances will contain only values between `1` and `100`. We can write a test that ensures that attempting to create a `Guess` " +"instance with a value outside that range panics." msgstr "" -"```console\n" -"$ cairo-run test.cairo\n" -"Run panicked with err values: [2]\n" -"```" - -#: src/ch09-01-unrecoverable-errors-with-panic.md:30 -msgid "As you can notice in the output, the print statement is never reached, as the program terminates after encountering the `panic` statement." -msgstr "正如你在输出中所注意到的,打印语句没有被执行,因为程序在遇到`panic`语句后就终止了。" +"除了检查返回值之外,检查我们的代码是否按照我们所期望的那样处理错误条件也很重要。例如,考虑示例8-8中的Guess类型。其他使用`Guess`的代码依赖于保证`Guess`实例只包含`1`和`100`之间的值。我" +"们可以写一个测试,以确保试图创建的`Guess`实例的值不在这个范围内时,会发生panic。" -#: src/ch09-01-unrecoverable-errors-with-panic.md:32 +#: src/ch08-01-how-to-write-tests.md:315 msgid "" -"An alternative and more idiomatic approach to panic in Cairo would be to use the `panic_with_felt252` function. This function serves as an abstraction of the array-defining process " -"and is often preferred due to its clearer and more concise expression of intent. By using `panic_with_felt252`, developers can panic in a one-liner by providing a felt252 error " -"message as argument, making the code more readable and maintainable." -msgstr "" -"在Cairo中,另一种更常见的方法是使用`panic_with_felt252`函数来处理恐慌。这个函数是对数组定义过程的抽象,由于它更清晰、更简洁地表达了意图,所以实际运用中经常使用该函数。通过使用" -"`panic_with_felt252`,开发者可以通过提供felt252错误信息作为参数,在一个单行代码中进行panic,使代码更易读和可维护。" +"We do this by adding the attribute `should_panic` to our test function. The test passes if the code inside the function panics; the test fails if the code inside the function doesn’t " +"panic." +msgstr "我们通过在我们的测试函数中添加属性`should_panic`来做到这一点。如果函数中的代码出现panic,则测试通过;如果函数中的代码没有出现panic,则测试失败。" -#: src/ch09-01-unrecoverable-errors-with-panic.md:34 -msgid "Let's consider an example:" -msgstr "让我们来考察一个例子:" +#: src/ch08-01-how-to-write-tests.md:317 +msgid "Listing 8-8 shows a test that checks that the error conditions of `GuessTrait::new` happen when we expect them to." +msgstr "示例8-8显示了一个测试,检查`GuessTrait::new`的错误条件是否在我们期望的时候发生。" -#: src/ch09-01-unrecoverable-errors-with-panic.md:36 +#: src/ch08-01-how-to-write-tests.md:321 msgid "" "```rust\n" -"fn main() {\n" -" panic_with_felt252(2);\n" +"#[derive(Copy, Drop)]\n" +"struct Guess {\n" +" value: u64,\n" +"}\n" +"\n" +"trait GuessTrait {\n" +" fn new(value: u64) -> Guess;\n" +"}\n" +"\n" +"impl GuessImpl of GuessTrait {\n" +" fn new(value: u64) -> Guess {\n" +" if value < 1 || value > 100 {\n" +" let mut data = ArrayTrait::new();\n" +" data.append('Guess must be >= 1 and <= 100');\n" +" panic(data);\n" +" }\n" +" Guess { value }\n" +" }\n" +"}\n" +"\n" +"#[cfg(test)]\n" +"mod tests {\n" +" use super::Guess;\n" +" use super::GuessTrait;\n" +"\n" +" #[test]\n" +" #[should_panic]\n" +" fn greater_than_100() {\n" +" GuessTrait::new(200);\n" +" }\n" "}\n" "```" msgstr "" "```rust\n" -"fn main() {\n" -" panic_with_felt252(2);\n" +"#[derive(Copy, Drop)]\n" +"struct Guess {\n" +" value: u64,\n" +"}\n" +"\n" +"trait GuessTrait {\n" +" fn new(value: u64) -> Guess;\n" +"}\n" +"\n" +"impl GuessImpl of GuessTrait {\n" +" fn new(value: u64) -> Guess {\n" +" if value < 1 || value > 100 {\n" +" let mut data = ArrayTrait::new();\n" +" data.append('Guess must be >= 1 and <= 100');\n" +" panic(data);\n" +" }\n" +" Guess { value }\n" +" }\n" +"}\n" +"\n" +"#[cfg(test)]\n" +"mod tests {\n" +" use super::Guess;\n" +" use super::GuessTrait;\n" +"\n" +" #[test]\n" +" #[should_panic]\n" +" fn greater_than_100() {\n" +" GuessTrait::new(200);\n" +" }\n" "}\n" "```" -#: src/ch09-01-unrecoverable-errors-with-panic.md:42 -msgid "" -"Executing this program will yield the same error message as before. In that case, if there is no need for an array and multiple values to be returned within the error, so " -"`panic_with_felt252` is a more succinct alternative." -msgstr "执行这个程序会产生和之前一样的错误信息。在这种情况下,如果在返回错误是不需要一个数组和多个值,那么`panic_with_felt252`是一个更简洁的选择。" - -#: src/ch09-01-unrecoverable-errors-with-panic.md:44 -msgid "## nopanic notation" -msgstr "## nopanic记号" - -#: src/ch09-01-unrecoverable-errors-with-panic.md:46 -msgid "You can use the `nopanic` notation to indicate that a function will never panic. Only `nopanic` functions can be called in a function annotated as `nopanic`." -msgstr "你可以使用`nopanic`记号来表示一个函数永远不会恐慌。只有 `nopanic`函数可以在标注为 `nopanic`的函数中被调用。" +#: src/ch08-01-how-to-write-tests.md:355 +msgid "Listing 8-8: Testing that a condition will cause a panic" +msgstr "示例8-8:测试一个条件是否会导致panic" -#: src/ch09-01-unrecoverable-errors-with-panic.md:48 src/ch09-01-unrecoverable-errors-with-panic.md:83 src/appendix-03-derivable-traits.md:17 src/appendix-03-derivable-traits.md:42 -#: src/appendix-03-derivable-traits.md:63 src/appendix-03-derivable-traits.md:85 src/appendix-03-derivable-traits.md:118 -msgid "Example:" -msgstr "例子:" +#: src/ch08-01-how-to-write-tests.md:357 +msgid "We place the `#[should_panic]` attribute after the `#[test]` attribute and before the test function it applies to. Let’s look at the result when this test passes:" +msgstr "我们把`#[should_panic]`属性放在`#[test]`属性之后和它适用的测试函数之前。让我们看一下这个测试通过后的结果:" -#: src/ch09-01-unrecoverable-errors-with-panic.md:50 +#: src/ch08-01-how-to-write-tests.md:359 msgid "" -"```rust\n" -"fn function_never_panic() -> felt252 nopanic {\n" -" 42\n" -"}\n" +"```shell\n" +"$ cairo-test .\n" +"running 1 tests\n" +"test adder::lib::tests::greater_than_100 ... ok\n" +"test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" "```" msgstr "" -"```rust\n" -"fn function_never_panic() -> felt252 nopanic {\n" -" 42\n" -"}\n" +"```shell\n" +"$ cairo-test .\n" +"running 1 tests\n" +"test adder::lib::tests::greater_than_100 … ok\n" +"test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" "```" -#: src/ch09-01-unrecoverable-errors-with-panic.md:56 -msgid "Wrong example:" -msgstr "错误的例子:" +#: src/ch08-01-how-to-write-tests.md:366 +msgid "Looks good! Now let’s introduce a bug in our code by removing the condition that the new function will panic if the value is greater than `100`:" +msgstr "看起来不错! 现在让我们在代码中引入一个错误,删除新函数在值大于`100`时将发生panic的条件:" -#: src/ch09-01-unrecoverable-errors-with-panic.md:58 +#: src/ch08-01-how-to-write-tests.md:368 msgid "" "```rust\n" -"fn function_never_panic() nopanic {\n" -" assert(1 == 1, 'what');\n" +"# #[derive(Copy, Drop)]\n" +"# struct Guess {\n" +"# value: u64,\n" +"# }\n" +"# \n" +"# trait GuessTrait {\n" +"# fn new(value: u64) -> Guess;\n" +"# }\n" +"# \n" +"impl GuessImpl of GuessTrait {\n" +" fn new(value: u64) -> Guess {\n" +" if value < 1 {\n" +" let mut data = ArrayTrait::new();\n" +" data.append('Guess must be >= 1 and <= 100');\n" +" panic(data);\n" +" }\n" +"\n" +" Guess { value, }\n" +" }\n" "}\n" +"# \n" +"# \n" "```" msgstr "" "```rust\n" -"fn function_never_panic() nopanic {\n" -" assert(1 == 1, 'what');\n" +"# #[derive(Copy, Drop)]\n" +"# struct Guess {\n" +"# value: u64,\n" +"# }\n" +"# \n" +"# trait GuessTrait {\n" +"# fn new(value: u64) -> Guess;\n" +"# }\n" +"# \n" +"impl GuessImpl of GuessTrait {\n" +" fn new(value: u64) -> Guess {\n" +" if value < 1 {\n" +" let mut data = ArrayTrait::new();\n" +" data.append('Guess must be >= 1 and <= 100');\n" +" panic(data);\n" +" }\n" +"\n" +" Guess { value, }\n" +" }\n" "}\n" +"# \n" +"# \n" "```" -#: src/ch09-01-unrecoverable-errors-with-panic.md:64 -msgid "If you write the following function that includes a function that may panic you will get the following error:" -msgstr "如果你写了以下函数,其中包括一个可能会panic的函数,你会得到以下错误:" +#: src/ch08-01-how-to-write-tests.md:393 +msgid "When we run the test in Listing 8-8, it will fail:" +msgstr "当我们运行示例8-8中的测试时,它将失败:" -#: src/ch09-01-unrecoverable-errors-with-panic.md:66 +#: src/ch08-01-how-to-write-tests.md:395 msgid "" -"```bash\n" -"error: Function is declared as nopanic but calls a function that may panic.\n" -" --> test.cairo:2:12\n" -" assert(1 == 1, 'what');\n" -" ^****^\n" -"Function is declared as nopanic but calls a function that may panic.\n" -" --> test.cairo:2:5\n" -" assert(1 == 1, 'what');\n" -" ^********************^\n" +"```shell\n" +"$ cairo-test .\n" +"running 1 tests\n" +"test adder::lib::tests::greater_than_100 ... fail\n" +"failures:\n" +" adder::lib::tests::greater_than_100 - expected panic but finished successfully.\n" +"Error: test result: FAILED. 0 passed; 1 failed; 0 ignored\n" "```" msgstr "" -"```bash\n" -"error: Function is declared as nopanic but calls a function that may panic.\n" -" --> test.cairo:2:12\n" -" assert(1 == 1, 'what');\n" -" ^****^\n" -"Function is declared as nopanic but calls a function that may panic.\n" -" --> test.cairo:2:5\n" -" assert(1 == 1, 'what');\n" -" ^********************^\n" +"```shell\n" +"$ cairo-test .\n" +"running 1 tests\n" +"test adder::lib::tests::greater_than_100 ... fail\n" +"failures:\n" +" adder::lib::tests::greater_than_100 - expected panic but finished successfully.\n" +"Error: test result: FAILED. 0 passed; 1 failed; 0 ignored\n" "```" -#: src/ch09-01-unrecoverable-errors-with-panic.md:77 -msgid "Note that there are two functions that may panic here, assert and equality." -msgstr "请注意,有两个函数可能会在这里发生panic,即断言和相等比较。" - -#: src/ch09-01-unrecoverable-errors-with-panic.md:79 -msgid "## panic_with macro" -msgstr "## panic_with 宏" - -#: src/ch09-01-unrecoverable-errors-with-panic.md:81 +#: src/ch08-01-how-to-write-tests.md:404 msgid "" -"You can use the `panic_with` macro to mark a function that returns an `Option` or `Result`. This macro takes two arguments, which are the data that is passed as the panic reason as " -"well as the name for a wrapping function. It will create a wrapper for your annotated function which will panic if the function returns `None` or `Err`, the panic function will be " -"called with the given data." -msgstr "" -"你可以使用`panic_with`宏来标记一个返回`Option`或`Result`的函数。这个宏需要两个参数,即作为panic原因传递的数据以及包装函数的名称。它将为你注释的函数创建一个包装器,如果该函数返回" -"`None` 或`Err`,该panic函数将被调用,并给出数据。" +"We don’t get a very helpful message in this case, but when we look at the test function, we see that it’s annotated with `#[should_panic]`. The failure we got means that the code in " +"the test function did not cause a panic." +msgstr "在这种情况下,我们没有得到一个非常有用的消息,但是当我们看测试函数时,我们看到它被注解为`#[should_panic]`。我们得到的失败意味着测试函数中的代码并没有引起panic。" + +#: src/ch08-01-how-to-write-tests.md:406 +msgid "" +"Tests that use `should_panic` can be imprecise. A `should_panic` test would pass even if the test panics for a different reason from the one we were expecting. To make `should_panic` " +"tests more precise, we can add an optional expected parameter to the `should_panic` attribute. The test harness will make sure that the failure message contains the provided text. " +"For example, consider the modified code for `Guess` in Listing 8-9 where the new function panics with different messages depending on whether the value is too small or too large." +msgstr "" +"使用`should_panic`的测试可能是不精确的。即使测试的panic原因与我们所期望的不同, 但只要发生了panic,一个`should_panic`测试就一定会通过。为了使`should_panic`测试更加精确,我们可以在" +"`should_panic`属性中添加一个可选的预期参数。该测试限制将确保故障信息包含所提供的文本。例如,考虑示例8-9中`Guess`的修改后的代码,新函数根据数值过小或过大的情况,以不同的消息进行恐慌。" -#: src/ch09-01-unrecoverable-errors-with-panic.md:85 +#: src/ch08-01-how-to-write-tests.md:410 msgid "" "```rust\n" -"use option::OptionTrait;\n" -"\n" -"#[panic_with('value is 0', wrap_not_zero)]\n" -"fn wrap_if_not_zero(value: u128) -> Option {\n" -" if value == 0 {\n" -" Option::None(())\n" -" } else {\n" -" Option::Some(value)\n" +"# #[derive(Copy, Drop)]\n" +"# struct Guess {\n" +"# value: u64,\n" +"# }\n" +"# \n" +"# trait GuessTrait {\n" +"# fn new(value: u64) -> Guess;\n" +"# }\n" +"# \n" +"# impl GuessImpl of GuessTrait {\n" +"# fn new(value: u64) -> Guess {\n" +"# if value < 1 {\n" +"# panic_with_felt252('Guess must be >= 1');\n" +"# } else if value > 100 {\n" +"# panic_with_felt252('Guess must be <= 100');\n" +"# }\n" +"# \n" +"# Guess { value, }\n" +"# }\n" +"# }\n" +"# \n" +"# #[cfg(test)]\n" +"# mod tests {\n" +"# use super::Guess;\n" +"# use super::GuessTrait;\n" +"# \n" +" #[test]\n" +" #[should_panic(expected: ('Guess must be <= 100',))]\n" +" fn greater_than_100() {\n" +" GuessTrait::new(200);\n" " }\n" -"}\n" -"\n" -"fn main() {\n" -" wrap_if_not_zero(0); // this returns None\n" -" wrap_not_zero(0); // this panic with 'value is 0'\n" -"}\n" +"# }\n" +"# \n" +"# \n" "```" msgstr "" "```rust\n" -"use option::OptionTrait;\n" -"\n" -"#[panic_with('value is 0', wrap_not_zero)]\n" -"fn wrap_if_not_zero(value: u128) -> Option {\n" -" if value == 0 {\n" -" Option::None(())\n" -" } else {\n" -" Option::Some(value)\n" +"# #[derive(Copy, Drop)]\n" +"# struct Guess {\n" +"# value: u64,\n" +"# }\n" +"# \n" +"# trait GuessTrait {\n" +"# fn new(value: u64) -> Guess;\n" +"# }\n" +"# \n" +"# impl GuessImpl of GuessTrait {\n" +"# fn new(value: u64) -> Guess {\n" +"# if value < 1 {\n" +"# panic_with_felt252('Guess must be >= 1');\n" +"# } else if value > 100 {\n" +"# panic_with_felt252('Guess must be <= 100');\n" +"# }\n" +"# \n" +"# Guess { value, }\n" +"# }\n" +"# }\n" +"# \n" +"# #[cfg(test)]\n" +"# mod tests {\n" +"# use super::Guess;\n" +"# use super::GuessTrait;\n" +"# \n" +" #[test]\n" +" #[should_panic(expected: ('Guess must be <= 100',))]\n" +" fn greater_than_100() {\n" +" GuessTrait::new(200);\n" " }\n" -"}\n" -"\n" -"fn main() {\n" -" wrap_if_not_zero(0); // this returns None\n" -" wrap_not_zero(0); // this panic with 'value is 0'\n" -"}\n" +"# }\n" +"# \n" +"# \n" "```" -#: src/ch09-01-unrecoverable-errors-with-panic.md:103 -msgid "## Using assert" -msgstr "## 使用断言(assert)" +#: src/ch08-01-how-to-write-tests.md:447 +msgid "Listing 8-9: Testing for a panic with a panic message containing the error message string" +msgstr "示例8-9:用包含错误信息字符串的恐慌信息来测试panic" -#: src/ch09-01-unrecoverable-errors-with-panic.md:105 +#: src/ch08-01-how-to-write-tests.md:449 msgid "" -"The assert function from the Cairo core library is actually a utility function based on panics. It asserts that a boolean expression is true at runtime, and if it is not, it calls " -"the panic function with an error value. The assert function takes two arguments: the boolean expression to verify, and the error value. The error value is specified as a felt252, so " -"any string passed must be able to fit inside a felt252." -msgstr "" -"Cairo核心库中的assert函数实际上是一个基于panic的实用函数。它断言一个布尔表达式在运行时是真的,如果不是,它就会调用带有错误值的panic函数。assert函数需要两个参数:要验证的布尔表达式,以" -"及错误值。错误值被指定为felt252,所以任何传递的字符串都必须能够容纳在felt252中。" +"This test will pass because the value we put in the `should_panic` attribute’s expected parameter is the array of string of the message that the `Guess::new` function panics with. We " +"need to specify the entire panic message that we expect." +msgstr "这个测试将通过,因为我们放在`should_panic`属性的预期参数中的值是`Guess::new`函数panic信息的字符串阵列。我们需要指定我们期望的整个panic信息。" -#: src/ch09-01-unrecoverable-errors-with-panic.md:107 -msgid "Here is an example of its usage:" -msgstr "下面是它的一个使用例子:" +#: src/ch08-01-how-to-write-tests.md:451 +msgid "" +"To see what happens when a `should_panic` test with an expected message fails, let’s again introduce a bug into our code by swapping the bodies of the if `value < 1` and the else if " +"`value > 100` blocks:" +msgstr "为了看看当一个带有预期信息的 `should_panic` 测试失败时会发生什么,让我们再次把if `value < 1`和else if `value > 100`块的主体互换,从而在我们的代码中引入一个错误:" -#: src/ch09-01-unrecoverable-errors-with-panic.md:109 +#: src/ch08-01-how-to-write-tests.md:453 msgid "" "```rust\n" -"fn main() {\n" -" let my_number: u8 = 0;\n" +"impl GuessImpl of GuessTrait {\n" +" fn new(value: u64) -> Guess {\n" +" if value < 1 {\n" +" let mut data = ArrayTrait::new();\n" +" data.append('Guess must be >= 1');\n" +" panic(data);\n" +" } else if value > 100 {\n" +" let mut data = ArrayTrait::new();\n" +" data.append('Guess must be <= 100');\n" +" panic(data);\n" +" }\n" "\n" -" assert(my_number != 0, 'number is zero');\n" +" Guess { value, }\n" +" }\n" +"}\n" "\n" -" 100 / my_number;\n" +"#[cfg(test)]\n" +"mod tests {\n" +" use super::Guess;\n" +" use super::GuessTrait;\n" +"\n" +" #[test]\n" +" #[should_panic(expected: ('Guess must be <= 100',))]\n" +" fn greater_than_100() {\n" +" GuessTrait::new(200);\n" +" }\n" "}\n" "```" msgstr "" "```rust\n" -"fn main() {\n" -" let my_number: u8 = 0;\n" +"impl GuessImpl of GuessTrait {\n" +" fn new(value: u64) -> Guess {\n" +" if value < 1 {\n" +" let mut data = ArrayTrait::new();\n" +" data.append('Guess must be >= 1');\n" +" panic(data);\n" +" } else if value > 100 {\n" +" let mut data = ArrayTrait::new();\n" +" data.append('Guess must be <= 100');\n" +" panic(data);\n" +" }\n" "\n" -" assert(my_number != 0, 'number is zero');\n" +" Guess { value, }\n" +" }\n" +"}\n" "\n" -" 100 / my_number;\n" +"#[cfg(test)]\n" +"mod tests {\n" +" use super::Guess;\n" +" use super::GuessTrait;\n" +"\n" +" #[test]\n" +" #[should_panic(expected: ('Guess must be <= 100',))]\n" +" fn greater_than_100() {\n" +" GuessTrait::new(200);\n" +" }\n" "}\n" "```" -#: src/ch09-01-unrecoverable-errors-with-panic.md:119 +#: src/ch08-01-how-to-write-tests.md:483 +msgid "This time when we run the `should_panic` test, it will fail:" +msgstr "这一次,当我们运行`should_panic`测试时,它将失败:" + +#: src/ch08-01-how-to-write-tests.md:485 msgid "" -"We are asserting in main that `my_number` is not zero to ensure that we're not performing a division by 0.\n" -"In this example, `my_number` is zero so the assertion will fail, and the program will panic\n" -"with the string 'number is zero' (as a felt252) and the division will not be reached." +"```shell\n" +"$ cairo-test .\n" +"running 1 tests\n" +"test adder::lib::tests::greater_than_100 ... fail\n" +"failures:\n" +" adder::lib::tests::greater_than_100 - panicked with [6224920189561486601619856539731839409791025 ('Guess must be >= 1'), ].\n" +"\n" +"Error: test result: FAILED. 0 passed; 1 failed; 0 ignored\n" +"```" msgstr "" -"我们在main中断言`my_number`不是0,以确保我们没有进行除以0的操作。\n" -"在这个例子中,`my_number`是零,所以断言会失败,程序会panic,\n" -"并给出 'number is zero'的字符串(保存在felt252中),除法将不会被执行。" - -#: src/ch09-02-error-handling.md:1 -msgid "# Recoverable Errors with `Result`" -msgstr "# 可恢复的错误与 `Result`" - -#: src/ch09-02-error-handling.md:3 src/ch09-02-error-handling.md:56 -msgid "
" -msgstr "
" +"```shell\n" +"$ cairo-test .\n" +"running 1 tests\n" +"test adder::lib::tests::greater_than_100 … fail\n" +"failures:\n" +" adder::lib::tests::greater_than_100 - panicked with [6224920189561486601619856539731839409791025 (‘Guess must be >= 1’), ].\n" +"\n" +"Error: test result: FAILED. 0 passed; 1 failed; 0 ignored\n" +"```" -#: src/ch09-02-error-handling.md:5 +#: src/ch08-01-how-to-write-tests.md:495 msgid "" -"Most errors aren’t serious enough to require the program to stop entirely. Sometimes, when a function fails, it’s for a reason that you can easily interpret and respond to. For " -"example, if you try to add two large integers and the operation overflows because the sum exceeds the maximum representable value, you might want to return an error or a wrapped " -"result instead of causing undefined behavior or terminating the process." +"The failure message indicates that this test did indeed panic as we expected, but the panic message did not include the expected string. The panic message that we did get in this " +"case was `Guess must be >= 1`. Now we can start figuring out where our bug is!" msgstr "" -"大多数错误并没有严重到需要程序完全停止的程度。有时,当一个函数失败时,它的原因是你可以很容易地解释和应对的。例如,如果你试图将两个大的整数相加,而操作溢出,因为总和超过了最大的可表示" -"值,你可能想返回一个错误或一个包装好的结果,而不是引起未定义行为或终止程序。" - -#: src/ch09-02-error-handling.md:7 -msgid "## The `Result` enum" -msgstr "## `Result`枚举" - -#: src/ch09-02-error-handling.md:9 -msgid "Recall from [“Generic data types”](ch07-01-generic-data-types.md#enums) in Chapter 7 that the `Result` enum is defined as having two variants, `Ok` and `Err`, as follows:" -msgstr "回顾第七章中的[\"通用数据类型\"](ch07-01-generic-data-types.md#enums),`Result`枚举被定义为有两个变体,`Ok`和`Err`,如下所示:" +"失败信息表明,这个测试确实像我们预期的那样发生了panic,但是panic信息不包括预期的字符串。在这种情况下,我们得到的panic信息是 `Guess must be >= 1`。现在我们可以开始找出我们的错误所在了!" -#: src/ch09-02-error-handling.md:20 -msgid "## The `ResultTrait`" -msgstr "## `ResultTrait`" +#: src/ch08-01-how-to-write-tests.md:497 +msgid "## Running Single Tests" +msgstr "## 运行单一测试" -#: src/ch09-02-error-handling.md:22 +#: src/ch08-01-how-to-write-tests.md:499 msgid "" -"The `ResultTrait` trait provides methods for working with the `Result` enum, such as unwrapping values, checking whether the `Result` is `Ok` or `Err`, and panicking with a " -"custom message. The `ResultTraitImpl` implementation defines the logic of these methods." -msgstr "`ResultTrait`特征提供了处理`Result`枚举的方法,例如解包值,检查`Result`是`Ok`还是`Err`,以及用自定义的消息进行panic。`ResultTraitImpl`实现定义了这些方法的逻辑。" +"Sometimes, running a full test suite can take a long time. If you’re working on code in a particular area, you might want to run only the tests pertaining to that code. You can " +"choose which tests to run by passing `cairo-test` the name of the test you want to run as an argument." +msgstr "" +"有时,运行一个完整的测试套件可能需要很长的时间。如果你正在处理某个特定领域的代码,你可能只想运行与该代码有关的测试。你可以通过传递`cairo-test`你想运行的测试名称作为参数来选择运行哪些" +"测试。" -#: src/ch09-02-error-handling.md:24 +#: src/ch08-01-how-to-write-tests.md:501 +msgid "To demonstrate how to run a single test, we’ll first create two tests functions, as shown in Listing 8-10, and choose which ones to run." +msgstr "为了演示如何运行一个测试,我们将首先创建两个测试函数,如示例8-10所示,并选择运行哪一个。" + +#: src/ch08-01-how-to-write-tests.md:505 msgid "" "```rust\n" -"trait ResultTrait {\n" -" fn expect>(self: Result, err: felt252) -> T;\n" -"\n" -" fn unwrap>(self: Result) -> T;\n" -"\n" -" fn expect_err>(self: Result, err: felt252) -> E;\n" -"\n" -" fn unwrap_err>(self: Result) -> E;\n" -"\n" -" fn is_ok(self: @Result) -> bool;\n" +"#[cfg(test)]\n" +"mod tests {\n" +" #[test]\n" +" fn add_two_and_two() {\n" +" let result = 2 + 2;\n" +" assert(result == 4, 'result is not 4');\n" +" }\n" "\n" -" fn is_err(self: @Result) -> bool;\n" +" #[test]\n" +" fn add_three_and_two() {\n" +" let result = 3 + 2;\n" +" assert(result == 5, 'result is not 5');\n" +" }\n" "}\n" "```" msgstr "" "```rust\n" -"trait ResultTrait {\n" -" fn expect>(self: Result, err: felt252) -> T;\n" -"\n" -" fn unwrap>(self: Result) -> T;\n" -"\n" -" fn expect_err>(self: Result, err: felt252) -> E;\n" -"\n" -" fn unwrap_err>(self: Result) -> E;\n" -"\n" -" fn is_ok(self: @Result) -> bool;\n" +"#[cfg(test)]\n" +"mod tests {\n" +" #[test]\n" +" fn add_two_and_two() {\n" +" let result = 2 + 2;\n" +" assert(result == 4, ‘result is not 4’);\n" +" }\n" "\n" -" fn is_err(self: @Result) -> bool;\n" +" #[test]\n" +" fn add_three_and_two() {\n" +" let result = 3 + 2;\n" +" assert(result == 5, ‘result is not 5’);\n" +" }\n" "}\n" "```" -#: src/ch09-02-error-handling.md:40 -msgid "" -"The `expect` and `unwrap` methods are similar in that they both attempt to extract the value of type `T` from a `Result` when it is in the `Ok` variant. If the `Result` is " -"`Ok(x)`, both methods return the value `x`. However, the key difference between the two methods lies in their behavior when the `Result` is in the `Err` variant. The `expect` method " -"allows you to provide a custom error message (as a `felt252` value) that will be used when panicking, giving you more control and context over the panic. On the other hand, the " -"`unwrap` method panics with a default error message, providing less information about the cause of the panic." -msgstr "" -"`expect`和`unwrap`方法类似,它们都试图从`Result`中提取`T`类型的值,当它处于`Ok`变体时。如果`Result`是 `Ok(x)`,两个方法都返回值 \"x\"。然而,这两个方法的关键区别在于当`Result`是" -"`Err`变量时的行为。`expect`方法允许你提供一个自定义的错误信息(作为`felt252`值)在panic时使用,从而让你获取更多对panic相关的控制和上下文。另一方面,`unwrap`方法用一个默认的错误信息进" -"行panic,提供的关于panic原因的信息较少。" +#: src/ch08-01-how-to-write-tests.md:522 +msgid "Listing 8-10: Two tests with two different names" +msgstr "示例8-10:两个不同名称的测试" -#: src/ch09-02-error-handling.md:42 -msgid "" -"The `expect_err` and `unwrap_err` have the exact opposite behavior. If the `Result` is `Err(x)`, both methods return the value `x`. However, the key difference between the two " -"methods is in case of `Result::Ok()`. The `expect_err` method allows you to provide a custom error message (as a `felt252` value) that will be used when panicking, giving you more " -"control and context over the panic. On the other hand, the `unwrap_err` method panics with a default error message, providing less information about the cause of the panic." -msgstr "" -"`expect_err`和`unwrap_err`的行为完全相反。如果`Result`是`Err(x)`,两个方法都返回值`x`。然而,这两个方法的关键区别是在`Result::Ok()`的情况下。`expect_err`方法允许你提供一个自定义的错误" -"信息(作为`felt252`值),在panic时使用,从而让你获取更多对panic相关的控制和上下文。另一方面,`unwrap_err`方法用一个默认的错误信息进行panic,提供的关于panic原因的信息较少。" +#: src/ch08-01-how-to-write-tests.md:524 +msgid "We can pass the name of any test function to `cairo-test` to run only that test using the `-f` flag:" +msgstr "我们可以将任何测试函数的名称传递给`cairo-test`,以使用`-f` 标志只运行该测试:" -#: src/ch09-02-error-handling.md:44 +#: src/ch08-01-how-to-write-tests.md:526 msgid "" -"A careful reader may have noticed the `>` and `>` in the first four methods signatures. This syntax represents generic type constraints in the " -"Cairo language. These constraints indicate that the associated functions require an implementation of the `Drop` trait for the generic types `T` and `E`, respectively." +"```shell\n" +"$ cairo-test . -f add_two_and_two\n" +"running 1 tests\n" +"test adder::lib::tests::add_two_and_two ... ok\n" +"test result: ok. 1 passed; 0 failed; 0 ignored; 1 filtered out;\n" +"```" msgstr "" -"细心的读者可能已经注意到前四个方法签名中的`>` and `>`。这种语法代表了Cairo语言中的通用类型约束。这些约束表示相关的函数需要分别对通用类型`T`和" -"`E`的`Drop`特性进行实现。" - -#: src/ch09-02-error-handling.md:46 -msgid "Finally, the `is_ok` and `is_err` methods are utility functions provided by the `ResultTrait` trait to check the variant of a `Result` enum value." -msgstr "最后,`is_ok`和`is_err`方法是`ResultTrait`特征提供的实用函数,用于检查`Result`枚举值的成员。" - -#: src/ch09-02-error-handling.md:48 -msgid "" -"`is_ok` takes a snapshot of a `Result` value and returns `true` if the `Result` is the `Ok` variant, meaning the operation was successful. If the `Result` is the `Err` variant, " -"it returns `false`." -msgstr "`is_ok`获取一个`Result`值的快照,如果`Result`是`Ok`成员,则返回`true`,意味着操作成功。如果`Result`是`Err`成员,则返回`false`。" - -#: src/ch09-02-error-handling.md:50 -msgid "" -"`is_err` takes a reference to a `Result` value and returns `true` if the `Result` is the `Err` variant, meaning the operation encountered an error. If the `Result` is the `Ok` " -"variant, it returns `false`." -msgstr "`is_err`接收一个对`Result`值的引用,如果`Result`是`Err`成员,意味着操作遇到了错误,则返回`true`。如果 `Result`是 `Ok`成员,则返回 `false`。" +"```shell\n" +"$ cairo-test . -f add_two_and_two\n" +"running 1 tests\n" +"test adder::lib::tests::add_two_and_two ... ok\n" +"test result: ok. 1 passed; 0 failed; 0 ignored; 1 filtered out;\n" +"```" -#: src/ch09-02-error-handling.md:52 +#: src/ch08-01-how-to-write-tests.md:533 msgid "" -"These methods are helpful when you want to check the success or failure of an operation without consuming the Result value, allowing you to perform additional operations or make " -"decisions based on the variant without unwrapping it." -msgstr "当你想在不消耗结果值的情况下检查一个操作的成功或失败时,这些方法很有帮助,允许你执行额外的操作或根据枚举成员做出决定,而不用解开(unwrap)它。" - -#: src/ch09-02-error-handling.md:54 -msgid "You can find the implementation ot the `ResultTrait` [here](https://github.com/starkware-libs/cairo/blob/main/corelib/src/result.cairo#L20)." -msgstr "你可以在[这里](https://github.com/starkware-libs/cairo/blob/main/corelib/src/result.cairo#L20)找到`ResultTrait`的实现。" +"Only the test with the name `add_two_and_two` ran; the other test didn’t match that name. The test output lets us know we had one more test that didn’t run by displaying 1 filtered " +"out at the end." +msgstr "只有名称为`add_two_and_two` 的测试被运行了,其他的测试不符合这个名称。测试输出最后显示了1个测试被过滤掉,让我们知道我们还有一个测试没有运行。" -#: src/ch09-02-error-handling.md:58 -msgid "It is always easier to understand with examples." -msgstr "有例子总是更容易理解。" +#: src/ch08-01-how-to-write-tests.md:535 +msgid "We can also specify part of a test name, and any test whose name contains that value will be run." +msgstr "我们还可以指定测试名称的一部分,任何名称包含该值的测试都将被运行。" -#: src/ch09-02-error-handling.md:60 -msgid "Have a look at this function signature:" -msgstr "请看一下这个函数签名:" +#: src/ch08-01-how-to-write-tests.md:537 +msgid "## Ignoring Some Tests Unless Specifically Requested" +msgstr "## 在非特别指定时,忽略一些测试" -#: src/ch09-02-error-handling.md:62 +#: src/ch08-01-how-to-write-tests.md:539 msgid "" -"```rust\n" -"fn u128_overflowing_add(a: u128, b: u128) -> Result;\n" -"```" +"Sometimes a few specific tests can be very time-consuming to execute, so you might want to exclude them during most runs of `cairo-test`. Rather than listing as arguments all tests " +"you do want to run, you can instead annotate the time-consuming tests using the `ignore` attribute to exclude them, as shown here:" msgstr "" -"```rust\n" -"fn u128_overflowing_add(a: u128, b: u128) -> Result;\n" -"```" - -#: src/ch09-02-error-handling.md:66 -msgid "" -"It takes two u128 integers, a and b, and returns a `Result` where the `Ok` variant holds the sum if the addition does not overflow, and the `Err` variant holds the " -"overflowed value if the addition does overflow." -msgstr "它接收两个u128整数,a和b,并返回一个`Result`,如果加法没有溢出,`Ok`成员存储加法的和,如果加法溢出,`Err’成员存储溢出的值。" - -#: src/ch09-02-error-handling.md:68 -msgid "Now, we can use this function elsewhere. For instance:" -msgstr "现在,我们可以在其他地方使用这个函数。比如说:" +"有时一些特定的测试执行起来非常耗时,所以你可能想在大多数`cairo-test`的运行中排除它们。与其将所有你想运行的测试列为参数,不如使用`ignore` 属性对耗时的测试进行注释,将其排除在外,如图所" +"示:" -#: src/ch09-02-error-handling.md:70 +#: src/ch08-01-how-to-write-tests.md:543 msgid "" "```rust\n" -"fn u128_checked_add(a: u128, b: u128) -> Option {\n" -" match u128_overflowing_add(a, b) {\n" -" Result::Ok(r) => Option::Some(r),\n" -" Result::Err(r) => Option::None(()),\n" +"#[cfg(test)]\n" +"mod tests {\n" +" #[test]\n" +" fn it_works() {\n" +" let result = 2 + 2;\n" +" assert(result == 4, 'result is not 4');\n" +" }\n" +"\n" +" #[test]\n" +" #[ignore]\n" +" fn expensive_test() { // code that takes an hour to run\n" " }\n" "}\n" "```" msgstr "" "```rust\n" -"fn u128_checked_add(a: u128, b: u128) -> Option {\n" -" match u128_overflowing_add(a, b) {\n" -" Result::Ok(r) => Option::Some(r),\n" -" Result::Err(r) => Option::None(()),\n" +"#[cfg(test)]\n" +"mod tests {\n" +" #[test]\n" +" fn it_works() {\n" +" let result = 2 + 2;\n" +" assert(result == 4, 'result is not 4');\n" +" }\n" +"\n" +" #[test]\n" +" #[ignore]\n" +" fn expensive_test() { // code that takes an hour to run\n" " }\n" "}\n" "```" -#: src/ch09-02-error-handling.md:79 +#: src/ch08-01-how-to-write-tests.md:559 +msgid "After `#[test]` we add the `#[ignore]` line to the test we want to exclude. Now when we run our tests, `it_works` runs, but `expensive_test` doesn’t:" +msgstr "对于想要排除的测试,我们在 `#[test]`之后,添加了 `#[ignore]`行。现在,当我们运行我们的测试时,`it_works`会运行,但`expensive_test`不会:" + +#: src/ch08-01-how-to-write-tests.md:561 msgid "" -"Here, it accepts two u128 integers, a and b, and returns an `Option`. It uses the `Result` returned by `u128_overflowing_add` to determine the success or failure of the " -"addition operation. The match expression checks the `Result` from `u128_overflowing_add`. If the result is `Ok(r)`, it returns `Option::Some(r)` containing the sum. If the result is " -"`Err(r)`, it returns `Option::None(())` to indicate that the operation has failed due to overflow. The function does not panic in case of an overflow." +"```shell\n" +"$ cairo-test .\n" +"running 2 tests\n" +"test adder::lib::tests::expensive_test ... ignored\n" +"test adder::lib::tests::it_works ... ok\n" +"test result: ok. 1 passed; 0 failed; 1 ignored; 0 filtered out;\n" +"```" msgstr "" -"这里,它接受两个u128整数,a和b,并返回一个`Option`。它使用`u128_overflowing_add`返回的`Result`来确定加法操作的成功或失败。匹配表达式检查来自`u128_overflowing_add`的`Result` 。如" -"果结果是`Ok(r)`,则返回`Option::Some(r)`,其中包含和。如果结果是`Err(r)`,则返回`Option::None(())`,表示由于溢出导致操作失败。在溢出的情况下,该函数不会panic。" +"```shell\n" +"$ cairo-test .\n" +"running 2 tests\n" +"test adder::lib::tests::expensive_test ... ignored\n" +"test adder::lib::tests::it_works ... ok\n" +"test result: ok. 1 passed; 0 failed; 1 ignored; 0 filtered out;\n" +"```" + +#: src/ch08-01-how-to-write-tests.md:569 +msgid "The `expensive_test` function is listed as ignored." +msgstr "`expensive_test`函数被列为`ignored`。" -#: src/ch09-02-error-handling.md:81 +#: src/ch08-01-how-to-write-tests.md:571 msgid "" -"Let's take another example demonstrating the use of `unwrap`.\n" -"First we import the necessary modules:" -msgstr "" -"让我们再举一个例子,演示一下`unwrap`的使用。\n" -"首先我们导入必要的模块:" +"When you’re at a point where it makes sense to check the results of the ignored tests and you have time to wait for the results, you can run `cairo-test --include-ignored` to run all " +"tests whether they’re ignored or not." +msgstr "当你到了需要检查被忽略的测试结果的时候,而且你有时间等待测试结果,你可以运行`cairo-test --include-ignored`来运行所有的测试,无论它们是否被标记忽略。" + +#: src/ch08-02-test-organization.md:1 +msgid "# Testing Organization" +msgstr "# 测试的组织结构" -#: src/ch09-02-error-handling.md:84 +#: src/ch08-02-test-organization.md:3 msgid "" -"```rust\n" -"use core::traits::Into;\n" -"use traits::TryInto;\n" -"use option::OptionTrait;\n" -"use result::ResultTrait;\n" -"use result::ResultTraitImpl;\n" -"```" +"We'll think about tests in terms of two main categories: unit tests and integration tests. Unit tests are small and more focused, testing one module in isolation at a time, and can " +"test private functions. Integration tests use your code in the same way any other external code would, using only the public interface and potentially exercising multiple modules per " +"test." msgstr "" -"```rust\n" -"use core::traits::Into;\n" -"use traits::TryInto;\n" -"use option::OptionTrait;\n" -"use result::ResultTrait;\n" -"use result::ResultTraitImpl;\n" -"```" +"我们倾向于根据测试的两个主要分类来考虑问题:单元测试和集成测试。单元测试(unit tests)与 集成测试(integration tests)。单元测试倾向于更小而更集中,在隔离的环境中一次测试一个模块,或" +"者是测试私有接口。而集成测试对于你的代码来说则完全是外部的。它们与其他外部代码一样,通过相同的方式使用你的代码,只测试公有接口而且每个测试都有可能会测试多个模块。" + +#: src/ch08-02-test-organization.md:5 +msgid "Writing both kinds of tests is important to ensure that the pieces of your library are doing what you expect them to, separately and together." +msgstr "为了保证你的库能够按照你的预期运行,从独立和整体的角度编写这两类测试都是非常重要的。" -#: src/ch09-02-error-handling.md:92 +#: src/ch08-02-test-organization.md:7 +msgid "## Unit Tests" +msgstr "## 单元测试" + +#: src/ch08-02-test-organization.md:9 msgid "" -"In this example, the `parse_u8` function takes a `felt252` integer and tries to convert it into a `u8` integer using the `try_into` method. If successful, it returns `Result::" -"Ok(value)`, otherwise it returns `Result::Err('Invalid integer')`." +"The purpose of unit tests is to test each unit of code in isolation from the rest of the code to quickly pinpoint where code is and isn’t working as expected. You’ll put unit tests " +"in the `src` directory in each file with the code that they’re testing." msgstr "" -"在这个例子中,`parse_u8`函数接收一个`felt252`的整数,并尝试用`try_into`方法将其转换为`u8`的整数。如果成功,它返回`Result::Ok(value)`,否则它返回`Result::Err('Invalid integer')`。" +"单元测试的目的是在与其他部分隔离的环境中测试每一个单元的代码,以便于快速而准确地验证某个单元的代码功能是否符合预期。单元测试与他们要测试的代码共同存放在位于 src 目录下相同的文件中。" + +#: src/ch08-02-test-organization.md:11 +msgid "The convention is to create a module named tests in each file to contain the test functions and to annotate the module with `cfg(test)`." +msgstr "规范是在每个文件中创建包含测试函数的 tests 模块,并使用 `cfg(test)` 标注模块。" + +#: src/ch08-02-test-organization.md:13 +msgid "### The Tests Module and `#[cfg(test)]`" +msgstr "### 测试模块和`#[cfg(test)]`" -#: src/ch09-02-error-handling.md:94 +#: src/ch08-02-test-organization.md:15 msgid "" -"```rust\n" -"fn parse_u8(s: felt252) -> Result {\n" -" match s.try_into() {\n" -" Option::Some(value) => Result::Ok(value),\n" -" Option::None(_) => Result::Err('Invalid integer'),\n" -" }\n" -"}\n" -"```" +"The `#[cfg(test)]` annotation on the tests module tells Cairo to compile and run the test code only when you run `cairo-test`, not when you run `cairo-run`. This saves compile time " +"when you only want to build the library and saves space in the resulting compiled artifact because the tests are not included. You’ll see that because integration tests go in a " +"different directory, they don’t need the `#[cfg(test)]` annotation. However, because unit tests go in the same files as the code, you’ll use `#[cfg(test)]` to specify that they " +"shouldn’t be included in the compiled result." msgstr "" -"```rust\n" -"fn parse_u8(s: felt252) -> Result {\n" -" match s.try_into() {\n" -" Option::Some(value) => Result::Ok(value),\n" -" Option::None(_) => Result::Err(‘Invalid integer’),\n" -" }\n" -"}\n" -"```" +"测试模块的 `#[cfg(test)]`注解告诉 Cairo 只在执行`cairo-test` 时才编译和运行测试代码,而在运行 `cairo-run` 时不这么做。这在只希望构建库的时候可以节省编译时间,并且因为它们并没有包含测" +"试,所以能减少编译产生的文件的大小。与之对应的集成测试因为位于另一个文件夹,所以它们并不需要 `#[cfg(test)]`注解。然而单元测试位于与源码相同的文件中,所以你需要使用 `#[cfg(test)]` 来指" +"定他们不应该被包含进编译结果中。" -#: src/ch09-02-error-handling.md:103 -msgid "Our two test cases are:" -msgstr "我们的两个测试案例是:" +#: src/ch08-02-test-organization.md:17 +msgid "Recall that when we created the new `adder` project in the first section of this chapter, we wrote this first test:" +msgstr "回顾一下,当我们在本章第一节创建新的`adder`项目时,我们写了这个测试:" -#: src/ch09-02-error-handling.md:105 +#: src/ch08-02-test-organization.md:21 msgid "" "```rust\n" -"#[test]\n" -"fn test_felt252_to_u8() {\n" -" let number: felt252 = 5_felt252;\n" -" // should not panic\n" -" let res = parse_u8(number).unwrap();\n" -"}\n" -"\n" -"#[test]\n" -"fn test_felt252_to_u8_panic() {\n" -" let number: felt252 = 256_felt252;\n" -" // should panic\n" -" let res = parse_u8(number).unwrap();\n" +"#[cfg(test)]\n" +"mod tests {\n" +" #[test]\n" +" fn it_works() {\n" +" let result = 2 + 2;\n" +" assert(result == 4, 'result is not 4');\n" +" }\n" "}\n" "```" msgstr "" "```rust\n" -"#[test]\n" -"fn test_felt252_to_u8() {\n" -" let number: felt252 = 5_felt252;\n" -" // should not panic\n" -" let res = parse_u8(number).unwrap();\n" -"}\n" -"\n" -"#[test]\n" -"fn test_felt252_to_u8_panic() {\n" -" let number: felt252 = 256_felt252;\n" -" // should panic\n" -" let res = parse_u8(number).unwrap();\n" +"#[cfg(test)]\n" +"mod tests {\n" +" #[test]\n" +" fn it_works() {\n" +" let result = 2 + 2;\n" +" assert(result == 4, ‘result is not 4’);\n" +" }\n" "}\n" "```" -#: src/ch09-02-error-handling.md:121 +#: src/ch08-02-test-organization.md:32 msgid "" -"The first one tests a valid conversion from `felt252` to `u8`, expecting the `unwrap` method not to panic. The second test function attempts to convert a value that is out of the " -"`u8` range, expecting the `unwrap` method to panic with the error message 'Invalid integer'." -msgstr "第一个测试函数是测试从`felt252`到`u8`的有效转换,期望`unwrap`方法不要panic。第二个测试函数试图转换一个超出`u8`范围的值,期望`unwrap`方法panic,错误信息是 ‘Invalid integer’。" - -#: src/ch09-02-error-handling.md:123 -msgid "> We could have also used the #[should_panic] attribute here." -msgstr "> 我们也可以在这里使用#[should_panic]属性。" +"The attribute `cfg` stands for configuration and tells Cairo that the following item should only be included given a certain configuration option. In this case, the configuration " +"option is `test`, which is provided by Cairo for compiling and running tests. By using the `cfg` attribute, Cairo compiles our test code only if we actively run the tests with `cairo-" +"test`. This includes any helper functions that might be within this module, in addition to the functions annotated with `#[test]`." +msgstr "" +"属性`cfg`代表配置,告诉Cairo只有在给定的配置选项的情况下才应该包含下面的项目。在本例中,配置选项是`test`,它由Cairo提供,用于编译和运行测试。通过使用`cfg`属性,Cairo只有在我们用" +"`cairo-test`主动运行测试时才会编译我们的测试代码。这包括任何可能在这个模块中的辅助函数,以及用`#[test]`标注的函数。" -#: src/ch09-02-error-handling.md:125 -msgid "### The `?` operator ?" -msgstr "### `?`运算符?" +#: src/ch08-02-test-organization.md:34 +msgid "## Integration Tests" +msgstr "## 集成测试" -#: src/ch09-02-error-handling.md:127 +#: src/ch08-02-test-organization.md:36 msgid "" -"The last operator we will talk about is the `?` operator. The `?` operator is used for more idiomatic and concise error handling. When you use the `?` operator on a `Result` or " -"`Option` type, it will do the following:" -msgstr "我们要谈的最后一个操作符是`?`操作符。`?`运算符用于更成文和简明的错误处理。当你在 `Result`或 `Option`类型上使用`?`运算符时,它将做以下事情:" +"Integration tests use your library in the same way any other code would. Their purpose is to test whether many parts of your library work together correctly. Units of code that work " +"correctly on their own could have problems when integrated, so test coverage of the integrated code is important as well. To create integration tests, you first need a `tests` " +"directory." +msgstr "" +"集成测试对于你需要测试的库来说完全是外部的。同其他使用库的代码一样使用库文件,也就是说它们只能调用一部分库中的公有 API。集成测试的目的是测试库的多个部分能否一起正常工作。一些单独能正" +"确运行的代码单元集成在一起也可能会出现问题,所以集成测试的覆盖率也是很重要的。为了创建集成测试,你需要先创建一个 `tests` 目录。" + +#: src/ch08-02-test-organization.md:38 +msgid "### The `tests` Directory" +msgstr "### `tests`目录" -#: src/ch09-02-error-handling.md:129 +#: src/ch08-02-test-organization.md:40 msgid "" -"- If the value is `Result::Ok(x)` or `Option::Some(x)`, it will return the inner value `x` directly.\n" -"- If the value is `Result::Err(e)` or `Option::None`, it will propagate the error or `None` by immediately returning from the function." +"```shell\n" +"adder\n" +"├── cairo_project.toml\n" +"├── src\n" +" ├── lib.cairo\n" +"│ └── main.cairo\n" +"└── tests\n" +" ├── lib.cairo\n" +" └── integration_test.cairo\n" +"```" msgstr "" -"- 如果值是`Result::Ok(x)`或`Option::Some(x)`,它将直接返回内部值`x`。\n" -"- 如果值是`Result::Err(e)`或`Option::None`,它将通过立即从函数返回来传播错误或`None`。" +"```shell\n" +"adder\n" +"├── cairo_project.toml\n" +"├── src\n" +" ├── lib.cairo\n" +"│ └── main.cairo\n" +"└── tests\n" +" ├── lib.cairo\n" +" └── integration_test.cairo\n" +"```" -#: src/ch09-02-error-handling.md:132 -msgid "The `?` operator is useful when you want to handle errors implicitly and let the calling function deal with them." -msgstr "当你想隐式处理错误并让调用函数处理它们时,`?`操作符很有用。" +#: src/ch08-02-test-organization.md:53 +msgid "" +"> To successfully run your tests with `cairo-test` you will need to update your `cairo_project.toml` file to add the declaration of your `tests` crate.\n" +">\n" +"> ```rust\n" +"> [crate_roots]\n" +"> adder = \"src\"\n" +"> tests = \"tests\"\n" +"> ```" +msgstr "" +"> 为了成功地用`cairo-test`运行你的测试,你需要更新你的`cairo_project.toml`文件,添加你的`tests`crate的声明。\n" +">\n" +"> ```rust\n" +"> [crate_roots]\n" +"> adder = “src”\n" +"> tests = “tests”\n" +"> ```" -#: src/ch09-02-error-handling.md:134 -msgid "Here is an example." -msgstr "下面是一个例子。" +#: src/ch08-02-test-organization.md:61 +msgid "Each test file is compiled as its own separate crate, that's why whenever you add a new test file you must add it to your _tests/lib.cairo_." +msgstr "每个测试文件都被编译为它自己独立的crate,这就是为什么每当你添加一个新的测试文件,你必须把它添加到你的 _tests/lib.cairo_ 文件中。" + +#: src/ch08-02-test-organization.md:63 +msgid "Filename: tests/lib.cairo" +msgstr "文件名:test/lib.cairo" -#: src/ch09-02-error-handling.md:136 +#: src/ch08-02-test-organization.md:65 msgid "" "```rust\n" -"fn do_something_with_parse_u8(input: felt252) -> Result {\n" -" let input_to_u8: u8 = parse_u8(input)?;\n" -" // DO SOMETHING\n" -" let res = input_to_u8 - 1;\n" -" Result::Ok(res)\n" -"}\n" +"#[cfg(tests)]\n" +"mod integration_tests;\n" "```" msgstr "" "```rust\n" -"fn do_something_with_parse_u8(input: felt252) -> Result {\n" -" let input_to_u8: u8 = parse_u8(input)?;\n" -" // DO SOMETHING\n" -" let res = input_to_u8 - 1;\n" -" Result::Ok(res)\n" -"}\n" +"#[cfg(tests)]\n" +"mod integration_tests;\n" "```" -#: src/ch09-02-error-handling.md:145 -msgid "" -"`do_something_with_parse_u8` function takes a `felt252` value as input and calls `parse_u8`. The `?` operator is used to propagate the error, if any, or unwrap the successful value." -msgstr "`do_something_with_parse_u8`函数接收一个`felt252`值作为输入并调用`parse_u8`。`?`操作符用来传播错误,如果有的话,或者unwrap成功的值。" +#: src/ch08-02-test-organization.md:70 +msgid "Enter the code in Listing 8-11 into the _tests/integration_test.cairo_ file:" +msgstr "将示例8-11中的代码输入到 _tests/integration_test.cairo_ 文件:" -#: src/ch09-02-error-handling.md:147 -msgid "And with a little test case:" -msgstr "这里还有一个小的测试案例:" +#: src/ch08-02-test-organization.md:72 +msgid "Filename: tests/integration_test.cairo" +msgstr "文件名:test/integration_test.cairo" -#: src/ch09-02-error-handling.md:149 +#: src/ch08-02-test-organization.md:74 msgid "" "```rust\n" "#[test]\n" -"fn test_function_2() {\n" -" let number: felt252 = 258_felt252;\n" -" match do_something_with_parse_u8(number) {\n" -" Result::Ok(value) => value.print(),\n" -" Result::Err(e) => e.print()\n" -" }\n" +"fn internal() {\n" +" assert(main::internal_adder(2, 2) == 4, 'internal_adder failed');\n" "}\n" "```" msgstr "" "```rust\n" "#[test]\n" -"fn test_function_2() {\n" -" let number: felt252 = 258_felt252;\n" -" match do_something_with_parse_u8(number) {\n" -" Result::Ok(value) => value.print(),\n" -" Result::Err(e) => e.print()\n" -" }\n" +"fn internal() {\n" +" assert(main::internal_adder(2, 2) == 4, 'internal_adder failed');\n" "}\n" "```" -#: src/ch09-02-error-handling.md:160 -msgid "The console will print the error \"Invalid Integer\"." -msgstr "控制台将打印错误 “Invalid Integer”。" - -#: src/ch09-02-error-handling.md:162 -msgid "
" -msgstr "
" +#: src/ch08-02-test-organization.md:81 +msgid "Listing 8-11: Testing functions from other modules" +msgstr "示例 8-11:从同一模块导入多个项" -#: src/ch09-02-error-handling.md:164 -msgid "### Summary" -msgstr "### 总结" +#: src/ch08-02-test-organization.md:83 +msgid "" +"Each file in the tests directory is a separate crate, so we need to bring our library into each test crate’s scope. For that reason we add `use adder::main` at the top of the code, " +"which we didn’t need in the unit tests." +msgstr "测试目录中的每个文件都是一个独立的crate,所以我们需要将我们的库引入每个测试crate的范围。出于这个原因,我们在代码的顶部添加了`use adder::main`,在单元测试中我们不需要这个。" -#: src/ch09-02-error-handling.md:166 +#: src/ch08-02-test-organization.md:85 msgid "" -"We saw that recoverable errors can be handled in Cairo using the Result enum, which has two variants: `Ok` and `Err`. The `Result` enum is generic, with types `T` and `E` " -"representing the successful and error values, respectively. The `ResultTrait` provides methods for working with `Result`, such as unwrapping values, checking if the result is " -"`Ok` or `Err`, and panicking with custom messages." +"```shell\n" +"$ cairo-test tests/\n" +"running 1 tests\n" +"test tests::tests_integration::it_adds_two ... ok\n" +"test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" +"```" msgstr "" -"我们看到,可恢复的错误可以在Cairo中使用结果枚举来处理,它有两个变体:`Ok`和`Err`。`Result`枚举是通用的,其类型`T`和`E`分别代表成功和错误值。`ResultTrait`提供了处理`Result`" -"的方法,例如解包值,检查结果是`Ok`还是`Err`,以及用自定义消息进行panic。" +"```shell\n" +"$ cairo-test tests/\n" +"running 1 tests\n" +"test tests::tests_integration::it_adds_two ... ok\n" +"test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;\n" +"```" + +#: src/ch08-02-test-organization.md:92 +msgid "The result of the tests is the same as what we've been seeing: one line for each test." +msgstr "测试的结果与我们之前看到的相同:每个测试一行。" + +#: src/ch09-00-error-handling.md:1 +msgid "# Error handling" +msgstr "# 错误处理" -#: src/ch09-02-error-handling.md:168 +#: src/ch09-00-error-handling.md:3 msgid "" -"To handle recoverable errors, a function can return a `Result` type and use pattern matching to handle the success or failure of an operation. The `?` operator can be used to " -"implicitly handle errors by propagating the error or unwrapping the successful value. This allows for more concise and clear error handling, where the caller is responsible for " -"managing errors raised by the called function." +"In this chapter, we will explore various error handling techniques provided by Cairo, which not only allow you to address potential issues in your code, but also make it easier to " +"create programs that are adaptable and maintainable. By examining different approaches to managing errors, such as pattern matching with the Result enum, using the ? operator for " +"more ergonomic error propagation, and employing the unwrap or expect methods for handling recoverable errors, you'll gain a deeper understanding of Cairo's error handling features. " +"These concepts are crucial for building robust applications that can effectively handle unexpected situations, ensuring your code is ready for production." msgstr "" -"为了处理可恢复的错误,一个函数可以返回一个`Result`类型,并使用模式匹配来处理操作的成功或失败。`?`操作符可用于通过传播错误或解包成功的值来隐含地处理错误。这使得错误处理更加简洁明了,调" -"用者负责管理由被调用函数引发的错误。" - -#: src/ch10-00-advanced-features.md:1 -msgid "# Advanced Features" -msgstr "# 高级特性" +"在本章中,我们将探讨Cairo提供的各种错误处理技术,这些技术不仅能让你解决代码中的潜在问题,还能让你更容易创建易适应和易维护的程序。通过研究管理错误的不同方法,如用Result枚举进行模式匹" +"配,使用 ? 操作符进行更人性化的错误传播,以及采用unwrap或expect方法来处理可恢复的错误,你将对Cairo的错误处理功能有更深入的了解。这些概念对于构建强大的应用程序至关重要,它可以有效地处" +"理意外情况,确保你的代码可以用于生产环境。" -#: src/ch10-01-operator-overloading.md:1 -msgid "# Operator Overloading" -msgstr "# 操作符重载" +#: src/ch09-01-unrecoverable-errors-with-panic.md:1 +msgid "# Unrecoverable Errors with panic" +msgstr "# 无法恢复的错误与恐慌(panic)" -#: src/ch10-01-operator-overloading.md:3 +#: src/ch09-01-unrecoverable-errors-with-panic.md:3 msgid "" -"Operator overloading is a feature in some programming languages that allows the redefinition of standard operators, such as addition (+), subtraction (-), multiplication (\\*), and " -"division (/), to work with user-defined types. This can make the syntax of the code more intuitive, by enabling operations on user-defined types to be expressed in the same way as " -"operations on primitive types." +"In Cairo, unexpected issues may arise during program execution, resulting in runtime errors. While the panic function from the core library doesn't provide a resolution for these " +"errors, it does acknowledge their occurrence and terminates the program. There are two primary ways that a panic can be triggered in Cairo: inadvertently, through actions causing the " +"code to panic (e.g., accessing an array beyond its bounds), or deliberately, by invoking the panic function." msgstr "" -"操作符重载是一些编程语言的一个特点,它允许在用户自定义的类型上重新定义标准操作符,如加法(+)、减法(-)、乘法(\\*)和除法(/)。这可以使代码的语法更加直观,因为它使对用户字定义类型" -"的操作与对原始类型的操作表达方式相同。" +"在Cairo中,程序执行过程中可能会出现意外问题,导致运行时错误。虽然核心库中的panic函数并没有为这些错误提供解决方案,但它确实承认这些错误的发生并终止程序。在Cairo中,有两种主要的方式可以" +"触发panic:无意地通过导致代码panic的行为(例如,访问一个超出其界限的数组),或故意地,通过调用panic函数。" -#: src/ch10-01-operator-overloading.md:5 +#: src/ch09-01-unrecoverable-errors-with-panic.md:5 msgid "" -"In Cairo, operator overloading is achieved through the implementation of specific traits. Each operator has an associated trait, and overloading that operator involves providing an " -"implementation of that trait for a custom type.\n" -"However, it's essential to use operator overloading judiciously. Misuse can lead to confusion, making the code more difficult to maintain, for example when there is no semantic " -"meaning to the operator being overloaded." +"When a panic occurs, it leads to an abrupt termination of the program. The `panic` function takes an array as argument, which can be used to provide an error message and performs an " +"unwind process where all variables are dropped and dictionaries squashed to ensure the soundness of the program to safely terminate the execution." msgstr "" -"在Cairo中,操作符重载是通过实现特定的trait来实现的。每个操作符都有一个相关的traits,操作符重载涉及到需为一个自定义类型提供该trait的实现。\n" -"然而,明智地使用操作符重载是非常重要的。误用会导致混乱,使代码更难维护,比如当被重载的操作符的语义与操作符原有的语义毫不相干的时候。" +"当panic发生时,它会导致程序的突然终止。`panic` 函数接受一个数组作为参数,可以用来提供一个错误信息,并执行一个展开(unwind)过程--所有的变量被丢弃,字典被压缩(squash),以确保程序的合理" +"地,安全地终止执行。" -#: src/ch10-01-operator-overloading.md:8 -msgid "Consider an example where two `Potions` need to be combined. `Potions` have two data fields, mana and health. Combining two `Potions` should add their respective fields." -msgstr "让我看一个例子,两个 `Potions` 需要合并。`Potions` 有两个数据字段,法力(mana)和健康(health)。合并两个`Potions` 应该是让它们各自的两个字段相加。" +#: src/ch09-01-unrecoverable-errors-with-panic.md:7 +msgid "Here is how we can `panic` from inside a program and return the error code `2`:" +msgstr "下面是我们如何在一个程序中`panic`并返回错误代码`2`:" -#: src/ch10-01-operator-overloading.md:10 +#: src/ch09-01-unrecoverable-errors-with-panic.md:11 msgid "" "```rust\n" -"struct Potion {\n" -" health: felt252,\n" -" mana: felt252\n" -"}\n" -"\n" -"impl PotionAdd of Add {\n" -" fn add(lhs: Potion, rhs: Potion) -> Potion {\n" -" Potion { health: lhs.health + rhs.health, mana: lhs.mana + rhs.mana, }\n" -" }\n" -"}\n" +"use debug::PrintTrait;\n" "\n" "fn main() {\n" -" let health_potion: Potion = Potion { health: 100, mana: 0 };\n" -" let mana_potion: Potion = Potion { health: 0, mana: 100 };\n" -" let super_potion: Potion = health_potion + mana_potion;\n" -" // Both potions were combined with the `+` operator.\n" -" assert(super_potion.health == 100, '');\n" -" assert(super_potion.mana == 100, '');\n" +" let mut data = ArrayTrait::new();\n" +" data.append(2);\n" +" if true == true {\n" +" panic(data);\n" +" }\n" +" 'This line isn\\'t reached'.print();\n" "}\n" "```" msgstr "" "```rust\n" -"struct Potion {\n" -" health: felt252,\n" -" mana: felt252\n" -"}\n" -"\n" -"impl PotionAdd of Add {\n" -" fn add(lhs: Potion, rhs: Potion) -> Potion {\n" -" Potion { health: lhs.health + rhs.health, mana: lhs.mana + rhs.mana, }\n" -" }\n" -"}\n" +"use debug::PrintTrait;\n" "\n" "fn main() {\n" -" let health_potion: Potion = Potion { health: 100, mana: 0 };\n" -" let mana_potion: Potion = Potion { health: 0, mana: 100 };\n" -" let super_potion: Potion = health_potion + mana_potion;\n" -" // Both potions were combined with the `+` operator.\n" -" assert(super_potion.health == 100, ‘’);\n" -" assert(super_potion.mana == 100, ‘’);\n" +" let mut data = ArrayTrait::new();\n" +" data.append(2);\n" +" if true == true {\n" +" panic(data);\n" +" }\n" +" 'This line isn\\'t reached'.print();\n" "}\n" "```" -#: src/ch10-01-operator-overloading.md:32 +#: src/ch09-01-unrecoverable-errors-with-panic.md:24 +msgid "Running the program will produce the following output:" +msgstr "运行该程序将产生以下输出:" + +#: src/ch09-01-unrecoverable-errors-with-panic.md:26 msgid "" -"In the code above, we're implementing the `Add` trait for the `Potion` type. The add function takes two arguments: `lhs` and `rhs` (left and right-hand side). The function body " -"returns a new `Potion` instance, its field values being a combination of `lhs` and `rhs`." +"```shell\n" +"$ scarb cairo-run\n" +"Run panicked with [2 (''), ].\n" +"```" msgstr "" -"在上面的代码中,我们为 `Potion`类型实现`Add`特性。Add函数需要两个参数:`lhs` 和 `rhs`(左手端和右手端,分别表示在运算式的左边还是右边)。函数主体返回一个新的`Potion`实例,其字段值是" -"`lhs`和`rhs`的组合。" +"```shell\n" +"$ scarb cairo-run\n" +"Run panicked with [2 (''), ].\n" +"```" -#: src/ch10-01-operator-overloading.md:34 +#: src/ch09-01-unrecoverable-errors-with-panic.md:31 +msgid "As you can notice in the output, the print statement is never reached, as the program terminates after encountering the `panic` statement." +msgstr "正如你在输出中所注意到的,打印语句没有被执行,因为程序在遇到`panic`语句后就终止了。" + +#: src/ch09-01-unrecoverable-errors-with-panic.md:33 msgid "" -"As illustrated in the example, overloading an operator requires specification of the concrete type being overloaded. The overloaded generic trait is `Add`, and we define a " -"concrete implementation for the type `Potion` with `Add`." -msgstr "正如例子中所说明的,重载一个操作符需要指定被重载的具体类型。这里被重载用泛型表示的trait是 `Add`,所以我们将用 `Add`为 ‘Potion`类型定义一个具体的实现。" +"An alternative and more idiomatic approach to panic in Cairo would be to use the `panic_with_felt252` function. This function serves as an abstraction of the array-defining process " +"and is often preferred due to its clearer and more concise expression of intent. By using `panic_with_felt252`, developers can panic in a one-liner by providing a felt252 error " +"message as argument, making the code more readable and maintainable." +msgstr "" +"在Cairo中,另一种更常见的方法是使用`panic_with_felt252`函数来处理恐慌。这个函数是对数组定义过程的抽象,由于它更清晰、更简洁地表达了意图,所以实际运用中经常使用该函数。通过使用" +"`panic_with_felt252`,开发者可以通过提供felt252错误信息作为参数,在一个单行代码中进行panic,使代码更易读和可维护。" -#: src/ch99-00-starknet-smart-contracts.md:1 -msgid "# Starknet Smart Contracts" -msgstr "# Starknet智能合约" - -#: src/ch99-00-starknet-smart-contracts.md:3 -msgid "All through the previous sections, you've mostly written programs with a `main` entrypoint. In the coming sections, you will learn to write and deploy Starknet contracts." -msgstr "在前面的章节中,你主要是用`main`入口来编写程序。在接下来的章节中,你将学习如何编写和部署Starknet合约。" +#: src/ch09-01-unrecoverable-errors-with-panic.md:35 +msgid "Let's consider an example:" +msgstr "让我们来考察一个例子:" -#: src/ch99-00-starknet-smart-contracts.md:5 +#: src/ch09-01-unrecoverable-errors-with-panic.md:37 msgid "" -"Starknet contracts, in simple words, are programs that can run on the Starknet VM. Since they run on the VM, they have access to Starknet’s persistent state, can alter or modify " -"variables in Starknet’s states, communicate with other contracts, and interact seamlessly with the underlying L1." +"```rust\n" +"fn main() {\n" +" panic_with_felt252(2);\n" +"}\n" +"```" msgstr "" -"Starknet合约,简单地说,就是可以在Starknet虚拟机上运行的程序。由于它们在虚拟机上运行,它们可以访问Starknet的持久性状态,可以改变或修改Starknet状态中的变量,与其他合约沟通,并与底层的" -"L1无缝交互。" +"```rust\n" +"fn main() {\n" +" panic_with_felt252(2);\n" +"}\n" +"```" -#: src/ch99-00-starknet-smart-contracts.md:7 -msgid "Starknet contracts are denoted by the `#[contract]` attribute. We'll dive deeper into this in the next sections." -msgstr "Starknet合约是由`#[contract]`属性表示的。我们将在接下来的章节中更深入地探讨这个问题。" +#: src/ch09-01-unrecoverable-errors-with-panic.md:43 +msgid "" +"Executing this program will yield the same error message as before. In that case, if there is no need for an array and multiple values to be returned within the error, so " +"`panic_with_felt252` is a more succinct alternative." +msgstr "执行这个程序会产生和之前一样的错误信息。在这种情况下,如果在返回错误是不需要一个数组和多个值,那么`panic_with_felt252`是一个更简洁的选择。" -#: src/ch99-01-01-introduction-to-smart-contracts.md:1 -msgid "# Introduction to smart-contracts" -msgstr "# 智能合约简介" +#: src/ch09-01-unrecoverable-errors-with-panic.md:45 +msgid "## nopanic notation" +msgstr "## nopanic记号" -#: src/ch99-01-01-introduction-to-smart-contracts.md:3 +#: src/ch09-01-unrecoverable-errors-with-panic.md:47 +msgid "You can use the `nopanic` notation to indicate that a function will never panic. Only `nopanic` functions can be called in a function annotated as `nopanic`." +msgstr "你可以使用`nopanic`记号来表示一个函数永远不会恐慌。只有 `nopanic`函数可以在标注为 `nopanic`的函数中被调用。" + +#: src/ch09-01-unrecoverable-errors-with-panic.md:49 src/ch09-01-unrecoverable-errors-with-panic.md:85 src/appendix-03-derivable-traits.md:17 src/appendix-03-derivable-traits.md:42 +#: src/appendix-03-derivable-traits.md:63 src/appendix-03-derivable-traits.md:85 src/appendix-03-derivable-traits.md:118 src/appendix-03-derivable-traits.md:155 +msgid "Example:" +msgstr "例子:" + +#: src/ch09-01-unrecoverable-errors-with-panic.md:51 msgid "" -"This chapter will give you a high level introduction to what smart-contracts are, what are they used for and why would blockchain developers use Cairo and Starknet.\n" -"If you are already familiar with blockchain programming, feel free to skip this chapter. The last part might still be interesting though." +"```rust,noplayground\n" +"fn function_never_panic() -> felt252 nopanic {\n" +" 42\n" +"}\n" +"```" msgstr "" -"本章是一个关于什么是智能合约,它们有什么用途,以及为什么区块链开发者会使用Cairo和Starknet的高度简介。\n" -"如果你已经熟悉了区块链编程,可以跳过这一章。不过最后一部分应该还是有点意思的。" +"```rust,noplayground\n" +"fn function_never_panic() -> felt252 nopanic {\n" +" 42\n" +"}\n" +"```" -#: src/ch99-01-01-introduction-to-smart-contracts.md:6 -msgid "## Smart-contracts" -msgstr "## 智能合约" +#: src/ch09-01-unrecoverable-errors-with-panic.md:57 +msgid "Wrong example:" +msgstr "错误的例子:" -#: src/ch99-01-01-introduction-to-smart-contracts.md:8 +#: src/ch09-01-unrecoverable-errors-with-panic.md:59 msgid "" -"Smart contracts gained popularity and became more widespread with the birth of Ethereum. Smart contracts are essentially programs deployed on a blockchain. The term \"smart " -"contract\" is somewhat misleading, as they are neither \"smart\" nor \"contracts\" but rather code and instructions that are executed based on specific inputs. They primarily consist " -"of two components: storage and functions. Once deployed, users can interact with smart contracts by initiating blockchain transactions containing execution data (which function to " -"call and with what input). Smart contracts can modify and read the storage of the underlying blockchain. A smart contract has its own address and is considered a blockchain account, " -"meaning it can hold tokens." +"```rust,noplayground\n" +"//TAG: does_not_compile\n" +"fn function_never_panic() nopanic {\n" +" assert(1 == 1, 'what');\n" +"}\n" +"```" msgstr "" -"随着以太坊的诞生,智能合约得到了普及并变得更加广泛。智能合约本质上是部署在区块链上的程序。术语 \"智能合约 \"有些误导,因为它们既不 \"智能 \"也不是 \"合约\",而只是根据特定输入执行的代" -"码和指令。它们主要由两部分组成:存储和函数。部署后,用户可以通过启动包含执行数据的区块链交易(调用哪个函数,输入什么参数)与智能合约互动。智能合约可以修改和读取底层区块链的存储。智能" -"合约有自己的地址,因此它是一个区块链账户,意味着它可以持有代币。" +"```rust,noplayground\n" +"//TAG: does_not_compile\n" +"fn function_never_panic() nopanic {\n" +" assert(1 == 1, 'what');\n" +"}\n" +"```" -#: src/ch99-01-01-introduction-to-smart-contracts.md:10 +#: src/ch09-01-unrecoverable-errors-with-panic.md:66 +msgid "If you write the following function that includes a function that may panic you will get the following error:" +msgstr "如果你写了以下函数,其中包括一个可能会panic的函数,你会得到以下错误:" + +#: src/ch09-01-unrecoverable-errors-with-panic.md:68 msgid "" -"The programming language used to write smart contracts varies depending on the blockchain. For example, on Ethereum and the [EVM-compatible ecosystem](https://ethereum.org/en/" -"developers/docs/evm/), the most commonly used language is Solidity, while on Starknet, it is Cairo. The way the code is compiled also differs based on the blockchain. On Ethereum, " -"Solidity is compiled into bytecode. On Starknet, Cairo is compiled into Sierra and then into Cairo Assembly (casm)." +"```shell\n" +"error: Function is declared as nopanic but calls a function that may panic.\n" +" --> test.cairo:2:12\n" +" assert(1 == 1, 'what');\n" +" ^****^\n" +"Function is declared as nopanic but calls a function that may panic.\n" +" --> test.cairo:2:5\n" +" assert(1 == 1, 'what');\n" +" ^********************^\n" +"```" msgstr "" -"用于编写智能合约的编程语言因区块链的不同而不同。例如,在以太坊和[EVM兼容的生态系统](https://ethereum.org/en/developers/docs/evm/)生态系统上,最常用的语言是Solidity,而在Starknet上,是" -"Cairo。代码的编译方式也根据区块链的不同而不同。在Ethereum上,Solidity被编译成字节码。在Starknet上,Cairo被编译成Sierra,然后再编译成Cairo Assembly(casm)。" +"```shell\n" +"error: Function is declared as nopanic but calls a function that may panic.\n" +" --> test.cairo:2:12\n" +" assert(1 == 1, 'what');\n" +" ^****^\n" +"Function is declared as nopanic but calls a function that may panic.\n" +" --> test.cairo:2:5\n" +" assert(1 == 1, 'what');\n" +" ^********************^\n" +"```" -#: src/ch99-01-01-introduction-to-smart-contracts.md:12 +#: src/ch09-01-unrecoverable-errors-with-panic.md:79 +msgid "Note that there are two functions that may panic here, assert and equality." +msgstr "请注意,有两个函数可能会在这里发生panic,即断言和相等比较。" + +#: src/ch09-01-unrecoverable-errors-with-panic.md:81 +msgid "## panic_with attribute" +msgstr "## panic_with 属性" + +#: src/ch09-01-unrecoverable-errors-with-panic.md:83 msgid "" -"Smart contracts possess several unique characteristics. They are **permissionless**, meaning anyone can deploy a smart contract on the network (within the context of a decentralized " -"blockchain, of course). Smart contracts are also **transparent**; the data stored by the smart contract is accessible to anyone. The code that composes the contract can also be " -"transparent, enabling **composability**. This allows developers to write smart contracts that use other smart contracts. Smart contracts can only access and interact with data from " -"the blockchain they are deployed on. They require third-party softwares (called `oracles`) to access external data (the price of a token for instance)." +"You can use the `panic_with` attribute to mark a function that returns an `Option` or `Result`. This attribute takes two arguments, which are the data that is passed as the panic " +"reason as well as the name for a wrapping function. It will create a wrapper for your annotated function which will panic if the function returns `None` or `Err`, the panic function " +"will be called with the given data." msgstr "" -"智能合约拥有几个独特的特点。它们是**无权限的**,意味着任何人都可以在网络上部署智能合约(当然该网络必须是去中心化区块链)。智能合约也是**透明的**;任何人都可以访问智能合约所存储的数" -"据。构成合约的代码也可以是透明的,实现了**可组合性**。这使得开发者可以编写使用其他智能合约的智能合约。智能合约只能访问它们所部署的区块链上的数据并与之互动。他们需要第三方工具或软件" -"(称为 \"oracles\")来访问外部数据(例如,代币的价格)。" +"您可以使用 `panic_with` 属性来标记返回 `Option` 或 `Result` 的函数。该属性需要两个参数,即作为 panic 原因传递的数据以及包装函数的名称。它将为您标注的函数创建一个封装函数,如果函数返" +"回 `None` 或 `Err`,该封装函数将被调用,并使用给定的数据。" -#: src/ch99-01-01-introduction-to-smart-contracts.md:14 +#: src/ch09-01-unrecoverable-errors-with-panic.md:87 msgid "" -"For developers to build smart contracts that can interact with each other, it is required to know what the other contracts look like. Hence, Ethereum developers started to build " -"standards for smart contract development, the `ERCxx`. The two most used and famous standards are the `ERC20`, used to build tokens like `USDC`, `DAI` or `STARK`, and the `ERC721`, " -"for NFTs (Non-fungible tokens) like `CryptoPunks` or `Everai`." +"```rust\n" +"#[panic_with('value is 0', wrap_not_zero)]\n" +"fn wrap_if_not_zero(value: u128) -> Option {\n" +" if value == 0 {\n" +" Option::None\n" +" } else {\n" +" Option::Some(value)\n" +" }\n" +"}\n" +"\n" +"fn main() {\n" +" wrap_if_not_zero(0); // this returns None\n" +" wrap_not_zero(0); // this panic with 'value is 0'\n" +"}\n" +"```" msgstr "" -"对于开发者来说,要想建立能够相互互动的智能合约,就必须知道其他合约的是什么样。因此,以太坊开发者建立了一些智能合约开发的标准,即 `ERCxx`。两个最常用和最著名的标准是 `ERC20`,用于建立 " -"`USDC`、`DAI`或 `STARK`等代币,以及 `ERC721`,用于 `CryptoPunks`或 `Everai`等NFT(Non-fungible token)。" +"```rust\n" +"#[panic_with('value is 0', wrap_not_zero)]\n" +"fn wrap_if_not_zero(value: u128) -> Option {\n" +" if value == 0 {\n" +" Option::None\n" +" } else {\n" +" Option::Some(value)\n" +" }\n" +"}\n" +"\n" +"fn main() {\n" +" wrap_if_not_zero(0); // this returns None\n" +" wrap_not_zero(0); // this panic with 'value is 0'\n" +"}\n" +"```" -#: src/ch99-01-01-introduction-to-smart-contracts.md:16 -msgid "## Use cases" -msgstr "## 使用案例" +#: src/ch09-01-unrecoverable-errors-with-panic.md:103 +msgid "## Using assert" +msgstr "## 使用断言(assert)" -#: src/ch99-01-01-introduction-to-smart-contracts.md:18 -msgid "There are many possible use cases for smart-contracts. The only limits are the technical constraints of the blockchain and the creativity of developers." -msgstr "智能合约有许多可能的用例。唯一的限制是区块链的技术限制和开发者的创造力。" +#: src/ch09-01-unrecoverable-errors-with-panic.md:105 +msgid "" +"The assert function from the Cairo core library is actually a utility function based on panics. It asserts that a boolean expression is true at runtime, and if it is not, it calls " +"the panic function with an error value. The assert function takes two arguments: the boolean expression to verify, and the error value. The error value is specified as a felt252, so " +"any string passed must be able to fit inside a felt252." +msgstr "" +"Cairo核心库中的assert函数实际上是一个基于panic的实用函数。它断言一个布尔表达式在运行时是真的,如果不是,它就会调用带有错误值的panic函数。assert函数需要两个参数:要验证的布尔表达式,以" +"及错误值。错误值被指定为felt252,所以任何传递的字符串都必须能够容纳在felt252中。" -#: src/ch99-01-01-introduction-to-smart-contracts.md:20 -msgid "#### DeFi" -msgstr "#### DeFi" +#: src/ch09-01-unrecoverable-errors-with-panic.md:107 +msgid "Here is an example of its usage:" +msgstr "下面是它的一个使用例子:" -#: src/ch99-01-01-introduction-to-smart-contracts.md:22 +#: src/ch09-01-unrecoverable-errors-with-panic.md:109 msgid "" -"Right now, the principal use case for smart contracts is similar to that of Ethereum or Bitcoin, which is essentially handling money. In the context of the alternative payment system " -"promised by Bitcoin, smart contracts on Ethereum enable the creation of decentralized financial applications that no longer rely on traditional financial intermediaries. This is what " -"we call DeFi (decentralized finance). DeFi consists of various projects such as lending/borrowing apps, decentralized exchanges (DEX), on-chain derivatives, stablecoins, " -"decentralized hedge funds, insurance, and many more." +"```rust\n" +"fn main() {\n" +" let my_number: u8 = 0;\n" +"\n" +" assert(my_number != 0, 'number is zero');\n" +"\n" +" 100 / my_number;\n" +"}\n" +"```" msgstr "" -"眼下,智能合约的主要用例与以太坊或比特币的用例类似,基本上是处理金钱。在比特币承诺的替代支付系统的背景下,我们在以太坊上可以使用智能合约创建去中心化的金融应用,不需要再依赖传统的金融" -"中介机构。这就是我们所说的DeFi(去中心化金融)。DeFi由各种项目组成,如借贷应用、去中心化交易所(DEX)、链上衍生品、稳定币、去中心化对冲基金、保险等等。" - -#: src/ch99-01-01-introduction-to-smart-contracts.md:24 -msgid "#### Tokenization" -msgstr "#### 代币化" +"```rust\n" +"fn main() {\n" +" let my_number: u8 = 0;\n" +"\n" +" assert(my_number != 0, 'number is zero');\n" +"\n" +" 100 / my_number;\n" +"}\n" +"```" -#: src/ch99-01-01-introduction-to-smart-contracts.md:26 +#: src/ch09-01-unrecoverable-errors-with-panic.md:119 msgid "" -"Smart contracts can facilitate the tokenization of real-world assets, such as real estate, art, or precious metals. Tokenization divides an asset into digital tokens, which can be " -"easily traded and managed on blockchain platforms. This can increase liquidity, enable fractional ownership, and simplify the buying and selling process." +"We are asserting in main that `my_number` is not zero to ensure that we're not performing a division by 0.\n" +"In this example, `my_number` is zero so the assertion will fail, and the program will panic\n" +"with the string 'number is zero' (as a felt252) and the division will not be reached." msgstr "" -"智能合约可以促进现实世界资产的代币化,如房地产、艺术品或贵金属。代币化将资产划分为数字代币,可以在区块链平台上轻松交易和管理。这可以增加流动性,实现部分所有权,并简化购买和销售过程。" +"我们在main中断言`my_number`不是0,以确保我们没有进行除以0的操作。\n" +"在这个例子中,`my_number`是零,所以断言会失败,程序会panic,\n" +"并给出 'number is zero'的字符串(保存在felt252中),除法将不会被执行。" -#: src/ch99-01-01-introduction-to-smart-contracts.md:28 -msgid "#### Voting" -msgstr "#### 投票" +#: src/ch09-02-recoverable-errors.md:1 +msgid "# Recoverable Errors with `Result`" +msgstr "# 可恢复的错误与 `Result`" -#: src/ch99-01-01-introduction-to-smart-contracts.md:30 +#: src/ch09-02-recoverable-errors.md:3 src/ch09-02-recoverable-errors.md:56 +msgid "
" +msgstr "
" + +#: src/ch09-02-recoverable-errors.md:5 msgid "" -"Smart contracts can be used to create secure and transparent voting systems. Votes can be recorded on the blockchain, ensuring immutability and transparency. The smart contract can " -"then automatically tally the votes and declare the results, minimizing the potential for fraud or manipulation." -msgstr "智能合约可用于创建安全和透明的投票系统。投票可以记录在区块链上,确保不可更改性和透明度。然后,智能合约可以自动统计票数并宣布结果,将欺诈或操纵的可能性降到最低。" +"Most errors aren’t serious enough to require the program to stop entirely. Sometimes, when a function fails, it’s for a reason that you can easily interpret and respond to. For " +"example, if you try to add two large integers and the operation overflows because the sum exceeds the maximum representable value, you might want to return an error or a wrapped " +"result instead of causing undefined behavior or terminating the process." +msgstr "" +"大多数错误并没有严重到需要程序完全停止的程度。有时,当一个函数失败时,它的原因是你可以很容易地解释和应对的。例如,如果你试图将两个大的整数相加,而操作溢出,因为总和超过了最大的可表示" +"值,你可能想返回一个错误或一个包装好的结果,而不是引起未定义行为或终止程序。" -#: src/ch99-01-01-introduction-to-smart-contracts.md:32 -msgid "#### Royalties" -msgstr "#### 特许权使用费(版税)" +#: src/ch09-02-recoverable-errors.md:7 +msgid "## The `Result` enum" +msgstr "## `Result`枚举" -#: src/ch99-01-01-introduction-to-smart-contracts.md:34 -msgid "" -"Smart contracts can automate royalty payments for artists, musicians, and other content creators. When a piece of content is consumed or sold, the smart contract can automatically " -"calculate and distribute the royalties to the rightful owners, ensuring fair compensation and reducing the need for intermediaries." -msgstr "智能合约可以为艺术家、音乐家和其他内容创作者自动支付版税。当一段内容被消费或出售时,智能合约可以自动计算并将版税分配给合法的所有者,确保公平的补偿并减少对中间人的需求。" +#: src/ch09-02-recoverable-errors.md:9 +msgid "Recall from [“Generic data types”](ch07-01-generic-data-types.md#enums) in Chapter 7 that the `Result` enum is defined as having two variants, `Ok` and `Err`, as follows:" +msgstr "回顾第七章中的[\"通用数据类型\"](ch07-01-generic-data-types.md#enums),`Result`枚举被定义为有两个变体,`Ok`和`Err`,如下所示:" -#: src/ch99-01-01-introduction-to-smart-contracts.md:36 -msgid "#### Decentralized identities DIDs" -msgstr "#### 去中心化身份 DIDs" +#: src/ch09-02-recoverable-errors.md:20 +msgid "## The `ResultTrait`" +msgstr "## `ResultTrait`" -#: src/ch99-01-01-introduction-to-smart-contracts.md:38 +#: src/ch09-02-recoverable-errors.md:22 msgid "" -"Smart contracts can be used to create and manage digital identities, allowing individuals to control their personal information and share it with third parties securely. The smart " -"contract could verify the authenticity of a user's identity and automatically grant or revoke access to specific services based on the user's credentials." -msgstr "智能合约可用于创建和管理数字身份,允许个人控制其个人信息,并与第三方安全地分享。智能合约可以验证用户身份的真实性,并根据用户的凭证自动授予或撤销对特定服务的访问。" +"The `ResultTrait` trait provides methods for working with the `Result` enum, such as unwrapping values, checking whether the `Result` is `Ok` or `Err`, and panicking with a " +"custom message. The `ResultTraitImpl` implementation defines the logic of these methods." +msgstr "`ResultTrait`特征提供了处理`Result`枚举的方法,例如解包值,检查`Result`是`Ok`还是`Err`,以及用自定义的消息进行panic。`ResultTraitImpl`实现定义了这些方法的逻辑。" -#: src/ch99-01-01-introduction-to-smart-contracts.md:40 -msgid "" -"
\n" -"
\n" -"As Ethereum continues to mature, we can expect the use cases and applications of smart contracts to expand further, bringing about exciting new opportunities and reshaping " -"traditional systems for the better." -msgstr "" -"
\n" -"
\n" -"随着以太坊的不断成熟,我们可以预期智能合约的用例和应用将进一步扩大,带来令人兴奋的新机会,并会更好地重塑传统系统。" - -#: src/ch99-01-01-introduction-to-smart-contracts.md:44 -msgid "## The rise of Starknet and Cairo" -msgstr "## Starknet和Cairo语言的崛起" - -#: src/ch99-01-01-introduction-to-smart-contracts.md:46 -msgid "" -"Ethereum, being the most widely used and resilient smart-contract platform, became a victim of its own success. With the rapid adoption of some previously mentioned use cases, mainly " -"DeFi, the cost of performing transactions became extremely high, rendering the network almost unusable. Engineers and researchers in the ecosystem began working on solutions to " -"address this scalability issue. A famous theorem in the blockchain space states that it is impossible to achieve a high level of scalability, decentralization, and security " -"simultaneously; trade-offs must be made. Ethereum is at the intersection of decentralization and security. Eventually, it was decided that Ethereum's purpose would be to serve as a " -"secure settlement layer, while complex computations would be offloaded to other networks built on top of Ethereum. These are called Layer 2s (L2s). The two primary types of L2s are " -"optimistic rollups and validity rollups. Both approaches involve compressing and batching numerous transactions together, computing the new state, and settling the result on Ethereum " -"(L1). The difference lies in the way the result is settled on L1. For optimistic rollups, the new state is considered valid by default, but there is a 7-day window for nodes to " -"identify malicious transactions. In contrast, validity rollups, such as Starknet, use cryptography to prove that the new state has been correctly computed. This is the purpose of " -"STARKs, this cryptographic technology could permit validity rollups to scale significantly more than optimistic rollups. You can learn more about STARKs from Starkware's Medium " -"[article](https://medium.com/starkware/starks-starkex-and-starknet-9a426680745a), which serves as a good primer." -msgstr "" -"以太坊作为使用最广泛、弹性最大的智能合约平台,成为了其自身成功的受害者。随着前面提到的一些用例的快速采用,主要是DeFi,执行交易的成本变得非常高,使网络几乎无法使用。生态系统中的工程师" -"和研究人员开始研究解决这一可扩展性问题的方案。区块链领域的一个著名定理指出,不可能同时实现高水平的可扩展性、去中心化和安全性;必须做出权衡。以太坊正处于去中心化和安全的交叉点。最终," -"人们决定,以太坊的目的是作为一个安全的结算层,而复杂的计算将被卸载到建立在以太坊之上的其他网络。这些被称为第二层(L2)。L2的两种主要类型是optimistic-rollups和validity-rollups。这两种" -"方法都涉及到将众多交易压缩和批量化,计算新的状态,并将结果在以太坊(L1)上结算。区别在于结果在L1上结算的方式。对于optimistic-rollups,新的状态默认被认为是有效的,但有一个7天的窗口供节" -"点识别恶意交易。相比之下,validity-rollups,如Starknet,使用密码学来证明新的状态已经被正确计算出来。这是STARKs的目的,这种加密技术可以允许validity-rollups的规模大大超过optimistic-" -"rollups。你可以从Starkware的Medium[文章](https://medium.com/starkware/starks-starkex-and-starknet-9a426680745a)中了解更多关于STARKs的信息,这可以作为一个很好的入门。" - -#: src/ch99-01-01-introduction-to-smart-contracts.md:48 -msgid "" -"Remember Cairo? It is, in fact, a language developed specifically to work with STARKs and make them general-purpose. With Cairo, we can write **provable code**. In the context of " -"Starknet, this allows proving the correctness of computations from one state to another. Unlike most (if not all) of Starknet's competitors that chose to use the EVM (either as-is or " -"adapted) as a base layer, Starknet employs its own VM. This frees developers from the constraints of the EVM, opening up a broader range of possibilities. Coupled with decreased " -"transaction costs, the combination of Starknet and Cairo creates an exciting playground for developers. Native account abstraction enables more complex logic for accounts and " -"transaction flows. Emerging use cases include **transparent AI** and artificial intelligence and machine learning applications. Finally, **blockchain games** can be developed " -"entirely **on-chain**. Starknet has been specifically designed to maximize the capabilities of STARK proofs for optimal scalability." -msgstr "" -"还记得Cairo吗?事实上,它是一种专门开发的语言,用于和STARKs一起工作并使其通用化。通过Cairo,我们可以编写**可证明的代码**。在Starknet中,这允许证明从一个状态到另一个状态的计算的正确" -"性。与大多数(如果不是全部)Starknet的竞争对手不同,他们选择使用EVM(无论是原版还是适配兼容)作为基础层,Starknet采用了自己的VM。这使开发者摆脱了EVM的限制,开辟了更广泛的可能性。再加" -"上交易成本的降低,Starknet和Cairo的结合为开发者创造了一个令人兴奋的游乐场。原生的账户抽象使账户和交易流的逻辑更加复杂。新兴的用例包括**透明的AI**和人工智能及机器学习应用。最后,**区块" -"链游戏**可以完全**在链上开发**。总之,Starknet是被专门来设计最大化发挥STARK证明能力,以实现最佳的可扩展性。" - -#: src/ch99-01-02-writing-starknet-contracts.md:1 -msgid "# Writing Starknet Contracts" -msgstr "# 撰写Starknet合约" - -#: src/ch99-01-02-writing-starknet-contracts.md:3 -msgid "This chapter will guide you on how to create smart contracts in Cairo, and will clarify the distinction between Cairo programs and Starknet contracts." -msgstr "本章将指导你如何在Cairo中创建智能合约,并将阐明Cairo程序和Starknet合约之间的区别。" - -#: src/ch99-01-02-writing-starknet-contracts.md:5 -msgid "## Cairo programs and Starknet contracts" -msgstr "## Cairo程序和Starknet合约" - -#: src/ch99-01-02-writing-starknet-contracts.md:7 -msgid "" -"Starknet contracts are a special subset of Cairo programs, so the concepts previously learned in this book are still applicable to write Starknet contracts.\n" -"As you may have already noticed, a Cairo program must always have a function `main` that serves as the entry point for this program:" -msgstr "" -"Starknet合约是Cairo程序的一个特殊子集,所以之前在本书中学到的概念仍然适用于编写Starknet合约。\n" -"你可能已经注意到,一个Cairo程序必须始终有一个函数`main`,作为这个程序的入口:" - -#: src/ch99-01-02-writing-starknet-contracts.md:10 -msgid "" -"```rust\n" -"fn main() {}\n" -"```" -msgstr "" -"```rust\n" -"fn main() {}\n" -"```" - -#: src/ch99-01-02-writing-starknet-contracts.md:14 -msgid "" -"Starknet contracts are essentially programs that can run on the Starknet OS, and as such, have access to Starknet's state. For a module to be handled as a contract by the compiler, " -"it must be annotated with the `#[contract]` attribute:" -msgstr "Starknet合约本质上是可以在Starknet操作系统上运行的程序,因此可以访问Starknet的状态。为了让编译器将一个module当作合约来处理,必须用`#[contract]`属性来标注:" - -#: src/ch99-01-02-writing-starknet-contracts.md:16 +#: src/ch09-02-recoverable-errors.md:24 msgid "" -"```rust\n" -"#[contract]\n" -"mod Example{\n" -" use starknet::get_caller_address;\n" -" use starknet::ContractAddress;\n" +"```rust,noplayground\n" +"trait ResultTrait {\n" +" fn expect>(self: Result, err: felt252) -> T;\n" "\n" -" struct Storage{\n" -" names: LegacyMap::,\n" -" }\n" +" fn unwrap>(self: Result) -> T;\n" "\n" -" #[event]\n" -" fn StoredName(caller: ContractAddress, name:felt252){}\n" +" fn expect_err>(self: Result, err: felt252) -> E;\n" "\n" -" #[constructor]\n" -" fn constructor(_name: felt252, _address: ContractAddress){\n" -" names::write(_address, _name);\n" -" }\n" +" fn unwrap_err>(self: Result) -> E;\n" "\n" -" #[external]\n" -" fn store_name(_name: felt252){\n" -" let caller = get_caller_address();\n" -" names::write(caller, _name);\n" -" StoredName(caller,_name);\n" -" }\n" +" fn is_ok(self: @Result) -> bool;\n" "\n" -" #[view]\n" -" fn get_name(_address:ContractAddress) -> felt252{\n" -" let name = names::read(_address);\n" -" return name;\n" -" }\n" +" fn is_err(self: @Result) -> bool;\n" "}\n" "```" msgstr "" -"```rust\n" -"#[contract]\n" -"mod Example{\n" -" use starknet::get_caller_address;\n" -" use starknet::ContractAddress;\n" +"```rust,noplayground\n" +"trait ResultTrait {\n" +" fn expect>(self: Result, err: felt252) -> T;\n" "\n" -" struct Storage{\n" -" names: LegacyMap::,\n" -" }\n" +" fn unwrap>(self: Result) -> T;\n" "\n" -" #[event]\n" -" fn StoredName(caller: ContractAddress, name:felt252){}\n" +" fn expect_err>(self: Result, err: felt252) -> E;\n" "\n" -" #[constructor]\n" -" fn constructor(_name: felt252, _address: ContractAddress){\n" -" names::write(_address, _name);\n" -" }\n" +" fn unwrap_err>(self: Result) -> E;\n" "\n" -" #[external]\n" -" fn store_name(_name: felt252){\n" -" let caller = get_caller_address();\n" -" names::write(caller, _name);\n" -" StoredName(caller,_name);\n" -" }\n" +" fn is_ok(self: @Result) -> bool;\n" "\n" -" #[view]\n" -" fn get_name(_address:ContractAddress) -> felt252{\n" -" let name = names::read(_address);\n" -" return name;\n" -" }\n" +" fn is_err(self: @Result) -> bool;\n" "}\n" "```" -#: src/ch99-01-02-writing-starknet-contracts.md:49 -msgid "Listing 9-1: A simple naming service contract" -msgstr "示例9-1:一个简单的命名服务合约" - -#: src/ch99-01-02-writing-starknet-contracts.md:51 -msgid "> Note: Starknet contracts are defined within [modules](./ch06-02-defining-modules-to-control-scope.md)." -msgstr "> 注意:Starknet合约是在模块([modules](./ch06-02-defining-modules-to-control-scope.md))中被定义的。" - -#: src/ch99-01-02-writing-starknet-contracts.md:53 -msgid "## Starknet Contract Attributes" -msgstr "## Starknet合约的属性" - -#: src/ch99-01-02-writing-starknet-contracts.md:55 -msgid "Attributes are special annotations that modify the behavior of certain functions or methods. They are placed preceding a function and are denoted by the `#[]` symbol." -msgstr "属性是修改某些函数或方法的行为的特殊标注。它们被放在一个函数的前面,用`#[]`符号来表示。" - -#: src/ch99-01-02-writing-starknet-contracts.md:57 -msgid "" -msgstr "" - -#: src/ch99-01-02-writing-starknet-contracts.md:59 -msgid "Here is a list of common attributes used in Starknet contracts:" -msgstr "以下是Starknet合约中使用的常见属性列表:" - -#: src/ch99-01-02-writing-starknet-contracts.md:61 +#: src/ch09-02-recoverable-errors.md:40 msgid "" -"1. `#[contract]`: This attribute is used to annotate a module to be compiled as a Starknet contract.\n" -" The compiler recognizes this attribute and prepares the module with necessary contract elements,\n" -" such as the logic to handle external contract calls or how to access storage variables.\n" -"\n" -"2. `#[constructor]`: This attribute marks a function as a constructor. The constructor function is called only once upon deploying a contract, setting the initial state of the " -"contract.\n" -"\n" -"3. `#[external]`: This attribute marks a function as an external function. External functions can be called by other contracts or externally and can modify the contract's state.\n" -"\n" -"4. `#[view]`: This attribute marks a function as a view function. View functions are read-only functions that allow you to access data from the contract, but prevent you from " -"modifying the state of the blockchain.\n" -"\n" -"5. `#[event]`: This is used to define events that can be emitted by the contract.\n" -"\n" -"6. `#[l1_handler]`: This attribute is used to mark functions which can receive messages from L1s." +"The `expect` and `unwrap` methods are similar in that they both attempt to extract the value of type `T` from a `Result` when it is in the `Ok` variant. If the `Result` is " +"`Ok(x)`, both methods return the value `x`. However, the key difference between the two methods lies in their behavior when the `Result` is in the `Err` variant. The `expect` method " +"allows you to provide a custom error message (as a `felt252` value) that will be used when panicking, giving you more control and context over the panic. On the other hand, the " +"`unwrap` method panics with a default error message, providing less information about the cause of the panic." msgstr "" -"1. `#[contract]`:这个属性用来标注一个要被编译为Starknet合约的模块。\n" -" 编译器会识别这个属性并为模块准备必要的合同元素、\n" -" 例如,处理外部合同调用的逻辑或如何访问存储变量。\n" -"\n" -"2. `#[constructor]`:这个属性标志着一个函数是一个构造函数。构造函数在部署合约时只被调用一次,设置合约的初始状态。\n" -"\n" -"3. `#[external]`:这个属性标志着一个函数是一个外部函数。外部函数可以被其他合约或外部调用,可以修改合约的状态。\n" -"\n" -"4. `#[view]`:这个属性标志着一个函数是一个视图函数。视图函数是只读函数,允许你访问合约中的数据,但阻止你修改区块链的状态。\n" -"\n" -"5. `#[event]`:这是用来定义可由合约发出的事件。\n" -"\n" -"6. `#[l1_handler]`:这个属性用来标记可以接收L1消息的函数。" - -#: src/ch99-01-02-writing-starknet-contracts.md:75 -msgid "## Storage Variables" -msgstr "## 存储用变量" - -#: src/ch99-01-02-writing-starknet-contracts.md:77 -msgid "" -"Storage variables allow you to store data that will be stored on the blockchain in the contract's storage. These data are persistent and can be accessed and modified anytime once the " -"contract is deployed." -msgstr "存储用变量允许你存储数据,这些数据将存储在合约的存储区块链上。这些数据是持久性的,一旦合约被部署,可以随时访问和修改。" - -#: src/ch99-01-02-writing-starknet-contracts.md:79 -msgid "Storage variables in Starknet contracts are stored in a special struct called `Storage`:" -msgstr "Starknet合同中的存储用变量被存储在一个特殊的结构中,称为`Storage`:" +"`expect`和`unwrap`方法类似,它们都试图从`Result`中提取`T`类型的值,当它处于`Ok`变体时。如果`Result`是 `Ok(x)`,两个方法都返回值 \"x\"。然而,这两个方法的关键区别在于当`Result`是" +"`Err`变量时的行为。`expect`方法允许你提供一个自定义的错误信息(作为`felt252`值)在panic时使用,从而让你获取更多对panic相关的控制和上下文。另一方面,`unwrap`方法用一个默认的错误信息进" +"行panic,提供的关于panic原因的信息较少。" -#: src/ch99-01-02-writing-starknet-contracts.md:81 +#: src/ch09-02-recoverable-errors.md:42 msgid "" -"```rust\n" -"struct Storage{\n" -" id: u8,\n" -" names: LegacyMap::,\n" -"}\n" -"```" +"The `expect_err` and `unwrap_err` have the exact opposite behavior. If the `Result` is `Err(x)`, both methods return the value `x`. However, the key difference between the two " +"methods is in case of `Result::Ok()`. The `expect_err` method allows you to provide a custom error message (as a `felt252` value) that will be used when panicking, giving you more " +"control and context over the panic. On the other hand, the `unwrap_err` method panics with a default error message, providing less information about the cause of the panic." msgstr "" -"```rust\n" -"struct Storage{\n" -" id: u8,\n" -" names: LegacyMap::,\n" -"}\n" -"```" - -#: src/ch99-01-02-writing-starknet-contracts.md:88 -msgid "Listing 9-2: A Storage Struct" -msgstr "示例9-2:存储用结构体" +"`expect_err`和`unwrap_err`的行为完全相反。如果`Result`是`Err(x)`,两个方法都返回值`x`。然而,这两个方法的关键区别是在`Result::Ok()`的情况下。`expect_err`方法允许你提供一个自定义的错误" +"信息(作为`felt252`值),在panic时使用,从而让你获取更多对panic相关的控制和上下文。另一方面,`unwrap_err`方法用一个默认的错误信息进行panic,提供的关于panic原因的信息较少。" -#: src/ch99-01-02-writing-starknet-contracts.md:90 +#: src/ch09-02-recoverable-errors.md:44 msgid "" -"The storage struct is a [struct](./ch04-00-using-structs-to-structure-related-data.md) like any other,\n" -"except that it allows you to define mappings using the `LegacyMap` type." +"A careful reader may have noticed the `>` and `>` in the first four methods signatures. This syntax represents generic type constraints in the " +"Cairo language. These constraints indicate that the associated functions require an implementation of the `Drop` trait for the generic types `T` and `E`, respectively." msgstr "" -"存储用结构体是一个[struct](./ch04-00-using-structs-to-structure-related-data.md) ,基本与其他结构一样、\n" -"但是它允许你使用 `LegacyMap`类型来定义映射。" - -#: src/ch99-01-02-writing-starknet-contracts.md:93 -msgid "### Storage Mappings" -msgstr "### 存储用映射" +"细心的读者可能已经注意到前四个方法签名中的`>` and `>`。这种语法代表了Cairo语言中的通用类型约束。这些约束表示相关的函数需要分别对通用类型`T`和" +"`E`的`Drop`特性进行实现。" -#: src/ch99-01-02-writing-starknet-contracts.md:95 -msgid "" -"Mappings are a key-value data structure that you can use to store data within a smart contract. They are essentially hash tables that allow you to associate a unique key with a " -"corresponding value. Mappings are also useful to store sets of data, as it's impossible to store arrays in storage." -msgstr "" -"映射是一种键值数据结构,你可以用它来存储智能合约中的数据。它们本质上是哈希表,允许你将一个唯一的键与一个相应的值联系起来。映射对于存储数据集也很有用,因为在存储中不可能存储数组。" +#: src/ch09-02-recoverable-errors.md:46 +msgid "Finally, the `is_ok` and `is_err` methods are utility functions provided by the `ResultTrait` trait to check the variant of a `Result` enum value." +msgstr "最后,`is_ok`和`is_err`方法是`ResultTrait`特征提供的实用函数,用于检查`Result`枚举值的成员。" -#: src/ch99-01-02-writing-starknet-contracts.md:97 +#: src/ch09-02-recoverable-errors.md:48 msgid "" -"A mapping is a variable of type LegacyMap, in which the key and value types are specified within angular brackets <>.\n" -"It is important to note that the `LegacyMap` type can only be used inside the `Storage` struct, and can't be used to define mappings in user-defined structs.\n" -"The syntax for declaring a mapping is as follows in Listing 9-2." -msgstr "" -"映射是一个LegacyMap类型的变量,其中键和值的类型在角括号<>内指定。\n" -"需要注意的是,\"LegacyMap \"类型只能在 \"Storage \"结构中使用,而不能用于在用户定义的结构中定义映射。\n" -"声明映射的语法如示例9-2所示。" +"`is_ok` takes a snapshot of a `Result` value and returns `true` if the `Result` is the `Ok` variant, meaning the operation was successful. If the `Result` is the `Err` variant, " +"it returns `false`." +msgstr "`is_ok`获取一个`Result`值的快照,如果`Result`是`Ok`成员,则返回`true`,意味着操作成功。如果`Result`是`Err`成员,则返回`false`。" -#: src/ch99-01-02-writing-starknet-contracts.md:101 +#: src/ch09-02-recoverable-errors.md:50 msgid "" -"You can also create more complex mappings than that found in Listing 9-2 like the popular `allowances` storage variable in the ERC20 Standard which maps the `owner` and `spender` to " -"the `allowance` using tuples:" -msgstr "你也可以创建比示例9-2中更复杂的映射,比如ERC20标准中流行的`allowances`存储变量,它使用元组将 `owner`和 `spender`映射到`allowance` 上:" +"`is_err` takes a reference to a `Result` value and returns `true` if the `Result` is the `Err` variant, meaning the operation encountered an error. If the `Result` is the `Ok` " +"variant, it returns `false`." +msgstr "`is_err`接收一个对`Result`值的引用,如果`Result`是`Err`成员,意味着操作遇到了错误,则返回`true`。如果 `Result`是 `Ok`成员,则返回 `false`。" -#: src/ch99-01-02-writing-starknet-contracts.md:103 +#: src/ch09-02-recoverable-errors.md:52 msgid "" -"```rust\n" -"struct Storage{\n" -" allowances: LegacyMap::<(ContractAddress, ContractAddress), u256>\n" -"}\n" -"```" -msgstr "" -"```rust\n" -"struct Storage{\n" -" allowances: LegacyMap::<(ContractAddress, ContractAddress), u256>\n" -"}\n" -"```" +"These methods are helpful when you want to check the success or failure of an operation without consuming the Result value, allowing you to perform additional operations or make " +"decisions based on the variant without unwrapping it." +msgstr "当你想在不消耗结果值的情况下检查一个操作的成功或失败时,这些方法很有帮助,允许你执行额外的操作或根据枚举成员做出决定,而不用解开(unwrap)它。" -#: src/ch99-01-02-writing-starknet-contracts.md:109 -msgid "" -"In mappings, the address of the value at key `k_1,...,k_n` is `h(...h(h(sn_keccak(variable_name),k_1),k_2),...,k_n)` where ℎ\n" -"is the Pedersen hash and the final value is taken `mod2251−256`. You can learn more about the contract storage layout in the [Starknet Documentation](https://docs.starknet.io/" -"documentation/architecture_and_concepts/Contracts/contract-storage/#storage_variables)" -msgstr "" -"在映射中,键`k_1,...,k_n`的值的地址是`h(...h(h(sn_keccak(variable_name),k_1),k_2),...,k_n)`,其中ℎ\n" -"是Pedersen哈希值,最终值取为 \"mod2251-256\"。你可以在[Starknet文档](https://docs.starknet.io/documentation/architecture_and_concepts/Contracts/contract-storage/#storage_variables)中" -"了解更多关于合约存储布局的信息。" +#: src/ch09-02-recoverable-errors.md:54 +msgid "You can find the implementation ot the `ResultTrait` [here](https://github.com/starkware-libs/cairo/blob/main/corelib/src/result.cairo#L20)." +msgstr "你可以在[这里](https://github.com/starkware-libs/cairo/blob/main/corelib/src/result.cairo#L20)找到`ResultTrait`的实现。" -#: src/ch99-01-02-writing-starknet-contracts.md:112 -msgid "### Reading from Storage" -msgstr "### 从存储中读取" +#: src/ch09-02-recoverable-errors.md:58 +msgid "It is always easier to understand with examples." +msgstr "有例子总是更容易理解。" -#: src/ch99-01-02-writing-starknet-contracts.md:114 -msgid "To read the value of the storage variable `names`, we call the `read` function on the `names` storage variable, passing in the key `_address` as a parameter." -msgstr "为了读取存储变量`names`的值,我们在`names`的存储变量上调用`read`函数,将键`_address`作为参数传入。" +#: src/ch09-02-recoverable-errors.md:60 +msgid "Have a look at this function signature:" +msgstr "请看一下这个函数签名:" -#: src/ch99-01-02-writing-starknet-contracts.md:116 +#: src/ch09-02-recoverable-errors.md:62 msgid "" -"```rust\n" -"let name = names::read(_address);\n" +"```rust,noplayground\n" +"fn u128_overflowing_add(a: u128, b: u128) -> Result;\n" "```" msgstr "" -"```rust\n" -"let name = names::read(_address);\n" +"```rust,noplayground\n" +"fn u128_overflowing_add(a: u128, b: u128) -> Result;\n" "```" -#: src/ch99-01-02-writing-starknet-contracts.md:120 -msgid "Listing 9-3: Calling the `read` function on the `names` variable" -msgstr "示例9-3:在`names`变量上调用`read`函数" - -#: src/ch99-01-02-writing-starknet-contracts.md:122 -msgid "> Note: When the storage variable does not store a mapping, its value is accessed without passing any parameters to the read method" -msgstr "> 注意:当存储变量不存储映射时,使用读取方法访问其值不需要传递任何参数" - -#: src/ch99-01-02-writing-starknet-contracts.md:124 -msgid "### Writing to Storage" -msgstr "### 写入存储" - -#: src/ch99-01-02-writing-starknet-contracts.md:126 -msgid "To write a value to the storage variable `names`, we call the `write` function on the `names` storage variable, passing in the key and values as arguments." -msgstr "为了给存储变量`names`写一个值,我们在`names`存储变量上调用`write`函数,将键和值作为参数传入。" - -#: src/ch99-01-02-writing-starknet-contracts.md:128 +#: src/ch09-02-recoverable-errors.md:66 msgid "" -"```rust\n" -"names::write(_address, _name);\n" -"```" -msgstr "" -"```rust\n" -"names::write(_address, _name);\n" -"```" - -#: src/ch99-01-02-writing-starknet-contracts.md:132 -msgid "Listing 9-4: Writing to the `names` variable" -msgstr "示例9-4:向 \"names \"变量写入内容" - -#: src/ch99-01-02-writing-starknet-contracts.md:136 -msgid "In this section, we are going to be looking at some popular function types you'd encounter with most contracts:" -msgstr "在这一节中,我们会看到一些大多数合同中会遇到的常用的函数类型:" - -#: src/ch99-01-02-writing-starknet-contracts.md:138 -msgid "### 1. Constructors" -msgstr "### 1.构造器(Constructors)" +"It takes two u128 integers, a and b, and returns a `Result` where the `Ok` variant holds the sum if the addition does not overflow, and the `Err` variant holds the " +"overflowed value if the addition does overflow." +msgstr "它接收两个u128整数,a和b,并返回一个`Result`,如果加法没有溢出,`Ok`成员存储加法的和,如果加法溢出,`Err’成员存储溢出的值。" -#: src/ch99-01-02-writing-starknet-contracts.md:140 -msgid "Constructors are a special type of function that runs only once when deploying a contract, and can be used to initialize the state of the contract." -msgstr "构造器是一种特殊的函数,在部署合约时只运行一次,可以用来初始化合约的状态。" +#: src/ch09-02-recoverable-errors.md:68 +msgid "Now, we can use this function elsewhere. For instance:" +msgstr "现在,我们可以在其他地方使用这个函数。比如说:" -#: src/ch99-01-02-writing-starknet-contracts.md:142 +#: src/ch09-02-recoverable-errors.md:70 msgid "" -"```rust\n" -"#[constructor]\n" -"fn constructor(_name: felt252, _address: ContractAddress){\n" -" names::write(_address, _name);\n" +"```rust,noplayground\n" +"fn u128_checked_add(a: u128, b: u128) -> Option {\n" +" match u128_overflowing_add(a, b) {\n" +" Result::Ok(r) => Option::Some(r),\n" +" Result::Err(r) => Option::None(()),\n" +" }\n" "}\n" "```" msgstr "" -"```rust\n" -"#[constructor]\n" -"fn constructor(_name: felt252, _address: ContractAddress){\n" -" names::write(_address, _name);\n" +"```rust,noplayground\n" +"fn u128_checked_add(a: u128, b: u128) -> Option {\n" +" match u128_overflowing_add(a, b) {\n" +" Result::Ok(r) => Option::Some(r),\n" +" Result::Err(r) => Option::None(()),\n" +" }\n" "}\n" "```" -#: src/ch99-01-02-writing-starknet-contracts.md:149 -msgid "Some important rules to note:" -msgstr "一些需要注意的重要规则:" - -#: src/ch99-01-02-writing-starknet-contracts.md:151 +#: src/ch09-02-recoverable-errors.md:79 msgid "" -"1. Your contract can't have more than one constructor.\n" -"2. Your constructor function must be named `constructor`.\n" -"3. Lastly, it must be annotated with the `#[constructor]` attribute." +"Here, it accepts two u128 integers, a and b, and returns an `Option`. It uses the `Result` returned by `u128_overflowing_add` to determine the success or failure of the " +"addition operation. The match expression checks the `Result` from `u128_overflowing_add`. If the result is `Ok(r)`, it returns `Option::Some(r)` containing the sum. If the result is " +"`Err(r)`, it returns `Option::None(())` to indicate that the operation has failed due to overflow. The function does not panic in case of an overflow." msgstr "" -"1.你的合约只能有一个构造函数。\n" -"\n" -"2.你的构造函数必须被命名为`constructor`。\n" -"\n" -"3.最后,它必须被标注为 `#[constructor]`属性。" - -#: src/ch99-01-02-writing-starknet-contracts.md:155 -msgid "### 2. External functions" -msgstr "### 2.外部函数" +"这里,它接受两个u128整数,a和b,并返回一个`Option`。它使用`u128_overflowing_add`返回的`Result`来确定加法操作的成功或失败。匹配表达式检查来自`u128_overflowing_add`的`Result` 。如" +"果结果是`Ok(r)`,则返回`Option::Some(r)`,其中包含和。如果结果是`Err(r)`,则返回`Option::None(())`,表示由于溢出导致操作失败。在溢出的情况下,该函数不会panic。" -#: src/ch99-01-02-writing-starknet-contracts.md:157 +#: src/ch09-02-recoverable-errors.md:81 msgid "" -"External functions are functions that can modify the state of a contract. They are public and can be called by any other contract or externally.\n" -"You can define external functions by annotating them with the `#[external]` attribute:" +"Let's take another example demonstrating the use of `unwrap`.\n" +"First we import the necessary modules:" msgstr "" -"外部函数是可以修改合同状态的函数。它们是公共的,可以被任何其他合约或外部调用。\n" -"你可以用 `#[external]`属性标注来定义外部函数:" +"让我们再举一个例子,演示一下`unwrap`的使用。\n" +"首先我们导入必要的模块:" -#: src/ch99-01-02-writing-starknet-contracts.md:160 +#: src/ch09-02-recoverable-errors.md:84 msgid "" -"```rust\n" -"#[external]\n" -"fn store_name(_name: felt252){\n" -" let caller = get_caller_address();\n" -" names::write(caller, _name);\n" -" StoredName(caller,_name);\n" -"}\n" +"```rust,noplayground\n" +"use core::traits::Into;\n" +"use traits::TryInto;\n" +"use option::OptionTrait;\n" +"use result::ResultTrait;\n" +"use result::ResultTraitImpl;\n" "```" msgstr "" -"```rust\n" -"#[external]\n" -"fn store_name(_name: felt252){\n" -" let caller = get_caller_address();\n" -" names::write(caller, _name);\n" -" StoredName(caller,_name);\n" -"}\n" +"```rust,noplayground\n" +"use core::traits::Into;\n" +"use traits::TryInto;\n" +"use option::OptionTrait;\n" +"use result::ResultTrait;\n" +"use result::ResultTraitImpl;\n" "```" -#: src/ch99-01-02-writing-starknet-contracts.md:169 -msgid "### 3. View functions" -msgstr "### 3.视图函数" - -#: src/ch99-01-02-writing-starknet-contracts.md:171 +#: src/ch09-02-recoverable-errors.md:92 msgid "" -"View functions are read-only functions allowing you to access data from the contract while ensuring that the state of the contract is not modified. They can be called by other " -"contracts or externally.\n" -"You can define view functions by annotating them with the `#[view]` attribute:" +"In this example, the `parse_u8` function takes a `felt252` integer and tries to convert it into a `u8` integer using the `try_into` method. If successful, it returns `Result::" +"Ok(value)`, otherwise it returns `Result::Err('Invalid integer')`." msgstr "" -"视图函数是只读函数,允许你从合同中访问数据,同时确保合同的状态不被修改。它们可以被其他合约或外部调用。\n" -"你可以通过用 `#[view]` 属性标注它们来定义视图函数:" +"在这个例子中,`parse_u8`函数接收一个`felt252`的整数,并尝试用`try_into`方法将其转换为`u8`的整数。如果成功,它返回`Result::Ok(value)`,否则它返回`Result::Err('Invalid integer')`。" -#: src/ch99-01-02-writing-starknet-contracts.md:174 +#: src/ch09-02-recoverable-errors.md:94 msgid "" -"```rust\n" -"#[view]\n" -"fn get_name(_address:ContractAddress) -> felt252{\n" -" let name = names::read(_address);\n" -" return name;\n" +"```rust,noplayground\n" +"fn parse_u8(s: felt252) -> Result {\n" +" match s.try_into() {\n" +" Option::Some(value) => Result::Ok(value),\n" +" Option::None(_) => Result::Err('Invalid integer'),\n" +" }\n" "}\n" "```" msgstr "" -"```rust\n" -"#[view]\n" -"fn get_name(_address:ContractAddress) -> felt252{\n" -" let name = names::read(_address);\n" -" return name;\n" -"}\n" +"```rust,noplayground\n" +"fn parse_u8(s: felt252) -> Result {\n" +" match s.try_into() {\n" +" Option::Some(value) => Result::Ok(value),\n" +" Option::None(_) => Result::Err('Invalid integer'),\n" +" }\n" +"}\n" "```" -#: src/ch99-01-02-writing-starknet-contracts.md:182 -msgid "" -"> **Note:** It's important to note that, both external and view functions are public. To create an internal function in a contract, you simply don't annotate it with any attribute." -msgstr "> **NB:** 需要注意的是,外部函数和视图函数都是公开的。要在合同中创建一个内部函数,你只需不给它标注任何属性即可。" +#: src/ch09-02-recoverable-errors.md:103 +msgid "Listing 9-1: Using the Result type" +msgstr "示例9-1:向 \"names \"变量写入内容" -#: src/ch99-01-02-writing-starknet-contracts.md:184 -msgid "## Events" -msgstr "## 事件" +#: src/ch09-02-recoverable-errors.md:105 +msgid "Our two test cases are:" +msgstr "我们的两个测试案例是:" -#: src/ch99-01-02-writing-starknet-contracts.md:186 +#: src/ch09-02-recoverable-errors.md:107 msgid "" -"Events are custom data structures that are emitted by smart contracts during execution.\n" -"They provide a way for smart contracts to communicate with the external world by logging information\n" -"about specific occurrences in a contract." +"```rust,noplayground\n" +"# fn parse_u8(s: felt252) -> Result {\n" +"# match s.try_into() {\n" +"# Option::Some(value) => Result::Ok(value),\n" +"# Option::None(_) => Result::Err('Invalid integer'),\n" +"# }\n" +"# }\n" +"# \n" +"#[cfg(test)]\n" +"mod tests {\n" +" use super::parse_u8;\n" +" #[test]\n" +" fn test_felt252_to_u8() {\n" +" let number: felt252 = 5_felt252;\n" +" // should not panic\n" +" let res = parse_u8(number).unwrap();\n" +" }\n" +"\n" +" #[test]\n" +" #[should_panic]\n" +" fn test_felt252_to_u8_panic() {\n" +" let number: felt252 = 256_felt252;\n" +" // should panic\n" +" let res = parse_u8(number).unwrap();\n" +" }\n" +"}\n" +"# \n" +"# \n" +"```" msgstr "" -"事件是定制的数据结构,由智能合约在执行期间发出。\n" -"它们为智能合约提供了一种与外部世界沟通的方式,即记录合约中所发生的特定事情的信息。" +"```rust,noplayground\n" +"# fn parse_u8(s: felt252) -> Result {\n" +"# match s.try_into() {\n" +"# Option::Some(value) => Result::Ok(value),\n" +"# Option::None(_) => Result::Err('Invalid integer'),\n" +"# }\n" +"# }\n" +"# \n" +"#[cfg(test)]\n" +"mod tests {\n" +" use super::parse_u8;\n" +" #[test]\n" +" fn test_felt252_to_u8() {\n" +" let number: felt252 = 5_felt252;\n" +" // should not panic\n" +" let res = parse_u8(number).unwrap();\n" +" }\n" +"\n" +" #[test]\n" +" #[should_panic]\n" +" fn test_felt252_to_u8_panic() {\n" +" let number: felt252 = 256_felt252;\n" +" // should panic\n" +" let res = parse_u8(number).unwrap();\n" +" }\n" +"}\n" +"# \n" +"# \n" +"```" -#: src/ch99-01-02-writing-starknet-contracts.md:190 +#: src/ch09-02-recoverable-errors.md:137 msgid "" -"Events play a crucial role in the creation of smart contracts. Take, for instance, the Non-Fungible Tokens (NFTs) minted on Starknet. All of these are indexed and stored in a " -"database, then displayed to users through the use of these events. Neglecting to include an event within your NFT contract could lead to a bad user experience. This is because users " -"may not see their NFTs appear in their wallets (wallets use these indexers to display a user's NFTs)." -msgstr "" -"事件在智能合约的创建中起着至关重要的作用。以Starknet上铸造的Non-Fungible Tokens(NFTs)为例。所有这些都被索引并存储在数据库中,然后通过使用这些事件显示给用户。忘记在你的NFT合约中编写" -"一个事件可能会导致糟糕的用户体验。这是因为用户可能看不到他们的NFT出现在他们的钱包里(钱包使用这些索引器来显示用户的NFT)。" +"The first one tests a valid conversion from `felt252` to `u8`, expecting the `unwrap` method not to panic. The second test function attempts to convert a value that is out of the " +"`u8` range, expecting the `unwrap` method to panic with the error message 'Invalid integer'." +msgstr "第一个测试函数是测试从`felt252`到`u8`的有效转换,期望`unwrap`方法不要panic。第二个测试函数试图转换一个超出`u8`范围的值,期望`unwrap`方法panic,错误信息是 ‘Invalid integer’。" -#: src/ch99-01-02-writing-starknet-contracts.md:192 -msgid "### Defining events" -msgstr "### 界定事件" +#: src/ch09-02-recoverable-errors.md:139 +msgid "> We could have also used the #[should_panic] attribute here." +msgstr "> 我们也可以在这里使用#[should_panic]属性。" + +#: src/ch09-02-recoverable-errors.md:141 +msgid "### The `?` operator ?" +msgstr "### `?`运算符?" + +#: src/ch09-02-recoverable-errors.md:143 +msgid "" +"The last operator we will talk about is the `?` operator. The `?` operator is used for more idiomatic and concise error handling. When you use the `?` operator on a `Result` or " +"`Option` type, it will do the following:" +msgstr "我们要谈的最后一个操作符是`?`操作符。`?`运算符用于更成文和简明的错误处理。当你在 `Result`或 `Option`类型上使用`?`运算符时,它将做以下事情:" -#: src/ch99-01-02-writing-starknet-contracts.md:194 +#: src/ch09-02-recoverable-errors.md:145 msgid "" -"An event is defined as an empty function annotated with the `#[event]` attribute. The parameters of this function\n" -"are the data that will be emitted by the event." +"- If the value is `Result::Ok(x)` or `Option::Some(x)`, it will return the inner value `x` directly.\n" +"- If the value is `Result::Err(e)` or `Option::None`, it will propagate the error or `None` by immediately returning from the function." msgstr "" -"一个事件被定义为一个用`#[event]`属性注释的空函数。这个函数的参数\n" -"的参数是将由该事件发出的数据。" +"- 如果值是`Result::Ok(x)`或`Option::Some(x)`,它将直接返回内部值`x`。\n" +"- 如果值是`Result::Err(e)`或`Option::None`,它将通过立即从函数返回来传播错误或`None`。" + +#: src/ch09-02-recoverable-errors.md:148 +msgid "The `?` operator is useful when you want to handle errors implicitly and let the calling function deal with them." +msgstr "当你想隐式处理错误并让调用函数处理它们时,`?`操作符很有用。" -#: src/ch99-01-02-writing-starknet-contracts.md:197 -msgid "In Listing 9-1, `StoredName` is an event that emits information when names are stored in the contract:" -msgstr "在示例9-1中,`StoredName`是一个当名字被存储在合约中时,会被触发并发出信息的事件:" +#: src/ch09-02-recoverable-errors.md:150 +msgid "Here is an example." +msgstr "下面是一个例子。" -#: src/ch99-01-02-writing-starknet-contracts.md:199 +#: src/ch09-02-recoverable-errors.md:152 msgid "" -"```rust\n" -"#[event]\n" -"fn StoredName(caller: ContractAddress, name:felt252){}\n" +"```rust,noplayground\n" +"fn do_something_with_parse_u8(input: felt252) -> Result {\n" +" let input_to_u8: u8 = parse_u8(input)?;\n" +" // DO SOMETHING\n" +" let res = input_to_u8 - 1;\n" +" Result::Ok(res)\n" +"}\n" "```" msgstr "" -"```rust\n" -"#[event]\n" -"fn StoredName(caller: ContractAddress, name:felt252){}\n" +"```rust,noplayground\n" +"fn do_something_with_parse_u8(input: felt252) -> Result {\n" +" let input_to_u8: u8 = parse_u8(input)?;\n" +" // DO SOMETHING\n" +" let res = input_to_u8 - 1;\n" +" Result::Ok(res)\n" +"}\n" "```" -#: src/ch99-01-02-writing-starknet-contracts.md:204 -msgid "" -"We pass in the emitted data types as parameters within the parentheses. In this example, our event will emit the contract address of the caller and the name stored within the " -"contract." -msgstr "我们在括号内传入作为把发射的数据类型参数传入。在这个例子中,我们的事件将发出调用者的合同地址和存储在合同中的名字的信息。" - -#: src/ch99-01-02-writing-starknet-contracts.md:206 -msgid "### Emitting events" -msgstr "### 发射事件" +#: src/ch09-02-recoverable-errors.md:161 +msgid "Listing 9-1: Using the `?` operator" +msgstr "示例9-1:向 \"names \"变量写入内容" -#: src/ch99-01-02-writing-starknet-contracts.md:208 +#: src/ch09-02-recoverable-errors.md:163 msgid "" -"After defining events, we can emit them by simply calling the event name like we'll call functions,\n" -"passing in the values to be emitted as parameters:" -msgstr "" -"定义完事件后,我们可以像调用函数一样简单地调用事件名称来发射它们、\n" -"作为参数传入要发射的值:" +"`do_something_with_parse_u8` function takes a `felt252` value as input and calls `parse_u8`. The `?` operator is used to propagate the error, if any, or unwrap the successful value." +msgstr "`do_something_with_parse_u8`函数接收一个`felt252`值作为输入并调用`parse_u8`。`?`操作符用来传播错误,如果有的话,或者unwrap成功的值。" + +#: src/ch09-02-recoverable-errors.md:165 +msgid "And with a little test case:" +msgstr "这里还有一个小的测试案例:" -#: src/ch99-01-02-writing-starknet-contracts.md:211 +#: src/ch09-02-recoverable-errors.md:167 msgid "" -"```rust\n" -"StoredName(caller,_name);\n" +"```rust,noplayground\n" +"# fn parse_u8(s: felt252) -> Result {\n" +"# match s.try_into() {\n" +"# Option::Some(value) => Result::Ok(value),\n" +"# Option::None(_) => Result::Err('Invalid integer'),\n" +"# }\n" +"# }\n" +"# \n" +"# fn do_something_with_parse_u8(input: felt252) -> Result {\n" +"# let input_to_u8: u8 = parse_u8(input)?;\n" +"# // DO SOMETHING\n" +"# let res = input_to_u8 - 1;\n" +"# Result::Ok(res)\n" +"# }\n" +"# \n" +"# #[cfg(test)]\n" +"# mod tests {\n" +"# use super::do_something_with_parse_u8;\n" +"# use debug::PrintTrait;\n" +" #[test]\n" +" fn test_function_2() {\n" +" let number: felt252 = 258_felt252;\n" +" match do_something_with_parse_u8(number) {\n" +" Result::Ok(value) => value.print(),\n" +" Result::Err(e) => e.print()\n" +" }\n" +" }\n" +"# }\n" +"# \n" "```" msgstr "" -"```rust\n" -"StoredName(caller,_name);\n" +"```rust,noplayground\n" +"# fn parse_u8(s: felt252) -> Result {\n" +"# match s.try_into() {\n" +"# Option::Some(value) => Result::Ok(value),\n" +"# Option::None(_) => Result::Err('Invalid integer'),\n" +"# }\n" +"# }\n" +"# \n" +"# fn do_something_with_parse_u8(input: felt252) -> Result {\n" +"# let input_to_u8: u8 = parse_u8(input)?;\n" +"# // DO SOMETHING\n" +"# let res = input_to_u8 - 1;\n" +"# Result::Ok(res)\n" +"# }\n" +"# \n" +"# #[cfg(test)]\n" +"# mod tests {\n" +"# use super::do_something_with_parse_u8;\n" +"# use debug::PrintTrait;\n" +" #[test]\n" +" fn test_function_2() {\n" +" let number: felt252 = 258_felt252;\n" +" match do_something_with_parse_u8(number) {\n" +" Result::Ok(value) => value.print(),\n" +" Result::Err(e) => e.print()\n" +" }\n" +" }\n" +"# }\n" +"# \n" "```" -#: src/ch99-02-00-abis-and-cross-contract-interactions.md:1 -msgid "# Starknet contracts: ABIs and cross-contract interactions" -msgstr "# Starknet合约:ABI和跨合约交互" +#: src/ch09-02-recoverable-errors.md:198 +msgid "The console will print the error \"Invalid Integer\"." +msgstr "控制台将打印错误 “Invalid Integer”。" -#: src/ch99-02-00-abis-and-cross-contract-interactions.md:3 -msgid "The ability of contracts to interact with other smart contracts on the blockchain is a common pattern found in smart contract development." -msgstr "合约与区块链上其他智能合约的互动能力是智能合约开发中的一个常见模式。" +#: src/ch09-02-recoverable-errors.md:200 +msgid "
" +msgstr "
" -#: src/ch99-02-00-abis-and-cross-contract-interactions.md:5 +#: src/ch09-02-recoverable-errors.md:202 +msgid "### Summary" +msgstr "### 总结" + +#: src/ch09-02-recoverable-errors.md:204 msgid "" -"This chapter covers how cross-contract interactions between Starknet contracts can be achieved. Specifically, you'll learn about ABIs, contract interfaces, the contract and library " -"dispatchers and their low-level system call equivalents!" -msgstr "这一章涵盖了如何实现Starknet合约之间的跨合约交互。具体来说,你会了解到ABI、合约接口、合约和库调度器以及它们的底层系统调用存在形式!" +"We saw that recoverable errors can be handled in Cairo using the Result enum, which has two variants: `Ok` and `Err`. The `Result` enum is generic, with types `T` and `E` " +"representing the successful and error values, respectively. The `ResultTrait` provides methods for working with `Result`, such as unwrapping values, checking if the result is " +"`Ok` or `Err`, and panicking with custom messages." +msgstr "" +"我们看到,可恢复的错误可以在Cairo中使用结果枚举来处理,它有两个变体:`Ok`和`Err`。`Result`枚举是通用的,其类型`T`和`E`分别代表成功和错误值。`ResultTrait`提供了处理`Result`" +"的方法,例如解包值,检查结果是`Ok`还是`Err`,以及用自定义消息进行panic。" -#: src/ch99-02-01-abis-and-interfaces.md:1 -msgid "# ABIs and Contract Interfaces" -msgstr "# ABI和合约接口" +#: src/ch09-02-recoverable-errors.md:206 +msgid "" +"To handle recoverable errors, a function can return a `Result` type and use pattern matching to handle the success or failure of an operation. The `?` operator can be used to " +"implicitly handle errors by propagating the error or unwrapping the successful value. This allows for more concise and clear error handling, where the caller is responsible for " +"managing errors raised by the called function." +msgstr "" +"为了处理可恢复的错误,一个函数可以返回一个`Result`类型,并使用模式匹配来处理操作的成功或失败。`?`操作符可用于通过传播错误或解包成功的值来隐含地处理错误。这使得错误处理更加简洁明了,调" +"用者负责管理由被调用函数引发的错误。" -#: src/ch99-02-01-abis-and-interfaces.md:3 -msgid "Cross-contract interactions between smart contracts on a blockchain is a common practice which enables us to build flexible contracts that can speak with each other." -msgstr "区块链上的智能合约之间的跨合约互动是一种常见的做法,它使我们能够建立灵活的合约,相互对话。" +#: src/ch10-00-advanced-features.md:1 +msgid "# Advanced Features" +msgstr "# 高级特性" -#: src/ch99-02-01-abis-and-interfaces.md:5 -msgid "Achieving this on Starknet requires something we call an interface." -msgstr "在Starknet上实现这一点需要我们称之为接口的东西。" +#: src/ch10-00-advanced-features.md:3 +msgid "Now, let's learn about more advanced features offered by Cairo." +msgstr "现在,让我们来了解 Cairo 提供的更多高级功能。" -#: src/ch99-02-01-abis-and-interfaces.md:7 -msgid "## Interface" -msgstr "## 接口" +#: src/ch10-01-operator-overloading.md:1 +msgid "# Operator Overloading" +msgstr "# 操作符重载" -#: src/ch99-02-01-abis-and-interfaces.md:9 +#: src/ch10-01-operator-overloading.md:3 msgid "" -"An interface is a list of a contract's function definitions without implementations. In other words, an interface specifies the function declarations (name, parameters, visibility " -"and return value) contained in a smart contract without including the function body." -msgstr "一个接口是一个合约的函数定义的列表,没有实现。换句话说,一个接口指定了智能合约中包含的函数声明(名称、参数、可见性和返回值),而不包括函数主体。" - -#: src/ch99-02-01-abis-and-interfaces.md:11 -msgid "Interfaces in Cairo are traits with the `#[abi]` attribute. If you are new to traits, check out the dedicated chapter on [traits](./ch07-02-traits-in-cairo.md)." -msgstr "Cairo中的接口是带有`#[abi]`属性的traits。如果你是traits的新手,请查看关于[traits](./ch07-02-traits-in-cairo.md)的专门章节。" - -#: src/ch99-02-01-abis-and-interfaces.md:13 -msgid "For your Cairo code to qualify as an interface, it must meet the following requirements:" -msgstr "要使你的Cairo代码有资格成为一个接口,它必须满足以下要求:" +"Operator overloading is a feature in some programming languages that allows the redefinition of standard operators, such as addition (+), subtraction (-), multiplication (\\*), and " +"division (/), to work with user-defined types. This can make the syntax of the code more intuitive, by enabling operations on user-defined types to be expressed in the same way as " +"operations on primitive types." +msgstr "" +"操作符重载是一些编程语言的一个特点,它允许在用户自定义的类型上重新定义标准操作符,如加法(+)、减法(-)、乘法(\\*)和除法(/)。这可以使代码的语法更加直观,因为它使对用户字定义类型" +"的操作与对原始类型的操作表达方式相同。" -#: src/ch99-02-01-abis-and-interfaces.md:15 +#: src/ch10-01-operator-overloading.md:5 msgid "" -"1. Must be appended with the `#[abi]` attribute.\n" -"2. Your interface functions should have no implementations.\n" -"3. You must explicitly declare the function's decorator.\n" -"4. Your interface should not declare a constructor.\n" -"5. Your interface should not declare state variables." +"In Cairo, operator overloading is achieved through the implementation of specific traits. Each operator has an associated trait, and overloading that operator involves providing an " +"implementation of that trait for a custom type.\n" +"However, it's essential to use operator overloading judiciously. Misuse can lead to confusion, making the code more difficult to maintain, for example when there is no semantic " +"meaning to the operator being overloaded." msgstr "" -"1. 必须附加 `#[abi]` 属性。\n" -"2. 你的接口函数不应该有任何实现。\n" -"3. 你必须明确地声明该函数的装饰器。\n" -"4. 你的接口不应该声明一个构造函数。\n" -"5. 你的接口不应该声明状态变量。" +"在Cairo中,操作符重载是通过实现特定的trait来实现的。每个操作符都有一个相关的traits,操作符重载涉及到需为一个自定义类型提供该trait的实现。\n" +"然而,明智地使用操作符重载是非常重要的。误用会导致混乱,使代码更难维护,比如当被重载的操作符的语义与操作符原有的语义毫不相干的时候。" -#: src/ch99-02-01-abis-and-interfaces.md:21 -msgid "Here's a sample interface for an ERC20 token contract:" -msgstr "下面是一个ERC20代币合约的接口样本:" +#: src/ch10-01-operator-overloading.md:8 +msgid "Consider an example where two `Potions` need to be combined. `Potions` have two data fields, mana and health. Combining two `Potions` should add their respective fields." +msgstr "让我看一个例子,两个 `Potions` 需要合并。`Potions` 有两个数据字段,法力(mana)和健康(health)。合并两个`Potions` 应该是让它们各自的两个字段相加。" -#: src/ch99-02-01-abis-and-interfaces.md:23 +#: src/ch10-01-operator-overloading.md:10 msgid "" "```rust\n" -"use starknet::ContractAddress;\n" -"\n" -"#[abi]\n" -"trait IERC20 {\n" -" #[view]\n" -" fn name() -> felt252;\n" -"\n" -" #[view]\n" -" fn symbol() -> felt252;\n" -"\n" -" #[view]\n" -" fn decimals() -> u8;\n" -"\n" -" #[view]\n" -" fn total_supply() -> u256;\n" -"\n" -" #[view]\n" -" fn balance_of(account: ContractAddress) -> u256;\n" -"\n" -" #[view]\n" -" fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256;\n" -"\n" -" #[external]\n" -" fn transfer(recipient: ContractAddress, amount: u256) -> bool;\n" +"struct Potion {\n" +" health: felt252,\n" +" mana: felt252\n" +"}\n" "\n" -" #[external]\n" -" fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool;\n" +"impl PotionAdd of Add {\n" +" fn add(lhs: Potion, rhs: Potion) -> Potion {\n" +" Potion { health: lhs.health + rhs.health, mana: lhs.mana + rhs.mana, }\n" +" }\n" +"}\n" "\n" -" #[external]\n" -" fn approve(spender: ContractAddress, amount: u256) -> bool;\n" +"fn main() {\n" +" let health_potion: Potion = Potion { health: 100, mana: 0 };\n" +" let mana_potion: Potion = Potion { health: 0, mana: 100 };\n" +" let super_potion: Potion = health_potion + mana_potion;\n" +" // Both potions were combined with the `+` operator.\n" +" assert(super_potion.health == 100, '');\n" +" assert(super_potion.mana == 100, '');\n" "}\n" "```" msgstr "" "```rust\n" -"use starknet::ContractAddress;\n" -"\n" -"#[abi]\n" -"trait IERC20 {\n" -" #[view]\n" -" fn name() -> felt252;\n" -"\n" -" #[view]\n" -" fn symbol() -> felt252;\n" -"\n" -" #[view]\n" -" fn decimals() -> u8;\n" -"\n" -" #[view]\n" -" fn total_supply() -> u256;\n" -"\n" -" #[view]\n" -" fn balance_of(account: ContractAddress) -> u256;\n" -"\n" -" #[view]\n" -" fn allowance(owner: ContractAddress, spender: ContractAddress) -> u256;\n" -"\n" -" #[external]\n" -" fn transfer(recipient: ContractAddress, amount: u256) -> bool;\n" +"struct Potion {\n" +" health: felt252,\n" +" mana: felt252\n" +"}\n" "\n" -" #[external]\n" -" fn transfer_from(sender: ContractAddress, recipient: ContractAddress, amount: u256) -> bool;\n" +"impl PotionAdd of Add {\n" +" fn add(lhs: Potion, rhs: Potion) -> Potion {\n" +" Potion { health: lhs.health + rhs.health, mana: lhs.mana + rhs.mana, }\n" +" }\n" +"}\n" "\n" -" #[external]\n" -" fn approve(spender: ContractAddress, amount: u256) -> bool;\n" +"fn main() {\n" +" let health_potion: Potion = Potion { health: 100, mana: 0 };\n" +" let mana_potion: Potion = Potion { health: 0, mana: 100 };\n" +" let super_potion: Potion = health_potion + mana_potion;\n" +" // Both potions were combined with the `+` operator.\n" +" assert(super_potion.health == 100, '');\n" +" assert(super_potion.mana == 100, '');\n" "}\n" "```" -#: src/ch99-02-01-abis-and-interfaces.md:57 -msgid "Listing 99-1: A simple ERC20 Interface" -msgstr "示例99-1:一个简单的ERC20接口" - -#: src/ch99-02-01-abis-and-interfaces.md:59 -msgid "## ABIs" -msgstr "## ABI" - -#: src/ch99-02-01-abis-and-interfaces.md:61 -msgid "" -"ABI stands for Application Binary Interface. ABIs gives a smart contract the ability to communicate and interact with external applications or other smart contracts. ABIs can be " -"likened to APIs in traditional web development, which helps data flow between applications and servers." -msgstr "ABI是指应用二进制接口。ABI使智能合约有能力与外部应用程序或其他智能合约进行沟通和互动。ABI可以比喻为传统网络开发中的API,它帮助数据在应用程序和服务器之间流动。" - -#: src/ch99-02-01-abis-and-interfaces.md:63 +#: src/ch10-01-operator-overloading.md:32 msgid "" -"While we write our smart contract logics in high-level Cairo, they are stored on the VM as executable bytecodes which are in binary formats. Since this bytecode is not human " -"readable, it requires interpretation to be understood. This is where ABIs come into play, defining specific methods which can be called to a smart contract for execution." +"In the code above, we're implementing the `Add` trait for the `Potion` type. The add function takes two arguments: `lhs` and `rhs` (left and right-hand side). The function body " +"returns a new `Potion` instance, its field values being a combination of `lhs` and `rhs`." msgstr "" -"虽然我们用高级语言Cairo编写智能合约逻辑,但它们被存储在虚拟机上的可执行字节码是二进制格式的。由于这种字节码不是人类可读的,它需要解释才能理解。这就是ABI发挥作用的地方,它定义了可以调" -"用智能合约执行的特定方法。" +"在上面的代码中,我们为 `Potion`类型实现`Add`特性。Add函数需要两个参数:`lhs` 和 `rhs`(左手端和右手端,分别表示在运算式的左边还是右边)。函数主体返回一个新的`Potion`实例,其字段值是" +"`lhs`和`rhs`的组合。" -#: src/ch99-02-01-abis-and-interfaces.md:65 -msgid "Every contract on Starknet has an Application Binary Interface (ABI) that defines how to encode and decode data when calling its methods." -msgstr "Starknet上的每个合约都有一个应用二进制接口(ABI),它定义了在调用其方法时如何对数据进行编码和解码。" +#: src/ch10-01-operator-overloading.md:34 +msgid "" +"As illustrated in the example, overloading an operator requires specification of the concrete type being overloaded. The overloaded generic trait is `Add`, and we define a " +"concrete implementation for the type `Potion` with `Add`." +msgstr "正如例子中所说明的,重载一个操作符需要指定被重载的具体类型。这里被重载用泛型表示的trait是 `Add`,所以我们将用 `Add`为 ‘Potion`类型定义一个具体的实现。" -#: src/ch99-02-01-abis-and-interfaces.md:67 -msgid "In the next chapter, we are going to be looking into how we can call other smart contracts using a `Contract Dispatcher`, `Library Dispatcher`, and `System calls`." -msgstr "在下一章,我们将研究如何使用 \"合约调度器\"、\"库调度器 \"和 \"系统调用 \"来调用其他智能合约。" +#: src/ch10-02-macros.md:1 +msgid "# Macros" +msgstr "# 宏" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:1 -msgid "# Contract Dispatcher, Library Dispatcher and System calls" -msgstr "# 合约调度器、库调度器和系统调用" +#: src/ch10-02-macros.md:3 +msgid "" +"The Cairo language has some plugins that allows developers to simplify their code. They are called `inline_macros` and are a way of writing code that generates other code. In Cairo, " +"there are only two `macros`: `array![]` and `consteval_int!()`." +msgstr "" +"Cairo语言有一些插件可以让开发人员简化代码。它们被称为 `内联宏`(inline_macros),是一种可以生成其他代码的代码编写方式。在Cairo语言中,只有两个 `宏`:\"array![]\"和 \"consteval_int!" +"()\"。" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:3 -msgid "Each time a contract interface is created on Starknet, two dispatchers are automatically created and exported:" -msgstr "每次在Starknet上创建一个合同接口时,都会自动创建并输出两个调度器:" +#: src/ch10-02-macros.md:5 +msgid "### Let's start by `array!`" +msgstr "### 让我们从 `array!` 宏开始" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:5 +#: src/ch10-02-macros.md:7 msgid "" -"1. The Contract Dispatcher\n" -"2. The Library Dispatcher" +"Sometimes, we need to create arrays with values that are already known at compile time. The basic way of doing that is redundant. You would first declare the array and then append " +"each value one by one. `array!` is a simpler way of doing this task by combining the two steps.\n" +"At compile-time, the compiler will create an array and append all values passed to the `array!` macro sequentially." msgstr "" -"1. 合约调度器\n" -"2. 库调度器" +"有时候,我们需要用在编译时已经知道的值来创建数组。这件事的基本做法是很不优雅且多余的。你需要首先声明数组,然后逐一为数组追加每个值。`array!` 是一种更简单的方法,它将这两个步骤合并在一" +"起。\n" +"在编译时,编译器将创建一个数组,并按顺序追加传递给 `array!` 宏的所有值。" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:8 -msgid "In this chapter, we are going to extensively discuss how these dispatchers work and their usage." -msgstr "在本章中,我们将进一步的讨论这些调度器的工作方式和使用方法。" - -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:10 -msgid "To effectively break down the concepts in this chapter, we are going to be using the IERC20 interface from the previous chapter (refer to Listing 99-1):" -msgstr "为了有效地拆解本章的概念,我们将使用前一章的IERC20接口(参考示例9-1):" +#: src/ch10-02-macros.md:10 +msgid "Without `array!`:" +msgstr "不使用 `array!`:" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:12 -msgid "## Contract Dispatcher" -msgstr "## 合约调度器" - -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:14 +#: src/ch10-02-macros.md:12 msgid "" -"Traits annotated with the `#[abi]` attribute are programmed to automatically generate and export the relevant dispatcher logic on compilation. The compiler also generates a new " -"trait, two new structs (one for contract calls, and the other for library calls) and their implementation of this trait. Our interface is expanded into something like this:" +"```rust\n" +" let mut arr = ArrayTrait::new();\n" +" arr.append(1);\n" +" arr.append(2);\n" +" arr.append(3);\n" +" arr.append(4);\n" +" arr.append(5);\n" +"```" msgstr "" -"用`#[abi]`属性注释的trait会在编译时自动生成并导出相关的调度器。编译器也会生成一个新的trait、两个新的结构体(一个用于合约调用,另一个用于库调用)以及它们对这个trait的实现。我们的接口被" -"扩展为如下:" +"```rust\n" +" let mut arr = ArrayTrait::new();\n" +" arr.append(1);\n" +" arr.append(2);\n" +" arr.append(3);\n" +" arr.append(4);\n" +" arr.append(5);\n" +"```" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:16 -msgid "" -"**Note:** The expanded code for our IERC20 interface is a lot longer, but to keep this chapter concise and straight to the point, we focused on one view function `get_name`, and one " -"external function `transfer`." -msgstr "**NB:** 真实的IERC20接口的扩展代码要全面得多,但为了保持本章的简洁和直奔主题,我们把重点放在一个视图函数`get_name`和一个外部函数`transfer`上。" +#: src/ch10-02-macros.md:21 +msgid "With `array!`:" +msgstr "使用 `array!`:" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:18 +#: src/ch10-02-macros.md:23 msgid "" "```rust\n" -"trait IERC20DispatcherTrait {\n" -" fn get_name(self: T) -> felt252;\n" -" fn transfer(self: T, recipient: ContractAddress, amount: u256);\n" -"}\n" -"\n" -"#[derive(Copy, Drop)]\n" -"struct IERC20Dispatcher {\n" -" contract_address: starknet::ContractAddress,\n" -"}\n" -"\n" -"impl IERC20DispatcherImpl of IERC20DispatcherTrait:: {\n" -" fn get_name(self: IERC20Dispatcher) -> felt252 {\n" -" // starknet::call_contract_syscall is called in here\n" -" }\n" -" fn transfer(self: IERC20Dispatcher, recipient: ContractAddress, amount: u256) {\n" -" // starknet::call_contract_syscall is called in here\n" -" }\n" -"}\n" +" let arr = array![1, 2, 3, 4, 5];\n" "```" msgstr "" "```rust\n" -"trait IERC20DispatcherTrait {\n" -" fn get_name(self: T) -> felt252;\n" -" fn transfer(self: T, recipient: ContractAddress, amount: u256);\n" -"}\n" -"\n" -"#[derive(Copy, Drop)]\n" -"struct IERC20Dispatcher {\n" -" contract_address: starknet::ContractAddress,\n" -"}\n" -"\n" -"impl IERC20DispatcherImpl of IERC20DispatcherTrait:: {\n" -" fn get_name(self: IERC20Dispatcher) -> felt252 {\n" -" // starknet::call_contract_syscall is called in here\n" -" }\n" -" fn transfer(self: IERC20Dispatcher, recipient: ContractAddress, amount: u256) {\n" -" // starknet::call_contract_syscall is called in here\n" -" }\n" -"}\n" +" let arr = array![1, 2, 3, 4, 5];\n" "```" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:39 -msgid "Listing 99-2: An expanded form of the IERC20 trait" -msgstr "示例99-2:IERC20 trait的扩展" - -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:41 -msgid "It's also worthy of note that all these are abstracted behind the scenes thanks to the power of Cairo plugins." -msgstr "而且值得注意的是,所有这些都被Cairo插件在幕后抽象化了。" - -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:43 -msgid "### Calling Contracts using the Contract Dispatcher" -msgstr "### 使用合约调度器调用合约" +#: src/ch10-02-macros.md:27 +msgid "### `consteval_int!`" +msgstr "### `consteval_int!`" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:45 +#: src/ch10-02-macros.md:29 msgid "" -"This is an example of a contract named `Dispatcher` using the Contract interface dispatcher to call an ERC-20 contract in the ERC-20 contract's context and, in the case of " -"`transfer_token`, altering the state of the ERC-20 contract:" -msgstr "这是一个名为`Dispatcher`的合同的例子,使用合约接口调度器在ERC-20合约的上下文中调用ERC-20合约,并在`transfer_token`的中,改变了ERC-20合同的状态:" +"In some situtations, a developer might need to declare a constant that is the result of a computation of integers. To compute a constant expression and use its result at compile " +"time, it is required to use the `consteval_int!` macro." +msgstr "在某些情况下,开发人员可能需要声明一个作为整数计算结果的常量。要计算常量表达式并在编译时使用其结果,需要使用 `consteval_int!` 宏。" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:47 +#: src/ch10-02-macros.md:31 +msgid "Here is an example of `consteval_int!`:" +msgstr "下面是 `consteval_int!`的示例:" + +#: src/ch10-02-macros.md:33 msgid "" "```rust\n" -"//**** Specify interface here ****//\n" -"\n" -"#[contract]\n" -"mod Dispatcher {\n" -" use super::IERC20DispatcherTrait;\n" -" use super::IERC20Dispatcher;\n" -" use starknet::ContractAddress;\n" -"\n" -" #[view]\n" -" fn token_name(\n" -" _contract_address: ContractAddress\n" -" ) -> felt252 {\n" -" IERC20Dispatcher {contract_address: _contract_address }.name()\n" -" }\n" -"\n" -" #[external]\n" -" fn transfer_token(\n" -" _contract_address: ContractAddress, recipient: ContractAddress, amount: u256\n" -" ) -> bool {\n" -" IERC20Dispatcher {contract_address: _contract_address }.transfer(recipient, amount)\n" -" }\n" -"}\n" +"const a: felt252 = consteval_int!(2 * 2 * 2);\n" "```" msgstr "" "```rust\n" -"//**** Specify interface here ****//\n" -"\n" -"#[contract]\n" -"mod Dispatcher {\n" -" use super::IERC20DispatcherTrait;\n" -" use super::IERC20Dispatcher;\n" -" use starknet::ContractAddress;\n" -"\n" -" #[view]\n" -" fn token_name(\n" -" _contract_address: ContractAddress\n" -" ) -> felt252 {\n" -" IERC20Dispatcher {contract_address: _contract_address }.name()\n" -" }\n" -"\n" -" #[external]\n" -" fn transfer_token(\n" -" _contract_address: ContractAddress, recipient: ContractAddress, amount: u256\n" -" ) -> bool {\n" -" IERC20Dispatcher {contract_address: _contract_address }.transfer(recipient, amount)\n" -" }\n" -"}\n" +"const a: felt252 = consteval_int!(2 * 2 * 2);\n" "```" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:72 -msgid "Listing 99-3: A sample contract which uses the Contract Dispatcher" -msgstr "示例99-3:一个使用合约调度器的样本合约" +#: src/ch10-02-macros.md:37 +msgid "This will be interprated as `const a: felt252 = 8;` by the compiler." +msgstr "编译器会将其解释为 `const a: felt252 = 8;`。" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:74 -msgid "" -"As you can see, we had to first import the `IERC20DispatcherTrait` and `IERC20Dispatcher` which was generated and exported on compiling our interface, then we make calls to the " -"methods implemented for the `IERC20Dispatcher` struct (`name`, `transfer`, etc), passing in the `contract_address` parameter which represents the address of the contract we want to " -"call." -msgstr "" -"正如你所看到的,我们必须首先导入`IERC20DispatcherTrait`和`IERC20Dispatcher`,这是在编译我们的接口时生成和导出的,然后我们调用为`IERC20Dispatcher`结构实现的方法(`name`、`transfer`" -"等),传入`contract_address`参数,表示我们要调用的合同地址。" +#: src/ch99-00-starknet-smart-contracts.md:1 +msgid "# Starknet Smart Contracts" +msgstr "# Starknet智能合约" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:76 -msgid "## Library Dispatcher" -msgstr "## 库调度器" +#: src/ch99-00-starknet-smart-contracts.md:3 +msgid "All through the previous sections, you've mostly written programs with a `main` entrypoint. In the coming sections, you will learn to write and deploy Starknet contracts." +msgstr "在前面的章节中,你主要是用`main`入口来编写程序。在接下来的章节中,你将学习如何编写和部署Starknet合约。" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:78 +#: src/ch99-00-starknet-smart-contracts.md:5 msgid "" -"The key difference between the contract dispatcher and the library dispatcher is that while the contract dispatcher calls an external contract's logic in the external contract's " -"context, the library dispatcher calls the target contract's classhash, whilst executing the call in the calling contract's context.\n" -"So unlike the contract dispatcher, calls made using the library dispatcher have no possibility of tampering with the target contract's state." +"One of the applications of the Cairo language is to write smart contracts for the Starknet network. Starknet is a permissionless network that leverages zk-STARKs technology for " +"scalability. As a Layer-2 scalability solution for Ethereum, Starknet's goal is to offer fast, secure, and low-cost transactions. It functions as a Validity Rollup (commonly known as " +"a zero-knowledge Rollup) and is built on top of the Cairo language and the StarkNet VM." msgstr "" -"合约调度器和库调度器的关键区别在于,合约调度器是在外部合约的上下文中调用外部合约的逻辑,而库调度器则是在调用合约的上下文中执行调用,调用目标契约的classhash。\n" -"因此,与合约调度器不同,使用库调度器进行的调用不可能篡改目标合约的状态。" +"Cairo语言的应用之一是为Starknet编写智能合约。Starknet 是一个无权限网络,利用 zk-STARKs 技术实现可扩展性。作为以太坊的第二层可扩展性解决方案,Starknet 的目标是提供快速、安全和低成本的" +"交易。它起着有效性卷积(通常称为零知识卷积)的作用,建立在Cairo语言和 StarkNet 虚拟机之上。" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:81 +#: src/ch99-00-starknet-smart-contracts.md:7 msgid "" -"As stated in the previous chapter, contracts annotated with the `#[abi]` macro on compilation generates a new trait, two new structs (one for contract calls, and the other for " -"library calls) and their implementation of this trait. The expanded form of the library traits looks like:" -msgstr "如前一章所述,在编译时用`#[abi]`宏标注的合约会生成一个新的trait、两个新的结构体(一个用于契约调用,另一个用于库调用)以及它们对该trait的实现。库特征的扩展形式看起来像:" +"Starknet contracts, in simple words, are programs that can run on the Starknet VM. Since they run on the VM, they have access to Starknet’s persistent state, can alter or modify " +"variables in Starknet’s states, communicate with other contracts, and interact seamlessly with the underlying L1." +msgstr "" +"简单来说,Starknet合约就是可以在Starknet虚拟机上运行的程序。由于它们在虚拟机上运行,它们可以访问Starknet的持久性状态,可以改变或修改Starknet状态中的变量,与其他合约沟通,并与底层的L1" +"无缝交互。" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:83 +#: src/ch99-00-starknet-smart-contracts.md:9 msgid "" -"```rust\n" -"trait IERC20DispatcherTrait {\n" -" fn get_name(self: T) -> felt252;\n" -" fn transfer(self: T, recipient: ContractAddress, amount: u256);\n" -"}\n" -"\n" -"#[derive(Copy, Drop)]\n" -"struct IERC20LibraryDispatcher {\n" -" class_hash: starknet::ClassHash,\n" -"}\n" -"\n" -"impl IERC20LibraryDispatcherImpl of IERC20DispatcherTrait:: {\n" -" fn get_name(self: IERC20LibraryDispatcher) -> felt252 {\n" -" // starknet::syscalls::library_call_syscall is called in here\n" -" }\n" -" fn transfer(self: IERC20LibraryDispatcher, recipient: ContractAddress, amount: u256) {\n" -" // starknet::syscalls::library_call_syscall is called in here\n" -" }\n" -"}\n" -"```" +"Starknet contracts are denoted by the `#[contract]` attribute. We'll dive deeper into this in the next sections.\n" +"If you want to learn more about the Starknet network itself, its architecture and the tooling available, you should read the [Starknet Book](https://book.starknet.io/). This section " +"will focus on writing smart contracts in Cairo." msgstr "" -"```rust\n" -"trait IERC20DispatcherTrait {\n" -" fn get_name(self: T) -> felt252;\n" -" fn transfer(self: T, recipient: ContractAddress, amount: u256);\n" -"}\n" -"\n" -"#[derive(Copy, Drop)]\n" -"struct IERC20LibraryDispatcher {\n" -" class_hash: starknet::ClassHash,\n" -"}\n" -"\n" -"impl IERC20LibraryDispatcherImpl of IERC20DispatcherTrait:: {\n" -" fn get_name(self: IERC20LibraryDispatcher) -> felt252 {\n" -" // starknet::syscalls::library_call_syscall is called in here\n" -" }\n" -" fn transfer(self: IERC20LibraryDispatcher, recipient: ContractAddress, amount: u256) {\n" -" // starknet::syscalls::library_call_syscall is called in here\n" -" }\n" -"}\n" -"```" +"Starknet合约由`#[contract]`属性标记。我们将在接下来的部分对此进行深入探讨。如果你想了解更多关于Starknet网络本身,其架构以及可用的工具,你应该阅读[Starknet Book](https://book.starknet." +"io/)。本节将只专注于如何使用Cairo编写智能合约。" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:104 -msgid "Listing 99-4: An expanded form of the IERC20 trait" -msgstr "示例99-4:IERC20trait的扩展形式" +#: src/ch99-00-starknet-smart-contracts.md:12 +msgid "#### Scarb" +msgstr "#### Scarb" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:106 -msgid "### Calling Contracts using the Library Dispatcher" -msgstr "### 使用库调度器调用合约" +#: src/ch99-00-starknet-smart-contracts.md:14 +msgid "" +"You can set up a Starknet development environment using Scarb as stated in the [Hello, Scarb! - Starknet Support](ch01-03-hello-scarb.md#starknet-support) section. Each example in " +"this chapter can be used with Scarb." +msgstr "您可以按照[你好,Scarb!--Starknet 支持](ch01-03-hello-scarb.md#starknet-support)一节中的说明,使用 Scarb 建立 Starknet 开发环境。本章中的每个示例都可以使用 Scarb。" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:108 -msgid "Below's a sample code on calling contracts using the Library Dispatcher:" -msgstr "下面是一个关于使用库调度器调用合约的示例代码:" +#: src/ch99-01-01-introduction-to-smart-contracts.md:1 +msgid "# Introduction to smart-contracts" +msgstr "# 智能合约简介" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:110 +#: src/ch99-01-01-introduction-to-smart-contracts.md:3 msgid "" -"```rust\n" -"//**** Specify interface here ****//\n" -"\n" -"use super::IERC20DispatcherTrait;\n" -"use super::IERC20LibraryDispatcher;\n" -"use starknet::ContractAddress;\n" -"\n" -"#[view]\n" -"fn token_name() -> felt252 {\n" -" IERC20LibraryDispatcher { class_hash: starknet::class_hash_const::<0x1234>() }.name()\n" -"}\n" -"\n" -"#[external]\n" -"fn transfer_token(\n" -" recipient: ContractAddress, amount: u256\n" -") -> bool {\n" -" IERC20LibraryDispatcher { class_hash: starknet::class_hash_const::<0x1234>() }.transfer(recipient, amount)\n" -"}\n" -"```" +"This chapter will give you a high level introduction to what smart-contracts are, what are they used for and why would blockchain developers use Cairo and Starknet.\n" +"If you are already familiar with blockchain programming, feel free to skip this chapter. The last part might still be interesting though." msgstr "" -"```rust\n" -"//**** Specify interface here ****//\n" -"\n" -"use super::IERC20DispatcherTrait;\n" -"use super::IERC20LibraryDispatcher;\n" -"use starknet::ContractAddress;\n" -"\n" -"#[view]\n" -"fn token_name() -> felt252 {\n" -" IERC20LibraryDispatcher { class_hash: starknet::class_hash_const::<0x1234>() }.name()\n" -"}\n" -"\n" -"#[external]\n" -"fn transfer_token(\n" -" recipient: ContractAddress, amount: u256\n" -") -> bool {\n" -" IERC20LibraryDispatcher { class_hash: starknet::class_hash_const::<0x1234>() }.transfer(recipient, amount)\n" -"}\n" -"```" +"本章是一个关于什么是智能合约,它们有什么用途,以及为什么区块链开发者会使用Cairo和Starknet的高度简介。\n" +"如果你已经熟悉了区块链编程,可以跳过这一章。不过最后一部分应该还是有点意思的。" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:130 -msgid "Listing 99-4: A sample contract using the Library Dispatcher" -msgstr "示例99-4:一个使用库调度器的样本合约" +#: src/ch99-01-01-introduction-to-smart-contracts.md:6 +msgid "## Smart-contracts" +msgstr "## 智能合约" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:132 +#: src/ch99-01-01-introduction-to-smart-contracts.md:8 msgid "" -"As you can see, we had to first import the `IERC20DispatcherTrait` and `IERC20LibraryDispatcher` which was generated and exported on compiling our interface, then we make calls to " -"the methods implemented for the `IERC20LibraryDispatcher` struct (`name`, `transfer`, etc), passing in the `class_hash` parameter which represents the class of the contract we want " -"to call." +"Smart contracts gained popularity and became more widespread with the birth of Ethereum. Smart contracts are essentially programs deployed on a blockchain. The term \"smart " +"contract\" is somewhat misleading, as they are neither \"smart\" nor \"contracts\" but rather code and instructions that are executed based on specific inputs. They primarily consist " +"of two components: storage and functions. Once deployed, users can interact with smart contracts by initiating blockchain transactions containing execution data (which function to " +"call and with what input). Smart contracts can modify and read the storage of the underlying blockchain. A smart contract has its own address and is considered a blockchain account, " +"meaning it can hold tokens." msgstr "" -"正如你所看到的,我们必须首先导入`IERC20DispatcherTrait`和`IERC20LibraryDispatcher`,这是在编译我们的接口时生成和导出的,然后我们对`IERC20LibraryDispatcher`结构实现的方法进行调用" -"(`name`、`transfer`等),传入`class_hash`参数,代表我们要调用的合约的类别。" - -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:134 -msgid "## Calling Contracts using low-level System calls" -msgstr "## 使用底层系统调用来调用合约" +"随着以太坊的诞生,智能合约得到了普及并变得更加广泛。智能合约本质上是部署在区块链上的程序。术语 \"智能合约 \"有些误导,因为它们既不 \"智能 \"也不是 \"合约\",而只是根据特定输入执行的代" +"码和指令。它们主要由两部分组成:存储和函数。部署后,用户可以通过启动包含执行数据的区块链交易(调用哪个函数,输入什么参数)与智能合约互动。智能合约可以修改和读取底层区块链的存储。智能" +"合约有自己的地址,因此它是一个区块链账户,意味着它可以持有代币。" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:136 +#: src/ch99-01-01-introduction-to-smart-contracts.md:10 msgid "" -"Another way to call other contracts is to use the `starknet::call_contract_syscall` system call. The Dispatchers we described in the previous sections are high-level syntaxes for " -"this low-level system call." -msgstr "另一种调用其他合约的方法是使用`starknet::call_contract_syscall`系统调用。我们在前几节描述的调度器是这种底层系统调用的高级语法。" +"The programming language used to write smart contracts varies depending on the blockchain. For example, on Ethereum and the [EVM-compatible ecosystem](https://ethereum.org/en/" +"developers/docs/evm/), the most commonly used language is Solidity, while on Starknet, it is Cairo. The way the code is compiled also differs based on the blockchain. On Ethereum, " +"Solidity is compiled into bytecode. On Starknet, Cairo is compiled into Sierra and then into Cairo Assembly (casm)." +msgstr "" +"用于编写智能合约的编程语言因区块链的不同而不同。例如,在以太坊和[EVM兼容的生态系统](https://ethereum.org/en/developers/docs/evm/)生态系统上,最常用的语言是Solidity,而在Starknet上,是" +"Cairo。代码的编译方式也根据区块链的不同而不同。在Ethereum上,Solidity被编译成字节码。在Starknet上,Cairo被编译成Sierra,然后再编译成Cairo Assembly(casm)。" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:138 +#: src/ch99-01-01-introduction-to-smart-contracts.md:12 msgid "" -"Using the system call `starknet::call_contract_syscall` can be handy for customized error handling or possessing more control over the serialization/deserialization of the call data " -"and the returned data. Here's an example demonstrating a low-level `transfer` call:" -msgstr "使用系统调用`starknet::call_contract_syscall`可以方便地进行自定义错误处理,或者对调用数据和返回数据的序列化/反序列化进行更多的控制。下面是一个演示底层的`transfer`调用的例子:" +"Smart contracts possess several unique characteristics. They are **permissionless**, meaning anyone can deploy a smart contract on the network (within the context of a decentralized " +"blockchain, of course). Smart contracts are also **transparent**; the data stored by the smart contract is accessible to anyone. The code that composes the contract can also be " +"transparent, enabling **composability**. This allows developers to write smart contracts that use other smart contracts. Smart contracts can only access and interact with data from " +"the blockchain they are deployed on. They require third-party softwares (called `oracles`) to access external data (the price of a token for instance)." +msgstr "" +"智能合约拥有几个独特的特点。它们是**无权限的**,意味着任何人都可以在网络上部署智能合约(当然该网络必须是去中心化区块链)。智能合约也是**透明的**;任何人都可以访问智能合约所存储的数" +"据。构成合约的代码也可以是透明的,实现了**可组合性**。这使得开发者可以编写使用其他智能合约的智能合约。智能合约只能访问它们所部署的区块链上的数据并与之互动。他们需要第三方工具或软件" +"(称为 \"oracles\")来访问外部数据(例如,代币的价格)。" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:140 +#: src/ch99-01-01-introduction-to-smart-contracts.md:14 msgid "" -"```rust\n" -"#[external]\n" -"fn transfer_token(\n" -" address: starknet::ContractAddress, selector: felt252, calldata: Array\n" -") -> Span:: {\n" -" starknet::call_contract_syscall(address, selector, calldata.span()).unwrap_syscall()\n" -"}\n" -"```" +"For developers to build smart contracts that can interact with each other, it is required to know what the other contracts look like. Hence, Ethereum developers started to build " +"standards for smart contract development, the `ERCxx`. The two most used and famous standards are the `ERC20`, used to build tokens like `USDC`, `DAI` or `STARK`, and the `ERC721`, " +"for NFTs (Non-fungible tokens) like `CryptoPunks` or `Everai`." msgstr "" -"```rust\n" -"#[external]\n" -"fn transfer_token(\n" -" address: starknet::ContractAddress, selector: felt252, calldata: Array\n" -") -> Span:: {\n" -" starknet::call_contract_syscall(address, selector, calldata.span()).unwrap_syscall()\n" -"}\n" -"```" +"对于开发者来说,要想建立能够相互互动的智能合约,就必须知道其他合约的是什么样。因此,以太坊开发者建立了一些智能合约开发的标准,即 `ERCxx`。两个最常用和最著名的标准是 `ERC20`,用于建立 " +"`USDC`、`DAI`或 `STARK`等代币,以及 `ERC721`,用于 `CryptoPunks`或 `Everai`等NFT(Non-fungible token)。" + +#: src/ch99-01-01-introduction-to-smart-contracts.md:16 +msgid "## Use cases" +msgstr "## 使用案例" + +#: src/ch99-01-01-introduction-to-smart-contracts.md:18 +msgid "There are many possible use cases for smart-contracts. The only limits are the technical constraints of the blockchain and the creativity of developers." +msgstr "智能合约有许多可能的用例。唯一的限制是区块链的技术限制和开发者的创造力。" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:149 -msgid "Listing 99-5: A sample contract implementing system calls" -msgstr "示例99-5:一个实现系统调用的样本合约" +#: src/ch99-01-01-introduction-to-smart-contracts.md:20 +msgid "#### DeFi" +msgstr "#### DeFi" -#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:151 +#: src/ch99-01-01-introduction-to-smart-contracts.md:22 msgid "" -"As you can see, rather than pass our function arguments directly, we passed in the contract address, function selector (which is a keccak hash of the function name), and the calldata " -"(function arguments). At the end, we get returned a serialized value which we'll need to deserialize ourselves!" +"Right now, the principal use case for smart contracts is similar to that of Ethereum or Bitcoin, which is essentially handling money. In the context of the alternative payment system " +"promised by Bitcoin, smart contracts on Ethereum enable the creation of decentralized financial applications that no longer rely on traditional financial intermediaries. This is what " +"we call DeFi (decentralized finance). DeFi consists of various projects such as lending/borrowing apps, decentralized exchanges (DEX), on-chain derivatives, stablecoins, " +"decentralized hedge funds, insurance, and many more." msgstr "" -"正如你所看到的,我们没有直接传递我们的函数参数,而是传递了合约地址、函数选择器(这是一个函数名称的keccak哈希值)和calldata(函数参数)。最后,我们得到了一个序列化的值,我们需要自己反" -"序列化它!" +"眼下,智能合约的主要用例与以太坊或比特币的用例类似,基本上是处理金钱。在比特币承诺的替代支付系统的背景下,我们在以太坊上可以使用智能合约创建去中心化的金融应用,不需要再依赖传统的金融" +"中介机构。这就是我们所说的DeFi(去中心化金融)。DeFi由各种项目组成,如借贷应用、去中心化交易所(DEX)、链上衍生品、稳定币、去中心化对冲基金、保险等等。" -#: src/appendix-00.md:1 -msgid "# Appendix" -msgstr "# 附录" +#: src/ch99-01-01-introduction-to-smart-contracts.md:24 +msgid "#### Tokenization" +msgstr "#### 代币化" -#: src/appendix-00.md:3 +#: src/ch99-01-01-introduction-to-smart-contracts.md:26 msgid "" -"The following sections contain reference material you may find useful in your\n" -"Cairo journey." -msgstr "以下章节包含的参考资料可能对您的Cairo之旅有所帮助。" +"Smart contracts can facilitate the tokenization of real-world assets, such as real estate, art, or precious metals. Tokenization divides an asset into digital tokens, which can be " +"easily traded and managed on blockchain platforms. This can increase liquidity, enable fractional ownership, and simplify the buying and selling process." +msgstr "" +"智能合约可以促进现实世界资产的代币化,如房地产、艺术品或贵金属。代币化将资产划分为数字代币,可以在区块链平台上轻松交易和管理。这可以增加流动性,实现部分所有权,并简化购买和销售过程。" -#: src/appendix-01-keywords.md:1 -msgid "## Appendix A: Keywords" -msgstr "## 附录 A:关键字" +#: src/ch99-01-01-introduction-to-smart-contracts.md:28 +msgid "#### Voting" +msgstr "#### 投票" -#: src/appendix-01-keywords.md:3 +#: src/ch99-01-01-introduction-to-smart-contracts.md:30 msgid "" -"The following list contains keywords that are reserved for current or future\n" -"use by the Cairo language." -msgstr "下面的列表包含了为当前或未来保留的Cairo 语言的关键字。" +"Smart contracts can be used to create secure and transparent voting systems. Votes can be recorded on the blockchain, ensuring immutability and transparency. The smart contract can " +"then automatically tally the votes and declare the results, minimizing the potential for fraud or manipulation." +msgstr "智能合约可用于创建安全和透明的投票系统。投票可以记录在区块链上,确保不可更改性和透明度。然后,智能合约可以自动统计票数并宣布结果,将欺诈或操纵的可能性降到最低。" -#: src/appendix-01-keywords.md:6 -msgid "There are two keyword categories:" -msgstr "有两个关键字类别:" +#: src/ch99-01-01-introduction-to-smart-contracts.md:32 +msgid "#### Royalties" +msgstr "#### 特许权使用费(版税)" -#: src/appendix-01-keywords.md:8 +#: src/ch99-01-01-introduction-to-smart-contracts.md:34 msgid "" -"- strict\n" -"- reserved" -msgstr "" -"- 严格(strict)关键字\n" -"- 保留(reserved)关键字" +"Smart contracts can automate royalty payments for artists, musicians, and other content creators. When a piece of content is consumed or sold, the smart contract can automatically " +"calculate and distribute the royalties to the rightful owners, ensuring fair compensation and reducing the need for intermediaries." +msgstr "智能合约可以为艺术家、音乐家和其他内容创作者自动支付版税。当一段内容被消费或出售时,智能合约可以自动计算并将版税分配给合法的所有者,确保公平的补偿并减少对中间人的需求。" -#: src/appendix-01-keywords.md:11 -msgid "" -"There is a third category, which are functions from the core library. While their names are not reserved,\n" -"they are not recommended to be used as names of any items to follow good practices." -msgstr "还有第三类,是来自核心库的函数。虽然它们并不是保留关键字,但以遵循惯例不建议将其用作任何项的标识符。" - -#: src/appendix-01-keywords.md:16 -msgid "### Strict keywords" -msgstr "### 严格关键字" +#: src/ch99-01-01-introduction-to-smart-contracts.md:36 +msgid "#### Decentralized identities DIDs" +msgstr "#### 去中心化身份 DIDs" -#: src/appendix-01-keywords.md:18 +#: src/ch99-01-01-introduction-to-smart-contracts.md:38 msgid "" -"These keywords can only be used in their correct contexts.\n" -"They cannot be used as names of any items." -msgstr "" -"这些关键词只能在其应该被使用的上下文中使用。\n" -"因此,这些关键字不能被用作标识符。" +"Smart contracts can be used to create and manage digital identities, allowing individuals to control their personal information and share it with third parties securely. The smart " +"contract could verify the authenticity of a user's identity and automatically grant or revoke access to specific services based on the user's credentials." +msgstr "智能合约可用于创建和管理数字身份,允许个人控制其个人信息,并与第三方安全地分享。智能合约可以验证用户身份的真实性,并根据用户的凭证自动授予或撤销对特定服务的访问。" -#: src/appendix-01-keywords.md:21 +#: src/ch99-01-01-introduction-to-smart-contracts.md:40 msgid "" -"- `as` - Rename import\n" -"- `break` - Exit a loop immediately\n" -"- `const` - Define constant items\n" -"- `continue` - Continue to the next loop iteration\n" -"- `else` - Fallback for `if` and `if let` control flow constructs\n" -"- `enum` - Define an enumeration\n" -"- `extern` - Function defined at the compiler level using hint available at cairo1 level with this declaration\n" -"- `false` - Boolean false literal\n" -"- `fn` - Define a function\n" -"- `if` - Branch based on the result of a conditional expression\n" -"- `impl` - Implement inherent or trait functionality\n" -"- `implicits` - Special kind of function parameters that are required to perform certain actions\n" -"- `let` - Bind a variable\n" -"- `loop` - Loop unconditionally\n" -"- `match` - Match a value to patterns\n" -"- `mod` - Define a module\n" -"- `mut` - Denote variable mutability\n" -"- `nopanic` - Functions marked with this notation mean that the function will never panic.\n" -"- `of` - Implement a trait\n" -"- `ref` - Bind by reference\n" -"- `return` - Return from function\n" -"- `struct` - Define a structure\n" -"- `trait` - Define a trait\n" -"- `true` - Boolean true literal\n" -"- `type` - Define a type alias\n" -"- `use` - Bring symbols into scope" +"
\n" +"
\n" +"As Ethereum continues to mature, we can expect the use cases and applications of smart contracts to expand further, bringing about exciting new opportunities and reshaping " +"traditional systems for the better." msgstr "" -"- `as` - 重命名导入\n" -"- `break` - 立即退出一个循环\n" -"- `const` - 定义常量项\n" -"- `continue` - 继续进行下一个循环迭代\n" -"- `else` - `if`和`if let`控制流结构的 fallback\n" -"- `enum` - 定义一个枚举项\n" -"- `extern` - 一个于编译器层级上定义的函数使用此声明来表示它可使用Cairo1等级的hint\n" -"- `false` - 布尔字面值假\n" -"- `fn` - 定义一个函数\n" -"- `if` - 基于条件表达式的结果分支\n" -"- `impl` - 实现自有或 ‘trait’ 功能\n" -"- `implicits` - 执行某些动作所需的特殊类型的函数参数\n" -"- `let` - 绑定一个变量\n" -"- `loop` -无条件地循环\n" -"- `match` - 模式匹配\n" -"- `mod` - 定义一个模块\n" -"- `mut` - 表示变量的可变性\n" -"- `nopanic` - 用这个符号标记的函数意味着该函数永远不会panic\n" -"- `of` - 实现trait\n" -"- `ref`- 通过引用绑定\n" -"- `return` - 从函数返回\n" -"- `struct` - 定义一个结构体\n" -"- `trait` - 定义一个trait\n" -"- `true` - 布尔字面值真\n" -"- `type` - 定义一个类型的别名\n" -"- `use` - 引入外部空间的符号" +"
\n" +"
\n" +"随着以太坊的不断成熟,我们可以预期智能合约的用例和应用将进一步扩大,带来令人兴奋的新机会,并会更好地重塑传统系统。" -#: src/appendix-01-keywords.md:50 -msgid "### Reserved keywords" -msgstr "### 保留关键字" +#: src/ch99-01-01-introduction-to-smart-contracts.md:44 +msgid "## The rise of Starknet and Cairo" +msgstr "## Starknet和Cairo语言的崛起" -#: src/appendix-01-keywords.md:52 +#: src/ch99-01-01-introduction-to-smart-contracts.md:46 msgid "" -"These keywords aren't used yet, but they are reserved for future use.\n" -"They have the same restrictions as strict keywords.\n" -"The reasoning behind this is to make current programs forward compatible with future versions of\n" -"Cairo by forbidding them to use these keywords." +"Ethereum, being the most widely used and resilient smart-contract platform, became a victim of its own success. With the rapid adoption of some previously mentioned use cases, mainly " +"DeFi, the cost of performing transactions became extremely high, rendering the network almost unusable. Engineers and researchers in the ecosystem began working on solutions to " +"address this scalability issue." msgstr "" -"这些关键字还没有被使用,但它们被保留下来供将来使用。\n" -"它们与严格关键字有同样的限制。\n" -"禁止使用这些关键字的原因是为了可以使现在的程序向前兼容新版本的Cairo语言。" +"以太坊作为应用最广泛、弹性最大的智能合约平台,成为了自身成功的牺牲品。随着前面提到的一些用例(主要是DeFi)的快速采用,执行交易的成本变得非常高,使得网络几乎无法使用。生态系统中的工程" +"师和研究人员开始研究解决这一可扩展性问题的方案。" -#: src/appendix-01-keywords.md:57 +#: src/ch99-01-01-introduction-to-smart-contracts.md:48 msgid "" -"- `do`\n" -"- `dyn`\n" -"- `macro`\n" -"- `move`\n" -"- `Self`\n" -"- `self`\n" -"- `static_assert`\n" -"- `static`\n" -"- `super`\n" -"- `try`\n" -"- `typeof`\n" -"- `unsafe`\n" -"- `where`\n" -"- `while`\n" -"- `with`\n" -"- `yield`" +"A famous trilemma ([The Blockchain Trilemma](https://vitalik.ca/general/2021/04/07/sharding.html#the-scalability-trilemma)) in the blockchain space states that it is impossible to " +"achieve a high level of scalability, decentralization, and security simultaneously; trade-offs must be made. Ethereum is at the intersection of decentralization and security. " +"Eventually, it was decided that Ethereum's purpose would be to serve as a secure settlement layer, while complex computations would be offloaded to other networks built on top of " +"Ethereum. These are called Layer 2s (L2s)." msgstr "" -"- `do`\n" -"- `dyn`\n" -"- `macro`\n" -"- `move`\n" -"- `Self`\n" -"- `self`\n" -"- `static_assert`\n" -"- `static`\n" -"- `super`\n" -"- `try`\n" -"- `typeof`\n" -"- `unsafe`\n" -"- `where`\n" -"- `while`\n" -"- `with`\n" -"- `yield`" +"区块链领域有一个著名的不可能三角([The Blockchain Trilemma](https://vitalik.ca/general/2021/04/07/sharding.html#the-scalability-trilemma)),即不可能同时实现高水平的可扩展性、去中心化" +"和安全性;我们必须做出权衡。以太坊处于去中心化和安全性的交叉点。最终,人们决定以太坊的目的是作为一个安全的结算层,而复杂的计算将被卸载到建立在以太坊之上的其他网络。这些网络被称为二层" +"网络(L2)。" -#: src/appendix-01-keywords.md:76 -msgid "### Built-in functions" -msgstr "### 内置函数" - -#: src/appendix-01-keywords.md:78 +#: src/ch99-01-01-introduction-to-smart-contracts.md:50 msgid "" -"The Cairo programming language provides several specific functions that serve a special purpose. We will not cover all of them in this book, but using the names of these functions as " -"names of other items is not recommended." -msgstr "Cairo编程语言提供了几个具有特殊用途的函数。我们不会在本书中介绍所有这些函数,但不建议使用这些函数的名称作为任何项的标识符。" - -#: src/appendix-01-keywords.md:80 -msgid "-`assert` - This function checks a boolean expression, and if it evaluates to false, it triggers the panic function. -`panic` - This function terminates the program." -msgstr "-`assert` - 这个函数检查一个布尔表达式,如果它的值是假的,就会触发panic函数。 -`panic` - 这个函数终止程序。" - -#: src/appendix-02-operators-and-symbols.md:1 -msgid "# Appendix B: Operators and Symbols" -msgstr "# 附录B:运算符和符号" - -#: src/appendix-02-operators-and-symbols.md:3 -msgid "This appendix includes a glossary of Cairo's syntax." -msgstr "本附录包含了Cairo语法的词汇表。" - -#: src/appendix-02-operators-and-symbols.md:5 -msgid "## Operators" -msgstr "## 运算符" +"The two primary types of L2s are optimistic rollups and validity rollups. Both approaches involve compressing and batching numerous transactions together, computing the new state, " +"and settling the result on Ethereum (L1). The difference lies in the way the result is settled on L1. For optimistic rollups, the new state is considered valid by default, but there " +"is a 7-day window for nodes to identify malicious transactions." +msgstr "" +"L2的两种主要类型是乐观rollup和有效性rollup。这两种方法都涉及压缩和批量处理大量交易,计算新状态,并将结果结算在以太坊(L1)上。区别在于在L1上结算结果的方式。对于乐观rollup,默认情况下" +"新状态被认为是有效的,但节点有7天的窗口期来识别恶意交易。" -#: src/appendix-02-operators-and-symbols.md:7 +#: src/ch99-01-01-introduction-to-smart-contracts.md:52 msgid "" -"Table B-1 contains the operators in Cairo, an example of how the operator would appear in context, a short explanation, and whether that operator is overloadable. If an operator is " -"overloadable, the relevant trait to use to overload that operator is listed." -msgstr "表B-1包含了开罗的运算符,运算符在上下文中出现的例子和简短的解释,以及该运算符是否可以重载。如果一个运算符是可重载的,则列出了用于重载该运算符的相关特性。" +"In contrast, validity rollups, such as Starknet, use cryptography to prove that the new state has been correctly computed. This is the purpose of STARKs, this cryptographic " +"technology could permit validity rollups to scale significantly more than optimistic rollups. You can learn more about STARKs from Starkware's Medium [article](https://medium.com/" +"starkware/starks-starkex-and-starknet-9a426680745a), which serves as a good primer." +msgstr "" +"与此相反,有效性rollup(如Starknet)使用加密技术来证明新状态的计算是正确的。这就是STARKs的目的,这种加密技术可以使有效性rollup的扩展能力大大超过乐观rollup。你可以从Starkware的" +"Medium[文章](https://medium.com/starkware/starks-starkex-and-starknet-9a426680745a)中了解更多关于STARKs的信息,它是一个很好的入门读物。" -#: src/appendix-02-operators-and-symbols.md:9 -msgid "Table B-1: Operators" -msgstr "表B-1:运算符" +#: src/ch99-01-01-introduction-to-smart-contracts.md:54 +msgid "" +"> Starknet's architecture is thoroughly described in the [Starknet Book](https://book.starknet.io/chapter_4/index.html), which is a great resource to learn more about the Starknet " +"network." +msgstr "> Starknet的架构在[Starknet Book](https://book.starknet.io/chapter_4/index.html)中有详细描述,是了解Starknet的重要资源。" -#: src/appendix-02-operators-and-symbols.md:11 +#: src/ch99-01-01-introduction-to-smart-contracts.md:56 msgid "" -"| Operator | Example | Explanation | Overloadable? |\n" -"|----------|---------|-------------|---------------|\n" -"| `!` | `!expr` | Bitwise or logical complement | `Not` |\n" -"| `!=` | `expr != expr` | Non-equality comparison | `PartialEq` |\n" -"| `%` | `expr % expr` | Arithmetic remainder | `Rem` |\n" -"| `%=` | `var %= expr` | Arithmetic remainder and assignment | `RemEq` |\n" -"| `&` | `expr & expr` | Bitwise AND | `BitAnd` |\n" -"| `*` | `expr * expr` | Arithmetic multiplication | `Mul` |\n" -"| `*=` | `var *= expr` | Arithmetic multiplication and assignment | `MulEq` |\n" -"| `@` | `@var` | Snapshot | |\n" -"| `*` | `*var` | Desnap | |\n" -"| `+` | `expr + expr` | Arithmetic addition | `Add` |\n" -"| `+=` | `var += expr` | Arithmetic addition and assignment | `AddEq` |\n" -"| `,` | `expr, expr` | Argument and element separator | |\n" -"| `-` | `-expr` | Arithmetic negation | `Neg` |\n" -"| `-` | `expr - expr` | Arithmetic subtraction | `Sub` |\n" -"| `-=` | `var -= expr` | Arithmetic subtraction and assignment | `SubEq` |\n" -"| `->` | `fn(...) -> type`, |...| -> type | Function and closure return type | |\n" -"| `.` | `expr.ident` | Member access | |\n" -"| `/` | `expr / expr` | Arithmetic division | `Div` |\n" -"| `/=` | `var /= expr` | Arithmetic division and assignment | `DivEq` |\n" -"| `:` | `pat: type`, `ident: type` | Constraints | |\n" -"| `:` | `ident: expr` | Struct field initializer | |\n" -"| `;` | `expr;` | Statement and item terminator | |\n" -"| `<` | `expr < expr` | Less than comparison | `PartialOrd` |\n" -"| `<=` | `expr <= expr` | Less than or equal to comparison | `PartialOrd` |\n" -"| `=` | `var = expr` | Assignment | |\n" -"| `==` | `expr == expr` | Equality comparison | `PartialEq` |\n" -"| `=>` | `pat => expr` | Part of match arm syntax | |\n" -"| `>` | `expr > expr` | Greater than comparison | `PartialOrd` |\n" -"| `>=` | `expr >= expr` | Greater than or equal to comparison | `PartialOrd` |\n" -"| `^` | `expr ^ expr` | Bitwise exclusive OR | `BitXor` |\n" -"| | | expr | expr | Bitwise OR | `BitOr` |" +"Remember Cairo? It is, in fact, a language developed specifically to work with STARKs and make them general-purpose. With Cairo, we can write **provable code**. In the context of " +"Starknet, this allows proving the correctness of computations from one state to another." msgstr "" -"| 运算符 | 例子 | 解释 | 可重载?|\n" -"|----------|---------|-------------|---------------|\n" -"| `!` `!expr` | 位数或逻辑补码 | `Not` !\n" -"| `!=` | `expr != expr` | 非等价比较 | `PartialEq` !\n" -"| `%` | `expr% expr` | 算术余数 | `Rem` !\n" -"| `%=` | `var %= expr` | 算术余数和赋值 | `RemEq` !\n" -"| `&` | `expr & expr` | Bitwise AND | `BitAnd` |\n" -"| `*` | `expr * expr` | 算术乘法 | `Mul` !\n" -"| `*=` | `var *= expr` | 算术乘法和赋值 | `MulEq` !\n" -"| `@` | `@var` | 快照| |\n" -"| `*` | `*var` | 灭活 | | 灭活\n" -"| `+` | `expr + expr` | 算术加法 | `Add` |\n" -"| `+=` | `var += expr` | 算术加法和赋值 | `AddEq` !\n" -"| `,` | `expr, expr` | 参数和元素分隔器 | |\n" -"| `-` | `-expr` | 算术否定法 | `Neg` !\n" -"| `-` | `expr - expr` | 算术减法 | `Sub` !\n" -"| `-=` | `var -= expr` | 算术减法和赋值 | `SubEq` !\n" -"| `->` | `fn(...) -> type`, |...| -> type | 函数和闭包的返回类型 | |\n" -"| `.` | `expr.ident` | 成员访问 |\n" -"| `/` | `expr / expr` | 算术除法 | `Div` !\n" -"| `/=` | `var /= expr` | 算术除法和赋值 | `DivEq` !\n" -"| `:` | `pat: type`, `ident: type` | 限制条件 | !\n" -"| `:` | `ident: expr` | 结构字段初始化器 | | `:` | `ident: expr` !\n" -"| `;` | `expr;` | 语句和项目的终止符 | | `;`;。\n" -"| `<` | `expr < expr` | 小于比较 | `PartialOrd` !\n" -"| `<=` | `expr <= expr` | Less than or equal to comparison | `PartialOrd` |\n" -"| `=` | `var = expr` | Assignment | |\n" -"| `==` | `expr == expr` | Equality comparison | `PartialEq` |\n" -"| `=>` | `pat => expr` | 部分匹配臂语法 | |\n" -"| `>` | `expr > expr` | 大于比较 | `PartialOrd` !\n" -"| `>=` | `expr >= expr` | 大于或等于比较 | `PartialOrd` !\n" -"| `^` | `expr ^ expr` | 位数排他性OR | `BitXor` !\n" -"| | | expr | expr | Bitwise OR | `BitOr` |" +"还记得Cairo吗?事实上,它是一种专门为STARKs开发的语言,并使其具有通用性。使用Cairo,我们可以编写**可证明的代码**。在 Starknet 中,这可以证明从一个状态到另一个状态的计算的正确性。" -#: src/appendix-02-operators-and-symbols.md:45 -msgid "## Non Operator Symbols" -msgstr "## 非运算符符号" +#: src/ch99-01-01-introduction-to-smart-contracts.md:58 +msgid "" +"Unlike most (if not all) of Starknet's competitors that chose to use the EVM (either as-is or adapted) as a base layer, Starknet employs its own VM. This frees developers from the " +"constraints of the EVM, opening up a broader range of possibilities. Coupled with decreased transaction costs, the combination of Starknet and Cairo creates an exciting playground " +"for developers. Native account abstraction enables more complex logic for accounts, that we call \"Smart Accounts\", and transaction flows. Emerging use cases include **transparent " +"AI** and machine learning applications. Finally, **blockchain games** can be developed entirely **on-chain**. Starknet has been specifically designed to maximize the capabilities of " +"STARK proofs for optimal scalability." +msgstr "" +"大多数(也许不是全部)Starknet的竞争对手都选择使用 EVM(原版或改版)作为基础层,而Starknet则不同,它采用了自己的虚拟机。这使开发人员摆脱了 EVM 的束缚,开辟了更广阔的可能性。加上交易成" +"本的降低,Starknet 与 Cairo 的结合为开发人员创造了一个令人兴奋的乐园。原生账户抽象使我们称之为 \"智能账户\" 的账户和交易流的逻辑更加复杂。新兴用例包括 **透明人工智能** 和机器学习应" +"用。最后,**区块链游戏** 可以完全在 **链上** 开发。Starknet 经过专门设计,可最大限度地发挥 STARK 证明的能力,实现最佳可扩展性。" -#: src/appendix-02-operators-and-symbols.md:47 -msgid "The following list contains all symbols that are not used as operators; that is, they do not have the same behavior as a function or method call." -msgstr "下面的列表包含了所有不作为运算符使用的符号;也就是说,他们并不像函数调用或方法调用一样表现。" +#: src/ch99-01-01-introduction-to-smart-contracts.md:60 +msgid "> Learn more about Account Abstraction in the [Starknet Book](https://book.starknet.io/chapter_5/index.html)." +msgstr "> 在[Starknet Book](https://book.starknet.io/chapter_5/index.html)中了解更多关于账户抽象的信息。" -#: src/appendix-02-operators-and-symbols.md:49 -msgid "Table B-2 shows symbols that appear on their own and are valid in a variety of locations." -msgstr "表B-2 展示了以其自身出现以及出现在合法其他各个地方的符号。" +#: src/ch99-01-01-introduction-to-smart-contracts.md:62 +msgid "## Cairo programs and Starknet contracts: what is the difference?" +msgstr "## Cairo程序和Starknet合约:有何区别?" -#: src/appendix-02-operators-and-symbols.md:51 -msgid "Table B-2: Stand-Alone Syntax" -msgstr "表B-2:独立语法" +#: src/ch99-01-01-introduction-to-smart-contracts.md:64 +msgid "" +"Starknet contracts are a special superset of Cairo programs, so the concepts previously learned in this book are still applicable to write Starknet contracts.\n" +"As you may have already noticed, a Cairo program must always have a function `main` that serves as the entry point for this program:" +msgstr "" +"Starknet合约是Cairo程序的一个特殊子集,所以之前在本书中学到的概念仍然适用于编写Starknet合约。\n" +"你可能已经注意到,一个Cairo程序必须始终有一个函数`main`,作为这个程序的入口:" -#: src/appendix-02-operators-and-symbols.md:53 +#: src/ch99-01-01-introduction-to-smart-contracts.md:67 msgid "" -"| Symbol | Explanation |\n" -"|--------|-------------|\n" -"| `..._u8`, `..._usize`, etc. | Numeric literal of specific type |\n" -"| `'...'` | Short string |\n" -"| `_` | “Ignored” pattern binding; also used to make integer literals readable |" +"```rust\n" +"fn main() {}\n" +"```" msgstr "" -"| 符号 | 解释 |\n" -"|--------|-------------|\n" -"| `..._u8`, `..._usize`, 等等。| 指定类型的数值常量 |\n" -"| `'...'` | 短字符串 |\n" -"| `_` | \"“忽略” 模式绑定;也用于增强整型字面值的可读性 |" +"```rust\n" +"fn main() {}\n" +"```" -#: src/appendix-02-operators-and-symbols.md:59 -msgid "Table B-3 shows symbols that are used within the context of a module hierarchy path to access an item." -msgstr "表B-3 展示了出现在从模块结构到项的路径上下文中的符号。" +#: src/ch99-01-01-introduction-to-smart-contracts.md:71 +msgid "" +"Starknet contracts are essentially programs that can run on the Starknet OS, and as such, have access to Starknet's state. For a module to be handled as a contract by the compiler, " +"it must be annotated with the `#[starknet::contract]` attribute." +msgstr "Starknet合约本质上是可以在Starknet操作系统上运行的程序,因此可以访问Starknet的状态。要让编译器把一个模块当作合约来处理,就必须用 `#[starknet::contract]`属性来标注它。" -#: src/appendix-02-operators-and-symbols.md:61 -msgid "Table B-3: Path-Related Syntax" -msgstr "表B-3:路径相关语法" +#: src/ch99-01-02-a-simple-contract.md:1 +msgid "# A simple contract" +msgstr "# 一个简单的合约" -#: src/appendix-02-operators-and-symbols.md:63 +#: src/ch99-01-02-a-simple-contract.md:3 msgid "" -"| Symbol | Explanation |\n" -"|--------|-------------|\n" -"| `ident::ident` | Namespace path |\n" -"| `super::path` | Path relative to the parent of the current module |\n" -"| `trait::method(...)` | Disambiguating a method call by naming the trait that defines it |" -msgstr "" -"| 符号 | 解释 |\n" -"|--------|-------------|\n" -"| `ident::ident` | 命名空间路径 |\n" -"| `super::path` | 相对于当前模块的父级路径。\n" -"| `trait::method(...)` | 通过命名定义该方法的trait来消除方法调用的二义性 |" +"This chapter will introduce you to the basics of Starknet contracts with an example of a basic contract. You will learn how to write a simple contract that stores a single number on " +"the blockchain." +msgstr "本章将通过一个基本合约的例子向您介绍Starknet合约的基础知识。您将学习如何编写一个在区块链上存储单个数字的简单合约。" -#: src/appendix-02-operators-and-symbols.md:69 -msgid "Table B-4 shows symbols that appear in the context of using generic type parameters." -msgstr "表B-4 展示了出现在泛型类型参数上下文中的符号。" +#: src/ch99-01-02-a-simple-contract.md:5 +msgid "## Anatomy of a simple Starknet Contract" +msgstr "## 一个简单Starknet合约剖析" -#: src/appendix-02-operators-and-symbols.md:71 -msgid "Table B-4: Generics" -msgstr "表 B-4:泛型" +#: src/ch99-01-02-a-simple-contract.md:7 +msgid "Let's consider the following contract to present the basics of a Starknet contract. It might not be easy to understand it all at once, but we will go through it step by step:" +msgstr "让我们通过下面的合同来了解Starknet合约的基本内容。可能一下子很难理解,但是我们将一步一步地进行讲解:" -#: src/appendix-02-operators-and-symbols.md:73 +#: src/ch99-01-02-a-simple-contract.md:9 msgid "" -"| Symbol | Explanation |\n" -"|--------|-------------|\n" -"| `path<...>` | Specifies parameters to generic type in a type (e.g., `Vec`) |\n" -"| `path::<...>`, `method::<...>` | Specifies parameters to generic type, function, or method in an expression; often referred to as turbofish |\n" -"| `fn ident<...> ...` | Define generic function |\n" -"| `struct ident<...> ...` | Define generic structure |\n" -"| `enum ident<...> ...` | Define generic enumeration |\n" -"| `impl<...> ...` | Define generic implementation |" +"```rust\n" +"#[starknet::interface]\n" +"trait ISimpleStorage {\n" +" fn set(ref self: TContractState, x: u128);\n" +" fn get(self: @TContractState) -> u128;\n" +"}\n" +"\n" +"#[starknet::contract]\n" +"mod SimpleStorage {\n" +" use starknet::get_caller_address;\n" +" use starknet::ContractAddress;\n" +"\n" +" #[storage]\n" +" struct Storage {\n" +" stored_data: u128\n" +" }\n" +"\n" +" #[external(v0)]\n" +" impl SimpleStorage of super::ISimpleStorage {\n" +" fn set(ref self: ContractState, x: u128) {\n" +" self.stored_data.write(x);\n" +" }\n" +" fn get(self: @ContractState) -> u128 {\n" +" self.stored_data.read()\n" +" }\n" +" }\n" +"}\n" +"```" msgstr "" -"| 符号 | 解释 |\n" -"|--------|-------------|\n" -"| `path<...>` | 为一个类型中的泛型指定具体参数(例如,`Vec`) |\n" -"| `path::<...>`, `method::<...>` | 为一个泛型、函数或表达式中的方法指定具体参数; 通常被称为Turbofish。\n" -"| `fn ident<...>...` | 泛型函数定义\n" -"| `struct ident<...>...` | 泛型结构体定义\n" -"| `enum ident<...>...` | 泛型枚举定义\n" -"| `impl<...>...` | 定义泛型实现 |" +"```rust\n" +"#[starknet::interface]\n" +"trait ISimpleStorage {\n" +" fn set(ref self: TContractState, x: u128);\n" +" fn get(self: @TContractState) -> u128;\n" +"}\n" +"\n" +"#[starknet::contract]\n" +"mod SimpleStorage {\n" +" use starknet::get_caller_address;\n" +" use starknet::ContractAddress;\n" +"\n" +" #[storage]\n" +" struct Storage {\n" +" stored_data: u128\n" +" }\n" +"\n" +" #[external(v0)]\n" +" impl SimpleStorage of super::ISimpleStorage {\n" +" fn set(ref self: ContractState, x: u128) {\n" +" self.stored_data.write(x);\n" +" }\n" +" fn get(self: @ContractState) -> u128 {\n" +" self.stored_data.read()\n" +" }\n" +" }\n" +"}\n" +"```" -#: src/appendix-02-operators-and-symbols.md:82 -msgid "Table B-5 shows symbols that appear in the context of calling or defining macros and specifying attributes on an item." -msgstr "表B-5展示了在调用或定义宏以及在其上指定属性时的上下文中出现的符号。" +#: src/ch99-01-02-a-simple-contract.md:38 +msgid "Listing 99-1: A simple storage contract" +msgstr "示例99-1:一个简单的存储合约" -#: src/appendix-02-operators-and-symbols.md:84 -msgid "Table B-5: Macros and Attributes" -msgstr "表B-5:宏和属性" +#: src/ch99-01-02-a-simple-contract.md:40 +msgid "> Note: Starknet contracts are defined within [modules](./ch06-02-defining-modules-to-control-scope.md)." +msgstr "> 注意:Starknet合约是在模块([modules](./ch06-02-defining-modules-to-control-scope.md))中被定义的。" -#: src/appendix-02-operators-and-symbols.md:86 +#: src/ch99-01-02-a-simple-contract.md:42 +msgid "### What is this contract?" +msgstr "## 这是什么合约?" + +#: src/ch99-01-02-a-simple-contract.md:44 msgid "" -"| Symbol | Explanation |\n" -"|--------|-------------|\n" -"| `#[meta]` | Outer attribute |" +"In this example, the `Storage` struct declares a storage variable called `stored_data` of type `u128` (unsigned integer of 128 bits).\n" +"You can think of it as a single slot in a database that you can query and alter by calling functions of the code that manages the database.\n" +"The contract defines and exposes publically the functions `set` and `get` that can be used to modify or retrieve the value of that variable." msgstr "" -"| 符号 | 解释 |\n" -"|--------|-------------|\n" -"| `#[meta]` | 外部属性 |" +"在这个示例中,`Storage`结构体声明了一个名为`stored_data`的存储变量,其类型为`u128`(128位无符号整数)。\n" +"您可以将其视为数据库中的一个槽,您可以通过调用管理数据库的代码函数来查询和更改该槽。\n" +"该合约定义并公开了函数`set`和`get`,可以用来修改或获取该变量的值。" -#: src/appendix-02-operators-and-symbols.md:90 -msgid "Table B-6 shows symbols that create comments." -msgstr "表B-6 展示了创建注释的符号。" +#: src/ch99-01-02-a-simple-contract.md:48 +msgid "### The Interface: the contract's blueprint" +msgstr "### 接口:合约的蓝图" -#: src/appendix-02-operators-and-symbols.md:92 -msgid "Table B-6: Comments" -msgstr "表B-6:注释" +#: src/ch99-01-02-a-simple-contract.md:50 +msgid "" +"```rust,noplayground\n" +"#[starknet::interface]\n" +"trait ISimpleStorage {\n" +" fn set(ref self: TContractState, x: u128);\n" +" fn get(self: @TContractState) -> u128;\n" +"}\n" +"```" +msgstr "" +"```rust,noplayground\n" +"#[starknet::interface]\n" +"trait ISimpleStorage {\n" +" fn set(ref self: TContractState, x: u128);\n" +" fn get(self: @TContractState) -> u128;\n" +"}\n" +"```" -#: src/appendix-02-operators-and-symbols.md:94 +#: src/ch99-01-02-a-simple-contract.md:58 msgid "" -"| Symbol | Explanation |\n" -"|--------|-------------|\n" -"| `//` | Line comment |" +"The interface of a contract represents the functions this contract exposes to the outside world. Here, the interface exposes two functions: `set` and `get`. By leveraging the [traits " +"& impls](./ch07-02-traits-in-cairo.md) mechanism from Cairo, we can make sure that the actual implementation of the contract matches its interface. In fact, you will get a " +"compilation error if your contract doesn’t conform with the declared interface." msgstr "" -"| 符号 | 解释 |\n" -"|--------|-------------|\n" -"| `//` | 行注释 |" +"合约的接口表示合同对外公开的功能。这里,接口公开了两个函数: `set` 和 `get`。通过利用Cairo中的[traits & impls](./ch07-02-traits-in-cairo.md)机制,我们可以确保合约的实际实现与其接口相" +"匹配。事实上,如果你的合约不符合声明的接口,你会得到一个编译错误。" -#: src/appendix-02-operators-and-symbols.md:98 -msgid "Table B-7 shows symbols that appear in the context of using tuples." -msgstr "表B-7 展示了出现在使用元组时上下文中的符号。" +#: src/ch99-01-02-a-simple-contract.md:60 +msgid "" +"```rust,noplayground\n" +" #[external(v0)]\n" +" impl SimpleStorage of super::ISimpleStorage {\n" +" fn set(ref self: ContractState) {}\n" +" fn get(self: @ContractState) -> u128 {\n" +" self.stored_data.read()\n" +" }\n" +" }\n" +"```" +msgstr "" +"```rust,noplayground\n" +" #[external(v0)]\n" +" impl SimpleStorage of super::ISimpleStorage {\n" +" fn set(ref self: ContractState) {}\n" +" fn get(self: @ContractState) -> u128 {\n" +" self.stored_data.read()\n" +" }\n" +" }\n" +"```" -#: src/appendix-02-operators-and-symbols.md:100 -msgid "Table B-7: Tuples" -msgstr "表B-7:元组" +#: src/ch99-01-02-a-simple-contract.md:70 +msgid "Listing 99-1-bis: A wrong implementation of the interface of the contract. This does not compile." +msgstr "示例 99-1-bis: 合约接口的错误实现。无法编译。" -#: src/appendix-02-operators-and-symbols.md:103 +#: src/ch99-01-02-a-simple-contract.md:72 msgid "" -"| Symbol | Explanation |\n" -"|--------|-------------|\n" -"| `()` | Empty tuple (aka unit), both literal and type |\n" -"| `(expr)` | Parenthesized expression |\n" -"| `(expr,)` | Single-element tuple expression |\n" -"| `(type,)` | Single-element tuple type |\n" -"| `(expr, ...)` | Tuple expression |\n" -"| `(type, ...)` | Tuple type |\n" -"| `expr(expr, ...)` | Function call expression; also used to initialize tuple `struct`s and tuple `enum` variants |" +"In the interface, note the generic type `TContractState` of the `self` argument which is passed by reference to the `set` function. The `self` parameter represents the contract " +"state. Seeing the `self` argument passed to `set` tells us that this function might access the state of the contract, as it is what gives us access to the contract’s storage. The " +"`ref` modifier implies that `self` may be modified, meaning that the storage variables of the contract may be modified inside the `set` function." msgstr "" -"| 符号 | 解释 |\n" -"|--------|-------------|\n" -"| `()` | 空元组(又称单元),空元组(亦称单元),即是字面值也是类型 |\n" -"| `(expr)` | 括号表达式 |\n" -"| `(expr,)` | 单元素元组表达式 |\n" -"| `(type,)` | 单元素元组类型 |\n" -"| `(expr, ...)` | 元组表达式\n" -"| `(type, ...)` | 元组类型 |\n" -"| `expr(expr, ...)` | 函数调用表达式;也用于初始化元组`struct`和元组`enum`变体" +"在接口中,请注意`self`参数的通用类型`TContractState`,它通过引用传递给`set`函数。参数 `self` 代表合约状态。看到 `self` 参数传递给 `set` 告诉我们这个函数可能会访问合约的状态,因为它使" +"我们能够访问合约的存储空间。`ref` 修饰符意味着 `self` 可以被修改,这意味着合约的存储变量可以在 `set` 函数中被修改。" -#: src/appendix-02-operators-and-symbols.md:113 -msgid "Table B-8 shows the contexts in which curly braces are used." -msgstr "表B-8展示了使用大括号的上下文。" +#: src/ch99-01-02-a-simple-contract.md:74 +msgid "" +"On the other hand, `get` takes a _snapshot_ of `TContractState`, which immediately tells us that it does not modify the state (and indeed, the compiler will complain if we try to " +"modify storage inside the `get` function)." +msgstr "另一方面,`get`获取`TContractState`的_snapshot_,这立即告诉我们它不会修改状态(事实上,如果我们试图在`get`函数中修改存储变量,编译器会报错)。" -#: src/appendix-02-operators-and-symbols.md:115 -msgid "Table B-8: Curly Brackets" -msgstr "表B-8:大括号" +#: src/ch99-01-02-a-simple-contract.md:76 +msgid "### Public functions are defined in an implementation block" +msgstr "#### 在实现里定义public函数" -#: src/appendix-02-operators-and-symbols.md:117 +#: src/ch99-01-02-a-simple-contract.md:78 +msgid "Before we explore things further down, let's define some terminology." +msgstr "在我们进一步探讨之前,让我们先定义一些术语。" + +#: src/ch99-01-02-a-simple-contract.md:80 msgid "" -"| Context | Explanation |\n" -"|---------|-------------|\n" -"| `{...}` | Block expression |\n" -"| `Type {...}` | `struct` literal |" +"- In the context of Starknet, a _public function_ is a function that is exposed to the outside world. In the example above, `set` and `get` are public functions. A public function " +"can be called by anyone, and can be called from outside the contract, or from within the contract. In the example above, `set` and `get` are public functions.\n" +"\n" +"- What we call an _external_ function is a public function that is invoked through a transaction and that can mutate the state of the contract. `set` is an external function.\n" +"\n" +"- A _view_ function is a public function that can be called from outside the contract, but that cannot mutate the state of the contract. `get` is a view function." msgstr "" -"| 上下文 | 解释 |\n" -"|---------|-------------|\n" -"| `{...}` | 块表达式 |\n" -"| `Type {...}` | `struct`字面值 |" - -#: src/appendix-03-derivable-traits.md:1 -msgid "# Appendix C: Derivable Traits" -msgstr "# 附录C: 可派生的 Trait" +"- 在Starknet中,_public function_ (公共函数)是一个对外公开的函数。在上面的例子中,`set`和`get`是公共函数。公有函数可以被任何人调用,可以从合约外部调用,也可以从合约内部调用。在上面" +"的示例中,`set`和`get`是公共函数。\n" +"\n" +"- 我们所说的 _external_ 函数是通过交易唤起的公共函数,它可以改变合约的状态。`set`就是一个外部函数。\n" +"\n" +"- 一个 _view_ 函数是一个公共函数,它可以从合约外部调用,但不能改变合约的状态。`get`是一个视图函数。" -#: src/appendix-03-derivable-traits.md:3 +#: src/ch99-01-02-a-simple-contract.md:86 msgid "" -"In various places in the book, we’ve discussed the `derive` attribute, which you can apply to a struct or enum definition. The `derive` attribute generates code to implement a " -"default trait on the type you’ve annotated with the `derive` syntax." -msgstr "在本书的各个部分中,我们讨论了可应用于结构体和枚举定义的 `derive` 属性。`derive` 属性会在使用 `derive` 语法标记的类型上生成对应 trait 的默认实现的代码。" +"```rust,noplayground\n" +" #[external(v0)]\n" +" impl SimpleStorage of super::ISimpleStorage {\n" +" fn set(ref self: ContractState, x: u128) {\n" +" self.stored_data.write(x);\n" +" }\n" +" fn get(self: @ContractState) -> u128 {\n" +" self.stored_data.read()\n" +" }\n" +" }\n" +"```" +msgstr "" +"```rust,noplayground\n" +" #[external(v0)]\n" +" impl SimpleStorage of super::ISimpleStorage {\n" +" fn set(ref self: ContractState, x: u128) {\n" +" self.stored_data.write(x);\n" +" }\n" +" fn get(self: @ContractState) -> u128 {\n" +" self.stored_data.read()\n" +" }\n" +" }\n" +"```" -#: src/appendix-03-derivable-traits.md:5 -msgid "In this appendix, we provide a comprehensive reference detailing all the traits in the standard library compatible with the `derive` attribute." -msgstr "在这个附录中,我们提供了一个全面的参考,详细介绍了标准库中所有与`derive`属性兼容的trait。" +#: src/ch99-01-02-a-simple-contract.md:98 +msgid "" +"Since the contract interface is defined as the `ISimpleStorage` trait, in order to match the interface, the external functions of the contract\n" +"must be defined in an implementation of this trait — which allows us to make sure that the implementation of the contract matches its interface." +msgstr "由于合约接口被定义为`ISimpleStorage`trait,为了匹配接口,合约的外部函数必须在这个trait的实现中定义--这使我们能够确保合约的实现与其接口相匹配。" -#: src/appendix-03-derivable-traits.md:7 +#: src/ch99-01-02-a-simple-contract.md:101 msgid "" -"These traits listed here are the only ones defined by the core library that can be implemented on your types using `derive`. Other traits defined in the standard library don’t have " -"sensible default behavior, so it’s up to you to implement them in the way that makes sense for what you’re trying to accomplish." +"However, simply defining the functions in the implementation is not enough. The implementation block must be annotated with the `#[external(v0)]` attribute. This attribute exposes " +"the functions defined in this implementation to the outside world — forget to add it and your functions will not be callable from the outside. All functions defined in a block marked " +"as `#[external(v0)]` are consequently _public functions_." msgstr "" -"这里列出的 trait 是仅有的在标准库中定义且能通过 `derive` 在类型上实现。标准库中定义的其它 trait 不能通过 `derive` 在类型上实现。这些 trait 不存在有意义的默认行为,所以由你负责以合理的" -"方式实现它们。" +"然而,仅仅在实现中定义函数是不够的。实现块必须标注上`#[external(v0)]`属性。如果忘记添加该属性,您的函数将无法从外部调用。所有在标记为 `#[external(v0)]`的代码块中定义的函数都是 " +"_public functions_ 。" -#: src/appendix-03-derivable-traits.md:9 +#: src/ch99-01-02-a-simple-contract.md:103 msgid "" -"The list of derivable traits provided in this appendix does not encompass all possibilities: external libraries can implement `derive` for their own traits, expanding the list of " -"traits compatible with `derive`." -msgstr "本附录所提供的可派生 trait 列表并不全面:库可以为其自己的 trait 实现 `derive`,可以使用 `derive` 的 trait 列表事实上是无限的。" - -#: src/appendix-03-derivable-traits.md:11 -msgid "## PartialEq for equality comparison" -msgstr "## 等值比较的 PartialEq 和 Eq" +"When writing the implementation of the interface, the generic parameter corresponding to the `self` argument in the trait must be `ContractState`. The `ContractState` type is " +"generated by the compiler, and gives access to the storage variables defined in the `Storage` struct.\n" +"Additionally, `ContractState` gives us the ability to emit events. The name `ContractState` is not surprising, as it’s a representation of the contract’s state, which is what we " +"think of `self` in the contract interface trait." +msgstr "" +"当编写接口的实现时,在trait中对应于`self`参数的泛型参数必须是`ContractState`。`ContractState`类型由编译器生成,它提供了对定义在 \"`Storage`结构中的存储变量的访问。\n" +"此外,`ContractState`还提供了emit事件的能力。不要对`ContractState` 这个名字感到奇怪,因为它是合约状态的表示,也就是我们在合约接口trait中认为的 `self`。" -#: src/appendix-03-derivable-traits.md:13 -msgid "The `PartialEq` trait allows for comparison between instances of a type for equality, thereby enabling the == and != operators." -msgstr "`PartialEq` trait允许在一个类型的实例之间进行等值比较,从而实现 == 和 != 运算符。" +#: src/ch99-01-02-a-simple-contract.md:106 +msgid "### Modifying the contract's state" +msgstr "### 修改合约状态" -#: src/appendix-03-derivable-traits.md:15 +#: src/ch99-01-02-a-simple-contract.md:108 msgid "" -"When `PartialEq` is derived on structs, two instances are equal only if all fields are equal, and the instances are not equal if any fields are not equal. When derived on enums, each " -"variant is equal to itself and not equal to the other variants." -msgstr "当`PartialEq`在结构上派生时,只有当所有字段都相等时,两个实例才相等,如果任何字段不相等,实例就不相等。当在枚举上派生时,每一个成员都和其自身相等,且和其他成员都不相等。" +"As you can notice, all functions that need to access the state of the contract are defined under the implementation of a trait that has a `TContractState` generic parameter, and take " +"a `self: ContractState` parameter.\n" +"This allows us to explicitly pass the `self: ContractState` parameter to the function, allowing access the storage variables of the contract.\n" +"To access a storage variable of the current contract, you add the `self` prefix to the storage variable name, which allows you to use the `read` and `write` methods to either read or " +"write the value of the storage variable." +msgstr "" +"正如你所注意到的,所有需要访问合约状态的函数都被定义在一个有`TContractState`泛型参数的trait的实现下,并接受一个`self:ContractState`参数。\n" +"这允许我们显式地将 `self:ContractState`参数给函数,允许访问合约的存储变量。\n" +"要访问当前合约的存储变量,可以在存储变量名后添加 `self` 前缀,这样就可以使用 `read` 和 `write` 方法读取或写入存储变量的值。" -#: src/appendix-03-derivable-traits.md:19 +#: src/ch99-01-02-a-simple-contract.md:112 msgid "" -"```Rust\n" -"#[derive(PartialEq, Drop)]\n" -"struct A {\n" -" item: felt252\n" -"}\n" -"\n" -"fn main() {\n" -" let first_struct = A {\n" -" item: 2\n" -" };\n" -" let second_struct = A {\n" -" item: 2\n" -" };\n" -" assert(first_struct == second_struct, 'Structs are different');\n" -"}\n" +"```rust,noplayground\n" +" fn set(ref self: ContractState, x: u128) {\n" +" self.stored_data.write(x);\n" +" }\n" "```" msgstr "" -"```Rust\n" -"#[derive(PartialEq, Drop)]\n" -"struct A {\n" -" item: felt252\n" -"}\n" -"\n" -"fn main() {\n" -" let first_struct = A {\n" -" item: 2\n" -" };\n" -" let second_struct = A {\n" -" item: 2\n" -" };\n" -" assert(first_struct == second_struct, 'Structs are different');\n" -"}\n" +"```rust,noplayground\n" +" fn set(ref self: ContractState, x: u128) {\n" +" self.stored_data.write(x);\n" +" }\n" "```" -#: src/appendix-03-derivable-traits.md:36 -msgid "## Clone and Copy for Duplicating Values" -msgstr "## 复制值的 Clone 和 Copy" +#: src/ch99-01-02-a-simple-contract.md:118 +msgid "Using `self` and the `write` method to modify the value of a storage variable" +msgstr "使用 `self` 和 `write` 方法修改存储变量的值" -#: src/appendix-03-derivable-traits.md:38 -msgid "The `Clone` trait provides the functionality to explicitly create a deep copy of a value." -msgstr "`Clone` trait 提供了明确创建一个值的深度拷贝的功能。" +#: src/ch99-01-02-a-simple-contract.md:120 +msgid "> Note: if the contract state is passed as a snapshot instead of `ref`, attempting to modify will result in a compilation error." +msgstr "> 注意:如果合约状态是作为snapshot而不是`ref`传递的,尝试修改它将导致编译错误。" -#: src/appendix-03-derivable-traits.md:40 +#: src/ch99-01-02-a-simple-contract.md:122 msgid "" -"Deriving `Clone` implements the `clone` method, which, in turn, calls clone on each of the type's components. This means all the fields or values in the type must also implement " -"`Clone` to derive `Clone`." -msgstr "派生 `Clone` 实现了 `clone` 方法,其为整个的类型实现时,在类型的每一部分上调用了`clone` 方法。这意味着类型中所有字段或值也必须实现了 `Clone`,这样才能够派生 `Clone`。" +"This contract does not do much yet apart from allowing anyone to store a single number that is accessible by anyone in the world. Anyone could call `set` again with a different value " +"and overwrite your number, but the number is still stored in the history of the blockchain. Later, you will see how you can impose access restrictions so that only you can alter the " +"number." +msgstr "" +"除了允许任何人存储世界上任何人都可以访问的单个号码外,该合约没做其他事。任何人都可以用不同的值再次调用`set`覆盖您的号码,但号码仍然存储在区块链的历史中。稍后,您将看到如何施加访问限" +"制,以便只有您可以更改号码。" -#: src/appendix-03-derivable-traits.md:44 +#: src/ch99-01-03-00-a-deeper-dive-into-contracts.md:1 +msgid "# A deeper dive into contracts" +msgstr "# 深入了解合约" + +#: src/ch99-01-03-00-a-deeper-dive-into-contracts.md:3 msgid "" -"```Rust\n" -"use clone::Clone;\n" +"In the previous section, we gave an introductory example of a smart contract written in Cairo. In this section, we'll be taking a deeper look at all the components of a smart " +"contract, step by step." +msgstr "在上一节中,我们给出了一个用Cairo语言编写的智能合约的介绍性示例。在本节中,我们将逐步深入了解智能合约的所有组成部分。" + +#: src/ch99-01-03-00-a-deeper-dive-into-contracts.md:5 +msgid "" +"When we discussed [_interfaces_](./ch99-01-02-a-simple-contract.md), we specified the difference between _public functions, external functions and view functions_, and we mentioned " +"how to interact with _storage_." +msgstr "在讨论[_interfaces_](./ch99-01-02-a-simple-contract.md)时,我们明确了_public函数、external函数和view函数_ 之间的区别,并提到了如何与 _storage_ 交互。" + +#: src/ch99-01-03-00-a-deeper-dive-into-contracts.md:7 +msgid "At this point, you should have multiple questions that come to mind:" +msgstr "此时,您应该会想到很多问题:" + +#: src/ch99-01-03-00-a-deeper-dive-into-contracts.md:9 +msgid "" +"- How do I define internal/private functions?\n" +"- How can I emit events? How can I index them?\n" +"- Where should I define functions that do not need to access the contract's state?\n" +"- Is there a way to reduce the boilerplate?\n" +"- How can I store more complex data types?" +msgstr "" +"- 如何定义内部/私有函数?\n" +"- 如何发出事件?如何索引事件?\n" +"- 我应该在哪里定义不需要访问合约状态的函数?\n" +"- 有办法减少冗余的模式代码吗?\n" +"- 如何存储更复杂的数据类型?" + +#: src/ch99-01-03-00-a-deeper-dive-into-contracts.md:15 +msgid "Luckily, we'll be answering all these questions in this chapter. Let's consider the following example contract that we'll be using throughout this chapter:" +msgstr "幸运的是,我们将在本章中回答所有这些问题。下面是我们在本章中将使用的合同示例:" + +#: src/ch99-01-03-00-a-deeper-dive-into-contracts.md:17 +msgid "" +"```rust,noplayground\n" "\n" -"#[derive(Clone, Drop)]\n" -"struct A {\n" -" item: felt252\n" -"}\n" +"use starknet::ContractAddress;\n" "\n" -"fn main() {\n" -" let first_struct = A {\n" -" item: 2\n" -" };\n" -" let second_struct = first_struct.clone();\n" -" assert(second_struct.item == 2, 'Not equal');\n" +"#[starknet::interface]\n" +"trait INameRegistry {\n" +" fn store_name(ref self: TContractState, name: felt252);\n" +" fn get_name(self: @TContractState, address: ContractAddress) -> felt252;\n" "}\n" -"```" -msgstr "" -"```Rust\n" -"use clone::Clone;\n" "\n" -"#[derive(Clone, Drop)]\n" -"struct A {\n" -" item: felt252\n" -"}\n" "\n" -"fn main() {\n" -" let first_struct = A {\n" -" item: 2\n" -" };\n" -" let second_struct = first_struct.clone();\n" -" assert(second_struct.item == 2, 'Not equal');\n" -"}\n" -"```" - -#: src/appendix-03-derivable-traits.md:61 -msgid "The `Copy` trait allows for the duplication of values. You can derive `Copy` on any type whose parts all implement `Copy`." -msgstr "`Copy` trait 允许你复制值而不需要额外的代码。你可以在任何部分都实现了`Copy`的类型上派生`Copy`。" - -#: src/appendix-03-derivable-traits.md:65 -msgid "" -"```Rust\n" -"#[derive(Copy, Drop)]\n" -"struct A {\n" -" item: felt252\n" -"}\n" +"#[starknet::contract]\n" +"mod NameRegistry {\n" +" use starknet::{ContractAddress, get_caller_address};\n" "\n" -"fn main() {\n" -" let first_struct = A {\n" -" item: 2\n" -" };\n" -" let second_struct = first_struct;\n" -" assert(second_struct.item == 2, 'Not equal');\n" -" assert(first_struct.item == 2, 'Not Equal'); // Copy Trait prevents firs_struct from moving into second_struct\n" +" #[storage]\n" +" struct Storage {\n" +" names: LegacyMap::,\n" +" total_names: u128,\n" +" owner: Person\n" +" }\n" +"\n" +" #[event]\n" +" #[derive(Drop, starknet::Event)]\n" +" enum Event {\n" +" StoredName: StoredName,\n" +" }\n" +"\n" +" #[derive(Drop, starknet::Event)]\n" +" struct StoredName {\n" +" #[key]\n" +" user: ContractAddress,\n" +" name: felt252\n" +" }\n" +"\n" +" #[derive(Copy, Drop, Serde, starknet::Store)]\n" +" struct Person {\n" +" name: felt252,\n" +" address: ContractAddress\n" +" }\n" +"\n" +" #[constructor]\n" +" fn constructor(ref self: ContractState, owner: Person) {\n" +" self.names.write(owner.address, owner.name);\n" +" self.total_names.write(1);\n" +" self.owner.write(owner);\n" +" }\n" +"\n" +" #[external(v0)]\n" +" impl NameRegistry of super::INameRegistry {\n" +" fn store_name(ref self: ContractState, name: felt252) {\n" +" let caller = get_caller_address();\n" +" self._store_name(caller, name);\n" +" }\n" +"\n" +" fn get_name(self: @ContractState, address: ContractAddress) -> felt252 {\n" +" let name = self.names.read(address);\n" +" name\n" +" }\n" +" }\n" +"\n" +" #[generate_trait]\n" +" impl InternalFunctions of InternalFunctionsTrait {\n" +" fn _store_name(ref self: ContractState, user: ContractAddress, name: felt252) {\n" +" let mut total_names = self.total_names.read();\n" +" self.names.write(user, name);\n" +" self.total_names.write(total_names + 1);\n" +" self.emit(StoredName { user: user, name: name });\n" +"\n" +" }\n" +" }\n" +"\n" +" fn _get_contract_name() -> felt252 {\n" +" 'Name Registry'\n" +" }\n" "}\n" "```" msgstr "" -"```Rust\n" -"#[derive(Copy, Drop)]\n" -"struct A {\n" -" item: felt252\n" +"```rust,noplayground\n" +"\n" +"use starknet::ContractAddress;\n" +"\n" +"#[starknet::interface]\n" +"trait INameRegistry {\n" +" fn store_name(ref self: TContractState, name: felt252);\n" +" fn get_name(self: @TContractState, address: ContractAddress) -> felt252;\n" "}\n" "\n" -"fn main() {\n" -" let first_struct = A {\n" -" item: 2\n" -" };\n" -" let second_struct = first_struct;\n" -" assert(second_struct.item == 2, 'Not equal');\n" -" assert(first_struct.item == 2, 'Not Equal'); // Copy Trait prevents firs_struct from moving into second_struct\n" +"\n" +"#[starknet::contract]\n" +"mod NameRegistry {\n" +" use starknet::{ContractAddress, get_caller_address};\n" +"\n" +" #[storage]\n" +" struct Storage {\n" +" names: LegacyMap::,\n" +" total_names: u128,\n" +" owner: Person\n" +" }\n" +"\n" +" #[event]\n" +" #[derive(Drop, starknet::Event)]\n" +" enum Event {\n" +" StoredName: StoredName,\n" +" }\n" +"\n" +" #[derive(Drop, starknet::Event)]\n" +" struct StoredName {\n" +" #[key]\n" +" user: ContractAddress,\n" +" name: felt252\n" +" }\n" +"\n" +" #[derive(Copy, Drop, Serde, starknet::Store)]\n" +" struct Person {\n" +" name: felt252,\n" +" address: ContractAddress\n" +" }\n" +"\n" +" #[constructor]\n" +" fn constructor(ref self: ContractState, owner: Person) {\n" +" self.names.write(owner.address, owner.name);\n" +" self.total_names.write(1);\n" +" self.owner.write(owner);\n" +" }\n" +"\n" +" #[external(v0)]\n" +" impl NameRegistry of super::INameRegistry {\n" +" fn store_name(ref self: ContractState, name: felt252) {\n" +" let caller = get_caller_address();\n" +" self._store_name(caller, name);\n" +" }\n" +"\n" +" fn get_name(self: @ContractState, address: ContractAddress) -> felt252 {\n" +" let name = self.names.read(address);\n" +" name\n" +" }\n" +" }\n" +"\n" +" #[generate_trait]\n" +" impl InternalFunctions of InternalFunctionsTrait {\n" +" fn _store_name(ref self: ContractState, user: ContractAddress, name: felt252) {\n" +" let mut total_names = self.total_names.read();\n" +" self.names.write(user, name);\n" +" self.total_names.write(total_names + 1);\n" +" self.emit(StoredName { user: user, name: name });\n" +"\n" +" }\n" +" }\n" +"\n" +" fn _get_contract_name() -> felt252 {\n" +" 'Name Registry'\n" +" }\n" "}\n" "```" -#: src/appendix-03-derivable-traits.md:81 -msgid "## Serializing with Serde" -msgstr "## 用Serde进行序列化" +#: src/ch99-01-03-00-a-deeper-dive-into-contracts.md:95 +msgid "Listing 99-1bis: Our reference contract for this chapter" +msgstr "示例 99-1bis:本章的参考合约" -#: src/appendix-03-derivable-traits.md:83 +#: src/ch99-01-03-01-storage-variables.md:1 +msgid "## Storage Variables" +msgstr "## 存储变量" + +#: src/ch99-01-03-01-storage-variables.md:3 msgid "" -"`Serde` provides trait implementations for `serialize` and `deserialize` functions for data structures defined in your crate. It allows you to transform your structure into an array " -"(or the opposite)." -msgstr "`Serde`为你的crate中定义的数据结构提供`serialize`和`deserialize`函数的trait实现。它允许你将你的结构体转化为数组(或相反)。" +"As stated previously, storage variables allow you to store data that will be stored in the contract's storage that is itself stored on the blockchain. These data are persistent and " +"can be accessed and modified anytime once the contract is deployed." +msgstr "如前所述,存储变量允许您存储数据,这些数据将存储在合约的存储空间中,而合约本身存储在区块链上。这些数据是持久的,一旦合约部署完成,就可以随时访问和修改。" -#: src/appendix-03-derivable-traits.md:87 +#: src/ch99-01-03-01-storage-variables.md:5 +msgid "Storage variables in Starknet contracts are stored in a special struct called `Storage`:" +msgstr "Starknet合同中的存储变量被存储在一个特殊的结构中,称为`Storage`:" + +#: src/ch99-01-03-01-storage-variables.md:7 msgid "" -"```Rust\n" -"use serde::Serde;\n" -"use array::ArrayTrait;\n" -"\n" -"#[derive(Serde, Drop)]\n" -"struct A {\n" -" item_one: felt252,\n" -" item_two: felt252,\n" -"}\n" -"\n" -"fn main() {\n" -" let first_struct = A {\n" -" item_one: 2,\n" -" item_two: 99,\n" -" };\n" -" let mut output_array = ArrayTrait::new();\n" -" let serialized = first_struct.serialize(ref output_array);\n" -" panic(output_array);\n" -"}\n" +"```rust, noplayground\n" +"# #[starknet::contract]\n" +"# mod contract {\n" +"# use starknet::ContractAddress;\n" +" #[storage]\n" +" struct Storage {\n" +" id: u8,\n" +" names: LegacyMap::,\n" +" }\n" +"# }\n" "```" msgstr "" -"```Rust\n" -"use serde::Serde;\n" -"use array::ArrayTrait;\n" -"\n" -"#[derive(Serde, Drop)]\n" -"struct A {\n" -" item_one: felt252,\n" -" item_two: felt252,\n" -"}\n" -"\n" -"fn main() {\n" -" let first_struct = A {\n" -" item_one: 2,\n" -" item_two: 99,\n" -" };\n" -" let mut output_array = ArrayTrait::new();\n" -" let serialized = first_struct.serialize(ref output_array);\n" -" panic(output_array);\n" -"}\n" +"```rust, noplayground\n" +"# #[starknet::contract]\n" +"# mod contract {\n" +"# use starknet::ContractAddress;\n" +" #[storage]\n" +" struct Storage {\n" +" id: u8,\n" +" names: LegacyMap::,\n" +" }\n" +"# }\n" "```" -#: src/appendix-03-derivable-traits.md:108 -msgid "Output:" -msgstr "输出:" +#: src/ch99-01-03-01-storage-variables.md:19 +msgid "Listing 99-2: A Storage Struct" +msgstr "示例99-2:存储用结构体" -#: src/appendix-03-derivable-traits.md:110 +#: src/ch99-01-03-01-storage-variables.md:21 msgid "" -"```Bash\n" -"Run panicked with [2 (''), 99 ('c'), ].\n" +"The storage struct is a [struct](./ch04-00-using-structs-to-structure-related-data.md) like any other,\n" +"except that it **must** be annotated with `#[storage]` allowing you to store mappings using the `LegacyMap` type." +msgstr "" +"存储结构是一个[结构体](./ch04-00-using-structs-to-structure-related-data.md),与其他结构体基本一样、\n" +"除了它 **必须** 被标注为`#[storage]`,以允许你使用`LegacyMap`类型来存储映射。" + +#: src/ch99-01-03-01-storage-variables.md:24 +msgid "### Storing Mappings" +msgstr "### 存储映射" + +#: src/ch99-01-03-01-storage-variables.md:26 +msgid "" +"Mappings are a key-value data structure that you can use to store data within a smart contract. They are essentially hash tables that allow you to associate a unique key with a " +"corresponding value. Mappings are also useful to store sets of data, as it's impossible to store arrays in storage." +msgstr "" +"映射是一种键值数据结构,你可以用它来存储智能合约中的数据。它们本质上是哈希表,允许你将一个唯一的键与一个相应的值联系起来。映射对于存储数据集也很有用,因为在存储中不可能存储数组。" + +#: src/ch99-01-03-01-storage-variables.md:28 +msgid "" +"A mapping is a variable of type `LegacyMap`, in which the key and value types are specified within angular brackets `<>`.\n" +"It is important to note that the `LegacyMap` type can only be used inside the `Storage` struct, and can't be used to define mappings in user-defined structs." +msgstr "" +"映射是一个类型为 `LegacyMap` 的变量,其中键和值的类型在角括号 `<>` 中指定。\n" +"需要注意的是,`LegacyMap`类型只能在 `LegacyMap`结构内部使用,不能用于在用户定义的结构中定义映射。" + +#: src/ch99-01-03-01-storage-variables.md:31 +msgid "" +"You can also create more complex mappings than that; you can find one in Listing 99-2bis like the popular `allowances` storage variable in the ERC20 Standard which maps the `owner` " +"and `spender` to the `allowance` using tuples:" +msgstr "您还可以创建比这更复杂的映射;您可以在示例 99-2bis中找到一个类似于 ERC20 标准中常见的 `allowances` 存储变量,它使用元组将 `owner` 和 `spender` 映射到 `allowance` 中:" + +#: src/ch99-01-03-01-storage-variables.md:33 +msgid "" +"```rust,noplayground\n" +" #[storage]\n" +" struct Storage {\n" +" allowances: LegacyMap::<(ContractAddress, ContractAddress), u256>\n" +" }\n" "```" msgstr "" -"```Bash\n" -"Run panicked with [2 (''), 99 ('c'), ].\n" +"```rust,noplayground\n" +" #[storage]\n" +" struct Storage {\n" +" allowances: LegacyMap::<(ContractAddress, ContractAddress), u256>\n" +" }\n" "```" -#: src/appendix-03-derivable-traits.md:114 -msgid "We can see here that our struct A has been serialized into the output array." -msgstr "我们在这里可以看到,我们的结构体A已经被序列化到输出数组中。" +#: src/ch99-01-03-01-storage-variables.md:40 +msgid "Listing 99-2bis: Storing mappings" +msgstr "示例99-2bis:存储映射" -#: src/appendix-03-derivable-traits.md:116 -msgid "Also, we can use `deserialize` function to convert the serialized array back into our A struct." -msgstr "另外,我们可以使用`deserialize`函数将序列化的数组转换回我们的结构体A。" +#: src/ch99-01-03-01-storage-variables.md:42 +msgid "" +"In mappings, the address of the value at key `k_1,...,k_n` is `h(...h(h(sn_keccak(variable_name),k_1),k_2),...,k_n)` where ℎ\n" +"is the Pedersen hash and the final value is taken `mod2251−256`. You can learn more about the contract storage layout in the [Starknet Documentation](https://docs.starknet.io/" +"documentation/architecture_and_concepts/Contracts/contract-storage/#storage_variables)" +msgstr "" +"在映射中,键`k_1,...,k_n`的值的地址是`h(...h(h(sn_keccak(variable_name),k_1),k_2),...,k_n)`,其中ℎ\n" +"是Pedersen哈希值,最终值取为 \"mod2251-256\"。你可以在[Starknet文档](https://docs.starknet.io/documentation/architecture_and_concepts/Contracts/contract-storage/#storage_variables)中" +"了解更多关于合约存储布局的信息。" -#: src/appendix-03-derivable-traits.md:120 +#: src/ch99-01-03-01-storage-variables.md:45 +msgid "### Storing custom structs" +msgstr "### 存储自定义结构体" + +#: src/ch99-01-03-01-storage-variables.md:47 msgid "" -"```Rust\n" -"use serde::Serde;\n" -"use array::ArrayTrait;\n" -"use option::OptionTrait;\n" -"\n" -"#[derive(Serde, Drop)]\n" -"struct A {\n" -" item_one: felt252,\n" -" item_two: felt252,\n" -"}\n" -"\n" -"fn main() {\n" -" let first_struct = A {\n" -" item_one: 2,\n" -" item_two: 99,\n" -" };\n" -" let mut output_array = ArrayTrait::new();\n" -" let mut serialized = first_struct.serialize(ref output_array);\n" -" let mut span_array = output_array.span();\n" -" let deserialized_struct: A = Serde::::deserialize(ref span_array).unwrap();\n" -"}\n" +"The compiler knows how to store basic data types, such as unsigned integers (`u8`, `u128`, `u256`...), `felt252`, `ContractAddress`, etc. But what if you want to store a custom " +"struct in storage? In that case, you have to explicitly tell the compiler how to store your struct in storage.\n" +"In our example, we want to store a `Person` struct in storage, so we have to tell the compiler how to store it in storage by adding a derive attribute of the `starknet::Store` trait " +"to our struct definition." +msgstr "" +"编译器知道如何存储基本数据类型,例如无符号整数(`u8`, `u128`, `u256`...), `felt252`,`ContractAddress`等。但是如果您想在存储空间中存储自定义结构体呢?在这种情况下,您必须明确地告诉编译" +"器如何在存储空间中存储您的结构。\n" +"在我们的示例中,我们希望将`Person`结构体存储在存储空间中,因此我们必须在结构体定义中添加`starknet::Store`trait的派生属性,告诉编译器如何将其存储在存储空间中。" + +#: src/ch99-01-03-01-storage-variables.md:50 +msgid "" +"```rust, noplayground\n" +" #[derive(Copy, Drop, Serde, starknet::Store)]\n" +" struct Person {\n" +" name: felt252,\n" +" address: ContractAddress\n" +" }\n" "```" msgstr "" -"```Rust\n" -"use serde::Serde;\n" -"use array::ArrayTrait;\n" -"use option::OptionTrait;\n" -"\n" -"#[derive(Serde, Drop)]\n" -"struct A {\n" -" item_one: felt252,\n" -" item_two: felt252,\n" -"}\n" -"\n" -"fn main() {\n" -" let first_struct = A {\n" -" item_one: 2,\n" -" item_two: 99,\n" -" };\n" -" let mut output_array = ArrayTrait::new();\n" -" let mut serialized = first_struct.serialize(ref output_array);\n" -" let mut span_array = output_array.span();\n" -" let deserialized_struct: A = Serde::::deserialize(ref span_array).unwrap();\n" -"}\n" +"```rust, noplayground\n" +" #[derive(Copy, Drop, Serde, starknet::Store)]\n" +" struct Person {\n" +" name: felt252,\n" +" address: ContractAddress\n" +" }\n" "```" -#: src/appendix-03-derivable-traits.md:143 +#: src/ch99-01-03-01-storage-variables.md:58 +msgid "### Reading from Storage" +msgstr "### 从存储中读取" + +#: src/ch99-01-03-01-storage-variables.md:60 +msgid "To read the value of the storage variable `names`, we call the `read` function on the `names` storage variable, passing in the key `address` as a parameter." +msgstr "要读取存储变量 `names` 的值,我们需要调用存储变量 `names` 的 `read` 函数,并将键值 `address` 作为参数传入。" + +#: src/ch99-01-03-01-storage-variables.md:62 msgid "" -"Here we are converting a serialized array span back to the struct A. `deserialize` returns an `Option` so we need to unwrap it. When using deserialize we also need to specify the " -"type we want to deserialize into." -msgstr "这里我们要把一个序列化的数组span转换回结构体A。`deserialize`返回一个`Option`,所以我们需要把它解包。当使用deserialize时,我们还需要指定我们想要反序列化的类型。" +"```rust, noplayground\n" +" let name = self.names.read(address);\n" +"```" +msgstr "" +"```rust, noplayground\n" +" let name = self.names.read(address);\n" +"```" + +#: src/ch99-01-03-01-storage-variables.md:66 +msgid "Listing 99-3: Calling the `read` function on the `names` variable" +msgstr "示例99-3:在`names`变量上调用`read`函数" + +#: src/ch99-01-03-01-storage-variables.md:68 +msgid "> Note: When the storage variable does not store a mapping, its value is accessed without passing any parameters to the read method" +msgstr "> 注意:当存储变量不存储映射时,使用读取方法访问其值不需要传递任何参数" + +#: src/ch99-01-03-01-storage-variables.md:70 +msgid "### Writing to Storage" +msgstr "### 写入存储" + +#: src/ch99-01-03-01-storage-variables.md:72 +msgid "To write a value to the storage variable `names`, we call the `write` function on the `names` storage variable, passing in the key and values as arguments." +msgstr "为了给存储变量`names`写一个值,我们在`names`存储变量上调用`write`函数,将键和值作为参数传入。" + +#: src/ch99-01-03-01-storage-variables.md:74 +msgid "" +"```rust, noplayground\n" +" self.names.write(user, name);\n" +"```" +msgstr "" +"```rust, noplayground\n" +" self.names.write(user, name);\n" +"```" + +#: src/ch99-01-03-01-storage-variables.md:78 +msgid "Listing 99-4: Writing to the `names` variable" +msgstr "示例99-4:向 \"names \"变量写入内容" + +#: src/ch99-01-03-02-contract-functions.md:1 +msgid "## Contract Functions" +msgstr "## 合约函数" + +#: src/ch99-01-03-02-contract-functions.md:3 +msgid "In this section, we are going to be looking at the different types of functions you could encounter in contracts:" +msgstr "在本节中,我们将了解合约中可能遇到的不同类型的函数:" + +#: src/ch99-01-03-02-contract-functions.md:5 +msgid "### 1. Constructors" +msgstr "### 1.构造器(Constructors)" + +#: src/ch99-01-03-02-contract-functions.md:7 +msgid "Constructors are a special type of function that only runs once when deploying a contract, and can be used to initialize the state of a contract." +msgstr "构造函数是一种特殊类型的函数,只在部署合约时运行一次,可用于初始化合约的状态。" + +#: src/ch99-01-03-02-contract-functions.md:9 +msgid "" +"```rust,noplayground\n" +" #[constructor]\n" +" fn constructor(ref self: ContractState, owner: Person) {\n" +" self.names.write(owner.address, owner.name);\n" +" self.total_names.write(1);\n" +" self.owner.write(owner);\n" +" }\n" +"```" +msgstr "" +"```rust,noplayground\n" +" #[constructor]\n" +" fn constructor(ref self: ContractState, owner: Person) {\n" +" self.names.write(owner.address, owner.name);\n" +" self.total_names.write(1);\n" +" self.owner.write(owner);\n" +" }\n" +"```" + +#: src/ch99-01-03-02-contract-functions.md:18 +msgid "Some important rules to note:" +msgstr "一些需要注意的重要规则:" + +#: src/ch99-01-03-02-contract-functions.md:20 +msgid "" +"1. Your contract can't have more than one constructor.\n" +"2. Your constructor function must be named `constructor`.\n" +"3. It must be annotated with the `#[constructor]` attribute." +msgstr "" +"1.您的合约不能有一个以上的构造函数。\n" +"2.您的构造函数必须命名为 `constructor`。\n" +"3.它必须使用 `#[constructor]` 属性标注。" + +#: src/ch99-01-03-02-contract-functions.md:24 +msgid "### 2. Public functions" +msgstr "### 2.公共函数" + +#: src/ch99-01-03-02-contract-functions.md:26 +msgid "" +"As stated previously, public functions are accessible from outside of the contract. They must be defined inside an implementation block annotated with the `#[external(v0)]` " +"attribute. This attribute only affects the visibility (public vs private/internal), but it doesn't inform us on the ability of these functions to modify the state of the contract." +msgstr "" +"如前所述,公有函数可以从合约外部访问。它们必须定义在带有`#[external(v0)]`属性注解的实现块中。这个属性只影响可见性(public 或 private/internal),但并不影响这些函数修改合约状态的能力。" + +#: src/ch99-01-03-02-contract-functions.md:28 +msgid "" +"```rust,noplayground\n" +" #[external(v0)]\n" +" impl NameRegistry of super::INameRegistry {\n" +" fn store_name(ref self: ContractState, name: felt252) {\n" +" let caller = get_caller_address();\n" +" self._store_name(caller, name);\n" +" }\n" +"\n" +" fn get_name(self: @ContractState, address: ContractAddress) -> felt252 {\n" +" let name = self.names.read(address);\n" +" name\n" +" }\n" +" }\n" +"```" +msgstr "" +"```rust,noplayground\n" +" #[external(v0)]\n" +" impl NameRegistry of super::INameRegistry {\n" +" fn store_name(ref self: ContractState, name: felt252) {\n" +" let caller = get_caller_address();\n" +" self._store_name(caller, name);\n" +" }\n" +"\n" +" fn get_name(self: @ContractState, address: ContractAddress) -> felt252 {\n" +" let name = self.names.read(address);\n" +" name\n" +" }\n" +" }\n" +"```" + +#: src/ch99-01-03-02-contract-functions.md:43 +msgid "#### External functions" +msgstr "### 外部函数" + +#: src/ch99-01-03-02-contract-functions.md:45 +msgid "" +"External functions are functions that can modify the state of a contract. They are public and can be called by any other contract or externally.\n" +"External functions are _public_ functions where the `self: ContractState` is passed as reference with the `ref` keyword, allowing you to modify the state of the contract." +msgstr "" +"外部函数是可以修改合约状态的函数。它们是公共的,可以被任何其他合约或外部调用。\n" +"外部函数是 _public_ 函数,其中的 `self:ContractState` 以引用的形式通过关键字 `ref` 传递,使得你可以修改合约的状态。" + +#: src/ch99-01-03-02-contract-functions.md:48 +msgid "" +"```rust,noplayground\n" +" fn store_name(ref self: ContractState, name: felt252) {\n" +" let caller = get_caller_address();\n" +" self._store_name(caller, name);\n" +" }\n" +"```" +msgstr "" +"```rust,noplayground\n" +" fn store_name(ref self: ContractState, name: felt252) {\n" +" let caller = get_caller_address();\n" +" self._store_name(caller, name);\n" +" }\n" +"```" + +#: src/ch99-01-03-02-contract-functions.md:55 +msgid "#### View functions" +msgstr "### 视图函数" + +#: src/ch99-01-03-02-contract-functions.md:57 +msgid "" +"View functions are read-only functions allowing you to access data from the contract while ensuring that the state of the contract is not modified. They can be called by other " +"contracts or externally.\n" +"View functions are _public_ functions where the `self: ContractState` is passed as snapshot, preventing you from modifying the state of the contract." +msgstr "" +"视图函数是只读函数,允许你访问合约中的数据,同时确保合约的状态不会被修改。它们可以被其他合约或外部调用。\n" +"视图函数是 _public_ 函数,其中 `self.ContractState` 被作为快照传入,这会防止你修改合约的状态。" + +#: src/ch99-01-03-02-contract-functions.md:60 +msgid "" +"```rust,noplayground\n" +" fn get_name(self: @ContractState, address: ContractAddress) -> felt252 {\n" +" let name = self.names.read(address);\n" +" name\n" +" }\n" +"```" +msgstr "" +"```rust,noplayground\n" +" fn get_name(self: @ContractState, address: ContractAddress) -> felt252 {\n" +" let name = self.names.read(address);\n" +" name\n" +" }\n" +"```" + +#: src/ch99-01-03-02-contract-functions.md:67 +msgid "" +"> **Note:** It's important to note that both external and view functions are public. To create an internal function in a contract, you will need to define it outside of the " +"implementation block annotated with the `#[external(v0)]` attribute." +msgstr "> **注意:** 外部函数和视图函数都是公共函数,这一点很重要。要在合约中创建内部函数,您需要在使用 `#[external(v0)]`属性标注的实现块之外定义它。" + +#: src/ch99-01-03-02-contract-functions.md:69 +msgid "### 3. Private functions" +msgstr "### 3.私有函数" + +#: src/ch99-01-03-02-contract-functions.md:71 +msgid "" +"Functions that are not defined in a block annotated with the `#[external(v0)]` attribute are private functions (also called internal functions). They can only be called from within " +"the contract." +msgstr "未在注有`#[external(v0)]`属性的代码块中定义的函数是私有函数(也称为内部函数)。它们只能在合约内部调用。" + +#: src/ch99-01-03-02-contract-functions.md:73 src/ch99-01-03-04-reducing-boilerplate.md:5 +msgid "" +"```rust,noplayground\n" +" #[generate_trait]\n" +" impl InternalFunctions of InternalFunctionsTrait {\n" +" fn _store_name(ref self: ContractState, user: ContractAddress, name: felt252) {\n" +" let mut total_names = self.total_names.read();\n" +" self.names.write(user, name);\n" +" self.total_names.write(total_names + 1);\n" +" self.emit(StoredName { user: user, name: name });\n" +"\n" +" }\n" +" }\n" +"```" +msgstr "" +"```rust,noplayground\n" +" #[generate_trait]\n" +" impl InternalFunctions of InternalFunctionsTrait {\n" +" fn _store_name(ref self: ContractState, user: ContractAddress, name: felt252) {\n" +" let mut total_names = self.total_names.read();\n" +" self.names.write(user, name);\n" +" self.total_names.write(total_names + 1);\n" +" self.emit(StoredName { user: user, name: name });\n" +"\n" +" }\n" +" }\n" +"```" + +#: src/ch99-01-03-02-contract-functions.md:86 +msgid "" +"> Wait, what is this `#[generate_trait]` attribute? Where is the trait definition for this implementation? Well, the `#[generate_trait]` attribute is a special attribute that tells " +"the compiler to generate a trait definition for the implementation block. This allows you to get rid of the boilerplate code of defining a trait and implementing it for the " +"implementation block. We will see more about this in the [next section](./ch99-01-03-04-reducing-boilerplate.md)." +msgstr "" +"> 等等,这个`#[generate_trait]`属性是什么?这个实现的特质定义在哪里?嗯,`#[generate_trait]`属性是一个特殊的属性,它告诉编译器为实现块生成一个特质定义。这允许你摆脱为实现块定义特质和" +"实现特质的模板代码。我们将在[下一节](./ch99-01-03-04-reducing-boilerplate.md)中看到更多关于这方面的内容。" + +#: src/ch99-01-03-02-contract-functions.md:88 +msgid "" +"At this point, you might still be wondering if all of this is really necessary if you don't need to access the contract's state in your function (for example, a helper/library " +"function). As a matter of fact, you can also define internal functions outside of implementation blocks. The only reason why we _need_ to define functions inside impl blocks is if we " +"want to access the contract's state." +msgstr "" +"说到这里,您可能还在想,如果您不需要在您的函数(例如,辅助函数/库函数)中访问合约的状态,所有这些是否真的有必要。事实上,您也可以在实现块之外定义内部函数。我们 _需要_ 在实现块内部定义" +"函数的唯一原因是我们想要访问合约的状态。" + +#: src/ch99-01-03-02-contract-functions.md:90 +msgid "" +"```rust,noplayground\n" +" fn _get_contract_name() -> felt252 {\n" +" 'Name Registry'\n" +" }\n" +"```" +msgstr "" +"```rust,noplayground\n" +" fn _get_contract_name() -> felt252 {\n" +" 'Name Registry'\n" +" }\n" +"```" + +#: src/ch99-01-03-03-contract-events.md:1 +msgid "## Events" +msgstr "## 事件" + +#: src/ch99-01-03-03-contract-events.md:3 +msgid "" +"Events are custom data structures that are emitted by smart contracts during execution.\n" +"They provide a way for smart contracts to communicate with the external world by logging information\n" +"about specific occurrences in a contract." +msgstr "" +"事件是定制的数据结构,由智能合约在执行期间发出。\n" +"它们为智能合约提供了一种与外部世界沟通的方式,即记录合约中所发生的特定事情的信息。" + +#: src/ch99-01-03-03-contract-events.md:7 +msgid "" +"Events play a crucial role in the creation of smart contracts. Take, for instance, the Non-Fungible Tokens (NFTs) minted on Starknet. All of these are indexed and stored in a " +"database, then displayed to users through the use of these events. Neglecting to include an event within your NFT contract could lead to a bad user experience. This is because users " +"may not see their NFTs appear in their wallets (wallets use these indexers to display a user's NFTs)." +msgstr "" +"事件在智能合约的创建中起着至关重要的作用。以Starknet上铸造的Non-Fungible Tokens(NFTs)为例。所有这些都被索引并存储在数据库中,然后通过使用这些事件显示给用户。忘记在你的NFT合约中编写" +"一个事件可能会导致糟糕的用户体验。这是因为用户可能看不到他们的NFT出现在他们的钱包里(钱包使用这些索引器来显示用户的NFT)。" + +#: src/ch99-01-03-03-contract-events.md:9 +msgid "### Defining events" +msgstr "### 界定事件" + +#: src/ch99-01-03-03-contract-events.md:11 +msgid "" +"All the different events in the contract are defined under the `Event` enum, which implements the `starknet::Event` trait, as enum variants. This trait is defined in the core library " +"as follows:" +msgstr "合约中所有不同的事件都定义在 `Event`枚举中,它实现了`starknet::Event` trait,作为枚举变量。该trait在核心库中定义如下:" + +#: src/ch99-01-03-03-contract-events.md:13 +msgid "" +"```rust,noplayground\n" +"trait Event {\n" +" fn append_keys_and_data(self: T, ref keys: Array, ref data: Array);\n" +" fn deserialize(ref keys: Span, ref data: Span) -> Option;\n" +"}\n" +"```" +msgstr "" +"```rust,noplayground\n" +"trait Event {\n" +" fn append_keys_and_data(self: T, ref keys: Array, ref data: Array);\n" +" fn deserialize(ref keys: Span, ref data: Span) -> Option;\n" +"}\n" +"```" + +#: src/ch99-01-03-03-contract-events.md:20 +msgid "" +"The `#[derive(starknet::Event)]` attribute causes the compiler to generate an implementation for the above trait,\n" +"instantiated with the Event type, which in our example is the following enum:" +msgstr "" +"属性 `#[derive(starknet::Event)]`会使得编译器为上述trait生成一个实现、\n" +"在我们的例子中,它是下面的枚举:" + +#: src/ch99-01-03-03-contract-events.md:23 +msgid "" +"```rust,noplayground\n" +" #[event]\n" +" #[derive(Drop, starknet::Event)]\n" +" enum Event {\n" +" StoredName: StoredName,\n" +" }\n" +"\n" +" #[derive(Drop, starknet::Event)]\n" +" struct StoredName {\n" +" #[key]\n" +" user: ContractAddress,\n" +" name: felt252\n" +" }\n" +"```" +msgstr "" +"```rust,noplayground\n" +" #[event]\n" +" #[derive(Drop, starknet::Event)]\n" +" enum Event {\n" +" StoredName: StoredName,\n" +" }\n" +"\n" +" #[derive(Drop, starknet::Event)]\n" +" struct StoredName {\n" +" #[key]\n" +" user: ContractAddress,\n" +" name: felt252\n" +" }\n" +"```" + +#: src/ch99-01-03-03-contract-events.md:38 +msgid "" +"Each event variant has to be a struct of the same name as the variant, and each variant needs to implement the `starknet::Event` trait itself.\n" +"Moreover, the members of these variants must implement the `Serde` trait (_c.f._ [Appendix C: Serializing with Serde](./appendix-03-derivable-traits.md)), as keys/data are added to " +"the event using a serialization process." +msgstr "" +"每个事件变体成员必须是一个与变体同名的结构体,并且每个变体本身需要实现`starknet::Event`trait。\n" +"此外,这些变体的成员必须实现`Serde`trait(_c.f._ [Appendix C: Serializing with Serde](./appendix-03-derivable-traits.md)),因为键/数据是通过序列化过程添加到事件中的。" + +#: src/ch99-01-03-03-contract-events.md:41 +msgid "" +"The auto implementation of the `starknet::Event` trait will implement the `append_keys_and_data` function for each variant of our `Event` enum. The generated implementation will " +"append a single key based on the variant name (`StoredName`), and then recursively call `append_keys_and_data` in the impl of the Event trait for the variant’s type ." +msgstr "" +"`starknet::Event`trait的自动实现将为我们的 `Event`枚举的每个变体成员实现 `append_keys_and_data`函数。生成的实现将根据变量名(`StoredName`)附加一个单独的键,然后递归调用`Event`trait" +"的实现中的`append_keys_and_data`函数。" + +#: src/ch99-01-03-03-contract-events.md:43 +msgid "" +"In our contract, we define an event named `StoredName` that emits the contract address of the caller and the name stored within the contract, where the `user` field is serialized as " +"a key and the `name` field is serialized as data.\n" +"To index the key of an event, simply annotate it with the `#[key]` as demonstrated in the example for the `user` key." +msgstr "" +"在我们的合约中,我们定义了一个名为 `StoredName` 的事件,该事件将调用者的合约地址和存储在合约中的名称发送出去,其中 `user` 字段序列化为键,而 `name` 字段序列化为数据。\n" +"要索引一个事件的键,只需用`#[key]`注释它,如`user`键的示例所示。" + +#: src/ch99-01-03-03-contract-events.md:46 +msgid "" +"When emitting the event with `self.emit(StoredName { user: user, name: name })`, a key corresponding to the name ` StoredName`, specifically `sn_keccak(StoredName)`, is appended to " +"the keys list. `user`is serialized as key, thanks to the `#[key]` attribute, while address is serialized as data. After everything is processed, we end up with the following keys and " +"data: `keys = [sn_keccak(\"StoredName\"),user]` and `data = [address]`." +msgstr "" +"当使用 `self.emit(StoredName { user: user, name: name })` 发布事件时,与名称 `StoredName` 相对应的键,特别是 `sn_keccak(StoredName)` 会被添加到键列表中。由于使用了 `#[key]`属性," +"`user` 被序列化为 key,而地址被序列化为数据。一切处理完毕后,我们将得到以下键和数据:`keys = [sn_keccak(\"StoredName\"),user]` 和 `data = [address]`。" + +#: src/ch99-01-03-03-contract-events.md:48 +msgid "### Emitting events" +msgstr "### 发射事件" + +#: src/ch99-01-03-03-contract-events.md:50 +msgid "After defining events, we can emit them using `self.emit`, with the following syntax:" +msgstr "定义事件后,我们可以使用`self.emit`来emit它们,语法如下:" + +#: src/ch99-01-03-03-contract-events.md:52 +msgid "" +"```rust,noplayground\n" +" self.emit(StoredName { user: user, name: name });\n" +"```" +msgstr "" +"```rust,noplayground\n" +" self.emit(StoredName { user: user, name: name });\n" +"```" + +#: src/ch99-01-03-04-reducing-boilerplate.md:1 +msgid "# Reducing boilerplate" +msgstr "# 减少冗余模板代码" + +#: src/ch99-01-03-04-reducing-boilerplate.md:3 +msgid "In a previous section, we saw this example of an implementation block in a contract that didn't have any corresponding trait." +msgstr "在上一节中,我们看到了这样一个示例:在一个没有任何相应trait的合约中,有一个实现块。" + +#: src/ch99-01-03-04-reducing-boilerplate.md:18 +msgid "" +"It's not the first time that we encounter this attribute, we already talked about in it [Traits in Cairo](./ch07-02-traits-in-cairo.md). In this section, we'll be taking a deeper " +"look at it and see how it can be used in contracts." +msgstr "这不是我们第一次遇到这个属性,我们已经在[Cairo中的Traits](./ch07-02-traits-in-cairo.md)中讨论过。在本节中,我们将对它进行更深入的了解,看看它在合约中是如何使用的。" + +#: src/ch99-01-03-04-reducing-boilerplate.md:20 +msgid "" +"Recall that in order to access the ContractState in a function, this function must be defined in an implementation block whose generic parameter is `ContractState`. This implies that " +"we first need to define a generic trait that takes a `TContractState`, and then implement this trait for the `ContractState` type.\n" +"But by using the `#[generate_trait]` attribute, this whole process can be skipped and we can simply define the implementation block directly, without any generic parameter, and use " +"`self: ContractState` in our functions." +msgstr "" +"回想一下,为了在函数中访问 ContractState,该函数必须定义在泛型参数为 `ContractState` 的实现块中。这意味着我们首先需要定义一个接受`TContractState`的泛型trait,然后为`ContractState`类型" +"实现这个trait。\n" +"但是通过使用 `#[generate_trait]` 属性,我们可以跳过整个过程,从而简单地直接定义实现块,不需要任何泛型参数,并在我们的函数中使用 `self.ContractState` 属性。" + +#: src/ch99-01-03-04-reducing-boilerplate.md:23 +msgid "If we had to manually define the trait for the `InternalFunctions` implementation, it would look something like this:" +msgstr "如果我们必须手动定义 `InternalFunctions` 所实现的trait,它将看起来像这样:" + +#: src/ch99-01-03-04-reducing-boilerplate.md:25 +msgid "" +"```rust,noplayground\n" +" trait InternalFunctionsTrait {\n" +" fn _store_name(ref self: TContractState, user: ContractAddress, name: felt252);\n" +" }\n" +" impl InternalFunctions of InternalFunctionsTrait {\n" +" fn _store_name(ref self: ContractState, user: ContractAddress, name: felt252) {\n" +" let mut total_names = self.total_names.read();\n" +" self.names.write(user, name);\n" +" self.total_names.write(total_names + 1);\n" +" self.emit(Event::StoredName(StoredName { user: user, name: name }));\n" +"\n" +" }\n" +" }\n" +"}\n" +"\n" +"\n" +"```" +msgstr "" +"```rust,noplayground\n" +" trait InternalFunctionsTrait {\n" +" fn _store_name(ref self: TContractState, user: ContractAddress, name: felt252);\n" +" }\n" +" impl InternalFunctions of InternalFunctionsTrait {\n" +" fn _store_name(ref self: ContractState, user: ContractAddress, name: felt252) {\n" +" let mut total_names = self.total_names.read();\n" +" self.names.write(user, name);\n" +" self.total_names.write(total_names + 1);\n" +" self.emit(Event::StoredName(StoredName { user: user, name: name }));\n" +"\n" +" }\n" +" }\n" +"}\n" +"\n" +"\n" +"```" + +#: src/ch99-01-03-05-optimizing-storage.md:1 +msgid "## Storage Optimization with `StorePacking`" +msgstr "## 使用`StorePacking`优化存储" + +#: src/ch99-01-03-05-optimizing-storage.md:3 +msgid "" +"Bit-packing is a simple concept: Use as few bit as possible to store a piece of data. When done well, it can significantly reduce the size of the data you need to store. This is " +"especially important in smart contracts, where storage is expensive." +msgstr "Bit-packing(位打包)是一个简单的概念:使用尽可能少的位来存储数据。如果做得好,它可以大大减少需要存储的数据大小。这在智能合约中尤为重要,因为智能合约的存储成本很高。" + +#: src/ch99-01-03-05-optimizing-storage.md:5 +msgid "" +"When writing Cairo smart contracts, it is important to optimize storage usage to reduce gas costs. Indeed, most of the cost associated to a transaction is related to storage updates; " +"and each storage slot costs gas to write to.\n" +"This means that by packing multiple values into fewer slots, you can decrease the gas cost incurred to the users of your smart contract." +msgstr "" +"在编写Cairo智能合约时,优化存储使用以降低gas成本非常重要。事实上,一笔交易的大部分成本都与存储更新有关;而每个存储槽的写入都会产生gas成本。\n" +"这意味着,通过将多个值打包到更少的槽中,可以降低智能合约用户的gas成本。" + +#: src/ch99-01-03-05-optimizing-storage.md:8 +msgid "" +"Cairo provides the `StorePacking` trait to enable packing struct fields into a fewer number of storage slots. For example, consider a `Sizes` struct with 3 fields of different types. " +"The total size is 8 + 32 + 64 = 104 bits. This is less than the 128 bits of a single `u128`. This means we can pack all 3 fields into a single `u128` variable. Since a storage slot " +"can hold up to 251 bits, our packed value will take only one storage slot instead of 3." +msgstr "" +"Cairo 提供了 `StorePacking` 特性,可以将结构体字段打包让其占用更少的存储槽。例如,考虑一个有 3 个不同类型字段的 `Sizes` 结构。总大小为 8 + 32 + 64 = 104 位。这小于单个 `u128` 的 128 " +"位。这意味着我们可以将所有 3 个字段打包到一个 `u128` 变量中。由于一个存储槽最多可容纳 251 位,我们打包后的值将只占用一个存储槽,而不是三个。" + +#: src/ch99-01-03-05-optimizing-storage.md:10 +msgid "" +"```rust\n" +"use starknet::{StorePacking};\n" +"use integer::{u128_safe_divmod, u128_as_non_zero};\n" +"\n" +"#[derive(Drop, Serde)]\n" +"struct Sizes {\n" +" tiny: u8,\n" +" small: u32,\n" +" medium: u64,\n" +"}\n" +"\n" +"const TWO_POW_8: u128 = 0x100;\n" +"const TWO_POW_40: u128 = 0x10000000000;\n" +"\n" +"const MASK_8: u128 = 0xff;\n" +"const MASK_32: u128 = 0xffffffff;\n" +"\n" +"\n" +"impl SizesStorePacking of StorePacking {\n" +" fn pack(value: Sizes) -> u128 {\n" +" value.tiny.into() + (value.small.into() * TWO_POW_8) + (value.medium.into() * TWO_POW_40)\n" +" }\n" +"\n" +" fn unpack(value: u128) -> Sizes {\n" +" let tiny = value & MASK_8;\n" +" let small = (value / TWO_POW_8) & MASK_32;\n" +" let medium = (value / TWO_POW_40);\n" +"\n" +" Sizes {\n" +" tiny: tiny.try_into().unwrap(),\n" +" small: small.try_into().unwrap(),\n" +" medium: medium.try_into().unwrap(),\n" +" }\n" +" }\n" +"}\n" +"\n" +"#[starknet::contract]\n" +"mod SizeFactory {\n" +" use super::Sizes;\n" +" use super::SizesStorePacking; //don't forget to import it!\n" +"\n" +" #[storage]\n" +" struct Storage {\n" +" remaining_sizes: Sizes\n" +" }\n" +"\n" +" #[external(v0)]\n" +" fn update_sizes(ref self: ContractState, sizes: Sizes) {\n" +" // This will automatically pack the\n" +" // struct into a single u128\n" +" self.remaining_sizes.write(sizes);\n" +" }\n" +"\n" +"\n" +" #[external(v0)]\n" +" fn get_sizes(ref self: ContractState) -> Sizes {\n" +" // this will automatically unpack the\n" +" // packed-representation into the Sizes struct\n" +" self.remaining_sizes.read()\n" +" }\n" +"}\n" +"\n" +"\n" +"```" +msgstr "" +"```rust\n" +"use starknet::{StorePacking};\n" +"use integer::{u128_safe_divmod, u128_as_non_zero};\n" +"\n" +"#[derive(Drop, Serde)]\n" +"struct Sizes {\n" +" tiny: u8,\n" +" small: u32,\n" +" medium: u64,\n" +"}\n" +"\n" +"const TWO_POW_8: u128 = 0x100;\n" +"const TWO_POW_40: u128 = 0x10000000000;\n" +"\n" +"const MASK_8: u128 = 0xff;\n" +"const MASK_32: u128 = 0xffffffff;\n" +"\n" +"\n" +"impl SizesStorePacking of StorePacking {\n" +" fn pack(value: Sizes) -> u128 {\n" +" value.tiny.into() + (value.small.into() * TWO_POW_8) + (value.medium.into() * TWO_POW_40)\n" +" }\n" +"\n" +" fn unpack(value: u128) -> Sizes {\n" +" let tiny = value & MASK_8;\n" +" let small = (value / TWO_POW_8) & MASK_32;\n" +" let medium = (value / TWO_POW_40);\n" +"\n" +" Sizes {\n" +" tiny: tiny.try_into().unwrap(),\n" +" small: small.try_into().unwrap(),\n" +" medium: medium.try_into().unwrap(),\n" +" }\n" +" }\n" +"}\n" +"\n" +"#[starknet::contract]\n" +"mod SizeFactory {\n" +" use super::Sizes;\n" +" use super::SizesStorePacking; //don't forget to import it!\n" +"\n" +" #[storage]\n" +" struct Storage {\n" +" remaining_sizes: Sizes\n" +" }\n" +"\n" +" #[external(v0)]\n" +" fn update_sizes(ref self: ContractState, sizes: Sizes) {\n" +" // This will automatically pack the\n" +" // struct into a single u128\n" +" self.remaining_sizes.write(sizes);\n" +" }\n" +"\n" +"\n" +" #[external(v0)]\n" +" fn get_sizes(ref self: ContractState) -> Sizes {\n" +" // this will automatically unpack the\n" +" // packed-representation into the Sizes struct\n" +" self.remaining_sizes.read()\n" +" }\n" +"}\n" +"\n" +"\n" +"```" + +#: src/ch99-01-03-05-optimizing-storage.md:75 +msgid "Optimizing storage by implementing the `StorePacking` trait" +msgstr "通过实现 `StorePacking` trait来优化存储" + +#: src/ch99-01-03-05-optimizing-storage.md:77 +msgid "" +"The `pack` function combines all three fields into a single `u128` value by performing bitshift and additions. The `unpack` reverses this process to extract the original fields back " +"into a struct." +msgstr "`pack` 函数通过位移和加法将所有三个字段合并为一个 `u128`值。`unpack`则将这一过程逆转,将原始字段提取回结构体中。" + +#: src/ch99-01-03-05-optimizing-storage.md:79 +msgid "" +"If you're not familiar with bit operations, here's an explanation of the operations performed in the example:\n" +"The goal is to pack the `tiny`, `small`, and `medium` fields into a single `u128` value.\n" +"First, when packing:" +msgstr "" +"如果您对位运算不熟悉,这里将解释示例中执行的运算:\n" +"我们的目标是将 `tiny`, `small`, 还有 `medium`字段打包成一个 `u128` 值。\n" +"首先,打包时:" + +#: src/ch99-01-03-05-optimizing-storage.md:83 +msgid "" +"- `tiny` is a `u8` so we just convert it directly to a `u128` with `.into()`. This creates a `u128` value with the low 8 bits set to `tiny`'s value.\n" +"- `small` is a `u32` so we first shift it left by 8 bits (add 8 bits with the value 0 to the left) to create room for the 8 bites taken by `tiny`. Then we add `tiny` to `small` to " +"combine them into a single `u128` value. The value of `tiny` now takes bits 0-7 and the value of small takes bits 8-39.\n" +"- Similarly `medium` is a `u64` so we shift it left by 40 (8 + 32) bits (`TWO_POW_40`) to make space for the previous fields. This takes bits 40-103." +msgstr "" +"- `tiny` 是一个 `u8`,因此我们只需用 `.into()` 将其直接转换为 `u128`。这会创建一个低 8 位设置为 `tiny` 值的 `u128` 值。\n" +"- `small` 是一个 `u32`,因此我们首先将它左移 8 位(向左添加 8 位值为 0 的比特),为 `tiny` 占用的 8 位留出空间。然后,我们将 `tiny` 添加到 `small` 中,将它们合并成一个 `u128` 值。现" +"在,`tiny` 的值占 0-7 位,`small` 的值占 8-39 位。\n" +"- 同样,`medium` 是一个 `u64`,因此我们将其左移 40 (8 + 32) 位(`TWO_POW_40`),为前面的字段腾出空间。这需要占用 40-103 位。" + +#: src/ch99-01-03-05-optimizing-storage.md:87 +msgid "When unpacking:" +msgstr "当解包时:" + +#: src/ch99-01-03-05-optimizing-storage.md:89 +msgid "" +"- First we extract `tiny` by bitwise ANDing (&) with a bitmask of 8 ones (`& MASK_8`). This isolates the lowest 8 bits of the packed value, which is `tiny`'s value.\n" +"- For `small`, we right shift by 8 bits (`/ TWO_POW_8`) to align it with the bitmask, then use bitwise AND with the 32 ones bitmask.\n" +"- For `medium` we right shift by 40 bits. Since it is the last value packed, we don't need to apply a bitmask as the higher bits are already 0." +msgstr "" +"- 首先,我们通过与 8 个 1 的位掩码(`& MASK_8`)进行比特 AND(&)来提取`tiny`。这样就分离出打包值的最低 8 位,也就是 `tiny` 的值。\n" +"- 对于 `small`,我们右移 8 位 (`/TWO_POW_8`),使其与位掩码对齐,然后与 32 个 1 的位掩码进行位和运算。\n" +"- 对于 `medium`,我们右移 40 位。由于它是最后打包的值,我们不需要应用位掩码,因为高位已经为 0。" + +#: src/ch99-01-03-05-optimizing-storage.md:93 +msgid "" +"This technique can be used for any group of fields that fit within the bit size of the packed storage type. For example, if you have a struct with multiple fields whose bit sizes add " +"up to 256 bits, you can pack them into a single `u256` variable. If the bit sizes add up to 512 bits, you can pack them into a single `u512` variable, and so on. You can define your " +"own structs and logic to pack and unpack them." +msgstr "" +"这种技术可用于任何一组适合打包存储类型位大小的字段。例如,如果一个结构体有多个字段,其位大小加起来为 256 位,那么可以将它们打包成一个 `u256` 变量。如果字段的位数加起来是 512 位,则可" +"以将它们打包到一个 `u512` 变量中,依此类推。你可以定义自己的结构和逻辑来打包和解包它们。" + +#: src/ch99-01-03-05-optimizing-storage.md:95 +msgid "" +"The rest of the work is done magically by the compiler - if a type implements the `StorePacking` trait, then the compiler will know it can use the `StoreUsingPacking` implementation " +"of the `Store` trait in order to pack before writing and unpack after reading from storage.\n" +"One important details, however, is that the type that `StorePacking::pack` spits out also has to implement `Store` for `StoreUsingPacking` to work. Most of the time, we will want to " +"pack into a felt252 or u256 - but if you want to pack into a type of your own, make sure that this one implements the `Store` trait." +msgstr "" +"其余的工作则由编译器神奇地完成--如果一个类型实现了 `StorePacking` 特性,那么编译器就会知道它可以使用 `StoreUsingPacking` 特性的 `StoreUsingPacking` 实现,以便在写入之前打包,在从存储" +"空间读取之后解包。\n" +"然而,一个重要的细节是,`StorePacking::pack` 输出的类型也必须实现 `Store` 才能让 `StoreUsingPacking` 起作用。大多数情况下,我们希望将数据打包到 felt252 或 u256 中,但如果你想打包到自" +"己的类型中,请确保该类型实现了 `Store` 特性。" + +#: src/ch99-02-00-abis-and-cross-contract-interactions.md:1 +msgid "# Starknet contracts: ABIs and cross-contract interactions" +msgstr "# Starknet合约:ABI和跨合约交互" + +#: src/ch99-02-00-abis-and-cross-contract-interactions.md:3 +msgid "" +"Interactions between smart contracts are an important feature when creating complex decentralized applications, as it allows for composability and separation of concerns. This " +"chapter sheds light on how to make contracts interact with each other." +msgstr "在创建复杂的去中心化应用程序时,智能合约之间的交互是一项重要功能,因为它可以实现可组合性和关注点分离。本章将介绍如何实现合约之间的交互。" + +#: src/ch99-02-00-abis-and-cross-contract-interactions.md:5 +msgid "Specifically, you'll learn about ABIs, contract interfaces, the contract and library dispatchers and their low-level system call equivalents!" +msgstr "具体来说,您将了解 ABI、合约接口、合约和库调度程序及其与底层系统调用等同程序!" + +#: src/ch99-02-01-abis-and-interfaces.md:1 +msgid "# ABIs and Contract Interfaces" +msgstr "# ABI和合约接口" + +#: src/ch99-02-01-abis-and-interfaces.md:3 +msgid "Cross-contract interactions between smart contracts on a blockchain is a common practice which enables us to build flexible contracts that can speak with each other." +msgstr "区块链上的智能合约之间的跨合约互动是一种常见的做法,它使我们能够建立灵活的合约,相互对话。" + +#: src/ch99-02-01-abis-and-interfaces.md:5 +msgid "Achieving this on Starknet requires something we call an interface." +msgstr "在Starknet上实现这一点需要我们称之为接口的东西。" + +#: src/ch99-02-01-abis-and-interfaces.md:7 +msgid "## ABI - Application Binary Interface" +msgstr "## ABI - 应用二进制接口" + +#: src/ch99-02-01-abis-and-interfaces.md:9 +msgid "" +"On Starknet, the ABI of a contract is a JSON representation of the contract's functions and structures, giving anyone (or any other contract) the ability to form encoded calls to it. " +"It is a blueprint that instructs how functions should be called, what input parameters they expect, and in what format." +msgstr "在Starknet上,合约的 ABI 是合约函数和结构的 JSON 表示,使任何人(或任何其他合约)都能对其进行编码调用。它是一个蓝图,指示如何调用函数、以及它们所需的输入参数和格式。" + +#: src/ch99-02-01-abis-and-interfaces.md:11 +msgid "" +"While we write our smart contract logics in high-level Cairo, they are stored on the VM as executable bytecodes which are in binary formats. Since this bytecode is not human " +"readable, it requires interpretation to be understood. This is where ABIs come into play, defining specific methods which can be called to a smart contract for execution. Without an " +"ABI, it becomes practically impossible for external actors to understand how to interact with a contract." +msgstr "" +"虽然我们用高级Cairo语言编写智能合约逻辑,但它们在虚拟机上存储为二进制格式的可执行字节码。由于这种字节码不是人类可读的,因此需要解释才能理解。这就是 ABI 的作用所在,它定义了可以调用智" +"能合约执行的特定方法。如果没有 ABI,外部参与者几乎不可能理解如何与合约交互。" + +#: src/ch99-02-01-abis-and-interfaces.md:13 +msgid "" +"ABIs are typically used in dApps frontends, allowing it to format data correctly, making it understandable by the smart contract and vice versa. When you interact with a smart " +"contract through a block explorer like [Voyager](https://voyager.online/) or [Starkscan](https://starkscan.co/), they use the contract's ABI to format the data you send to the " +"contract and the data it returns." +msgstr "" +"ABI 通常用于 dApps 前端,使其能够正确格式化数据,使智能合约能够理解数据,反之亦然。当你通过 [Voyager](https://voyager.online/) 或 [Starkscan](https://starkscan.co/) 等区块资源管理器与" +"智能合约交互时,它们会使用合约的 ABI 来格式化你发送给合约的数据以及合约返回的数据。" + +#: src/ch99-02-01-abis-and-interfaces.md:15 +msgid "## Interface" +msgstr "## 接口" + +#: src/ch99-02-01-abis-and-interfaces.md:17 +msgid "" +"The interface of a contract is a list of the functions it exposes publically.\n" +"It specifies the function signatures (name, parameters, visibility and return value) contained in a smart contract without including the function body." +msgstr "" +"合约接口是合约公开的函数列表。\n" +"它指定了智能合约中包含的函数签名(名称、参数、可见性和返回值),但不包括函数体。" + +#: src/ch99-02-01-abis-and-interfaces.md:20 +msgid "" +"Contract interfaces in Cairo are traits annotated with the `#[starknet::interface]` attribute. If you are new to traits, check out the dedicated chapter on [traits](./ch07-02-traits-" +"in-cairo.md)." +msgstr "Cairo中的接口是带有`#[starknet::interface]`属性的trait。如果你不太了解trait,请查看关于[traits](./ch07-02-traits-in-cairo.md)的专门章节。" + +#: src/ch99-02-01-abis-and-interfaces.md:22 +msgid "" +"One important specification is that this trait must be generic over the `TContractState` type. This is required for functions to access the contract's storage, so that they can read " +"and write to it." +msgstr "一个重要的规范是,该trait必须是基于 `TContractState` 类型的泛型。函数访问想要合约存储空间必须基于此trait,这样函数才能读写合约。" + +#: src/ch99-02-01-abis-and-interfaces.md:24 +msgid "> Note: The contract constructor is not part of the interface. Nor are internal functions part of the interface." +msgstr "> 注意:合约的构造函数不是接口的一部分。内部函数也不是接口的一部分。" + +#: src/ch99-02-01-abis-and-interfaces.md:26 +msgid "" +"Here's a sample interface for an ERC20 token contract. As you can see, it's a generic trait over the `TContractState` type. `view` functions have a self parameter of type " +"`@TContractState`, while `external` functions have a self parameter of type passed by reference `ref self: TContractState`." +msgstr "" +"下面是 ERC20 代币合约的接口示例。正如您所看到的,它是在 `TContractState` 类型上的泛型trait。`view`函数有一个类型为`@TContractState`的自参数,而 `external` 函数有一个类型为 `ref self: " +"TContractState`.的自参数。" + +#: src/ch99-02-01-abis-and-interfaces.md:28 +msgid "" +"```rust,noplayground\n" +"use starknet::ContractAddress;\n" +"\n" +"#[starknet::interface]\n" +"trait IERC20 {\n" +" fn name(self: @TContractState) -> felt252;\n" +"\n" +" fn symbol(self: @TContractState) -> felt252;\n" +"\n" +" fn decimals(self: @TContractState) -> u8;\n" +"\n" +" fn total_supply(self: @TContractState) -> u256;\n" +"\n" +" fn balance_of(self: @TContractState, account: ContractAddress) -> u256;\n" +"\n" +" fn allowance(self: @TContractState, owner: ContractAddress, spender: ContractAddress) -> u256;\n" +"\n" +" fn transfer(ref self: TContractState, recipient: ContractAddress, amount: u256) -> bool;\n" +"\n" +" fn transfer_from(\n" +" ref self: TContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256\n" +" ) -> bool;\n" +"\n" +" fn approve(ref self: TContractState, spender: ContractAddress, amount: u256) -> bool;\n" +"}\n" +"```" +msgstr "" +"```rust,noplayground\n" +"use starknet::ContractAddress;\n" +"\n" +"#[starknet::interface]\n" +"trait IERC20 {\n" +" fn name(self: @TContractState) -> felt252;\n" +"\n" +" fn symbol(self: @TContractState) -> felt252;\n" +"\n" +" fn decimals(self: @TContractState) -> u8;\n" +"\n" +" fn total_supply(self: @TContractState) -> u256;\n" +"\n" +" fn balance_of(self: @TContractState, account: ContractAddress) -> u256;\n" +"\n" +" fn allowance(self: @TContractState, owner: ContractAddress, spender: ContractAddress) -> u256;\n" +"\n" +" fn transfer(ref self: TContractState, recipient: ContractAddress, amount: u256) -> bool;\n" +"\n" +" fn transfer_from(\n" +" ref self: TContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256\n" +" ) -> bool;\n" +"\n" +" fn approve(ref self: TContractState, spender: ContractAddress, amount: u256) -> bool;\n" +"}\n" +"```" + +#: src/ch99-02-01-abis-and-interfaces.md:55 +msgid "Listing 99-4: A simple ERC20 Interface" +msgstr "示例99-4:一个简单的ERC20接口" + +#: src/ch99-02-01-abis-and-interfaces.md:57 +msgid "In the next chapter, we will see how we can call contracts from other smart contracts using _dispatchers_ and _syscalls_ ." +msgstr "在下一章,我们将研究如何使用 合约调度器 ( _dispatchers_ )、和 系统调用( _syscalls_ ) 来调用其他智能合约。" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:1 +msgid "# Interacting with other contracts and classes using Dispatchers and syscalls" +msgstr "# 使用调度程序和系统调用与其他合约和类交互" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:3 +msgid "" +"Each time a contract interface is defined, two dispatchers are automatically created and exported by the compiler. Let's consider an interface that we named IERC20, these would be:" +msgstr "每次定义合约接口时,编译器都会自动创建并导出两个调度程序。我们将一个接口命名为 IERC20,它们是:" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:5 +msgid "" +"1. The Contract Dispatcher `IERC20Dispatcher`\n" +"2. The Library Dispatcher `IERC20LibraryDispatcher`" +msgstr "" +"1. 合约调度器 `IERC20Dispatcher`\n" +"2. 库调度器 `IERC20LibraryDispatcher`" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:8 +msgid "The compiler also generates a trait `IERC20DispatcherTrait`, allowing us to call the functions defined in the interface on the dispatcher struct." +msgstr "编译器还会生成一个名为 \"IERC20DispatcherTrait\"的trait,这使得我们可以在调度器结构上调用接口中定义的函数。" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:10 +msgid "In this chapter, we are going to discuss what these are, how they work and how to use them." +msgstr "在本章中,我们将讨论它们是什么、如何工作以及如何使用。" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:12 +msgid "To effectively break down the concepts in this chapter, we are going to be using the IERC20 interface from the previous chapter (refer to Listing 99-4):" +msgstr "为了有效地拆解本章的概念,我们将使用前一章的IERC20接口(参考示例99-4):" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:14 +msgid "## Contract Dispatcher" +msgstr "## 合约调度器" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:16 +msgid "" +"As mentioned previously, traits annotated with the `#[starknet::interface]` attribute automatically generate a dispatcher and a trait on compilation.\n" +"Our `IERC20` interface is expanded into something like this:" +msgstr "" +"如前所述,使用 `#[starknet::interface]` 属性注释的特质会在编译时自动生成一个调度器和一个trait。\n" +"我们的 `IERC20` 接口扩展至如下:" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:19 +msgid "" +"**Note:** The expanded code for our IERC20 interface is a lot longer, but to keep this chapter concise and straight to the point, we focused on one view function `name`, and one " +"external function `transfer`." +msgstr "**注:** IERC20 界面的扩展代码较长,但为了使本章简明扼要,我们将重点放在一个视图函数 `name` 和一个外部函数 `transfer`上。" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:21 +msgid "" +"```rust,noplayground\n" +"//TAG: does_not_compile\n" +"use starknet::{ContractAddress};\n" +"\n" +"trait IERC20DispatcherTrait {\n" +" fn name(self: T) -> felt252;\n" +" fn transfer(self: T, recipient: ContractAddress, amount: u256);\n" +"}\n" +"\n" +"#[derive(Copy, Drop, starknet::Store, Serde)]\n" +"struct IERC20Dispatcher {\n" +" contract_address: starknet::ContractAddress,\n" +"}\n" +"\n" +"impl IERC20DispatcherImpl of IERC20DispatcherTrait {\n" +" fn name(\n" +" self: IERC20Dispatcher\n" +" ) -> felt252 { // starknet::call_contract_syscall is called in here\n" +" }\n" +" fn transfer(\n" +" self: IERC20Dispatcher, recipient: ContractAddress, amount: u256\n" +" ) { // starknet::call_contract_syscall is called in here\n" +" }\n" +"}\n" +"```" +msgstr "" +"```rust,noplayground\n" +"//TAG: does_not_compile\n" +"use starknet::{ContractAddress};\n" +"\n" +"trait IERC20DispatcherTrait {\n" +" fn name(self: T) -> felt252;\n" +" fn transfer(self: T, recipient: ContractAddress, amount: u256);\n" +"}\n" +"\n" +"#[derive(Copy, Drop, starknet::Store, Serde)]\n" +"struct IERC20Dispatcher {\n" +" contract_address: starknet::ContractAddress,\n" +"}\n" +"\n" +"impl IERC20DispatcherImpl of IERC20DispatcherTrait {\n" +" fn name(\n" +" self: IERC20Dispatcher\n" +" ) -> felt252 { // starknet::call_contract_syscall is called in here\n" +" }\n" +" fn transfer(\n" +" self: IERC20Dispatcher, recipient: ContractAddress, amount: u256\n" +" ) { // starknet::call_contract_syscall is called in here\n" +" }\n" +"}\n" +"```" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:47 +msgid "Listing 99-5: An expanded form of the IERC20 trait" +msgstr "示例99-5:IERC20 trait的扩展" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:49 +msgid "" +"As you can see, the \"classic\" dispatcher is just a struct that wraps a contract address and implements the `DispatcherTrait` generated by the compiler, allowing us to call " +"functions from another contract. This means that we can instantiate a struct with the address of the contract we want to call, and then simply call the functions defined in the " +"interface on the dispatcher struct as if they were methods of that type." +msgstr "" +"如你所见,\"典型\"的调度器只是一个结构体,它封装了一个合约地址,并实现了编译器生成的 `DispatcherTrait`,允许我们调用另一个合约的函数。这意味着我们可以用要调用的合约地址实例化一个结构" +"体,然后简单地调用调度器结构体上的接口定义的函数,就像调用该类型的方法一样。" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:51 +msgid "It's also worthy of note that all these are abstracted behind the scenes thanks to the power of Cairo plugins." +msgstr "而且值得注意的是,所有这些都被Cairo插件在幕后抽象化了。" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:53 +msgid "### Calling Contracts using the Contract Dispatcher" +msgstr "### 使用合约调度器调用合约" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:55 +msgid "" +"This is an example of a contract named `TokenWrapper` using a dispatcher to call functions defined on an ERC-20 token. Calling `transfer_token` will modify the state of the contract " +"deployed at `contract_address`." +msgstr "这是一个名为 `TokenWrapper` 的合约使用调度器调用定义在 ERC-20 令牌上的函数的示例。调用 `transfer_token` 将修改部署在 `contract_address` 的合约状态。" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:57 +msgid "" +"```rust,noplayground\n" +"# use starknet::ContractAddress;\n" +"# \n" +"# #[starknet::interface]\n" +"# trait IERC20 {\n" +"# fn name(self: @TContractState) -> felt252;\n" +"# \n" +"# fn symbol(self: @TContractState) -> felt252;\n" +"# \n" +"# fn decimals(self: @TContractState) -> u8;\n" +"# \n" +"# fn total_supply(self: @TContractState) -> u256;\n" +"# \n" +"# fn balance_of(self: @TContractState, account: ContractAddress) -> u256;\n" +"# \n" +"# fn allowance(self: @TContractState, owner: ContractAddress, spender: ContractAddress) -> u256;\n" +"# \n" +"# fn transfer(ref self: TContractState, recipient: ContractAddress, amount: u256) -> bool;\n" +"# \n" +"# fn transfer_from(\n" +"# ref self: TContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256\n" +"# ) -> bool;\n" +"# \n" +"# fn approve(ref self: TContractState, spender: ContractAddress, amount: u256) -> bool;\n" +"# }\n" +"# \n" +"# #[starknet::interface]\n" +"# trait ITokenWrapper {\n" +"# fn token_name(self: @TContractState, contract_address: ContractAddress) -> felt252;\n" +"# \n" +"# fn transfer_token(\n" +"# ref self: TContractState,\n" +"# contract_address: ContractAddress,\n" +"# recipient: ContractAddress,\n" +"# amount: u256\n" +"# ) -> bool;\n" +"# }\n" +"# \n" +"# \n" +"//**** Specify interface here ****//\n" +"#[starknet::contract]\n" +"mod TokenWrapper {\n" +" use super::IERC20DispatcherTrait;\n" +" use super::IERC20Dispatcher;\n" +" use super::ITokenWrapper;\n" +" use starknet::ContractAddress;\n" +"\n" +" #[storage]\n" +" struct Storage {}\n" +"\n" +" impl TokenWrapper of ITokenWrapper {\n" +" fn token_name(self: @ContractState, contract_address: ContractAddress) -> felt252 {\n" +" IERC20Dispatcher { contract_address }.name()\n" +" }\n" +"\n" +" fn transfer_token(\n" +" ref self: ContractState,\n" +" contract_address: ContractAddress,\n" +" recipient: ContractAddress,\n" +" amount: u256\n" +" ) -> bool {\n" +" IERC20Dispatcher { contract_address }.transfer(recipient, amount)\n" +" }\n" +" }\n" +"}\n" +"# \n" +"# \n" +"```" +msgstr "" +"```rust,noplayground\n" +"# use starknet::ContractAddress;\n" +"# \n" +"# #[starknet::interface]\n" +"# trait IERC20 {\n" +"# fn name(self: @TContractState) -> felt252;\n" +"# \n" +"# fn symbol(self: @TContractState) -> felt252;\n" +"# \n" +"# fn decimals(self: @TContractState) -> u8;\n" +"# \n" +"# fn total_supply(self: @TContractState) -> u256;\n" +"# \n" +"# fn balance_of(self: @TContractState, account: ContractAddress) -> u256;\n" +"# \n" +"# fn allowance(self: @TContractState, owner: ContractAddress, spender: ContractAddress) -> u256;\n" +"# \n" +"# fn transfer(ref self: TContractState, recipient: ContractAddress, amount: u256) -> bool;\n" +"# \n" +"# fn transfer_from(\n" +"# ref self: TContractState, sender: ContractAddress, recipient: ContractAddress, amount: u256\n" +"# ) -> bool;\n" +"# \n" +"# fn approve(ref self: TContractState, spender: ContractAddress, amount: u256) -> bool;\n" +"# }\n" +"# \n" +"# #[starknet::interface]\n" +"# trait ITokenWrapper {\n" +"# fn token_name(self: @TContractState, contract_address: ContractAddress) -> felt252;\n" +"# \n" +"# fn transfer_token(\n" +"# ref self: TContractState,\n" +"# contract_address: ContractAddress,\n" +"# recipient: ContractAddress,\n" +"# amount: u256\n" +"# ) -> bool;\n" +"# }\n" +"# \n" +"# \n" +"//**** Specify interface here ****//\n" +"#[starknet::contract]\n" +"mod TokenWrapper {\n" +" use super::IERC20DispatcherTrait;\n" +" use super::IERC20Dispatcher;\n" +" use super::ITokenWrapper;\n" +" use starknet::ContractAddress;\n" +"\n" +" #[storage]\n" +" struct Storage {}\n" +"\n" +" impl TokenWrapper of ITokenWrapper {\n" +" fn token_name(self: @ContractState, contract_address: ContractAddress) -> felt252 {\n" +" IERC20Dispatcher { contract_address }.name()\n" +" }\n" +"\n" +" fn transfer_token(\n" +" ref self: ContractState,\n" +" contract_address: ContractAddress,\n" +" recipient: ContractAddress,\n" +" amount: u256\n" +" ) -> bool {\n" +" IERC20Dispatcher { contract_address }.transfer(recipient, amount)\n" +" }\n" +" }\n" +"}\n" +"# \n" +"# \n" +"```" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:126 +msgid "Listing 99-6: A sample contract which uses the Contract Dispatcher" +msgstr "示例99-6:一个使用合约调度器的样本合约" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:128 +msgid "" +"As you can see, we had to first import `IERC20DispatcherTrait` and `IERC20Dispatcher` generated by the compiler, which allows us to make calls to the methods implemented for the " +"`IERC20Dispatcher` struct (`name`, `transfer`, etc), passing in the `contract_address` of the contract we want to call in the `IERC20Dispatcher` struct." +msgstr "" +"正如您所看到的,我们必须首先导入编译器生成的 `IERC20DispatcherTrait` 和 `IERC20Dispatcher`,这样我们就可以调用为 `IERC20Dispatcher` 结构实现的方法(`name`、`transfer` 等),并在 " +"`IERC20Dispatcher` 结构中传入我们要调用的合约的 `contract_address` 。" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:130 +msgid "## Library Dispatcher" +msgstr "## 库调度器" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:132 +msgid "" +"The key difference between the contract dispatcher and the library dispatcher lies in the execution context of the logic defined in the class. While regular dispatchers are used to " +"call functions from **contracts** (with an associated state), library dispatchers are used to call **classes** (stateless)." +msgstr "合约调度器和库调度器的主要区别在于类中定义的逻辑的执行上下文。普通调度程序用于调用来自 **合约**(有相关状态)的函数,而库调度程序则用于调用 **类**(无状态)。" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:134 +msgid "Let's consider two contracts A and B." +msgstr "让我们设想两个合约 A 和 B。" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:136 +msgid "" +"When A uses `IBDispatcher` to call functions from the **contract** B, the execution context of the logic defined in B is that of B. This means that the value returned by " +"`get_caller_address()` in B will return the address of A, and updating a storage variable in B will update the storage of B." +msgstr "" +"当A使用 `IBDispatcher` 来调用 **合约** B中的函数时,定义在B中的逻辑的执行上下文是B的。这意味着在B中由`get_caller_address()`返回的值将返回A的地址,并且在B中更新存储变量将更新B的存储。" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:138 +msgid "" +"When A uses `IBLibraryDispatcher` to call functions from the **class** of B, the execution context of the logic defined in B's class is that of A. This means that the value returned " +"by `get_caller_address()` variable in B will return the address of the caller of A, and updating a storage variable in B's class will update the storage of A (remember that the " +"**class** of B is stateless; there is no state that can be updated!)" +msgstr "" +"当A使用 `IBLibraryDispatcher` 来调用B的 **类** 中的函数时,定义在B类中的逻辑的执行上下文是A的。这意味着在B中由 `get_caller_address()` 变量返回的值将返回A的调用者的地址,并且在B的类中" +"更新存储变量将更新A的存储(请记住,B的类是无状态的;没有可以更新的状态!)" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:140 +msgid "The expanded form of the struct and trait generated by the compiler look like:" +msgstr "编译器生成的 struct 和 trait 的扩展形式如下:" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:142 +msgid "" +"```rust,noplayground\n" +"//TAG: does_not_compile\n" +"use starknet::ContractAddress;\n" +"\n" +"trait IERC20DispatcherTrait {\n" +" fn name(self: T) -> felt252;\n" +" fn transfer(self: T, recipient: ContractAddress, amount: u256);\n" +"}\n" +"\n" +"#[derive(Copy, Drop, starknet::Store, Serde)]\n" +"struct IERC20LibraryDispatcher {\n" +" class_hash: starknet::ClassHash,\n" +"}\n" +"\n" +"impl IERC20LibraryDispatcherImpl of IERC20DispatcherTrait {\n" +" fn name(\n" +" self: IERC20LibraryDispatcher\n" +" ) -> felt252 { // starknet::syscalls::library_call_syscall is called in here\n" +" }\n" +" fn transfer(\n" +" self: IERC20LibraryDispatcher, recipient: ContractAddress, amount: u256\n" +" ) { // starknet::syscalls::library_call_syscall is called in here\n" +" }\n" +"}\n" +"```" +msgstr "" +"```rust,noplayground\n" +"//TAG: does_not_compile\n" +"use starknet::ContractAddress;\n" +"\n" +"trait IERC20DispatcherTrait {\n" +" fn name(self: T) -> felt252;\n" +" fn transfer(self: T, recipient: ContractAddress, amount: u256);\n" +"}\n" +"\n" +"#[derive(Copy, Drop, starknet::Store, Serde)]\n" +"struct IERC20LibraryDispatcher {\n" +" class_hash: starknet::ClassHash,\n" +"}\n" +"\n" +"impl IERC20LibraryDispatcherImpl of IERC20DispatcherTrait {\n" +" fn name(\n" +" self: IERC20LibraryDispatcher\n" +" ) -> felt252 { // starknet::syscalls::library_call_syscall is called in here\n" +" }\n" +" fn transfer(\n" +" self: IERC20LibraryDispatcher, recipient: ContractAddress, amount: u256\n" +" ) { // starknet::syscalls::library_call_syscall is called in here\n" +" }\n" +"}\n" +"```" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:168 +msgid "" +"Notice that the main difference between the regular contract dispatcher and the library dispatcher is that the former uses `call_contract_syscall` while the latter uses " +"`library_call_syscall`." +msgstr "请注意,普通合约调度程序与库调度程序的主要区别在于,前者是通过 `call_contract_syscall` 生成的,而后者则使用了 `library_call_syscall`。" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:170 +msgid "Listing 99-7: An expanded form of the IERC20 trait" +msgstr "示例99-7:IERC20 trait的扩展" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:172 +msgid "### Calling Contracts using the Library Dispatcher" +msgstr "### 使用库调度器调用合约" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:174 +msgid "Below's a sample code for calling contracts using the Library Dispatcher." +msgstr "下面是一个关于使用库调度器调用合约的示例代码。" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:176 +msgid "" +"```rust,noplayground\n" +"use starknet::ContractAddress;\n" +"#[starknet::interface]\n" +"trait IContractB {\n" +" fn set_value(ref self: TContractState, value: u128);\n" +"\n" +" fn get_value(self: @TContractState) -> u128;\n" +"}\n" +"\n" +"#[starknet::contract]\n" +"mod ContractA {\n" +" use super::{IContractBDispatcherTrait, IContractBLibraryDispatcher};\n" +" use starknet::ContractAddress;\n" +"\n" +" #[storage]\n" +" struct Storage {\n" +" value: u128\n" +" }\n" +"\n" +" #[generate_trait]\n" +" #[external(v0)]\n" +" impl ContractA of IContractA {\n" +" fn set_value(ref self: ContractState, value: u128) {\n" +" IContractBLibraryDispatcher { class_hash: starknet::class_hash_const::<0x1234>() }\n" +" .set_value(value)\n" +" }\n" +"\n" +" fn get_value(self: @ContractState) -> u128 {\n" +" self.value.read()\n" +" }\n" +" }\n" +"}\n" +"```" +msgstr "" +"```rust,noplayground\n" +"use starknet::ContractAddress;\n" +"#[starknet::interface]\n" +"trait IContractB {\n" +" fn set_value(ref self: TContractState, value: u128);\n" +"\n" +" fn get_value(self: @TContractState) -> u128;\n" +"}\n" +"\n" +"#[starknet::contract]\n" +"mod ContractA {\n" +" use super::{IContractBDispatcherTrait, IContractBLibraryDispatcher};\n" +" use starknet::ContractAddress;\n" +"\n" +" #[storage]\n" +" struct Storage {\n" +" value: u128\n" +" }\n" +"\n" +" #[generate_trait]\n" +" #[external(v0)]\n" +" impl ContractA of IContractA {\n" +" fn set_value(ref self: ContractState, value: u128) {\n" +" IContractBLibraryDispatcher { class_hash: starknet::class_hash_const::<0x1234>() }\n" +" .set_value(value)\n" +" }\n" +"\n" +" fn get_value(self: @ContractState) -> u128 {\n" +" self.value.read()\n" +" }\n" +" }\n" +"}\n" +"```" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:210 +msgid "Listing 99-8: A sample contract using the Library Dispatcher" +msgstr "示例99-8:一个使用库调度器的样本合约" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:212 +msgid "" +"As you can see, we had to first import in our contract the `IContractBDispatcherTrait` and `IContractBLibraryDispatcher` which were generated from our interface by the compiler. " +"Then, we can create an instance of `IContractBLibraryDispatcher` passing in the `class_hash` of the class we want to make library calls to. From there, we can call the functions " +"defined in that class, executing its logic in the context of our contract. When we call `set_value` on ContractA, it will make a library call to the `set_value` function in " +"ContractB, updating the value of the storage variable `value` in ContractA." +msgstr "" +"正如你所看到的,我们必须首先在我们的合约中导入`IContractBDispatcherTrait`和`IContractBLibraryDispatcher`,它们是由编译器从我们的接口中生成的。然后,我们可以创建一个 " +"`IContractBLibraryDispatcher` 实例,并将我们要调用库的类的 `class_hash` 传递进去。在这里,我们可以调用该类中定义的函数,在我们的合约上下文中执行其逻辑。当我们在合约 A 上调用 " +"`set_value` 时,它将对合约 B 中的 `set_value` 函数进行库调用,更新合约 A 中存储变量 `value` 的值。" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:214 +msgid "## Using low-level syscalls" +msgstr "## 使用底层系统调用来" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:216 +msgid "" +"Another way to call other contracts and classes is to use the `starknet::call_contract_syscall`and `starknet::library_call_syscall` system calls. The dispatchers we described in the " +"previous sections are high-level syntaxes for these low-level system calls." +msgstr "调用其他合约和类的另一种方法是使用 `starknet::call_contract_syscall` 和 `starknet::library_call_syscall` 系统调用。我们在前几节中描述的调度器就是这些低级系统调用的高级语法。" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:218 +msgid "" +"Using these syscalls can be handy for customized error handling or to get more control over the serialization/deserialization of the call data and the returned data. Here's an " +"example demonstrating how to use a `call_contract_sycall` to call the `transfer` function of an ERC20 contract:" +msgstr "" +"使用这些系统调用可以方便地进行自定义错误处理,或对调用数据和返回数据的序列化/反序列化进行更多控制。下面的示例演示了如何使用 `call_contract_sycall`调用 ERC20 合约的 `transfer`函数:" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:220 +msgid "" +"```rust,noplayground\n" +"#[starknet::interface]\n" +"trait ITokenWrapper {\n" +" fn transfer_token(\n" +" ref self: TContractState,\n" +" address: starknet::ContractAddress,\n" +" selector: felt252,\n" +" calldata: Array\n" +" ) -> bool;\n" +"}\n" +"\n" +"#[starknet::contract]\n" +"mod TokenWrapper {\n" +" use super::ITokenWrapper;\n" +" use starknet::SyscallResultTrait;\n" +"\n" +" #[storage]\n" +" struct Storage {}\n" +"\n" +" impl TokenWrapper of ITokenWrapper {\n" +" fn transfer_token(\n" +" ref self: ContractState,\n" +" address: starknet::ContractAddress,\n" +" selector: felt252,\n" +" calldata: Array\n" +" ) -> bool {\n" +" let mut res = starknet::call_contract_syscall(address, selector, calldata.span())\n" +" .unwrap_syscall();\n" +" Serde::::deserialize(ref res).unwrap()\n" +" }\n" +" }\n" +"}\n" +"```" +msgstr "" +"```rust,noplayground\n" +"#[starknet::interface]\n" +"trait ITokenWrapper {\n" +" fn transfer_token(\n" +" ref self: TContractState,\n" +" address: starknet::ContractAddress,\n" +" selector: felt252,\n" +" calldata: Array\n" +" ) -> bool;\n" +"}\n" +"\n" +"#[starknet::contract]\n" +"mod TokenWrapper {\n" +" use super::ITokenWrapper;\n" +" use starknet::SyscallResultTrait;\n" +"\n" +" #[storage]\n" +" struct Storage {}\n" +"\n" +" impl TokenWrapper of ITokenWrapper {\n" +" fn transfer_token(\n" +" ref self: ContractState,\n" +" address: starknet::ContractAddress,\n" +" selector: felt252,\n" +" calldata: Array\n" +" ) -> bool {\n" +" let mut res = starknet::call_contract_syscall(address, selector, calldata.span())\n" +" .unwrap_syscall();\n" +" Serde::::deserialize(ref res).unwrap()\n" +" }\n" +" }\n" +"}\n" +"```" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:254 +msgid "Listing 99-9: A sample contract using syscalls" +msgstr "示例 99-9:使用系统调用的合约示例" + +#: src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md:256 +msgid "" +"To use this syscall, we passed in the contract address, the function selector (which is the `starknet_keccak` hash of the function name), and the calldata (function arguments). At " +"the end, we get returned a serialized value which we'll need to deserialize ourselves!" +msgstr "要使用此系统调用,我们需要传入合约地址、函数选择器(即函数名的 `starknet_keccak` 哈希值)和 calldata(函数参数)。最后,我们会得到一个序列化值,我们需要自己对其进行反序列化!" + +#: src/ch99-01-04-00-other-examples.md:1 +msgid "# Other examples " +msgstr "# 其他例子" + +#: src/ch99-01-04-00-other-examples.md:3 +msgid "" +"This section contains additional examples of Starknet smart contracts, utilizing various features of the Cairo programming language. Your contributions are welcome and encouraged, as " +"we aim to gather as many diverse examples as possible." +msgstr "本节包含了Starknet智能合约的其他示例,利用了Cairo编程语言的各种功能。我们欢迎并鼓励大家贡献自己的代码,因为我们的目标是收集尽可能多的不同例子。" + +#: src/ch99-01-04-01-voting-contract.md:1 +msgid "# Deploying and Interacting with a Voting contract" +msgstr "# 部署表决合同并与之互动" + +#: src/ch99-01-04-01-voting-contract.md:3 +msgid "" +"The **`Vote`** contract in Starknet begins by registering voters through the contract's constructor. Three voters are initialized at this stage, and their addresses are passed to an " +"internal function **`_register_voters`**. This function adds the voters to the contract's state, marking them as registered and eligible to vote." +msgstr "" +"Starknet的 **`Vote`** 合约首先要通过合约的构造函数注册投票人。在此阶段,三个投票人被初始化,他们的地址被传递给内部函数 **`_register_voters`**。该函数将选民添加到合约的状态中,标记为已" +"注册并有资格投票。" + +#: src/ch99-01-04-01-voting-contract.md:5 +msgid "" +"Within the contract, the constants **`YES`** and **`NO`** are defined to represent the voting options (1 and 0, respectively). These constants facilitate the voting process by " +"standardizing the input values." +msgstr "在合约中,常量 **`YES`** 和 **`NO`** 被定义为表决选项(分别为 1 和 0)。这些常量使输入值标准化,从而方便了投票过程。" + +#: src/ch99-01-04-01-voting-contract.md:7 +msgid "" +"Once registered, a voter is able to cast a vote using the **`vote`** function, selecting either the 1 (YES) or 0 (NO) as their vote. When voting, the state of the contract is " +"updated, recording the vote and marking the voter as having voted. This ensures that the voter is not able to cast a vote again within the same proposal. The casting of a vote " +"triggers the **`VoteCast`** event, logging the action." +msgstr "" +"注册完成后,投票者可使用 **`vote`** 函数进行投票,选择 1(YES)或 0(NO)作为其投票。投票时,合约状态会被更新,记录投票情况并标记投票人已投票。这样可以确保投票者无法在同一提案中再次投" +"票。投票会触发 **`VoteCast`** 事件,记录投票行为。" + +#: src/ch99-01-04-01-voting-contract.md:9 +msgid "" +"The contract also monitors unauthorized voting attempts. If an unauthorized action is detected, such as a non-registered user attempting to vote or a user trying to vote again, the " +"**`UnauthorizedAttempt`** event is emitted." +msgstr "该合约还会监控未经授权的投票尝试。如果检测到未经授权的行为,如非注册用户试图投票或用户试图再次投票,就会发出 **`UnauthorizedAttempt`** 事件。" + +#: src/ch99-01-04-01-voting-contract.md:11 +msgid "" +"Together, these functions, states, constants, and events create a structured voting system, managing the lifecycle of a vote from registration to casting, event logging, and result " +"retrieval within the Starknet environment. Constants like **`YES`** and **`NO`** help streamline the voting process, while events play a vital role in ensuring transparency and " +"traceability." +msgstr "" +"这些功能、状态、常量和事件共同创建了一个结构化投票系统,在Starknet环境中管理着从注册到投票、事件记录、以及结果检索的投票生命周期。常量(如 **`YES`** 和 **`NO`** )有助于简化投票流程," +"而事件则在确保透明度和可追溯性方面发挥着重要作用。" + +#: src/ch99-01-04-01-voting-contract.md:13 +msgid "" +"```rust,noplayground\n" +"/// @dev Core Library Imports for the Traits outside the Starknet Contract\n" +"use starknet::ContractAddress;\n" +"\n" +"/// @dev Trait defining the functions that can be implemented or called by the Starknet Contract\n" +"#[starknet::interface]\n" +"trait VoteTrait {\n" +" /// @dev Function that returns the current vote status\n" +" fn get_vote_status(self: @T) -> (u8, u8, u8, u8);\n" +" /// @dev Function that checks if the user at the specified address is allowed to vote\n" +" fn voter_can_vote(self: @T, user_address: ContractAddress) -> bool;\n" +" /// @dev Function that checks if the specified address is registered as a voter\n" +" fn is_voter_registered(self: @T, address: ContractAddress) -> bool;\n" +" /// @dev Function that allows a user to vote\n" +" fn vote(ref self: T, vote: u8);\n" +"}\n" +"\n" +"/// @dev Starknet Contract allowing three registered voters to vote on a proposal\n" +"#[starknet::contract]\n" +"mod Vote {\n" +" use starknet::ContractAddress;\n" +" use starknet::get_caller_address;\n" +"\n" +" const YES: u8 = 1_u8;\n" +" const NO: u8 = 0_u8;\n" +"\n" +" /// @dev Structure that stores vote counts and voter states\n" +" #[storage]\n" +" struct Storage {\n" +" yes_votes: u8,\n" +" no_votes: u8,\n" +" can_vote: LegacyMap::,\n" +" registered_voter: LegacyMap::,\n" +" }\n" +"\n" +" /// @dev Contract constructor initializing the contract with a list of registered voters and 0 vote count\n" +" #[constructor]\n" +" fn constructor(\n" +" ref self: ContractState,\n" +" voter_1: ContractAddress,\n" +" voter_2: ContractAddress,\n" +" voter_3: ContractAddress\n" +" ) {\n" +" // Register all voters by calling the _register_voters function\n" +" self._register_voters(voter_1, voter_2, voter_3);\n" +"\n" +" // Initialize the vote count to 0\n" +" self.yes_votes.write(0_u8);\n" +" self.no_votes.write(0_u8);\n" +" }\n" +"\n" +" /// @dev Event that gets emitted when a vote is cast\n" +" #[event]\n" +" #[derive(Drop, starknet::Event)]\n" +" enum Event {\n" +" VoteCast: VoteCast,\n" +" UnauthorizedAttempt: UnauthorizedAttempt,\n" +" }\n" +"\n" +" /// @dev Represents a vote that was cast\n" +" #[derive(Drop, starknet::Event)]\n" +" struct VoteCast {\n" +" voter: ContractAddress,\n" +" vote: u8,\n" +" }\n" +"\n" +" /// @dev Represents an unauthorized attempt to vote\n" +" #[derive(Drop, starknet::Event)]\n" +" struct UnauthorizedAttempt {\n" +" unauthorized_address: ContractAddress,\n" +" }\n" +"\n" +" /// @dev Implementation of VoteTrait for ContractState\n" +" #[external(v0)]\n" +" impl VoteImpl of super::VoteTrait {\n" +" /// @dev Returns the voting results\n" +" fn get_vote_status(self: @ContractState) -> (u8, u8, u8, u8) {\n" +" let (n_yes, n_no) = self._get_voting_result();\n" +" let (yes_percentage, no_percentage) = self._get_voting_result_in_percentage();\n" +" return (n_yes, n_no, yes_percentage, no_percentage);\n" +" }\n" +"\n" +" /// @dev Check whether a voter is allowed to vote\n" +" fn voter_can_vote(self: @ContractState, user_address: ContractAddress) -> bool {\n" +" self.can_vote.read(user_address)\n" +" }\n" +"\n" +" /// @dev Check whether an address is registered as a voter\n" +" fn is_voter_registered(self: @ContractState, address: ContractAddress) -> bool {\n" +" self.registered_voter.read(address)\n" +" }\n" +"\n" +" /// @dev Submit a vote\n" +" fn vote(ref self: ContractState, vote: u8) {\n" +" assert(vote == NO || vote == YES, 'VOTE_0_OR_1');\n" +" let caller: ContractAddress = get_caller_address();\n" +" self._assert_allowed(caller);\n" +" self.can_vote.write(caller, false);\n" +"\n" +" if (vote == NO) {\n" +" self.no_votes.write(self.no_votes.read() + 1_u8);\n" +" }\n" +" if (vote == YES) {\n" +" self.yes_votes.write(self.yes_votes.read() + 1_u8);\n" +" }\n" +"\n" +" self.emit(VoteCast { voter: caller, vote: vote, });\n" +" }\n" +" }\n" +"\n" +" /// @dev Internal Functions implementation for the Vote contract\n" +" #[generate_trait]\n" +" impl InternalFunctions of InternalFunctionsTrait {\n" +" /// @dev Registers the voters and initializes their voting status to true (can vote)\n" +" fn _register_voters(\n" +" ref self: ContractState,\n" +" voter_1: ContractAddress,\n" +" voter_2: ContractAddress,\n" +" voter_3: ContractAddress\n" +" ) {\n" +" self.registered_voter.write(voter_1, true);\n" +" self.can_vote.write(voter_1, true);\n" +"\n" +" self.registered_voter.write(voter_2, true);\n" +" self.can_vote.write(voter_2, true);\n" +"\n" +" self.registered_voter.write(voter_3, true);\n" +" self.can_vote.write(voter_3, true);\n" +" }\n" +" }\n" +"\n" +" /// @dev Asserts implementation for the Vote contract\n" +" #[generate_trait]\n" +" impl AssertsImpl of AssertsTrait {\n" +" // @dev Internal function that checks if an address is allowed to vote\n" +" fn _assert_allowed(ref self: ContractState, address: ContractAddress) {\n" +" let is_voter: bool = self.registered_voter.read((address));\n" +" let can_vote: bool = self.can_vote.read((address));\n" +"\n" +" if (can_vote == false) {\n" +" self.emit(UnauthorizedAttempt { unauthorized_address: address, });\n" +" }\n" +"\n" +" assert(is_voter == true, 'USER_NOT_REGISTERED');\n" +" assert(can_vote == true, 'USER_ALREADY_VOTED');\n" +" }\n" +" }\n" +"\n" +" /// @dev Implement the VotingResultTrait for the Vote contract\n" +" #[generate_trait]\n" +" impl VoteResultFunctionsImpl of VoteResultFunctionsTrait {\n" +" // @dev Internal function to get the voting results (yes and no vote counts)\n" +" fn _get_voting_result(self: @ContractState) -> (u8, u8) {\n" +" let n_yes: u8 = self.yes_votes.read();\n" +" let n_no: u8 = self.no_votes.read();\n" +"\n" +" return (n_yes, n_no);\n" +" }\n" +"\n" +" // @dev Internal function to calculate the voting results in percentage\n" +" fn _get_voting_result_in_percentage(self: @ContractState) -> (u8, u8) {\n" +" let n_yes: u8 = self.yes_votes.read();\n" +" let n_no: u8 = self.no_votes.read();\n" +"\n" +" let total_votes: u8 = n_yes + n_no;\n" +"\n" +" let yes_percentage: u8 = (n_yes * 100_u8) / (total_votes);\n" +" let no_percentage: u8 = (n_no * 100_u8) / (total_votes);\n" +"\n" +" return (yes_percentage, no_percentage);\n" +" }\n" +" }\n" +"}\n" +"```" +msgstr "" +"```rust,noplayground\n" +"/// @dev Core Library Imports for the Traits outside the Starknet Contract\n" +"use starknet::ContractAddress;\n" +"\n" +"/// @dev Trait defining the functions that can be implemented or called by the Starknet Contract\n" +"#[starknet::interface]\n" +"trait VoteTrait {\n" +" /// @dev Function that returns the current vote status\n" +" fn get_vote_status(self: @T) -> (u8, u8, u8, u8);\n" +" /// @dev Function that checks if the user at the specified address is allowed to vote\n" +" fn voter_can_vote(self: @T, user_address: ContractAddress) -> bool;\n" +" /// @dev Function that checks if the specified address is registered as a voter\n" +" fn is_voter_registered(self: @T, address: ContractAddress) -> bool;\n" +" /// @dev Function that allows a user to vote\n" +" fn vote(ref self: T, vote: u8);\n" +"}\n" +"\n" +"/// @dev Starknet Contract allowing three registered voters to vote on a proposal\n" +"#[starknet::contract]\n" +"mod Vote {\n" +" use starknet::ContractAddress;\n" +" use starknet::get_caller_address;\n" +"\n" +" const YES: u8 = 1_u8;\n" +" const NO: u8 = 0_u8;\n" +"\n" +" /// @dev Structure that stores vote counts and voter states\n" +" #[storage]\n" +" struct Storage {\n" +" yes_votes: u8,\n" +" no_votes: u8,\n" +" can_vote: LegacyMap::,\n" +" registered_voter: LegacyMap::,\n" +" }\n" +"\n" +" /// @dev Contract constructor initializing the contract with a list of registered voters and 0 vote count\n" +" #[constructor]\n" +" fn constructor(\n" +" ref self: ContractState,\n" +" voter_1: ContractAddress,\n" +" voter_2: ContractAddress,\n" +" voter_3: ContractAddress\n" +" ) {\n" +" // Register all voters by calling the _register_voters function\n" +" self._register_voters(voter_1, voter_2, voter_3);\n" +"\n" +" // Initialize the vote count to 0\n" +" self.yes_votes.write(0_u8);\n" +" self.no_votes.write(0_u8);\n" +" }\n" +"\n" +" /// @dev Event that gets emitted when a vote is cast\n" +" #[event]\n" +" #[derive(Drop, starknet::Event)]\n" +" enum Event {\n" +" VoteCast: VoteCast,\n" +" UnauthorizedAttempt: UnauthorizedAttempt,\n" +" }\n" +"\n" +" /// @dev Represents a vote that was cast\n" +" #[derive(Drop, starknet::Event)]\n" +" struct VoteCast {\n" +" voter: ContractAddress,\n" +" vote: u8,\n" +" }\n" +"\n" +" /// @dev Represents an unauthorized attempt to vote\n" +" #[derive(Drop, starknet::Event)]\n" +" struct UnauthorizedAttempt {\n" +" unauthorized_address: ContractAddress,\n" +" }\n" +"\n" +" /// @dev Implementation of VoteTrait for ContractState\n" +" #[external(v0)]\n" +" impl VoteImpl of super::VoteTrait {\n" +" /// @dev Returns the voting results\n" +" fn get_vote_status(self: @ContractState) -> (u8, u8, u8, u8) {\n" +" let (n_yes, n_no) = self._get_voting_result();\n" +" let (yes_percentage, no_percentage) = self._get_voting_result_in_percentage();\n" +" return (n_yes, n_no, yes_percentage, no_percentage);\n" +" }\n" +"\n" +" /// @dev Check whether a voter is allowed to vote\n" +" fn voter_can_vote(self: @ContractState, user_address: ContractAddress) -> bool {\n" +" self.can_vote.read(user_address)\n" +" }\n" +"\n" +" /// @dev Check whether an address is registered as a voter\n" +" fn is_voter_registered(self: @ContractState, address: ContractAddress) -> bool {\n" +" self.registered_voter.read(address)\n" +" }\n" +"\n" +" /// @dev Submit a vote\n" +" fn vote(ref self: ContractState, vote: u8) {\n" +" assert(vote == NO || vote == YES, 'VOTE_0_OR_1');\n" +" let caller: ContractAddress = get_caller_address();\n" +" self._assert_allowed(caller);\n" +" self.can_vote.write(caller, false);\n" +"\n" +" if (vote == NO) {\n" +" self.no_votes.write(self.no_votes.read() + 1_u8);\n" +" }\n" +" if (vote == YES) {\n" +" self.yes_votes.write(self.yes_votes.read() + 1_u8);\n" +" }\n" +"\n" +" self.emit(VoteCast { voter: caller, vote: vote, });\n" +" }\n" +" }\n" +"\n" +" /// @dev Internal Functions implementation for the Vote contract\n" +" #[generate_trait]\n" +" impl InternalFunctions of InternalFunctionsTrait {\n" +" /// @dev Registers the voters and initializes their voting status to true (can vote)\n" +" fn _register_voters(\n" +" ref self: ContractState,\n" +" voter_1: ContractAddress,\n" +" voter_2: ContractAddress,\n" +" voter_3: ContractAddress\n" +" ) {\n" +" self.registered_voter.write(voter_1, true);\n" +" self.can_vote.write(voter_1, true);\n" +"\n" +" self.registered_voter.write(voter_2, true);\n" +" self.can_vote.write(voter_2, true);\n" +"\n" +" self.registered_voter.write(voter_3, true);\n" +" self.can_vote.write(voter_3, true);\n" +" }\n" +" }\n" +"\n" +" /// @dev Asserts implementation for the Vote contract\n" +" #[generate_trait]\n" +" impl AssertsImpl of AssertsTrait {\n" +" // @dev Internal function that checks if an address is allowed to vote\n" +" fn _assert_allowed(ref self: ContractState, address: ContractAddress) {\n" +" let is_voter: bool = self.registered_voter.read((address));\n" +" let can_vote: bool = self.can_vote.read((address));\n" +"\n" +" if (can_vote == false) {\n" +" self.emit(UnauthorizedAttempt { unauthorized_address: address, });\n" +" }\n" +"\n" +" assert(is_voter == true, 'USER_NOT_REGISTERED');\n" +" assert(can_vote == true, 'USER_ALREADY_VOTED');\n" +" }\n" +" }\n" +"\n" +" /// @dev Implement the VotingResultTrait for the Vote contract\n" +" #[generate_trait]\n" +" impl VoteResultFunctionsImpl of VoteResultFunctionsTrait {\n" +" // @dev Internal function to get the voting results (yes and no vote counts)\n" +" fn _get_voting_result(self: @ContractState) -> (u8, u8) {\n" +" let n_yes: u8 = self.yes_votes.read();\n" +" let n_no: u8 = self.no_votes.read();\n" +"\n" +" return (n_yes, n_no);\n" +" }\n" +"\n" +" // @dev Internal function to calculate the voting results in percentage\n" +" fn _get_voting_result_in_percentage(self: @ContractState) -> (u8, u8) {\n" +" let n_yes: u8 = self.yes_votes.read();\n" +" let n_no: u8 = self.no_votes.read();\n" +"\n" +" let total_votes: u8 = n_yes + n_no;\n" +"\n" +" let yes_percentage: u8 = (n_yes * 100_u8) / (total_votes);\n" +" let no_percentage: u8 = (n_no * 100_u8) / (total_votes);\n" +"\n" +" return (yes_percentage, no_percentage);\n" +" }\n" +" }\n" +"}\n" +"```" + +#: src/ch99-01-04-01-voting-contract.md:188 +msgid "Voting smart contract" +msgstr "投票智能合约" + +#: src/ch99-01-04-01-voting-contract.md:190 +msgid "## Deploying, calling and invoking the Voting Contract" +msgstr "## 部署、调用和唤起投票合约" + +#: src/ch99-01-04-01-voting-contract.md:192 +msgid "Part of the Starknet experience is deploying and interacting with smart contracts." +msgstr "Starknet 体验的一部分就是部署智能合约并与之交互。" + +#: src/ch99-01-04-01-voting-contract.md:194 +msgid "Once the contract is deployed, we can interact with it by calling and invoking its functions:" +msgstr "一旦部署了合约,我们就可以通过调用合约的函数与之交互:" + +#: src/ch99-01-04-01-voting-contract.md:196 +msgid "" +"- Calling contracts: Interacting with external functions that only read from the state. These functions do not alter the state of the network, so they don't require fees or signing.\n" +"- Invoking contracts: Interacting with external functions that can write to the state. These functions do alter the state of the network and require fees and signing." +msgstr "" +"- 调用合约:与只读取状态的外部函数交互。这些函数不会改变网络的状态,因此不需要付费或签署。\n" +"- 唤起合约:与可以写入状态的外部函数交互。这些函数会改变网络状态,因此需要付费或签署。" + +#: src/ch99-01-04-01-voting-contract.md:199 +msgid "" +"We will setup a local development node using `katana` to deploy the voting contract. Then, we'll interact with the contract by calling and invoking its functions. You can also use " +"the Goerli Testnet instead of `katana`. However, we recommend using `katana` for local development and testing. You can find the complete tutorial for `katana` on [Chapter 3](https://" +"book.starknet.io/chapter_3/katana.html) of the Starknet Book." +msgstr "" +"我们将使用 `katana` 设置一个本地开发节点,以部署投票合约。然后,我们将通过调用合约的函数与合约进行交互。你也可以使用 Goerli Testnet 来代替 `katana`。不过,我们建议在本地开发和测试中使" +"用 `katana`。你可以在Starknet Book的[第3章](https://book.starknet.io/chapter_3/katana.html)中找到`katana`的完整教程。" + +#: src/ch99-01-04-01-voting-contract.md:201 +msgid "### The `katana` local Starknet node" +msgstr "### `katana` 本地Starknet节点" + +#: src/ch99-01-04-01-voting-contract.md:203 +msgid "" +"`katana` is designed to support local development by the [Dojo team](https://github.com/dojoengine/dojo/blob/main/crates/katana/README.md). It will allow you to do everything you " +"need to do with Starknet, but locally. It is a great tool for development and testing." +msgstr "" +"`katana`旨在支持[Dojo 团队](https://github.com/dojoengine/dojo/blob/main/crates/katana/README.md)的本地开发。通过它,您可以在本地完成星网所需的一切工作。它是开发和测试的绝佳工具。" + +#: src/ch99-01-04-01-voting-contract.md:205 +msgid "To install `katana` from the source code, please refer to the [katana subchapter in Chapter 3](https://book.starknet.io/chapter_3/katana.html) of the Starknet Book." +msgstr "要从源代码安装`katana`,请参阅Starknet Book的[第 3 章 katana 子章节](https://book.starknet.io/chapter_3/katana.html)。" + +#: src/ch99-01-04-01-voting-contract.md:207 +msgid "Once you have `katana` installed, you can start the local Starknet node with:" +msgstr "一旦安装了 `katana`,就可以用以下命令启动本地Starknet节点:" + +#: src/ch99-01-04-01-voting-contract.md:209 +msgid "" +"```bash\n" +"katana --accounts 3 --seed 0 --gas-price 250\n" +"```" +msgstr "" +"```bash\n" +"katana --accounts 3 --seed 0 --gas-price 250\n" +"```" + +#: src/ch99-01-04-01-voting-contract.md:213 +msgid "This command will start a local Starknet node with 3 deployed accounts. We will use these accounts to deploy and interact with the voting contract:" +msgstr "该命令将启动一个本地 Starknet 节点,并部署 3 个账户。我们将使用这些账户部署投票合约并与之交互:" + +#: src/ch99-01-04-01-voting-contract.md:215 +msgid "" +"```bash\n" +"...\n" +"PREFUNDED ACCOUNTS\n" +"==================\n" +"\n" +"| Account address | 0x03ee9e18edc71a6df30ac3aca2e0b02a198fbce19b7480a63a0d71cbd76652e0\n" +"| Private key | 0x0300001800000000300000180000000000030000000000003006001800006600\n" +"| Public key | 0x01b7b37a580d91bc3ad4f9933ed61f3a395e0e51c9dd5553323b8ca3942bb44e\n" +"\n" +"| Account address | 0x033c627a3e5213790e246a917770ce23d7e562baa5b4d2917c23b1be6d91961c\n" +"| Private key | 0x0333803103001800039980190300d206608b0070db0012135bd1fb5f6282170b\n" +"| Public key | 0x04486e2308ef3513531042acb8ead377b887af16bd4cdd8149812dfef1ba924d\n" +"\n" +"| Account address | 0x01d98d835e43b032254ffbef0f150c5606fa9c5c9310b1fae370ab956a7919f5\n" +"| Private key | 0x07ca856005bee0329def368d34a6711b2d95b09ef9740ebf2c7c7e3b16c1ca9c\n" +"| Public key | 0x07006c42b1cfc8bd45710646a0bb3534b182e83c313c7bc88ecf33b53ba4bcbc\n" +"...\n" +"```" +msgstr "" +"```bash\n" +"...\n" +"PREFUNDED ACCOUNTS\n" +"==================\n" +"\n" +"| Account address | 0x03ee9e18edc71a6df30ac3aca2e0b02a198fbce19b7480a63a0d71cbd76652e0\n" +"| Private key | 0x0300001800000000300000180000000000030000000000003006001800006600\n" +"| Public key | 0x01b7b37a580d91bc3ad4f9933ed61f3a395e0e51c9dd5553323b8ca3942bb44e\n" +"\n" +"| Account address | 0x033c627a3e5213790e246a917770ce23d7e562baa5b4d2917c23b1be6d91961c\n" +"| Private key | 0x0333803103001800039980190300d206608b0070db0012135bd1fb5f6282170b\n" +"| Public key | 0x04486e2308ef3513531042acb8ead377b887af16bd4cdd8149812dfef1ba924d\n" +"\n" +"| Account address | 0x01d98d835e43b032254ffbef0f150c5606fa9c5c9310b1fae370ab956a7919f5\n" +"| Private key | 0x07ca856005bee0329def368d34a6711b2d95b09ef9740ebf2c7c7e3b16c1ca9c\n" +"| Public key | 0x07006c42b1cfc8bd45710646a0bb3534b182e83c313c7bc88ecf33b53ba4bcbc\n" +"...\n" +"```" + +#: src/ch99-01-04-01-voting-contract.md:234 +msgid "" +"Before we can interact with the voting contract, we need to prepare the voter and admin accounts on Starknet. Each voter account must be registered and sufficiently funded for " +"voting. For a more detailed understanding of how accounts operate with Account Abstraction, refer to the [Account Abstraction](https://book.starknet.io/chapter_5/index.html) chapter " +"of the Starknet Book." +msgstr "" +"在与投票合同互动之前,我们需要在Starknet中准备好投票人和管理员账户。每个投票人账户都必须注册并有足够的资金用于投票。如需更详细地了解账户抽象的操作方法,请参阅Starknet Book中的[账户抽" +"象](https://book.starknet.io/chapter_5/index.html)章节。" + +#: src/ch99-01-04-01-voting-contract.md:236 +msgid "### Smart wallets for voting" +msgstr "### 用于投票的智能钱包" + +#: src/ch99-01-04-01-voting-contract.md:238 +msgid "" +"Aside from Scarb you will need to have Starkli installed. Starkli is a command line tool that allows you to interact with Starknet. You can find the installation instructions in the " +"[Chapter 1](https://book.starknet.io/chapter_1/environment_setup.html) of the Starknet Book." +msgstr "" +"除了 Scarb,您还需要安装 Starkli。Starkli 是一个命令行工具,可以让你与 Starknet 交互。你可以在Starknet Book的[第1章](https://book.starknet.io/chapter_1/environment_setup.html)中找到安" +"装说明。" + +#: src/ch99-01-04-01-voting-contract.md:240 +msgid "" +"For each smart wallet we'll use, we must create a Signer within the encrypted keystore and an Account Descriptor. This process is detailed in the [first chapter of the Starknet Book]" +"(https://book.starknet.io/chapter_1/first_contract.html)." +msgstr "" +"对于我们要使用的每一个智能钱包,我们都必须在加密密钥库中创建一个签名者(Signer)和一个账户描述符(Account Descriptor)。Starknet的[第一章](https://book.starknet.io/chapter_1/" +"first_contract.html) 详细介绍了这一过程。" + +#: src/ch99-01-04-01-voting-contract.md:242 +msgid "We can create Signers and Account Descriptors for the accounts we want to use for voting. Let's create a smart wallet for voting in our smart contract." +msgstr "我们可以为要用于投票的账户创建签名者和账户描述符。让我们在智能合约中创建一个用于投票的智能钱包。" + +#: src/ch99-01-04-01-voting-contract.md:244 +msgid "Firstly, we create a signer from a private key:" +msgstr "首先,我们用私钥创建一个签名者:" + +#: src/ch99-01-04-01-voting-contract.md:246 +msgid "" +"```bash\n" +"starkli signer keystore from-key ~/.starkli-wallets/deployer/account0_keystore.json\n" +"```" +msgstr "" +"```bash\n" +"starkli signer keystore from-key ~/.starkli-wallets/deployer/account0_keystore.json\n" +"```" + +#: src/ch99-01-04-01-voting-contract.md:250 +msgid "Then, we create the Account Descriptor:" +msgstr "然后,我们创建账户描述符:" + +#: src/ch99-01-04-01-voting-contract.md:252 +msgid "" +"```bash\n" +"touch ~/.starkli-wallets/deployer/account0_account.json\n" +"```" +msgstr "" +"```bash\n" +"touch ~/.starkli-wallets/deployer/account0_account.json\n" +"```" + +#: src/ch99-01-04-01-voting-contract.md:256 +msgid "The Account Descriptor will look like this. You can get the public key and the smart wallet address from the output of the initial `katana` command:" +msgstr "账户描述符将如下所示。你可以从初始 `katana` 命令的输出中获取公钥和智能钱包地址:" + +#: src/ch99-01-04-01-voting-contract.md:258 +msgid "" +"```bash\n" +"{\n" +" \"version\": 1,\n" +" \"variant\": {\n" +" \"type\": \"open_zeppelin\",\n" +" \"version\": 1,\n" +" \"public_key\": \"\"\n" +" },\n" +" \"deployment\": {\n" +" \"status\": \"deployed\",\n" +" \"class_hash\": \"\",\n" +" \"address\": \"\"\n" +" }\n" +"}\n" +"```" +msgstr "" +"```bash\n" +"{\n" +" \"version\": 1,\n" +" \"variant\": {\n" +" \"type\": \"open_zeppelin\",\n" +" \"version\": 1,\n" +" \"public_key\": \"\"\n" +" },\n" +" \"deployment\": {\n" +" \"status\": \"deployed\",\n" +" \"class_hash\": \"\",\n" +" \"address\": \"\"\n" +" }\n" +"}\n" +"```" + +#: src/ch99-01-04-01-voting-contract.md:274 +msgid "" +"You can retrieve the smart wallet class hash (it will be the same for all your smart wallets) with the following command. Notice the use of the `--rpc` flag and the RPC endpoint " +"provided by `katana`:" +msgstr "你可以用以下命令获取智能钱包的 class hash(所有智能钱包的class hash都一样)。注意使用了 `--rpc` 标志和 `katana` 提供的 RPC 端点:" + +#: src/ch99-01-04-01-voting-contract.md:276 +msgid "" +"```\n" +"starkli class-hash-at --rpc http://0.0.0.0:5050\n" +"```" +msgstr "" +"```\n" +"starkli class-hash-at --rpc http://0.0.0.0:5050\n" +"```" + +#: src/ch99-01-04-01-voting-contract.md:280 +msgid "For the public key, you can use the `starkli signer keystore inspect` command with the directory of the keystore json file:" +msgstr "要获取公钥,可以使用 `starkli signer keystore inspect` 命令,并输入 keystore json 文件的目录:" + +#: src/ch99-01-04-01-voting-contract.md:282 +msgid "" +"```bash\n" +"starkli signer keystore inspect ~/.starkli-wallets/deployer/account0_keystore.json\n" +"```" +msgstr "" +"```bash\n" +"starkli signer keystore inspect ~/.starkli-wallets/deployer/account0_keystore.json\n" +"```" + +#: src/ch99-01-04-01-voting-contract.md:286 +msgid "This process is identical for `account_1` and `account_2` in case you want to have a second and a third voter." +msgstr "如果您想拥有第二个和第三个投票人,用同样的过程对 `account_1` 和 `account_2` 进行操作即可。" + +#: src/ch99-01-04-01-voting-contract.md:288 +msgid "### Contract Deployment" +msgstr "### 合约部署" + +#: src/ch99-01-04-01-voting-contract.md:290 +msgid "Before deploying, we need to declare the contract. We can do this with the `starkli declare` command:" +msgstr "在部署之前,我们需要声明合约。我们可以使用 `starkli declare` 命令来完成这项工作:" + +#: src/ch99-01-04-01-voting-contract.md:292 +msgid "" +"```bash\n" +"starkli declare target/dev/starknetbook_chapter_2_Vote.sierra.json --compiler-version 2.0.1 --rpc http://0.0.0.0:5050 --account ~/.starkli-wallets/deployer/account0_account.json --" +"keystore ~/.starkli-wallets/deployer/account0_keystore.json\n" +"```" +msgstr "" +"```bash\n" +"starkli declare target/dev/starknetbook_chapter_2_Vote.sierra.json --compiler-version 2.0.1 --rpc http://0.0.0.0:5050 --account ~/.starkli-wallets/deployer/account0_account.json --" +"keystore ~/.starkli-wallets/deployer/account0_keystore.json\n" +"```" + +#: src/ch99-01-04-01-voting-contract.md:296 +msgid "" +"The class hash of the contract is: `0x06974677a079b7edfadcd70aa4d12aac0263a4cda379009fca125e0ab1a9ba52`. You can find it [on any block explorer](https://goerli.voyager.online/" +"class/0x06974677a079b7edfadcd70aa4d12aac0263a4cda379009fca125e0ab1a9ba52)." +msgstr "" +"合约的的class hash是`0x06974677a079b7edfadcd70aa4d12aac0263a4cda379009fca125e0ab1a9ba52`.您可以在 [任何区块浏览器] (https://goerli.voyager.online/" +"class/0x06974677a079b7edfadcd70aa4d12aac0263a4cda379009fca125e0ab1a9ba52)中看到他。" + +#: src/ch99-01-04-01-voting-contract.md:298 +msgid "" +"The `--rpc` flag specifies the RPC endpoint to use (the one provided by `katana`). The `--account` flag specifies the account to use for signing the transaction. The account we use " +"here is the one we created in the previous step. The `--keystore` flag specifies the keystore file to use for signing the transaction." +msgstr "`--rpc`标志指定要使用的 RPC 端点(由 `katana`提供)。`--account` 标志指定用于签署交易的账户。这里使用的账户是上一步创建的账户。 `--keystore`标记用于指定签署交易的密钥存储文件。" + +#: src/ch99-01-04-01-voting-contract.md:300 +msgid "" +"Since we are using a local node, the transaction will achieve finality immediately. If you are using the Goerli Testnet, you will need to wait for the transaction to be final, which " +"usually takes a few seconds." +msgstr "由于我们使用的是本地节点,因此交易将立即完成。如果您使用的是 Goerli Testnet,则需要等待交易最终完成,这通常需要几秒钟。" + +#: src/ch99-01-04-01-voting-contract.md:302 +msgid "" +"The following command deploys the voting contract and registers voter_0, voter_1, and voter_2 as eligible voters. These are the constructor arguments, so add a voter account that you " +"can later vote with." +msgstr "以下命令将部署投票合约,并将 voter_0、voter_1 和 voter_2 注册为合格投票人。这些是构造函数参数,因此请添加一个以后可以用来投票的选民账户。" + +#: src/ch99-01-04-01-voting-contract.md:304 +msgid "" +"```bash\n" +"starkli deploy --rpc http://0.0.0.0:5050 --account ~/.starkli-wallets/deployer/" +"account0_account.json --keystore ~/.starkli-wallets/deployer/account0_keystore.json\n" +"```" +msgstr "" +"```bash\n" +"starkli deploy --rpc http://0.0.0.0:5050 --account ~/.starkli-wallets/deployer/" +"account0_account.json --keystore ~/.starkli-wallets/deployer/account0_keystore.json\n" +"```" + +#: src/ch99-01-04-01-voting-contract.md:308 +msgid "An example command:" +msgstr "命令示例:" + +#: src/ch99-01-04-01-voting-contract.md:310 +msgid "" +"```bash\n" +"starkli deploy 0x06974677a079b7edfadcd70aa4d12aac0263a4cda379009fca125e0ab1a9ba52 0x03ee9e18edc71a6df30ac3aca2e0b02a198fbce19b7480a63a0d71cbd76652e0 " +"0x033c627a3e5213790e246a917770ce23d7e562baa5b4d2917c23b1be6d91961c 0x01d98d835e43b032254ffbef0f150c5606fa9c5c9310b1fae370ab956a7919f5 --rpc http://0.0.0.0:5050 --account ~/.starkli-" +"wallets/deployer/account0_account.json --keystore ~/.starkli-wallets/deployer/account0_keystore.json\n" +"```" +msgstr "" +"```bash\n" +"starkli deploy 0x06974677a079b7edfadcd70aa4d12aac0263a4cda379009fca125e0ab1a9ba52 0x03ee9e18edc71a6df30ac3aca2e0b02a198fbce19b7480a63a0d71cbd76652e0 " +"0x033c627a3e5213790e246a917770ce23d7e562baa5b4d2917c23b1be6d91961c 0x01d98d835e43b032254ffbef0f150c5606fa9c5c9310b1fae370ab956a7919f5 --rpc http://0.0.0.0:5050 --account ~/.starkli-" +"wallets/deployer/account0_account.json --keystore ~/.starkli-wallets/deployer/account0_keystore.json\n" +"```" + +#: src/ch99-01-04-01-voting-contract.md:314 +msgid "" +"In this case, the contract has been deployed at an specific address: `0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349`. This address will be different for you. We " +"will use this address to interact with the contract." +msgstr "在本例中,合同已部署到特定地址:`0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349`。您应该会看到不同的地址。我们将使用此地址与合约进行交互。" + +#: src/ch99-01-04-01-voting-contract.md:316 +msgid "### Voter Eligibility Verification" +msgstr "### 投票人资格验证" + +#: src/ch99-01-04-01-voting-contract.md:318 +msgid "" +"In our voting contract, we have two functions to validate voter eligibility, `voter_can_vote` and `is_voter_registered`. These are external read functions, which mean they don't " +"alter the state of the contract but only read the current state." +msgstr "在我们的投票合约中,我们有两个函数来验证投票人的资格,即 `voter_can_vote` 和 `is_voter_registered`。这些函数是外部只读函数,这意味着它们不会改变合约的状态,而只是读取当前状态。" + +#: src/ch99-01-04-01-voting-contract.md:320 +msgid "" +"The `is_voter_registered` function checks whether a particular address is registered as an eligible voter in the contract. The `voter_can_vote` function, on the other hand, checks " +"whether the voter at a specific address is currently eligible to vote, i.e., they are registered and haven't voted already." +msgstr "`is_voter_registered`函数检查特定地址是否在合同中登记为合格投票人。另一方面,`voter_can_vote`函数会检查特定地址的投票人当前是否有资格投票,即他们是否已登记且尚未投票。" + +#: src/ch99-01-04-01-voting-contract.md:322 +msgid "" +"You can call these functions using the `starkli call` command. Note that the `call` command is used for read functions, while the `invoke` command is used for functions that can also " +"write to storage. The `call` command does not require signing, while the `invoke` command does." +msgstr "你可以使用 `starkli call` 命令来调用这些函数。请注意,`call`命令用于只读函数,而 `invoke`命令用于也可以写入存储空间的函数。调用 `call` 命令不需要签名,而 `invoke`命令需要签名。" + +#: src/ch99-01-04-01-voting-contract.md:324 +msgid "" +"```bash+\n" +"starkli call 0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349 voter_can_vote 0x03ee9e18edc71a6df30ac3aca2e0b02a198fbce19b7480a63a0d71cbd76652e0 --rpc " +"http://0.0.0.0:5050\n" +"```" +msgstr "" +"```bash+\n" +"starkli call 0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349 voter_can_vote 0x03ee9e18edc71a6df30ac3aca2e0b02a198fbce19b7480a63a0d71cbd76652e0 --rpc " +"http://0.0.0.0:5050\n" +"```" + +#: src/ch99-01-04-01-voting-contract.md:328 +msgid "" +"First we added the address of the contract, then the function we want to call, and finally the input for the function. In this case, we are checking whether the voter at the address " +"`0x03ee9e18edc71a6df30ac3aca2e0b02a198fbce19b7480a63a0d71cbd76652e0` can vote." +msgstr "" +"首先,我们添加了合约的地址,然后是要调用的函数,最后是函数的输入。在本例中,我们要检查地址为 `0x03ee9e18edc71a6df30ac3aca2e0b02a198fbce19b7480a63a0d71cbd76652e0` 的投票人是否可以投" +"票。" + +#: src/ch99-01-04-01-voting-contract.md:330 +msgid "Since we provided a registered voter address as an input, the result is 1 (boolean true), indicating the voter is eligible to vote." +msgstr "由于我们提供了已登记的投票人的地址作为输入,因此结果为 1(布尔值为 true),表明该选民有资格投票。" + +#: src/ch99-01-04-01-voting-contract.md:332 +msgid "Next, let's call the `is_voter_registered` function using an unregistered account address to observe the output:" +msgstr "接下来,让我们使用一个未注册的账户地址调用 `is_voter_registered` 函数来观察输出结果:" + +#: src/ch99-01-04-01-voting-contract.md:334 +msgid "" +"```bash\n" +"starkli call 0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349 is_voter_registered 0x44444444444444444 --rpc http://0.0.0.0:5050\n" +"```" +msgstr "" +"```bash\n" +"starkli call 0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349 is_voter_registered 0x44444444444444444 --rpc http://0.0.0.0:5050\n" +"```" + +#: src/ch99-01-04-01-voting-contract.md:338 +msgid "With an unregistered account address, the terminal output is 0 (i.e., false), confirming that the account is not eligible to vote." +msgstr "对于未注册的账户地址,终端输出为 0(即假),确认该账户没有投票资格。" + +#: src/ch99-01-04-01-voting-contract.md:340 +msgid "### Casting a Vote" +msgstr "### 投票" + +#: src/ch99-01-04-01-voting-contract.md:342 +msgid "" +"Now that we have established how to verify voter eligibility, we can vote! To vote, we interact with the `vote` function, which is flagged as external, necessitating the use of the " +"`starknet invoke` command." +msgstr "既然我们已经确定了如何验证选民资格,那么我们就可以投票了!投票时,我们要与`vote`函数交互,该函数被标记为外部函数,因此必须使用 `starknet invoke`命令。" + +#: src/ch99-01-04-01-voting-contract.md:344 +msgid "" +"The `invoke` command syntax resembles the `call` command, but for voting, we submit either `1` (for Yes) or `0` (for No) as our input. When we invoke the `vote` function, we are " +"charged a fee, and the transaction must be signed by the voter; we are writing to the contract's storage." +msgstr "" +"`invoke`命令的语法与 `call` 命令类似,但在投票时,我们需要输入 \"1\"(表示 \"是\")或 \"0\"(表示 \"否\")。当我们唤起 `vote` 函数时,我们会被收取一定的费用,而且交易必须由投票人签" +"署;我们正在向合约的存储空间写入内容。" + +#: src/ch99-01-04-01-voting-contract.md:346 +msgid "" +"```bash\n" +"//Voting Yes\n" +"starkli invoke 0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349 vote 1 --rpc http://0.0.0.0:5050 --account ~/.starkli-wallets/deployer/account0_account.json --" +"keystore ~/.starkli-wallets/deployer/account0_keystore.json\n" +"\n" +"//Voting No\n" +"starkli invoke 0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349 vote 0 --rpc http://0.0.0.0:5050 --account ~/.starkli-wallets/deployer/account0_account.json --" +"keystore ~/.starkli-wallets/deployer/account0_keystore.json\n" +"```" +msgstr "" +"```bash\n" +"//Voting Yes\n" +"starkli invoke 0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349 vote 1 --rpc http://0.0.0.0:5050 --account ~/.starkli-wallets/deployer/account0_account.json --" +"keystore ~/.starkli-wallets/deployer/account0_keystore.json\n" +"\n" +"//Voting No\n" +"starkli invoke 0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349 vote 0 --rpc http://0.0.0.0:5050 --account ~/.starkli-wallets/deployer/account0_account.json --" +"keystore ~/.starkli-wallets/deployer/account0_keystore.json\n" +"```" + +#: src/ch99-01-04-01-voting-contract.md:354 +msgid "" +"You will be prompted to enter the password for the signer. Once you enter the password, the transaction will be signed and submitted to the Starknet network. You will receive the " +"transaction hash as output. With the starkli transaction command, you can get more details about the transaction:" +msgstr "系统将提示您输入签名者的密码。输入密码后,交易将被签署并提交到Starknet网络。你将收到交易哈希值作为输出。使用 starkli 交易命令,你可以获得更多关于交易的详细信息:" + +#: src/ch99-01-04-01-voting-contract.md:356 +msgid "" +"```bash\n" +"starkli transaction --rpc http://0.0.0.0:5050\n" +"```" +msgstr "" +"```bash\n" +"starkli transaction --rpc http://0.0.0.0:5050\n" +"```" + +#: src/ch99-01-04-01-voting-contract.md:360 +msgid "This returns:" +msgstr "这个会返回:" + +#: src/ch99-01-04-01-voting-contract.md:362 +msgid "" +"```bash\n" +"{\n" +" \"transaction_hash\": \"0x5604a97922b6811060e70ed0b40959ea9e20c726220b526ec690de8923907fd\",\n" +" \"max_fee\": \"0x430e81\",\n" +" \"version\": \"0x1\",\n" +" \"signature\": [\n" +" \"0x75e5e4880d7a8301b35ff4a1ed1e3d72fffefa64bb6c306c314496e6e402d57\",\n" +" \"0xbb6c459b395a535dcd00d8ab13d7ed71273da4a8e9c1f4afe9b9f4254a6f51\"\n" +" ],\n" +" \"nonce\": \"0x3\",\n" +" \"type\": \"INVOKE\",\n" +" \"sender_address\": \"0x3ee9e18edc71a6df30ac3aca2e0b02a198fbce19b7480a63a0d71cbd76652e0\",\n" +" \"calldata\": [\n" +" \"0x1\",\n" +" \"0x5ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349\",\n" +" \"0x132bdf85fc8aa10ac3c22f02317f8f53d4b4f52235ed1eabb3a4cbbe08b5c41\",\n" +" \"0x0\",\n" +" \"0x1\",\n" +" \"0x1\",\n" +" \"0x1\"\n" +" ]\n" +"}\n" +"```" +msgstr "" +"```bash\n" +"{\n" +" \"transaction_hash\": \"0x5604a97922b6811060e70ed0b40959ea9e20c726220b526ec690de8923907fd\",\n" +" \"max_fee\": \"0x430e81\",\n" +" \"version\": \"0x1\",\n" +" \"signature\": [\n" +" \"0x75e5e4880d7a8301b35ff4a1ed1e3d72fffefa64bb6c306c314496e6e402d57\",\n" +" \"0xbb6c459b395a535dcd00d8ab13d7ed71273da4a8e9c1f4afe9b9f4254a6f51\"\n" +" ],\n" +" \"nonce\": \"0x3\",\n" +" \"type\": \"INVOKE\",\n" +" \"sender_address\": \"0x3ee9e18edc71a6df30ac3aca2e0b02a198fbce19b7480a63a0d71cbd76652e0\",\n" +" \"calldata\": [\n" +" \"0x1\",\n" +" \"0x5ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349\",\n" +" \"0x132bdf85fc8aa10ac3c22f02317f8f53d4b4f52235ed1eabb3a4cbbe08b5c41\",\n" +" \"0x0\",\n" +" \"0x1\",\n" +" \"0x1\",\n" +" \"0x1\"\n" +" ]\n" +"}\n" +"```" + +#: src/ch99-01-04-01-voting-contract.md:386 +msgid "If you try to vote twice with the same signer you will get an error:" +msgstr "如果您尝试用同一个签名者投票两次,则会出现错误:" + +#: src/ch99-01-04-01-voting-contract.md:388 +msgid "" +"```bash\n" +"Error: code=ContractError, message=\"Contract error\"\n" +"```" +msgstr "" +"```bash\n" +"Error: code=ContractError, message=\"Contract error\"\n" +"```" + +#: src/ch99-01-04-01-voting-contract.md:392 +msgid "The error is not very informative, but you can get more details when looking at the output in the terminal where you started `katana` (our local Starknet node):" +msgstr "错误信息很简略,但你可以启动 `katana`(我们的本地Starknet节点)的终端中查看输出,获得更多细节:" + +#: src/ch99-01-04-01-voting-contract.md:394 +msgid "" +"```bash\n" +"...\n" +"Transaction execution error: \"Error in the called contract (0x03ee9e18edc71a6df30ac3aca2e0b02a198fbce19b7480a63a0d71cbd76652e0):\n" +" Error at pc=0:81:\n" +" Got an exception while executing a hint: Custom Hint Error: Execution failed. Failure reason: \\\"USER_ALREADY_VOTED\\\".\n" +" ...\n" +"```" +msgstr "" +"```bash\n" +"...\n" +"Transaction execution error: \"Error in the called contract (0x03ee9e18edc71a6df30ac3aca2e0b02a198fbce19b7480a63a0d71cbd76652e0):\n" +" Error at pc=0:81:\n" +" Got an exception while executing a hint: Custom Hint Error: Execution failed. Failure reason: \\\"USER_ALREADY_VOTED\\\".\n" +" ...\n" +"```" + +#: src/ch99-01-04-01-voting-contract.md:402 +msgid "The key for the error is `USER_ALREADY_VOTED`." +msgstr "错误的关键字是 `USER_ALREADY_VOTED`。" + +#: src/ch99-01-04-01-voting-contract.md:404 +msgid "" +"```bash\n" +"assert(can_vote == true, 'USER_ALREADY_VOTED');\n" +"```" +msgstr "" +"```bash\n" +"assert(can_vote == true, 'USER_ALREADY_VOTED');\n" +"```" + +#: src/ch99-01-04-01-voting-contract.md:408 +msgid "" +"We can repeat the process to create Signers and Account Descriptors for the accounts we want to use for voting. Remember that each Signer must be created from a private key, and each " +"Account Descriptor must be created from a public key, a smart wallet address, and the smart wallet class hash (which is the same for each voter)." +msgstr "" +"我们可以重复上述过程,为要将用于投票的账户创建签名者和账户描述符。请记住,每个签名者都必须用私钥创建,每个账户描述符都必须用公钥、智能钱包地址和智能钱包class hash (每个投票者的class " +"hash 都一样)创建。" + +#: src/ch99-01-04-01-voting-contract.md:410 +msgid "" +"```bash\n" +"starkli invoke 0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349 vote 0 --rpc http://0.0.0.0:5050 --account ~/.starkli-wallets/deployer/account1_account.json --" +"keystore ~/.starkli-wallets/deployer/account1_keystore.json\n" +"\n" +"starkli invoke 0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349 vote 1 --rpc http://0.0.0.0:5050 --account ~/.starkli-wallets/deployer/account2_account.json --" +"keystore ~/.starkli-wallets/deployer/account2_keystore.json\n" +"```" +msgstr "" +"```bash\n" +"starkli invoke 0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349 vote 0 --rpc http://0.0.0.0:5050 --account ~/.starkli-wallets/deployer/account1_account.json --" +"keystore ~/.starkli-wallets/deployer/account1_keystore.json\n" +"\n" +"starkli invoke 0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349 vote 1 --rpc http://0.0.0.0:5050 --account ~/.starkli-wallets/deployer/account2_account.json --" +"keystore ~/.starkli-wallets/deployer/account2_keystore.json\n" +"```" + +#: src/ch99-01-04-01-voting-contract.md:416 +msgid "### Visualizing Vote Outcomes" +msgstr "### 投票结果可视化" + +#: src/ch99-01-04-01-voting-contract.md:418 +msgid "To examine the voting results, we invoke the `get_vote_status` function, another view function, through the `starknet call` command." +msgstr "为了检查投票结果,我们通过 `starknet call`命令调用另一个视图函数 `get_vote_status`。" + +#: src/ch99-01-04-01-voting-contract.md:420 +msgid "" +"```bash\n" +"starkli call 0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349 get_vote_status --rpc http://0.0.0.0:5050\n" +"```" +msgstr "" +"```bash\n" +"starkli call 0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349 get_vote_status --rpc http://0.0.0.0:5050\n" +"```" + +#: src/ch99-01-04-01-voting-contract.md:424 +msgid "The output reveals the tally of \"Yes\" and \"No\" votes along with their relative percentages." +msgstr "输出结果显示了 \"Yes\"和 \"No\" 票数及其相对百分比。" + +#: src/ch99-04-00-L1-L2-messaging.md:1 +msgid "# L1-L2 Messaging" +msgstr "# L1-L2 间信息传递" + +#: src/ch99-04-00-L1-L2-messaging.md:3 +msgid "A crucial feature of a Layer 2 is its ability to interact with Layer 1." +msgstr "Layer 2的一个重要特征是它能与Layer 1交互。" + +#: src/ch99-04-00-L1-L2-messaging.md:5 +msgid "" +"Starknet has its own L1 <> L2 Messaging system, which is different from its consensus mechanism and the submission of state updates on L1. Messaging is a way for smart-contracts on " +"L1 to interact with smart-contracts on L2 (or the other way around), allowing us to do \"cross-chain\" transactions. For example, we can do some computations on a chain and use the " +"result of this computation on the other chain." +msgstr "" +"Starknet拥有自己的 L1 <> L2 消息传递系统,它不同于共识机制和 L1 上的状态更新提交。消息传递是 L1 上的智能合约与 L2 上的智能合约进行交互(或反方向)的一种方式,允许我们进行 \"跨链 \"交" +"易。例如,我们可以在一条链上进行一些计算,并在另一条链上使用计算结果。" + +#: src/ch99-04-00-L1-L2-messaging.md:7 +msgid "" +"Bridges on Staknet all use L1-L2 messaging. Let's say that you want to bridge tokens from Ethereum to Starknet. You will simply have to deposit your tokens in the L1 bridge contract, " +"which will automatically trigger the minting of the same token on L2. Another good use case for L1-L2 messaging would be [DeFi pooling](https://starkware.co/resource/defi-pooling/)." +msgstr "" +"Staknet 上的桥都使用 L1-L2 消息传递。比方说,您想将代币从以太坊桥接到Staknet。您只需在 L1 桥接合约中存入您的代币,这将自动触发 L2 上相同代币的铸造。L1-L2 消息传递的另一个很好的例子是 " +"[DeFi 资金池](https://starkware.co/resource/defi-pooling/)。" + +#: src/ch99-04-00-L1-L2-messaging.md:9 +msgid "Let's dive into the details." +msgstr "让我们来详细了解一下。" + +#: src/ch99-04-00-L1-L2-messaging.md:11 +msgid "## The StarknetMessaging Contract" +msgstr "## Starknet消息传递合约" + +#: src/ch99-04-00-L1-L2-messaging.md:13 +msgid "" +"The crucial component of the L1 <> L2 Messaging system is the [`StarknetCore`](https://etherscan.io/address/0xc662c410C0ECf747543f5bA90660f6ABeBD9C8c4) contract. It is a set of " +"Solidity contracts deployed on Ethereum that allows Starknet to function properly. One of the contracts of `StarknetCore` is called `StarknetMessaging` and it is the contract " +"responsible for passing messages between Starknet and Ethereum. `StarknetMessaging` follows an [interface](https://github.com/starkware-libs/cairo-lang/" +"blob/4e233516f52477ad158bc81a86ec2760471c1b65/src/starkware/starknet/eth/IStarknetMessaging.sol#L6) with functions allowing to send message to L2, receiving messages on L1 from L2 " +"and canceling messages." +msgstr "" +"L1 <> L2消息传递系统的关键组成部分是[`StarknetCore`](https://etherscan.io/address/0xc662c410C0ECf747543f5bA90660f6ABeBD9C8c4)合约。它是一组部署在以太坊上的 Solidity 合约,可以让" +"Starknet正常运行。`StarknetCore`的其中一个合约叫做 `StarknetMessaging`,它负责在Starknet和以太坊之间传递消息。`StarknetMessaging` 遵循一个[接口](https://github.com/starkware-libs/" +"cairo-lang/blob/4e233516f52477ad158bc81a86ec2760471c1b65/src/starkware/starknet/eth/IStarknetMessaging.sol#L6),其功能允许向 L2 发送消息、从 L2 接收 L1 上的消息以及取消消息。" + +#: src/ch99-04-00-L1-L2-messaging.md:15 +msgid "" +"```js\n" +"interface IStarknetMessaging is IStarknetMessagingEvents {\n" +"\n" +" function sendMessageToL2(\n" +" uint256 toAddress,\n" +" uint256 selector,\n" +" uint256[] calldata payload\n" +" ) external returns (bytes32);\n" +"\n" +" function consumeMessageFromL2(uint256 fromAddress, uint256[] calldata payload)\n" +" external\n" +" returns (bytes32);\n" +"\n" +" function startL1ToL2MessageCancellation(\n" +" uint256 toAddress,\n" +" uint256 selector,\n" +" uint256[] calldata payload,\n" +" uint256 nonce\n" +" ) external;\n" +"\n" +" function cancelL1ToL2Message(\n" +" uint256 toAddress,\n" +" uint256 selector,\n" +" uint256[] calldata payload,\n" +" uint256 nonce\n" +" ) external;\n" +"}\n" +"```" +msgstr "" +"```js\n" +"interface IStarknetMessaging is IStarknetMessagingEvents {\n" +"\n" +" function sendMessageToL2(\n" +" uint256 toAddress,\n" +" uint256 selector,\n" +" uint256[] calldata payload\n" +" ) external returns (bytes32);\n" +"\n" +" function consumeMessageFromL2(uint256 fromAddress, uint256[] calldata payload)\n" +" external\n" +" returns (bytes32);\n" +"\n" +" function startL1ToL2MessageCancellation(\n" +" uint256 toAddress,\n" +" uint256 selector,\n" +" uint256[] calldata payload,\n" +" uint256 nonce\n" +" ) external;\n" +"\n" +" function cancelL1ToL2Message(\n" +" uint256 toAddress,\n" +" uint256 selector,\n" +" uint256[] calldata payload,\n" +" uint256 nonce\n" +" ) external;\n" +"}\n" +"```" + +#: src/ch99-04-00-L1-L2-messaging.md:44 +msgid " Starknet messaging contract interface" +msgstr "Starknet消息传送合约接口" + +#: src/ch99-04-00-L1-L2-messaging.md:46 +msgid "" +"The Starknet sequencer can receive the messages sent from Ethereum to the `StarknetMessaging` contract and trigger the appropriate functions on L2, or send messages to `StarknetCore` " +"on L1." +msgstr "Starknet排序器可以接收从以太坊发送到 `StarknetMessaging` 合约的信息,并在 L2 上触发相应的功能,或在 L1 上向 `StarknetCore`发送信息。" + +#: src/ch99-04-00-L1-L2-messaging.md:48 +msgid "## Sending messages from Ethereum to Starknet" +msgstr "## 从以太坊向Starknet发送信息" + +#: src/ch99-04-00-L1-L2-messaging.md:50 +msgid "" +"If you want to send messages from Ethereum to Starknet, your Solidity contracts must call the `sendMessageToL2` function of the `StarknetMessaging` contract. To receive these " +"messages on Starknet, you will need to annotate functions that can be called from L1 with the `#[l1_handler]` attribute." +msgstr "" +"如果你想从 Ethereum 向 Starknet 发送消息,你的 Solidity 合约必须调用 `StarknetMessaging` 合约的 `sendMessageToL2` 函数。要在 Starknet 上接收这些消息,你需要用 `#[l1_handler]` 属性注解" +"可从 L1 调用的函数。" + +#: src/ch99-04-00-L1-L2-messaging.md:52 +msgid "" +"Let's take an example. It is adapted from the [starknet-edu L1-L2 exercises](https://github.com/starknet-edu/starknet-messaging-bridge/tree/main). It's a contract that can receive a " +"message sent from L1 and store it, and also send a message to L1." +msgstr "" +"让我们举个例子。它改编自 [starknet-edu L1-L2 练习](https://github.com/starknet-edu/starknet-messaging-bridge/tree/main)。这是一个可以接收 L1 发送的信息并将其存储起来,同时也可以向 L1 " +"发送信息的合约。" + +#: src/ch99-04-00-L1-L2-messaging.md:54 +msgid "" +"To give a bit of context, here we have two contracts, one on Ethereum and the other on Starknet. Both interact with each other. The goal of the workshop is to find a way to earn " +"points by sending messages from one chain to the other." +msgstr "在这里,我们有两个合约,一个在 Ethereum 上,另一个在 Starknet 上。两者相互影响。这个练习的目标是找到一种方法,通过从一个链向另一个链发送信息来赚取积分。" + +#: src/ch99-04-00-L1-L2-messaging.md:56 +msgid "Here is a snippet of the solidity code to send a simple message from Ethereum to Starknet:" +msgstr "下面是一段 solidity 代码,用于从 Ethereum 向 Starknet 发送一条简单的信息:" + +#: src/ch99-04-00-L1-L2-messaging.md:58 +msgid "" +"```rust\n" +"function ex01SendMessageToL2(uint256 value) external payable{\n" +"\n" +" // This function call requires money to send L2 messages, we check there is enough\n" +" require(msg.value>=10000000000, \"Message fee missing\");\n" +"\n" +" // Sending the message to the l2 contract\n" +" // Creating the payload\n" +" uint256[] memory payload = new uint256[](1);\n" +" // Adding the value to the payload\n" +" payload[0] = value;\n" +" // Sending the message\n" +" starknetCore.sendMessageToL2{value: 10000000000}(l2Evaluator, ex01_selector, payload);\n" +"}\n" +"```" +msgstr "" +"```rust\n" +"function ex01SendMessageToL2(uint256 value) external payable{\n" +"\n" +" // This function call requires money to send L2 messages, we check there is enough\n" +" require(msg.value>=10000000000, \"Message fee missing\");\n" +"\n" +" // Sending the message to the l2 contract\n" +" // Creating the payload\n" +" uint256[] memory payload = new uint256[](1);\n" +" // Adding the value to the payload\n" +" payload[0] = value;\n" +" // Sending the message\n" +" starknetCore.sendMessageToL2{value: 10000000000}(l2Evaluator, ex01_selector, payload);\n" +"}\n" +"```" + +#: src/ch99-04-00-L1-L2-messaging.md:74 +msgid "The signature of `StarknetCore.sendMessageToL2` is:" +msgstr "`StarknetCore.sendMessageToL2`的签名是:" + +#: src/ch99-04-00-L1-L2-messaging.md:76 +msgid "" +"```js\n" +"function sendMessageToL2(\n" +" uint256 toAddress,\n" +" uint256 selector,\n" +" uint256[] calldata payload\n" +" ) external override returns (bytes32);\n" +"```" +msgstr "" +"```js\n" +"function sendMessageToL2(\n" +" uint256 toAddress,\n" +" uint256 selector,\n" +" uint256[] calldata payload\n" +" ) external override returns (bytes32);\n" +"```" + +#: src/ch99-04-00-L1-L2-messaging.md:84 +msgid "" +"In `ex01SendMessageToL2`, we first construct the message (the payload). It is an array of `uint256`. Then we call `StarknetCore.sendMessageToL2`. The first parameter is the L2 " +"contract address. The second is the selector (or the `sn_keccak` hash of the name of the function we want to call on L2), followed by the payload. We add a fee to it as a `msg.value` " +"because we need to pay the transaction on L2." +msgstr "" +"在 `ex01SendMessageToL2` 中,我们首先构建信息(有效载荷)。它是一个 `uint256` 数组。然后,我们调用 `StarknetCore.sendMessageToL2`。第一个参数是 L2 合约地址。第二个参数是选择器(或我们" +"要在 L2 上调用的函数名称的 `sn_keccak` 的哈希值),然后是payload。我们在其中添加gas费用作为 `msg.value`,因为我们需要在 L2 上支付交易费用。" + +#: src/ch99-04-00-L1-L2-messaging.md:86 +msgid "On the Starknet side, to receive this message, we have:" +msgstr "在Starknet方面,要接收这条信息,我们需要:" + +#: src/ch99-04-00-L1-L2-messaging.md:88 +msgid "" +"```rust\n" +" #[l1_handler]\n" +" fn ex_01_receive_message_from_l1(\n" +" ref self: ContractState, from_address: felt252, message: usize\n" +" ) {\n" +" // Selector: 0x274ab8abc4e270a94c36e1a54c794cd4dd537eeee371e7188c56ee768c4c0c4\n" +" // Check that the sender is the correct L1 evaluator\n" +" assert(from_address == self.l1_evaluator_address.read(), 'WRONG L1 EVALUATOR');\n" +" // Adding a check on the message, because why not?\n" +" assert(message > 168111, 'MESSAGE TOO SMALL');\n" +" assert(message < 5627895, 'MESSAGE TOO BIG');\n" +"\n" +" // Store the message received from L1\n" +" let mut message_count = self.messages_count.read();\n" +" self.messages.write(message_count, message);\n" +" message_count += 1;\n" +" self.messages_count.write(message_count);\n" +" }\n" +"```" +msgstr "" +"```rust\n" +" #[l1_handler]\n" +" fn ex_01_receive_message_from_l1(\n" +" ref self: ContractState, from_address: felt252, message: usize\n" +" ) {\n" +" // Selector: 0x274ab8abc4e270a94c36e1a54c794cd4dd537eeee371e7188c56ee768c4c0c4\n" +" // Check that the sender is the correct L1 evaluator\n" +" assert(from_address == self.l1_evaluator_address.read(), 'WRONG L1 EVALUATOR');\n" +" // Adding a check on the message, because why not?\n" +" assert(message > 168111, 'MESSAGE TOO SMALL');\n" +" assert(message < 5627895, 'MESSAGE TOO BIG');\n" +"\n" +" // Store the message received from L1\n" +" let mut message_count = self.messages_count.read();\n" +" self.messages.write(message_count, message);\n" +" message_count += 1;\n" +" self.messages_count.write(message_count);\n" +" }\n" +"```" + +#: src/ch99-04-00-L1-L2-messaging.md:108 +msgid "" +"We need to add the `#[l1_handler]` attribute to our function. L1 handlers are special functions that can only be triggered by the sequencer following a message sent from L1. There is " +"nothing particular to do to receive transactions from L1, as the message is relayed by the sequencer automatically. In your `#[l1_handler]` functions, it is important to verify the " +"sender of the L1 message to ensure that our contract can only receive messages from a trusted L1 contract." +msgstr "" +"我们需要在函数中添加 `#[l1_handler]` 属性。L1 handler是一种特殊函数,只能由排序器在收到 L1 发送的信息后触发。接收来自 L1 的事务无需做任何特殊处理,因为排序器会自动转发消息。在您的 " +"`#[l1_handler]` 函数中,必须验证 L1 消息的发送者,以确保我们的合约只能接收来自可信 L1 合约的消息。" + +#: src/ch99-04-00-L1-L2-messaging.md:110 +msgid "## Sending messages from Starknet to Ethereum" +msgstr "## 从Starknet向以太坊发送信息" + +#: src/ch99-04-00-L1-L2-messaging.md:112 +msgid "" +"When sending messages from Starknet to Ethereum, you will have to use the `send_message_to_l1` syscall in your Cairo contracts. This syscall allows you to send messages to the " +"`StarknetMessaging` contract on L1. Unlike L1-to-L2 messages, L2-to-L1 messages are not automatically consumed, which means that you will need your Solidity contract to call the " +"`consumeMessageFromL2` function explicitly in order to consume the message." +msgstr "" +"当从Starknet向以太坊发送消息时,你必须在Cairo合约中使用`send_message_to_l1`系统调用。该系统调用允许你向 L1 上的 `StarknetMessaging` 合约发送消息。与 L1 到 L2 的消息不同,L2 到 L1 的消" +"息不会被自动消费,这意味着你需要在 Solidity 合约中明确调用 `consumeMessageFromL2` 函数才能消费消息。" + +#: src/ch99-04-00-L1-L2-messaging.md:114 +msgid "To send a message from L2 to L1, what we would do on Starknet is:" +msgstr "要从 L2 向 L1 发送信息,我们在Starknet上要做的是:" + +#: src/ch99-04-00-L1-L2-messaging.md:116 +msgid "" +"```rust\n" +"\n" +" #[external(v0)]\n" +" #[generate_trait]\n" +" impl Evaluator of IEvaluator {\n" +" fn ex_02_send_message_to_l1(ref self: ContractState, value: usize) {\n" +" // Create the message payload\n" +" // By default it's an array of felt252\n" +" let mut message_payload = ArrayTrait::new();\n" +" // Adding the address of the caller on L2\n" +" message_payload.append(get_caller_address().into());\n" +" // Adding the value\n" +" message_payload.append(value.into());\n" +" // Sending the message\n" +" send_message_to_l1_syscall(self.l1_evaluator_address.read(), message_payload.span());\n" +" }\n" +"\n" +" fn get_l1_evaluator_address(self: @ContractState) -> felt252 {\n" +" self.l1_evaluator_address.read()\n" +" }\n" +" }\n" +"```" +msgstr "" +"```rust\n" +"\n" +" #[external(v0)]\n" +" #[generate_trait]\n" +" impl Evaluator of IEvaluator {\n" +" fn ex_02_send_message_to_l1(ref self: ContractState, value: usize) {\n" +" // Create the message payload\n" +" // By default it's an array of felt252\n" +" let mut message_payload = ArrayTrait::new();\n" +" // Adding the address of the caller on L2\n" +" message_payload.append(get_caller_address().into());\n" +" // Adding the value\n" +" message_payload.append(value.into());\n" +" // Sending the message\n" +" send_message_to_l1_syscall(self.l1_evaluator_address.read(), message_payload.span());\n" +" }\n" +"\n" +" fn get_l1_evaluator_address(self: @ContractState) -> felt252 {\n" +" self.l1_evaluator_address.read()\n" +" }\n" +" }\n" +"```" + +#: src/ch99-04-00-L1-L2-messaging.md:139 +msgid "We simply build the payload and pass it, along with the L1 contract address, to the syscall function." +msgstr "我们只需构建payload,并将其与 L1 合约地址一起传递给系统调用函数。" + +#: src/ch99-04-00-L1-L2-messaging.md:141 +msgid "On L1, the important part is to build the same payload as on L2. Then you call `starknetCore.consumeMessageFromL2` by passing the L2 contract address and the payload." +msgstr "在 L1 上,重要的是构建与 L2 上相同的payload。然后,调用 `starknetCore.consumeMessageFromL2`并将 L2 合约地址和payload 传递给它。" + +#: src/ch99-04-00-L1-L2-messaging.md:143 +msgid "" +"```js\n" +"function ex02ReceiveMessageFromL2(uint256 player_l2_address, uint256 message) external payable{\n" +"\n" +" require(msg.value>=10000000000, \"Message fee missing\");\n" +" // Consuming the message\n" +" // Reconstructing the payload of the message we want to consume\n" +" uint256[] memory payload = new uint256[](2);\n" +" // Adding the address of the player on L2\n" +" payload[0] = caller_l2_address;\n" +" // Adding the message\n" +" payload[1] = message;\n" +" // Adding a constraint on the message, to make sure players read BOTH contracts ;-)\n" +" require(message>3121906, 'Message too small');\n" +" require(message<4230938, 'Message too big');\n" +"\n" +" // If the message constructed above was indeed sent by starknet, this returns the hash of the message\n" +" // If the message was NOT sent by starknet, the cal will revert\n" +" starknetCore.consumeMessageFromL2(l2Evaluator, payload);\n" +"\n" +" // Firing an event, for fun\n" +" emit MessageReceived(message);\n" +" }\n" +"```" +msgstr "" +"```js\n" +"function ex02ReceiveMessageFromL2(uint256 player_l2_address, uint256 message) external payable{\n" +"\n" +" require(msg.value>=10000000000, \"Message fee missing\");\n" +" // Consuming the message\n" +" // Reconstructing the payload of the message we want to consume\n" +" uint256[] memory payload = new uint256[](2);\n" +" // Adding the address of the player on L2\n" +" payload[0] = caller_l2_address;\n" +" // Adding the message\n" +" payload[1] = message;\n" +" // Adding a constraint on the message, to make sure players read BOTH contracts ;-)\n" +" require(message>3121906, 'Message too small');\n" +" require(message<4230938, 'Message too big');\n" +"\n" +" // If the message constructed above was indeed sent by starknet, this returns the hash of the message\n" +" // If the message was NOT sent by starknet, the cal will revert\n" +" starknetCore.consumeMessageFromL2(l2Evaluator, payload);\n" +"\n" +" // Firing an event, for fun\n" +" emit MessageReceived(message);\n" +" }\n" +"```" + +#: src/ch99-04-00-L1-L2-messaging.md:167 +msgid "" +"It is important to remember that on L1 we are sending a payload of `uint256`, but the basic data type on Starknet is `felt252`; however, `felt252` are approximatively 4 bits smaller " +"than `uint256`. So we have to pay attention to the values contained in the payload of the messages we are sending. If, on L1, we build a message with values above the maximum " +"`felt252`, the message will be stuck and never consumed on L2." +msgstr "" +"重要的是要记住,在 L1 上,我们发送的payload是 `uint256`,但Starknet的基本数据类型是 `felt252`;但是,`felt252`比 `uint256`大约小 4 位。因此,我们必须注意发送信息的payload中包含的值。" +"如果我们在 L1 上构建的报文的值超过了 `felt252`的最大值,那么该报文就会被卡住,在 L2 上永远不会被消费。" + +#: src/ch99-04-00-L1-L2-messaging.md:169 +msgid "" +"If you want to learn more about the messaging mechanism, you can visit the [Starknet documentation](https://docs.starknet.io/documentation/architecture_and_concepts/L1-" +"L2_Communication/messaging-mechanism/)." +msgstr "如果你想了解更多关于消息机制的信息,可以访问 [Starknet 文档](https://docs.starknet.io/documentation/architecture_and_concepts/L1-L2_Communication/messaging-mechanism/)。" + +#: src/ch99-03-security-considerations.md:1 +msgid "# Security Considerations" +msgstr "# 安全考量" + +#: src/ch99-03-security-considerations.md:3 +msgid "When developing software, ensuring it functions as intended is usually straightforward. However, preventing unintended usage and vulnerabilities can be more challenging." +msgstr "在开发软件时,确保其按预期运行通常比较简单而直接。然而,防止非预期的使用和漏洞可能更具挑战性。" + +#: src/ch99-03-security-considerations.md:5 +msgid "In smart contract development, security is very important. A single error can result in the loss of valuable assets or the improper functioning of certain features." +msgstr "在智能合约的开发中,安全性非常重要。仅仅一个简单的错误就可能导致宝贵资产的损失或某些功能的错误运行。" + +#: src/ch99-03-security-considerations.md:7 +msgid "" +"Smart contracts are executed in a public environment where anyone can examine the code and interact with it. Any errors or vulnerabilities in the code can be exploited by malicious " +"actors." +msgstr "智能合约在一个公开的环境中执行,任何人都可以检查代码并与之交互。代码中的任何错误或漏洞都可能被恶意行为者利用。" + +#: src/ch99-03-security-considerations.md:9 +msgid "" +"This chapter presents general recommendations for writing secure smart contracts. By incorporating these concepts during development, you can create robust and reliable smart " +"contracts. This reduces the chances of unexpected behavior or vulnerabilities." +msgstr "本章介绍了编写安全智能合约的一般建议。在开发过程中,通过融入这些概念,你可以创建健壮可靠的智能合约。这将减少出现意外行为或漏洞的机会。" + +#: src/ch99-03-security-considerations.md:11 +msgid "## Disclaimer" +msgstr "## 免责声明" + +#: src/ch99-03-security-considerations.md:13 +msgid "This chapter does not provide an exhaustive list of all possible security issues, and it does not guarantee that your contracts will be completely secure." +msgstr "本章并未提供所有可能的安全问题的详尽列表,也不能保证您的合约完全安全。" + +#: src/ch99-03-security-considerations.md:15 +msgid "If you are developing smart contracts for production use, it is highly recommended to conduct external audits performed by security experts." +msgstr "如果您正在开发用于实际生产环境中的智能合约,强烈建议由安全专家对其进行第三方审计。" + +#: src/ch99-03-security-considerations.md:17 +msgid "## Mindset" +msgstr "## 安全思维" + +#: src/ch99-03-security-considerations.md:19 +msgid "" +"Cairo is a highly safe language inspired by rust. It is designed in a way that force you to cover all possible cases. Security issues on Starknet mostly arise from the way smart " +"contracts flows are designed, not much from the language itself." +msgstr "Cairo 是一种受到 Rust 启发的高度安全的语言。它的设计方式强制你覆盖所有可能的情况。在 Starknet 上的安全问题主要源于智能合约流程的设计,而非语言本身。" + +#: src/ch99-03-security-considerations.md:21 +msgid "Adopting a security mindset is the initial step in writing secure smart contracts. Try to always consider all possible scenarios when writing code." +msgstr "采用安全思维是编写安全智能合约的第一步。在编写代码时,尽量始终考虑所有可能的场景。" + +#: src/ch99-03-security-considerations.md:23 +msgid "### Viewing smart contract as Finite State Machines" +msgstr "### 将智能合约视为有限状态机" + +#: src/ch99-03-security-considerations.md:25 +msgid "Transactions in smart contracts are atomic, meaning they either succeed or fail without making any changes." +msgstr "智能合约中的交易是原子性的,这意味着它们要么成功,要么失败且不发生任何变化。" + +#: src/ch99-03-security-considerations.md:27 +msgid "" +"Think of smart contracts as state machines: they have a set of initial states defined by the constructor constraints, and external function represents a set of possible state " +"transitions. A transaction is nothing more than a state transition." +msgstr "将智能合约视为状态机:它们有一组由构造函数约束定义的初始状态,而外部函数表示一组可能的状态转换。所谓交易也不过是一个状态转换。" + +#: src/ch99-03-security-considerations.md:29 +msgid "" +"The `assert` or `panic` functions can be used to validate conditions before performing specific actions. You can learn more about these on the [Unrecoverable Errors with panic](./" +"ch09-01-unrecoverable-errors-with-panic.md) page." +msgstr "`assert` 或 `panic` 函数可以用于在执行特定操作之前验证条件。您可以在[无法恢复的错误与panic](./ch09-01-unrecoverable-errors-with-panic.md)页面上了解更多信息。" + +#: src/ch99-03-security-considerations.md:31 +msgid "These validations can include:" +msgstr "这些验证会包括:" + +#: src/ch99-03-security-considerations.md:33 +msgid "" +"- Inputs provided by the caller\n" +"- Execution requirements\n" +"- Invariants (conditions that must always be true)\n" +"- Return values from other function calls" +msgstr "" +"- 调用者提供的输入参数\n" +"- 执行要求\n" +"- 不变量(必须始终为真的条件)\n" +"- 其他函数调用的返回值" + +#: src/ch99-03-security-considerations.md:38 +msgid "" +"For example, you could use the `assert` function to validate that a user has enough funds to perform a withdraw transaction. If the condition is not met, the transaction will fail " +"and the state of the contract will not change." +msgstr "例如,您可以使用 `assert` 函数来验证用户是否具有足够的资金执行提款交易。如果条件不满足,交易将失败,并且合约的状态不会发生变化。" + +#: src/ch99-03-security-considerations.md:40 +msgid "" +"```rust,noplayground\n" +" impl Contract of IContract {\n" +" fn withdraw(ref self: ContractState, amount: u256) {\n" +" let current_balance = self.balance.read();\n" +"\n" +" assert(self.balance.read() >= amount, 'Insufficient funds');\n" +"\n" +" self.balance.write(current_balance - amount);\n" +" }\n" +"```" +msgstr "" +"```rust,noplayground\n" +" impl Contract of IContract {\n" +" fn withdraw(ref self: ContractState, amount: u256) {\n" +" let current_balance = self.balance.read();\n" +"\n" +" assert(self.balance.read() >= amount, 'Insufficient funds');\n" +"\n" +" self.balance.write(current_balance - amount);\n" +" }\n" +"```" + +#: src/ch99-03-security-considerations.md:51 +msgid "" +"Using these functions to check conditions adds constraints that help clearly define the boundaries of possible state transitions for each function in your smart contract. These " +"checks ensure that the behavior of the contract stays within the expected limits." +msgstr "使用这些函数来进行条件检查,添加一些有助于清晰地定义智能合约中每个函数可能的状态转换的边界的约束。这些检查确保合约的行为保持在预期范围内。" + +#: src/ch99-03-security-considerations.md:53 +msgid "## Recommendations" +msgstr "## 建议" + +#: src/ch99-03-security-considerations.md:55 +msgid "### Checks Effects Interactions Pattern" +msgstr "### 检查-效果-交互 模式" + +#: src/ch99-03-security-considerations.md:57 +msgid "" +"The Checks Effects Interactions pattern is a common design pattern used to prevent reentrancy attacks on Ethereum. While reentrancy is harder to achieve in Starknet, it is still " +"recommended to use this pattern in your smart contracts." +msgstr "检查-效果-交互模式是一种常见的设计模式,用于防止以太坊上的重入攻击。尽管在 Starknet 上更难实现重入攻击,但仍建议在智能合约中使用这种模式。" + +#: src/ch99-03-security-considerations.md:59 +msgid "" +msgstr "" + +#: src/ch99-03-security-considerations.md:61 +msgid "The pattern consists of following a specific order of operations in your functions:" +msgstr "该模式由在函数中按照特定的操作顺序进行操作来实现:" + +#: src/ch99-03-security-considerations.md:63 +msgid "" +"1. **Checks**: Validate all conditions and inputs before performing any state changes.\n" +"2. **Effects**: Perform all state changes.\n" +"3. **Interactions**: All external calls to other contracts should be made at the end of the function." +msgstr "" +"1. **Checks(检查)**: 在执行任何状态更改之前,验证所有条件和输入。\n" +"2. **Effects(效果)**: 执行所有状态更改。\n" +"3. **Interactions(交互)**: 所有对其他合约的外部调用应在函数的最后进行。" + +#: src/ch99-03-security-considerations.md:67 +msgid "### Access control" +msgstr "### 访问控制" + +#: src/ch99-03-security-considerations.md:69 +msgid "" +"Access control is the process of restricting access to certain features or resources. It is a common security mechanism used to prevent unauthorized access to sensitive information " +"or actions. In smart contracts, some functions may often be restricted to specific users or roles." +msgstr "访问控制是限制对特定功能或资源的访问的过程。它是一种常见的安全机制,用于防止未经授权的敏感信息访问或操作。在智能合约中,某些函数可能经常需要被限制为特定的用户或角色使用。" + +#: src/ch99-03-security-considerations.md:71 +msgid "" +"You can implement the access control pattern to easily manage permissions. This pattern consists of defining a set of roles and assigning them to specific users. Each function can " +"then be restricted to specific roles." +msgstr "您可以使用访问控制模式来轻松管理权限。该模式包括定义一组不同权限角色,并给不同用户分配对应的角色。每个函数都可限制为特定的角色才可访问。" + +#: src/ch99-03-security-considerations.md:73 +msgid "" +"```rust,noplayground\n" +"#[starknet::contract]\n" +"mod access_control_contract {\n" +" use starknet::ContractAddress;\n" +" use starknet::get_caller_address;\n" +"\n" +" trait IContract {\n" +" fn is_owner(self: @TContractState) -> bool;\n" +" fn is_role_a(self: @TContractState) -> bool;\n" +" fn only_owner(self: @TContractState);\n" +" fn only_role_a(self: @TContractState);\n" +" fn only_allowed(self: @TContractState);\n" +" fn set_role_a(ref self: TContractState, _target: ContractAddress, _active: bool);\n" +" fn role_a_action(ref self: ContractState);\n" +" fn allowed_action(ref self: ContractState);\n" +" }\n" +"\n" +" #[storage]\n" +" struct Storage {\n" +" // Role 'owner': only one address\n" +" owner: ContractAddress,\n" +" // Role 'role_a': a set of addresses\n" +" role_a: LegacyMap::\n" +" }\n" +"\n" +" #[constructor]\n" +" fn constructor(ref self: ContractState) {\n" +" self.owner.write(get_caller_address());\n" +" }\n" +"\n" +" // Guard functions to check roles\n" +"\n" +" impl Contract of IContract {\n" +" #[inline(always)]\n" +" fn is_owner(self: @ContractState) -> bool {\n" +" self.owner.read() == get_caller_address()\n" +" }\n" +"\n" +" #[inline(always)]\n" +" fn is_role_a(self: @ContractState) -> bool {\n" +" self.role_a.read(get_caller_address())\n" +" }\n" +"\n" +" #[inline(always)]\n" +" fn only_owner(self: @ContractState) {\n" +" assert(Contract::is_owner(self), 'Not owner');\n" +" }\n" +"\n" +" #[inline(always)]\n" +" fn only_role_a(self: @ContractState) {\n" +" assert(Contract::is_role_a(self), 'Not role A');\n" +" }\n" +"\n" +" // You can easily combine guards to perfom complex checks\n" +" fn only_allowed(self: @ContractState) {\n" +" assert(Contract::is_owner(self) || Contract::is_role_a(self), 'Not allowed');\n" +" }\n" +"\n" +" // Functions to manage roles\n" +"\n" +" fn set_role_a(ref self: ContractState, _target: ContractAddress, _active: bool) {\n" +" Contract::only_owner(@self);\n" +" self.role_a.write(_target, _active);\n" +" }\n" +"\n" +" // You can now focus on the business logic of your contract\n" +" // and reduce the complexity of your code by using guard functions\n" +"\n" +" fn role_a_action(ref self: ContractState) {\n" +" Contract::only_role_a(@self);\n" +" // ...\n" +" }\n" +"\n" +" fn allowed_action(ref self: ContractState) {\n" +" Contract::only_allowed(@self);\n" +" // ...\n" +" }\n" +" }\n" +"}\n" +"\n" +"```" +msgstr "" +"```rust,noplayground\n" +"#[starknet::contract]\n" +"mod access_control_contract {\n" +" use starknet::ContractAddress;\n" +" use starknet::get_caller_address;\n" +"\n" +" trait IContract {\n" +" fn is_owner(self: @TContractState) -> bool;\n" +" fn is_role_a(self: @TContractState) -> bool;\n" +" fn only_owner(self: @TContractState);\n" +" fn only_role_a(self: @TContractState);\n" +" fn only_allowed(self: @TContractState);\n" +" fn set_role_a(ref self: TContractState, _target: ContractAddress, _active: bool);\n" +" fn role_a_action(ref self: ContractState);\n" +" fn allowed_action(ref self: ContractState);\n" +" }\n" +"\n" +" #[storage]\n" +" struct Storage {\n" +" // Role 'owner': only one address\n" +" owner: ContractAddress,\n" +" // Role 'role_a': a set of addresses\n" +" role_a: LegacyMap::\n" +" }\n" +"\n" +" #[constructor]\n" +" fn constructor(ref self: ContractState) {\n" +" self.owner.write(get_caller_address());\n" +" }\n" +"\n" +" // Guard functions to check roles\n" +"\n" +" impl Contract of IContract {\n" +" #[inline(always)]\n" +" fn is_owner(self: @ContractState) -> bool {\n" +" self.owner.read() == get_caller_address()\n" +" }\n" +"\n" +" #[inline(always)]\n" +" fn is_role_a(self: @ContractState) -> bool {\n" +" self.role_a.read(get_caller_address())\n" +" }\n" +"\n" +" #[inline(always)]\n" +" fn only_owner(self: @ContractState) {\n" +" assert(Contract::is_owner(self), 'Not owner');\n" +" }\n" +"\n" +" #[inline(always)]\n" +" fn only_role_a(self: @ContractState) {\n" +" assert(Contract::is_role_a(self), 'Not role A');\n" +" }\n" +"\n" +" // You can easily combine guards to perfom complex checks\n" +" fn only_allowed(self: @ContractState) {\n" +" assert(Contract::is_owner(self) || Contract::is_role_a(self), 'Not allowed');\n" +" }\n" +"\n" +" // Functions to manage roles\n" +"\n" +" fn set_role_a(ref self: ContractState, _target: ContractAddress, _active: bool) {\n" +" Contract::only_owner(@self);\n" +" self.role_a.write(_target, _active);\n" +" }\n" +"\n" +" // You can now focus on the business logic of your contract\n" +" // and reduce the complexity of your code by using guard functions\n" +"\n" +" fn role_a_action(ref self: ContractState) {\n" +" Contract::only_role_a(@self);\n" +" // ...\n" +" }\n" +"\n" +" fn allowed_action(ref self: ContractState) {\n" +" Contract::only_allowed(@self);\n" +" // ...\n" +" }\n" +" }\n" +"}\n" +"\n" +"```" + +#: src/ch99-03-security-considerations.md:155 +msgid "### Static analysis tool" +msgstr "### 静态分析工具" + +#: src/ch99-03-security-considerations.md:157 +msgid "" +"Static analysis refers to the process of examining code without its execution, focusing on its structure, syntax, and properties. It involves analyzing the source code to identify " +"potential issues, vulnerabilities, or violations of specified rules." +msgstr "静态分析指的是在不执行代码的情况下对其进行检查的过程,重点关注其结构、语法和属性。它涉及到分析源代码,以识别潜在的问题、漏洞或违反特定规则的行为。" + +#: src/ch99-03-security-considerations.md:159 +msgid "By defining rules, such as coding conventions or security guidelines, developers can utilize static analysis tools to automatically check the code against these standards." +msgstr "通过定义规则,例如编码规范或安全指南,开发人员可以使用静态分析工具自动检查代码是否符合这些标准。" + +#: src/ch99-03-security-considerations.md:161 +msgid "Reference:" +msgstr "参考文献:" + +#: src/ch99-03-security-considerations.md:163 +msgid "- [Semgrep Cairo 1.0 support](https://semgrep.dev/blog/2023/semgrep-now-supports-cairo-1-0)" +msgstr "- [Semgrep Cairo 1.0 support](https://semgrep.dev/blog/2023/semgrep-now-supports-cairo-1-0)" + +#: src/appendix-00.md:1 +msgid "# Appendix" +msgstr "# 附录" + +#: src/appendix-00.md:3 +msgid "" +"The following sections contain reference material you may find useful in your\n" +"Cairo journey." +msgstr "以下章节包含的参考资料可能对您的Cairo之旅有所帮助。" + +#: src/appendix-01-keywords.md:1 +msgid "## Appendix A: Keywords" +msgstr "## 附录 A:关键字" + +#: src/appendix-01-keywords.md:3 +msgid "" +"The following list contains keywords that are reserved for current or future\n" +"use by the Cairo language." +msgstr "下面的列表包含了为当前或未来保留的Cairo 语言的关键字。" + +#: src/appendix-01-keywords.md:6 +msgid "There are two keyword categories:" +msgstr "有两个关键字类别:" + +#: src/appendix-01-keywords.md:8 +msgid "" +"- strict\n" +"- reserved" +msgstr "" +"- 严格(strict)关键字\n" +"- 保留(reserved)关键字" + +#: src/appendix-01-keywords.md:11 +msgid "" +"There is a third category, which are functions from the core library. While their names are not reserved,\n" +"they are not recommended to be used as names of any items to follow good practices." +msgstr "还有第三类,是来自核心库的函数。虽然它们并不是保留关键字,但以遵循惯例不建议将其用作任何项的标识符。" + +#: src/appendix-01-keywords.md:16 +msgid "### Strict keywords" +msgstr "### 严格关键字" + +#: src/appendix-01-keywords.md:18 +msgid "" +"These keywords can only be used in their correct contexts.\n" +"They cannot be used as names of any items." +msgstr "" +"这些关键词只能在其应该被使用的上下文中使用。\n" +"因此,这些关键字不能被用作标识符。" + +#: src/appendix-01-keywords.md:21 +msgid "" +"- `as` - Rename import\n" +"- `break` - Exit a loop immediately\n" +"- `const` - Define constant items\n" +"- `continue` - Continue to the next loop iteration\n" +"- `else` - Fallback for `if` and `if let` control flow constructs\n" +"- `enum` - Define an enumeration\n" +"- `extern` - Function defined at the compiler level using hint available at cairo1 level with this declaration\n" +"- `false` - Boolean false literal\n" +"- `fn` - Define a function\n" +"- `if` - Branch based on the result of a conditional expression\n" +"- `impl` - Implement inherent or trait functionality\n" +"- `implicits` - Special kind of function parameters that are required to perform certain actions\n" +"- `let` - Bind a variable\n" +"- `loop` - Loop unconditionally\n" +"- `match` - Match a value to patterns\n" +"- `mod` - Define a module\n" +"- `mut` - Denote variable mutability\n" +"- `nopanic` - Functions marked with this notation mean that the function will never panic.\n" +"- `of` - Implementation a trait\n" +"- `ref` - Parameter passed implicitly returned at the end of a function\n" +"- `return` - Return from function\n" +"- `struct` - Define a structure\n" +"- `trait` - Define a trait\n" +"- `true` - Boolean true literal\n" +"- `type` - Define a type alias\n" +"- `use` - Bring symbols into scope" +msgstr "" +"- `as` - 重命名导入\n" +"- `break` - 立即退出一个循环\n" +"- `const` - 定义常量项\n" +"- `continue` - 继续进行下一个循环迭代\n" +"- `else` - `if`和`if let`控制流结构的 fallback\n" +"- `enum` - 定义一个枚举项\n" +"- `extern` - 于编译器层级使用此声明来表示此函数可使用Cairo1等级的hint\n" +"- `false` - 布尔字面值假\n" +"- `fn` - 定义一个函数\n" +"- `if` - 基于条件表达式的结果分支\n" +"- `impl` - 实现自有或 ‘trait’ 功能\n" +"- `implicits` - 执行某些动作所需的特殊类型的函数参数\n" +"- `let` - 绑定一个变量\n" +"- `loop` -无条件地循环\n" +"- `match` - 模式匹配\n" +"- `mod` - 定义一个模块\n" +"- `mut` - 表示变量的可变性\n" +"- `nopanic` - 用这个符号标记的函数意味着该函数永远不会panic\n" +"- `of` - 实现trait\n" +"- `ref`- 通过引用绑定\n" +"- `return` - 从函数返回\n" +"- `struct` - 定义一个结构体\n" +"- `trait` - 定义一个trait\n" +"- `true` - 布尔字面值真\n" +"- `type` - 定义一个类型的别名\n" +"- `use` - 引入外部空间的符号" + +#: src/appendix-01-keywords.md:50 +msgid "### Reserved keywords" +msgstr "### 保留关键字" + +#: src/appendix-01-keywords.md:52 +msgid "" +"These keywords aren't used yet, but they are reserved for future use.\n" +"They have the same restrictions as strict keywords.\n" +"The reasoning behind this is to make current programs forward compatible with future versions of\n" +"Cairo by forbidding them to use these keywords." +msgstr "" +"这些关键字还没有被使用,但它们被保留下来供将来使用。\n" +"它们与严格关键字有同样的限制。\n" +"禁止使用这些关键字的原因是为了可以使现在的程序向前兼容新版本的Cairo语言。" + +#: src/appendix-01-keywords.md:57 +msgid "" +"- `Self`\n" +"- `assert`\n" +"- `do`\n" +"- `dyn`\n" +"- `for`\n" +"- `hint`\n" +"- `in`\n" +"- `macro`\n" +"- `move`\n" +"- `pub`\n" +"- `static_assert`\n" +"- `self`\n" +"- `static`\n" +"- `super`\n" +"- `try`\n" +"- `typeof`\n" +"- `unsafe`\n" +"- `where`\n" +"- `while`\n" +"- `with`\n" +"- `yield`" +msgstr "" +"- `Self`\n" +"- `assert`\n" +"- `do`\n" +"- `dyn`\n" +"- `for`\n" +"- `hint`\n" +"- `in`\n" +"- `macro`\n" +"- `move`\n" +"- `pub`\n" +"- `static_assert`\n" +"- `self`\n" +"- `static`\n" +"- `super`\n" +"- `try`\n" +"- `typeof`\n" +"- `unsafe`\n" +"- `where`\n" +"- `while`\n" +"- `with`\n" +"- `yield`" + +#: src/appendix-01-keywords.md:81 +msgid "### Built-in functions" +msgstr "### 内置函数" + +#: src/appendix-01-keywords.md:83 +msgid "" +"The Cairo programming language provides several specific functions that serve a special purpose. We will not cover all of them in this book, but using the names of these functions as " +"names of other items is not recommended." +msgstr "Cairo编程语言提供了几个具有特殊用途的函数。我们不会在本书中介绍所有这些函数,但不建议使用这些函数的名称作为任何项的标识符。" + +#: src/appendix-01-keywords.md:85 +msgid "-`assert` - This function checks a boolean expression, and if it evaluates to false, it triggers the panic function. -`panic` - This function terminates the program." +msgstr "-`assert` - 这个函数检查一个布尔表达式,如果它的值是假的,就会触发panic函数。 -`panic` - 这个函数终止程序。" + +#: src/appendix-02-operators-and-symbols.md:1 +msgid "# Appendix B: Operators and Symbols" +msgstr "# 附录B:运算符和符号" + +#: src/appendix-02-operators-and-symbols.md:3 +msgid "This appendix includes a glossary of Cairo's syntax." +msgstr "本附录包含了Cairo语法的词汇表。" + +#: src/appendix-02-operators-and-symbols.md:5 +msgid "## Operators" +msgstr "## 运算符" + +#: src/appendix-02-operators-and-symbols.md:7 +msgid "" +"Table B-1 contains the operators in Cairo, an example of how the operator would appear in context, a short explanation, and whether that operator is overloadable. If an operator is " +"overloadable, the relevant trait to use to overload that operator is listed." +msgstr "表B-1包含了开罗的运算符,运算符在上下文中出现的例子和简短的解释,以及该运算符是否可以重载。如果一个运算符是可重载的,则列出了用于重载该运算符的相关特性。" + +#: src/appendix-02-operators-and-symbols.md:9 +msgid "Table B-1: Operators" +msgstr "表B-1:运算符" + +#: src/appendix-02-operators-and-symbols.md:11 +msgid "" +"| Operator | Example | Explanation | Overloadable? |\n" +"|----------|---------|-------------|---------------|\n" +"| `!` | `!expr` | Bitwise or logical complement | `Not` |\n" +"| `!=` | `expr != expr` | Non-equality comparison | `PartialEq` |\n" +"| `%` | `expr % expr` | Arithmetic remainder | `Rem` |\n" +"| `%=` | `var %= expr` | Arithmetic remainder and assignment | `RemEq` |\n" +"| `&` | `expr & expr` | Bitwise AND | `BitAnd` |\n" +"| `&&` | `expr && expr` | Short-circuiting logical AND | |\n" +"| `*` | `expr * expr` | Arithmetic multiplication | `Mul` |\n" +"| `*=` | `var *= expr` | Arithmetic multiplication and assignment | `MulEq` |\n" +"| `@` | `@var` | Snapshot | |\n" +"| `*` | `*var` | Desnap | |\n" +"| `+` | `expr + expr` | Arithmetic addition | `Add` |\n" +"| `+=` | `var += expr` | Arithmetic addition and assignment | `AddEq` |\n" +"| `,` | `expr, expr` | Argument and element separator | |\n" +"| `-` | `-expr` | Arithmetic negation | `Neg` |\n" +"| `-` | `expr - expr` | Arithmetic subtraction | `Sub` |\n" +"| `-=` | `var -= expr` | Arithmetic subtraction and assignment | `SubEq` |\n" +"| `->` | `fn(...) -> type`, |...| -> type | Function and closure return type | |\n" +"| `.` | `expr.ident` | Member access | |\n" +"| `/` | `expr / expr` | Arithmetic division | `Div` |\n" +"| `/=` | `var /= expr` | Arithmetic division and assignment | `DivEq` |\n" +"| `:` | `pat: type`, `ident: type` | Constraints | |\n" +"| `:` | `ident: expr` | Struct field initializer | |\n" +"| `;` | `expr;` | Statement and item terminator | |\n" +"| `<` | `expr < expr` | Less than comparison | `PartialOrd` |\n" +"| `<=` | `expr <= expr` | Less than or equal to comparison | `PartialOrd` |\n" +"| `=` | `var = expr` | Assignment | |\n" +"| `==` | `expr == expr` | Equality comparison | `PartialEq` |\n" +"| `=>` | `pat => expr` | Part of match arm syntax | |\n" +"| `>` | `expr > expr` | Greater than comparison | `PartialOrd` |\n" +"| `>=` | `expr >= expr` | Greater than or equal to comparison | `PartialOrd` |\n" +"| `^` | `expr ^ expr` | Bitwise exclusive OR | `BitXor` |\n" +"| | | expr | expr | Bitwise OR | `BitOr` |\n" +"| || | expr || expr | Short-circuiting logical OR | |" +msgstr "" +"| 运算符 | 示例 | 解释 | 是否可重载? |\n" +"|----------|---------|-------------|---------------|\n" +"| `!` | `!expr` | 位或逻辑补码 | `Not` |\n" +"| `!=` | `expr != expr` | 不等于 | `PartialEq` |\n" +"| `%` | `expr % expr` | 算数取余 | `Rem` |\n" +"| `%=` | `var %= expr` | 算数取余并赋值 | `RemEq` |\n" +"| `&` | `expr & expr` | 按位与 | `BitAnd` |\n" +"| `&&` | `expr && expr` | 短路逻辑与 | |\n" +"| `*` | `expr * expr` | 算数乘 | `Mul` |\n" +"| `*=` | `var *= expr` | 算数乘并赋值 | `MulEq` |\n" +"| `@` | `@var` | Snapshot | |\n" +"| `*` | `*var` | Desnap | |\n" +"| `+` | `expr + expr` | 算术加 | `Add` |\n" +"| `+=` | `var += expr` | 算数加并赋值 | `AddEq` |\n" +"| `,` | `expr, expr` | 参数和元素分隔符 | |\n" +"| `-` | `-expr` | 算数负号 | `Neg` |\n" +"| `-` | `expr - expr` | 算数减 | `Sub` |\n" +"| `-=` | `var -= expr` | 算数减并赋值 | `SubEq` |\n" +"| `->` | `fn(...) -> type`, |...| -> type | 函数与闭包的返回类型 | |\n" +"| `.` | `expr.ident` | 成员访问 | |\n" +"| `/` | `expr / expr` | 算数除 | `Div` |\n" +"| `/=` | `var /= expr` | 算数除并赋值 | `DivEq` |\n" +"| `:` | `pat: type`, `ident: type` | 约束条件 | |\n" +"| `:` | `ident: expr` | 结构体字段初始化器 | |\n" +"| `;` | `expr;` | 语句和条目结束符号 | |\n" +"| `<` | `expr < expr` | 小于比较 | `PartialOrd` |\n" +"| `<=` | `expr <= expr` | 小于等于比较 | `PartialOrd` |\n" +"| `=` | `var = expr` | 赋值 | |\n" +"| `==` | `expr == expr` | 等于比较 | `PartialEq` |\n" +"| `=>` | `pat => expr` | 匹配分支的一部分语法 | |\n" +"| `>` | `expr > expr` | 大于比较 | `PartialOrd` |\n" +"| `>=` | `expr >= expr` | 大于等于比较 | `PartialOrd` |\n" +"| `^` | `expr ^ expr` | 按位异或 | `BitXor` |\n" +"| | | expr | expr | 按位或 | `BitOr` |\n" +"| || | expr || expr | 短路逻辑或 | |" + +#: src/appendix-02-operators-and-symbols.md:47 +msgid "## Non Operator Symbols" +msgstr "## 非运算符符号" + +#: src/appendix-02-operators-and-symbols.md:49 +msgid "The following list contains all symbols that are not used as operators; that is, they do not have the same behavior as a function or method call." +msgstr "下面的列表包含了所有不作为运算符使用的符号;也就是说,他们并不像函数调用或方法调用一样表现。" + +#: src/appendix-02-operators-and-symbols.md:51 +msgid "Table B-2 shows symbols that appear on their own and are valid in a variety of locations." +msgstr "表B-2 展示了以其自身出现以及出现在合法其他各个地方的符号。" + +#: src/appendix-02-operators-and-symbols.md:53 +msgid "Table B-2: Stand-Alone Syntax" +msgstr "表B-2:独立语法" + +#: src/appendix-02-operators-and-symbols.md:55 +msgid "" +"| Symbol | Explanation |\n" +"|--------|-------------|\n" +"| `..._u8`, `..._usize`, etc. | Numeric literal of specific type |\n" +"| `'...'` | Short string |\n" +"| `_` | “Ignored” pattern binding; also used to make integer literals readable |" +msgstr "" +"| 符号 | 解释 |\n" +"|--------|-------------|\n" +"| `..._u8`, `..._usize`, 等等。| 指定类型的数值常量 |\n" +"| `'...'` | 短字符串 |\n" +"| `_` | \"“忽略” 模式绑定;也用于增强整型字面值的可读性 |" + +#: src/appendix-02-operators-and-symbols.md:61 +msgid "Table B-3 shows symbols that are used within the context of a module hierarchy path to access an item." +msgstr "表B-3 展示了出现在从模块结构到项的路径上下文中的符号。" + +#: src/appendix-02-operators-and-symbols.md:63 +msgid "Table B-3: Path-Related Syntax" +msgstr "表B-3:路径相关语法" + +#: src/appendix-02-operators-and-symbols.md:65 +msgid "" +"| Symbol | Explanation |\n" +"|--------|-------------|\n" +"| `ident::ident` | Namespace path |\n" +"| `super::path` | Path relative to the parent of the current module |\n" +"| `trait::method(...)` | Disambiguating a method call by naming the trait that defines it |" +msgstr "" +"| 符号 | 解释 |\n" +"|--------|-------------|\n" +"| `ident::ident` | 命名空间路径 |\n" +"| `super::path` | 相对于当前模块的父级路径。\n" +"| `trait::method(...)` | 通过命名定义该方法的trait来消除方法调用的二义性 |" + +#: src/appendix-02-operators-and-symbols.md:71 +msgid "Table B-4 shows symbols that appear in the context of using generic type parameters." +msgstr "表B-4 展示了出现在泛型类型参数上下文中的符号。" + +#: src/appendix-02-operators-and-symbols.md:73 +msgid "Table B-4: Generics" +msgstr "表 B-4:泛型" + +#: src/appendix-02-operators-and-symbols.md:75 +msgid "" +"| Symbol | Explanation |\n" +"|--------|-------------|\n" +"| `path<...>` | Specifies parameters to generic type in a type (e.g., `Vec`) |\n" +"| `path::<...>`, `method::<...>` | Specifies parameters to generic type, function, or method in an expression; often referred to as turbofish |\n" +"| `fn ident<...> ...` | Define generic function |\n" +"| `struct ident<...> ...` | Define generic structure |\n" +"| `enum ident<...> ...` | Define generic enumeration |\n" +"| `impl<...> ...` | Define generic implementation |" +msgstr "" +"| 符号 | 解释 |\n" +"|--------|-------------|\n" +"| `path<...>` | 为一个类型中的泛型指定具体参数(例如,`Vec`) |\n" +"| `path::<...>`, `method::<...>` | 为一个泛型、函数或表达式中的方法指定具体参数; 通常被称为Turbofish。\n" +"| `fn ident<...>...` | 泛型函数定义\n" +"| `struct ident<...>...` | 泛型结构体定义\n" +"| `enum ident<...>...` | 泛型枚举定义\n" +"| `impl<...>...` | 定义泛型实现 |" + +#: src/appendix-02-operators-and-symbols.md:84 +msgid "Table B-5 shows symbols that appear in the context of calling or defining macros and specifying attributes on an item." +msgstr "表B-5展示了在调用或定义宏以及在其上指定属性时的上下文中出现的符号。" + +#: src/appendix-02-operators-and-symbols.md:86 +msgid "Table B-5: Macros and Attributes" +msgstr "表B-5:宏和属性" + +#: src/appendix-02-operators-and-symbols.md:88 +msgid "" +"| Symbol | Explanation |\n" +"|--------|-------------|\n" +"| `#[meta]` | Outer attribute |" +msgstr "" +"| 符号 | 解释 |\n" +"|--------|-------------|\n" +"| `#[meta]` | 外部属性 |" + +#: src/appendix-02-operators-and-symbols.md:92 +msgid "Table B-6 shows symbols that create comments." +msgstr "表B-6 展示了创建注释的符号。" + +#: src/appendix-02-operators-and-symbols.md:94 +msgid "Table B-6: Comments" +msgstr "表B-6:注释" + +#: src/appendix-02-operators-and-symbols.md:96 +msgid "" +"| Symbol | Explanation |\n" +"|--------|-------------|\n" +"| `//` | Line comment |" +msgstr "" +"| 符号 | 解释 |\n" +"|--------|-------------|\n" +"| `//` | 行注释 |" + +#: src/appendix-02-operators-and-symbols.md:100 +msgid "Table B-7 shows symbols that appear in the context of using tuples." +msgstr "表B-7 展示了出现在使用元组时上下文中的符号。" + +#: src/appendix-02-operators-and-symbols.md:102 +msgid "Table B-7: Tuples" +msgstr "表B-7:元组" + +#: src/appendix-02-operators-and-symbols.md:105 +msgid "" +"| Symbol | Explanation |\n" +"|--------|-------------|\n" +"| `()` | Empty tuple (aka unit), both literal and type |\n" +"| `(expr)` | Parenthesized expression |\n" +"| `(expr,)` | Single-element tuple expression |\n" +"| `(type,)` | Single-element tuple type |\n" +"| `(expr, ...)` | Tuple expression |\n" +"| `(type, ...)` | Tuple type |\n" +"| `expr(expr, ...)` | Function call expression; also used to initialize tuple `struct`s and tuple `enum` variants |" +msgstr "" +"| 符号 | 解释 |\n" +"|--------|-------------|\n" +"| `()` | 空元组(又称单元),空元组(亦称单元),即是字面值也是类型 |\n" +"| `(expr)` | 括号表达式 |\n" +"| `(expr,)` | 单元素元组表达式 |\n" +"| `(type,)` | 单元素元组类型 |\n" +"| `(expr, ...)` | 元组表达式\n" +"| `(type, ...)` | 元组类型 |\n" +"| `expr(expr, ...)` | 函数调用表达式;也用于初始化元组`struct`和元组`enum`变体" + +#: src/appendix-02-operators-and-symbols.md:115 +msgid "Table B-8 shows the contexts in which curly braces are used." +msgstr "表B-8展示了使用大括号的上下文。" + +#: src/appendix-02-operators-and-symbols.md:117 +msgid "Table B-8: Curly Brackets" +msgstr "表B-8:大括号" + +#: src/appendix-02-operators-and-symbols.md:119 +msgid "" +"| Context | Explanation |\n" +"|---------|-------------|\n" +"| `{...}` | Block expression |\n" +"| `Type {...}` | `struct` literal |" +msgstr "" +"| 上下文 | 解释 |\n" +"|---------|-------------|\n" +"| `{...}` | 块表达式 |\n" +"| `Type {...}` | `struct`字面值 |" + +#: src/appendix-03-derivable-traits.md:1 +msgid "# Appendix C: Derivable Traits" +msgstr "# 附录C: 可派生的 Trait" + +#: src/appendix-03-derivable-traits.md:3 +msgid "" +"In various places in the book, we’ve discussed the `derive` attribute, which you can apply to a struct or enum definition. The `derive` attribute generates code to implement a " +"default trait on the type you’ve annotated with the `derive` syntax." +msgstr "在本书的各个部分中,我们讨论了可应用于结构体和枚举定义的 `derive` 属性。`derive` 属性会在使用 `derive` 语法标记的类型上生成对应 trait 的默认实现的代码。" + +#: src/appendix-03-derivable-traits.md:5 +msgid "In this appendix, we provide a comprehensive reference detailing all the traits in the standard library compatible with the `derive` attribute." +msgstr "在这个附录中,我们提供了一个全面的参考,详细介绍了标准库中所有与`derive`属性兼容的trait。" + +#: src/appendix-03-derivable-traits.md:7 +msgid "" +"These traits listed here are the only ones defined by the core library that can be implemented on your types using `derive`. Other traits defined in the standard library don’t have " +"sensible default behavior, so it’s up to you to implement them in the way that makes sense for what you’re trying to accomplish." +msgstr "" +"这里列出的 trait 是仅有的在标准库中定义且能通过 `derive` 在类型上实现。标准库中定义的其它 trait 不能通过 `derive` 在类型上实现。这些 trait 不存在有意义的默认行为,所以由你负责以合理的" +"方式实现它们。" + +#: src/appendix-03-derivable-traits.md:9 +msgid "" +"The list of derivable traits provided in this appendix does not encompass all possibilities: external libraries can implement `derive` for their own traits, expanding the list of " +"traits compatible with `derive`." +msgstr "本附录所提供的可派生 trait 列表并不全面:库可以为其自己的 trait 实现 `derive`,可以使用 `derive` 的 trait 列表事实上是无限的。" + +#: src/appendix-03-derivable-traits.md:11 +msgid "## PartialEq for equality comparison" +msgstr "## 等值比较的 PartialEq 和 Eq" + +#: src/appendix-03-derivable-traits.md:13 +msgid "The `PartialEq` trait allows for comparison between instances of a type for equality, thereby enabling the == and != operators." +msgstr "`PartialEq` trait允许在一个类型的实例之间进行等值比较,从而实现 == 和 != 运算符。" + +#: src/appendix-03-derivable-traits.md:15 +msgid "" +"When `PartialEq` is derived on structs, two instances are equal only if all fields are equal, and the instances are not equal if any fields are not equal. When derived on enums, each " +"variant is equal to itself and not equal to the other variants." +msgstr "当`PartialEq`在结构上派生时,只有当所有字段都相等时,两个实例才相等,如果任何字段不相等,实例就不相等。当在枚举上派生时,每一个成员都和其自身相等,且和其他成员都不相等。" + +#: src/appendix-03-derivable-traits.md:19 +msgid "" +"```rust\n" +"#[derive(PartialEq, Drop)]\n" +"struct A {\n" +" item: felt252\n" +"}\n" +"\n" +"fn main() {\n" +" let first_struct = A {\n" +" item: 2\n" +" };\n" +" let second_struct = A {\n" +" item: 2\n" +" };\n" +" assert(first_struct == second_struct, 'Structs are different');\n" +"}\n" +"```" +msgstr "" +"```rust\n" +"#[derive(PartialEq, Drop)]\n" +"struct A {\n" +" item: felt252\n" +"}\n" +"\n" +"fn main() {\n" +" let first_struct = A {\n" +" item: 2\n" +" };\n" +" let second_struct = A {\n" +" item: 2\n" +" };\n" +" assert(first_struct == second_struct, 'Structs are different');\n" +"}\n" +"```" + +#: src/appendix-03-derivable-traits.md:36 +msgid "## Clone and Copy for Duplicating Values" +msgstr "## 复制值的 Clone 和 Copy" + +#: src/appendix-03-derivable-traits.md:38 +msgid "The `Clone` trait provides the functionality to explicitly create a deep copy of a value." +msgstr "`Clone` trait 提供了明确创建一个值的深度拷贝的功能。" + +#: src/appendix-03-derivable-traits.md:40 +msgid "" +"Deriving `Clone` implements the `clone` method, which, in turn, calls clone on each of the type's components. This means all the fields or values in the type must also implement " +"`Clone` to derive `Clone`." +msgstr "派生 `Clone` 实现了 `clone` 方法,其为整个的类型实现时,在类型的每一部分上调用了`clone` 方法。这意味着类型中所有字段或值也必须实现了 `Clone`,这样才能够派生 `Clone`。" + +#: src/appendix-03-derivable-traits.md:44 +msgid "" +"```rust\n" +"use clone::Clone;\n" +"\n" +"#[derive(Clone, Drop)]\n" +"struct A {\n" +" item: felt252\n" +"}\n" +"\n" +"fn main() {\n" +" let first_struct = A {\n" +" item: 2\n" +" };\n" +" let second_struct = first_struct.clone();\n" +" assert(second_struct.item == 2, 'Not equal');\n" +"}\n" +"```" +msgstr "" +"```rust\n" +"use clone::Clone;\n" +"\n" +"#[derive(Clone, Drop)]\n" +"struct A {\n" +" item: felt252\n" +"}\n" +"\n" +"fn main() {\n" +" let first_struct = A {\n" +" item: 2\n" +" };\n" +" let second_struct = first_struct.clone();\n" +" assert(second_struct.item == 2, 'Not equal');\n" +"}\n" +"```" + +#: src/appendix-03-derivable-traits.md:61 +msgid "The `Copy` trait allows for the duplication of values. You can derive `Copy` on any type whose parts all implement `Copy`." +msgstr "`Copy` trait 允许你复制值而不需要额外的代码。你可以在任何部分都实现了`Copy`的类型上派生`Copy`。" + +#: src/appendix-03-derivable-traits.md:65 +msgid "" +"```rust\n" +"#[derive(Copy, Drop)]\n" +"struct A {\n" +" item: felt252\n" +"}\n" +"\n" +"fn main() {\n" +" let first_struct = A {\n" +" item: 2\n" +" };\n" +" let second_struct = first_struct;\n" +" assert(second_struct.item == 2, 'Not equal');\n" +" assert(first_struct.item == 2, 'Not Equal'); // Copy Trait prevents firs_struct from moving into second_struct\n" +"}\n" +"```" +msgstr "" +"```rust\n" +"#[derive(Copy, Drop)]\n" +"struct A {\n" +" item: felt252\n" +"}\n" +"\n" +"fn main() {\n" +" let first_struct = A {\n" +" item: 2\n" +" };\n" +" let second_struct = first_struct;\n" +" assert(second_struct.item == 2, 'Not equal');\n" +" assert(first_struct.item == 2, 'Not Equal'); // Copy Trait prevents firs_struct from moving into second_struct\n" +"}\n" +"```" + +#: src/appendix-03-derivable-traits.md:81 +msgid "## Serializing with Serde" +msgstr "## 用Serde进行序列化" + +#: src/appendix-03-derivable-traits.md:83 +msgid "" +"`Serde` provides trait implementations for `serialize` and `deserialize` functions for data structures defined in your crate. It allows you to transform your structure into an array " +"(or the opposite)." +msgstr "`Serde`为你的crate中定义的数据结构提供`serialize`和`deserialize`函数的trait实现。它允许你将你的结构体转化为数组(或相反)。" + +#: src/appendix-03-derivable-traits.md:87 +msgid "" +"```rust\n" +"use serde::Serde;\n" +"use array::ArrayTrait;\n" +"\n" +"#[derive(Serde, Drop)]\n" +"struct A {\n" +" item_one: felt252,\n" +" item_two: felt252,\n" +"}\n" +"\n" +"fn main() {\n" +" let first_struct = A {\n" +" item_one: 2,\n" +" item_two: 99,\n" +" };\n" +" let mut output_array = ArrayTrait::new();\n" +" let serialized = first_struct.serialize(ref output_array);\n" +" panic(output_array);\n" +"}\n" +"```" +msgstr "" +"```rust\n" +"use serde::Serde;\n" +"use array::ArrayTrait;\n" +"\n" +"#[derive(Serde, Drop)]\n" +"struct A {\n" +" item_one: felt252,\n" +" item_two: felt252,\n" +"}\n" +"\n" +"fn main() {\n" +" let first_struct = A {\n" +" item_one: 2,\n" +" item_two: 99,\n" +" };\n" +" let mut output_array = ArrayTrait::new();\n" +" let serialized = first_struct.serialize(ref output_array);\n" +" panic(output_array);\n" +"}\n" +"```" + +#: src/appendix-03-derivable-traits.md:108 +msgid "Output:" +msgstr "输出:" + +#: src/appendix-03-derivable-traits.md:110 +msgid "" +"```Bash\n" +"Run panicked with [2 (''), 99 ('c'), ].\n" +"```" +msgstr "" +"```Bash\n" +"Run panicked with [2 (''), 99 ('c'), ].\n" +"```" + +#: src/appendix-03-derivable-traits.md:114 +msgid "We can see here that our struct A has been serialized into the output array." +msgstr "我们在这里可以看到,我们的结构体A已经被序列化到输出数组中。" + +#: src/appendix-03-derivable-traits.md:116 +msgid "Also, we can use `deserialize` function to convert the serialized array back into our A struct." +msgstr "另外,我们可以使用`deserialize`函数将序列化的数组转换回我们的结构体A。" + +#: src/appendix-03-derivable-traits.md:120 +msgid "" +"```rust\n" +"use serde::Serde;\n" +"use array::ArrayTrait;\n" +"use option::OptionTrait;\n" +"\n" +"#[derive(Serde, Drop)]\n" +"struct A {\n" +" item_one: felt252,\n" +" item_two: felt252,\n" +"}\n" +"\n" +"fn main() {\n" +" let first_struct = A {\n" +" item_one: 2,\n" +" item_two: 99,\n" +" };\n" +" let mut output_array = ArrayTrait::new();\n" +" let mut serialized = first_struct.serialize(ref output_array);\n" +" let mut span_array = output_array.span();\n" +" let deserialized_struct: A = Serde::::deserialize(ref span_array).unwrap();\n" +"}\n" +"```" +msgstr "" +"```rust\n" +"use serde::Serde;\n" +"use array::ArrayTrait;\n" +"use option::OptionTrait;\n" +"\n" +"#[derive(Serde, Drop)]\n" +"struct A {\n" +" item_one: felt252,\n" +" item_two: felt252,\n" +"}\n" +"\n" +"fn main() {\n" +" let first_struct = A {\n" +" item_one: 2,\n" +" item_two: 99,\n" +" };\n" +" let mut output_array = ArrayTrait::new();\n" +" let mut serialized = first_struct.serialize(ref output_array);\n" +" let mut span_array = output_array.span();\n" +" let deserialized_struct: A = Serde::::deserialize(ref span_array).unwrap();\n" +"}\n" +"```" + +#: src/appendix-03-derivable-traits.md:143 +msgid "" +"Here we are converting a serialized array span back to the struct A. `deserialize` returns an `Option` so we need to unwrap it. When using deserialize we also need to specify the " +"type we want to deserialize into." +msgstr "这里我们要把一个序列化的数组span转换回结构体A。`deserialize`返回一个`Option`,所以我们需要把它解包。当使用deserialize时,我们还需要指定我们想要反序列化的类型。" + +#: src/appendix-03-derivable-traits.md:145 +msgid "## Drop and Destruct" +msgstr "## Drop 和 Destruct" + +#: src/appendix-03-derivable-traits.md:147 +msgid "" +"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](ch03-01-what-is-ownership." +"md#the-drop-trait)." +msgstr "当离开作用域时,需要先移动变量。这就是 `Drop` trait起作用的地方。你可以在[这里](ch03-01-what-is-ownership.md#the-drop-trait)找到更多关于它的用法的细节。" + +#: src/appendix-03-derivable-traits.md:149 +msgid "" +"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](ch03-01-what-is-ownership.md#the-destruct-trait)." +msgstr "" +"此外,字典在离开作用域之前需要被squash(压缩)。在每个字典上手动调用`squash`方法很快就不再是必须操作。`Destruct` 特性允许字典在超出范围时被自动压缩。你也可以在[这里](ch03-01-what-is-" +"ownership.md#the-destruct-trait) 找到更多关于`Destruct`的信息。" + +#: src/appendix-03-derivable-traits.md:151 +msgid "## Store" +msgstr "## 存储" + +#: src/appendix-03-derivable-traits.md:153 +msgid "" +"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." +msgstr "在Starknet合约中的存储变量中存储用户定义的结构体需要为该类型实现 `Store` trait 。您可以为所有不包含字典或数组等复杂类型的结构体自动派生 `Store` trait 。" + +#: src/appendix-03-derivable-traits.md:157 +msgid "" +"```rust, noplayground\n" +"#[starknet::contract]\n" +"mod contract {\n" +" #[derive(Drop, starknet::Store)]\n" +" struct A {\n" +" item_one: felt252,\n" +" item_two: felt252,\n" +" }\n" +"\n" +" #[storage]\n" +" struct Storage {\n" +" my_storage: A,\n" +" }\n" +"}\n" +"\n" +"```" +msgstr "" +"```rust, noplayground\n" +"#[starknet::contract]\n" +"mod contract {\n" +" #[derive(Drop, starknet::Store)]\n" +" struct A {\n" +" item_one: felt252,\n" +" item_two: felt252,\n" +" }\n" +"\n" +" #[storage]\n" +" struct Storage {\n" +" my_storage: A,\n" +" }\n" +"}\n" +"\n" +"```" + +#: src/appendix-03-derivable-traits.md:174 +msgid "" +"Here we demonstrate the implementation of a `struct A` that derives the Store trait. This `struct A` is subsequently used\n" +"as a storage variable in the contract." +msgstr "在这里,我们演示了一个派生了Store trait的`struct A`的实现。这个 `struct A`随后被用作合约中的存储变量。" + +#: src/appendix-03-derivable-traits.md:177 +msgid "## PartialOrd and Ord for Ordering Comparisons" +msgstr "## 用于排序比较的PartialOrd和Ord" + +#: src/appendix-03-derivable-traits.md:179 +msgid "In addition to the `PartialEq` trait, the standard library also provides the `PartialOrd` and `Ord` traits to compare values for ordering." +msgstr "除了 `PartialEq` trait,标准库还提供了 `PartialOrd` 和 `Ord` trait,用于值排序中的比较。" + +#: src/appendix-03-derivable-traits.md:181 +msgid "The `PartialOrd` trait allows for comparison between instances of a type for ordering, thereby enabling the <, <=, >, and >= operators." +msgstr "`PartialOrd`特质允许在一个类型的实例之间进行排序比较,从而使得我们可以使用 <、<=、> 和 >= 操作符。" + +#: src/appendix-03-derivable-traits.md:183 +msgid "When `PartialOrd` is derived on structs, two instances are ordered by comparing each field in turn." +msgstr "当在结构体上派生 `PartialOrd` 时,两个实例通过依次比较每个字段来排序。" + +#: src/appendix-04-useful-development-tools.md:1 +msgid "## Appendix D - Useful Development Tools" +msgstr "## 附录D - 实用开发工具" + +#: src/appendix-04-useful-development-tools.md:3 +msgid "" +"In this appendix, we talk about some useful development tools that the Cairo\n" +"project provides. We’ll look at automatic formatting, quick ways to apply\n" +"warning fixes, a linter, and integrating with IDEs." +msgstr "" +"在本附录中,我们将提到由Cairo项目提供的一些有用的开发工具。\n" +"我们将看看自动格式化、快速应用警告修正,linter,以及与IDE的整合。" + +#: src/appendix-04-useful-development-tools.md:7 +msgid "### Automatic Formatting with `scarb fmt`" +msgstr "### 用`scarb fmt`自动格式化" + +#: src/appendix-04-useful-development-tools.md:9 +msgid "" +"Scarb projects can be formatted using the `scarb fmt` command.\n" +"If you're using the cairo binaries directly, you can run `cairo-format` instead.\n" +"Many collaborative projects use `scarb fmt` to prevent arguments about which\n" +"style to use when writing Cairo: everyone formats their code using the tool." +msgstr "" +"Scarb 项目可以使用 `scarb fmt` 命令进行格式化。\n" +"如果直接使用 cairo 二进制文件,可以运行 `cairo-format` 代替。\n" +"在大多多人合作项目里,每个成员都会使用`scarb fmt` 以防止在编写Cairo时争论使用哪种代码风格。" + +#: src/appendix-04-useful-development-tools.md:14 +msgid "To format any Cairo project, enter the following:" +msgstr "要格式化任何Cairo项目,请输入以下命令:" + +#: src/appendix-04-useful-development-tools.md:16 +msgid "### IDE Integration Using `cairo-language-server`" +msgstr "### 使用`cairo-language-server`的IDE集成" + +#: src/appendix-04-useful-development-tools.md:18 +msgid "" +"To help IDE integration, the Cairo community recommends using the\n" +"[`cairo-language-server`][cairo-language-server]. This tool is a set of\n" +"compiler-centric utilities that speaks the [Language Server Protocol][lsp], which is a specification for IDEs and programming languages to\n" +"communicate with each other. Different clients can use `cairo-language-server`, such as\n" +"[the Cairo extension for Visual Studio Code][vscode-cairo]." +msgstr "" +"为了帮助IDE整合,Cairo社区建议使用\n" +"[`cairo-language-server`][cairo-language-server]。这是\n" +"[Language Server Protocol][lsp]的一套以编译器为中心的实用工具。\n" +"它是用于IDE和编程语言互相通信的规范。不同的客户端都可以使用`cairo-language-server`,例如\n" +"[Visual Studio Code的Cairo扩展][vscode-cairo]。" + +#: src/appendix-04-useful-development-tools.md:28 +msgid "" +"Visit the `vscode-cairo` [page][vscode-cairo]\n" +"to install it on VSCode. You will get abilities such as autocompletion, jump to\n" +"definition, and inline errors." +msgstr "" +"请访问 `vscode-cairo` [page][vscode-cairo]\n" +"将其安装到 VSCode 上。您将获得自动完成、跳转到\n" +"定义和内联错误等功能。" + +#: src/appendix-04-useful-development-tools.md:34 +msgid "> Note: If you have Scarb installed, it should work out of the box with the Cairo VSCode extension, without a manual installation of the language server." +msgstr "> 注意:如果你已安装 Scarb,则无需手动安装语言服务器,即可使用Cairo VSCode 扩展。" + +#: src/appendix-05-most-common-types-and-traits.md:1 +msgid "## Appendix E - Most Common Types and Traits Required To Write Contracts" +msgstr "## 附录 E - 编写合约所需最常见的类型 和Trait" + +#: src/appendix-05-most-common-types-and-traits.md:3 +msgid "This appendix provides a reference for common types and traits used in contract development, along with their corresponding imports, paths, and usage examples." +msgstr "本附录提供了合约开发中使用的常见类型和trait的参考,以及相应的导入方法、路径和使用方法的范例。" + +#: src/appendix-05-most-common-types-and-traits.md:5 +msgid "" +"| Import | Path | " +"Usage " +"|\n" +"| ------------------------- | ----------------------------------------------------- | " +"-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- " +"|\n" +"| `OptionTrait` | `std::option::OptionTrait` | `OptionTrait` defines a set of methods required to manipulate optional " +"value. |\n" +"| `ResultTrait` | `std::result::ResultTrait` | `ResultTrait` Type for Starknet contract address, a value in the range [0, 2 \\*\\* " +"251). |\n" +"| `ContractAddress` | `starknet::ContractAddress` | `ContractAddress` is a type to represent the smart contract " +"address |\n" +"| `ContractAddressZeroable` | `starknet::contract_address::ContractAddressZeroable` | `ContractAddressZeroable` is the implementation of the trait `Zeroable` for the " +"`ContractAddress` type. It is required to check whether a value of `t:ContractAddress` is zero or not. |\n" +"| `contract_address_const` | `starknet::contract_address_const` | The `contract_address_const!` it's a function that allows instantiating constant contract " +"address values. |\n" +"| `Into` | `traits::Into;` | `Into` is a trait used for conversion between types. If there is an implementation of Into for the types T and S, you can convert T into S. |\n" +"| `TryInto` | `traits::TryInto;` | `TryInto` is a trait used for conversion between types.If there is an implementation of " +"TryInto for the types T and S, you can convert T into S. |\n" +"| `get_caller_address` | `starknet::get_caller_address` | `get_caller_address()` is a function that returns the address of the caller of the contract. It " +"can be used to identify the caller of a contract function. |\n" +"| `get_contract_address` | `starknet::info::get_contract_address` | `get_contract_address()` is a function that returns the address of the current contract. It can " +"be used to obtain the address of the contract being executed. |" +msgstr "" +"| Import | Path | " +"Usage " +"|\n" +"| ------------------------- | ----------------------------------------------------- | " +"-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- " +"|\n" +"| `OptionTrait` | `std::option::OptionTrait` | `OptionTrait` defines a set of methods required to manipulate optional " +"value. |\n" +"| `ResultTrait` | `std::result::ResultTrait` | `ResultTrait` Type for Starknet contract address, a value in the range [0, 2 \\*\\* " +"251). |\n" +"| `ContractAddress` | `starknet::ContractAddress` | `ContractAddress` is a type to represent the smart contract " +"address |\n" +"| `ContractAddressZeroable` | `starknet::contract_address::ContractAddressZeroable` | `ContractAddressZeroable` is the implementation of the trait `Zeroable` for the " +"`ContractAddress` type. It is required to check whether a value of `t:ContractAddress` is zero or not. |\n" +"| `contract_address_const` | `starknet::contract_address_const` | The `contract_address_const!` it's a function that allows instantiating constant contract " +"address values. |\n" +"| `Into` | `traits::Into;` | `Into` is a trait used for conversion between types. If there is an implementation of Into for the types T and S, you can convert T into S. |\n" +"| `TryInto` | `traits::TryInto;` | `TryInto` is a trait used for conversion between types.If there is an implementation of " +"TryInto for the types T and S, you can convert T into S. |\n" +"| `get_caller_address` | `starknet::get_caller_address` | `get_caller_address()` is a function that returns the address of the caller of the contract. It " +"can be used to identify the caller of a contract function. |\n" +"| `get_contract_address` | `starknet::info::get_contract_address` | `get_contract_address()` is a function that returns the address of the current contract. It can " +"be used to obtain the address of the contract being executed. |" + +#: src/appendix-05-most-common-types-and-traits.md:17 +msgid "" +"This is not an exhaustive list, but it covers some of the commonly used types and traits in contract development. For more details, refer to the official documentation and explore " +"the available libraries and frameworks." +msgstr "这并不是一个详尽的列表,但它涵盖了合约开发中一些常用的类型和trait。关于更多的细节,请参考官方文档并参考可用的库以及框架。" + +#: src/appendix-06-cairo-binaries.md:1 +msgid "# Appendix F: Installing the Cairo binaries" +msgstr "# 附录 F:安装Cairo二进制文件" + +#: src/appendix-06-cairo-binaries.md:3 +msgid "If you want to have access to the Cairo binaries, for anything that you could not achieve by purely using Scarb you can install them by following the instructions below." +msgstr "如果你想访问Cairo二进制文件,以获取任何仅使用 Scarb 无法实现的功能时,可以按照下面的说明安装它们。" + +#: src/appendix-06-cairo-binaries.md:5 +msgid "The first step is to install Cairo. We will download Cairo manually, using cairo repository or with an installation script. You’ll need an internet connection for the download." +msgstr "" +"第一步是安装Cairo。我们可以手动下载Cairo(使用Cairo仓库)或使用安装脚本。下载过程需要连接互联网。\n" +"译注:如果你生活在中国大陆,你可能需要一些特殊方法来保证能够顺利安装所有的依赖包。" + +#: src/appendix-06-cairo-binaries.md:7 +msgid "### Prerequisites" +msgstr "### 先决条件" + +#: src/appendix-06-cairo-binaries.md:9 +msgid "First you will need to have Rust and Git installed." +msgstr "首先,你需要安装Rust和Git。" + +#: src/appendix-06-cairo-binaries.md:11 +msgid "" +"```bash\n" +"# Install stable Rust\n" +"rustup override set stable && rustup update\n" +"```" +msgstr "" +"```bash\n" +"# Install stable Rust\n" +"rustup override set stable && rustup update\n" +"```" + +#: src/appendix-06-cairo-binaries.md:16 +msgid "Install [Git](https://git-scm.com/)." +msgstr "安装[Git](https://git-scm.com/)。" + +#: src/appendix-06-cairo-binaries.md:18 +msgid "## Installing Cairo with a Script ([Installer](https://github.com/franalgaba/cairo-installer) by [Fran](https://github.com/franalgaba))" +msgstr "## 用脚本安装Cairo([Installer](https://github.com/franalgaba/cairo-installer) by [Fran](https://github.com/franalgaba))" + +#: src/appendix-06-cairo-binaries.md:20 +msgid "### Install" +msgstr "### 安装" + +#: src/appendix-06-cairo-binaries.md:22 +msgid "If you wish to install a specific release of Cairo rather than the latest head, set the `CAIRO_GIT_TAG` environment variable (e.g. `export CAIRO_GIT_TAG=v2.2.0`)." +msgstr "如果你想安装一个特定的Cairo版本,而不是最新版本,可以设置`CAIRO_GIT_TAG`环境变量(比如执行 `export CAIRO_GIT_TAG=v2.2.0` 来设置)。" + +#: src/appendix-06-cairo-binaries.md:24 +msgid "" +"```bash\n" +"curl -L https://github.com/franalgaba/cairo-installer/raw/main/bin/cairo-installer | bash\n" +"```" +msgstr "" +"```bash\n" +"curl -L https://github.com/franalgaba/cairo-installer/raw/main/bin/cairo-installer | bash\n" +"```" + +#: src/appendix-06-cairo-binaries.md:28 +msgid "After installing, follow [these instructions](#set-up-your-shell-environment-for-cairo) to set up your shell environment." +msgstr "安装完毕后,按照[说明](#set-up-your-shell-environment-for-cairo)来设置你的shell环境。" + +#: src/appendix-06-cairo-binaries.md:30 +msgid "### Update" +msgstr "### 更新" + +#: src/appendix-06-cairo-binaries.md:32 +msgid "" +"```\n" +"rm -fr ~/.cairo\n" +"curl -L https://github.com/franalgaba/cairo-installer/raw/main/bin/cairo-installer | bash\n" +"```" +msgstr "" +"```\n" +"rm -fr ~/.cairo\n" +"curl -L https://github.com/franalgaba/cairo-installer/raw/main/bin/cairo-installer | bash\n" +"```" + +#: src/appendix-06-cairo-binaries.md:37 +msgid "### Uninstall" +msgstr "### 卸载" + +#: src/appendix-06-cairo-binaries.md:39 +msgid "Cairo is installed within `$CAIRO_ROOT` (default: ~/.cairo). To uninstall, just remove it:" +msgstr "Cairo被安装在`$CAIRO_ROOT`(默认:~/.cairo)。要卸载它,只需删除它:" + +#: src/appendix-06-cairo-binaries.md:41 +msgid "" +"```bash\n" +"rm -fr ~/.cairo\n" +"```" +msgstr "" +"```bash\n" +"rm -fr ~/.cairo\n" +"```" + +#: src/appendix-06-cairo-binaries.md:45 +msgid "then remove these three lines from .bashrc:" +msgstr "然后从.bashrc中删除这三行:" + +#: src/appendix-06-cairo-binaries.md:47 +msgid "" +"```bash\n" +"export PATH=\"$HOME/.cairo/target/release:$PATH\"\n" +"```" +msgstr "" +"```bash\n" +"export PATH=“$HOME/.cairo/target/release:$PATH”\n" +"```" + +#: src/appendix-06-cairo-binaries.md:51 +msgid "and finally, restart your shell:" +msgstr "最后,重新启动你的shell:" + +#: src/appendix-06-cairo-binaries.md:53 +msgid "" +"```bash\n" +"exec $SHELL\n" +"```" +msgstr "" +"```bash\n" +"exec $SHELL\n" +"```" + +#: src/appendix-06-cairo-binaries.md:57 +msgid "### Set up your shell environment for Cairo" +msgstr "### 为Cairo设置你的shell环境" + +#: src/appendix-06-cairo-binaries.md:59 +msgid "" +"- Define environment variable `CAIRO_ROOT` to point to the path where\n" +" Cairo will store its data. `$HOME/.cairo` is the default.\n" +" If you installed Cairo via Git checkout, we recommend\n" +" to set it to the same location as where you cloned it.\n" +"- Add the `cairo-*` executables to your `PATH` if it's not already there" +msgstr "" +"- 定义环境变量`CAIRO_ROOT`,以指向Cairo存储自身数据的路径。默认为`$HOME/.cairo`。\n" +" 如果你通过Git checkout安装Cairo,我们建议把它设置到与你Git clone它相同的位置。\n" +"- 将`cairo-*`可执行文件添加到你的`PATH`中,如果还没被自动添加的话" + +#: src/appendix-06-cairo-binaries.md:65 +msgid "The below setup should work for the vast majority of users for common use cases." +msgstr "下面的设置应该适用于绝大多数用户的一般使用情况。" + +#: src/appendix-06-cairo-binaries.md:67 +msgid "" +"- For **bash**:\n" +"\n" +" Stock Bash startup files vary widely between distributions in which of them source\n" +" which, under what circumstances, in what order and what additional configuration they perform.\n" +" As such, the most reliable way to get Cairo in all environments is to append Cairo\n" +" configuration commands to both `.bashrc` (for interactive shells)\n" +" and the profile file that Bash would use (for login shells).\n" +"\n" +" First, add the commands to `~/.bashrc` by running the following in your terminal:\n" +"\n" +" ```bash\n" +" echo 'export CAIRO_ROOT=\"$HOME/.cairo\"' >> ~/.bashrc\n" +" echo 'command -v cairo-compile >/dev/null || export PATH=\"$CAIRO_ROOT/target/release:$PATH\"' >> ~/.bashrc\n" +" ```\n" +"\n" +" Then, if you have `~/.profile`, `~/.bash_profile` or `~/.bash_login`, add the commands there as well.\n" +" If you have none of these, add them to `~/.profile`.\n" +"\n" +" - to add to `~/.profile`:\n" +"\n" +" ```bash\n" +" echo 'export CAIRO_ROOT=\"$HOME/.cairo\"' >> ~/.profile\n" +" echo 'command -v cairo-compile >/dev/null || export PATH=\"$CAIRO_ROOT/target/release:$PATH\"' >> ~/.profile\n" +" ```\n" +"\n" +" - to add to `~/.bash_profile`:\n" +" ```bash\n" +" echo 'export CAIRO_ROOT=\"$HOME/.cairo\"' >> ~/.bash_profile\n" +" echo 'command -v cairo-compile >/dev/null || export PATH=\"$CAIRO_ROOT/target/release:$PATH\"' >> ~/.bash_profile\n" +" ```\n" +"\n" +"- For **Zsh**:\n" +"\n" +" ```zsh\n" +" echo 'export CAIRO_ROOT=\"$HOME/.cairo\"' >> ~/.zshrc\n" +" echo 'command -v cairo-compile >/dev/null || export PATH=\"$CAIRO_ROOT/target/release:$PATH\"' >> ~/.zshrc\n" +" ```\n" +"\n" +" If you wish to get Cairo in non-interactive login shells as well, also add the commands to `~/.zprofile` or `~/.zlogin`.\n" +"\n" +"- For **Fish shell**:\n" +"\n" +" If you have Fish 3.2.0 or newer, execute this interactively:\n" +"\n" +" ```fish\n" +" set -Ux CAIRO_ROOT $HOME/.cairo\n" +" fish_add_path $CAIRO_ROOT/target/release\n" +" ```\n" +"\n" +" Otherwise, execute the snippet below:\n" +"\n" +" ```fish\n" +" set -Ux CAIRO_ROOT $HOME/.cairo\n" +" set -U fish_user_paths $CAIRO_ROOT/target/release $fish_user_paths\n" +" ```" +msgstr "" +"- 对于**bash** :\n" +"\n" +" 各个发行版间的 Stock Bash 的启动文件在什么情况下调用什么样的文件,以什么顺序执行,并进行哪些额外的配置都存在很大的差异\n" +" 因此,在所有环境中获得 Cairo 的最可靠方法是将 Cairo 配置命令附加到`.bashrc`(用于交互式shell)和Bash将使用的配置文件中。(用于登录shell)。\n" +"\n" +" 首先,通过在终端运行以下命令,将这些命令添加到`~/.bashrc`中:\n" +"\n" +" ```bash\n" +" echo 'export CAIRO_ROOT=\"$HOME/.cairo\"' >> ~/.bashrc\n" +" echo 'command -v cairo-compile >/dev/null || export PATH=\"$CAIRO_ROOT/target/release:$PATH\"' >> ~/.bashrc\n" +" ```\n" +"\n" +" 然后,如果你有 `~/.profile`、`~/.bash_profile`或`~/.bash_login`,也将这些命令添加到它们所对应的文件中。如果没有这些文件,则添加到 `~/.profile`中。\n" +"\n" +" - 添加到 `~/.profile` 中:\n" +"\n" +" ```bash\n" +" echo ‘export CAIRO_ROOT=“$HOME/.cairo”’ >> ~/.profile\n" +" echo ‘command -v cairo-compile >/dev/null || export PATH=“$CAIRO_ROOT/target/release:$PATH”’ >> ~/.profile\n" +" ```\n" +"\n" +" - 添加到`~/.bash_profile`:\n" +" ```bash\n" +" echo 'export CAIRO_ROOT=\"$HOME/.cairo\"' >> ~/.bash_profile\n" +" echo 'command -v cairo-compile >/dev/null || export PATH=\"$CAIRO_ROOT/target/release:$PATH\"' >> ~/.bash_profile\n" +" ```\n" +"\n" +"- 对于**Zsh**:\n" +"\n" +" ```zsh\n" +" echo 'export CAIRO_ROOT=\"$HOME/.cairo\"' >> ~/.zshrc\n" +" echo 'command -v cairo-compile >/dev/null || export PATH=\"$CAIRO_ROOT/target/release:$PATH\"' >> ~/.zshrc\n" +" ```\n" +"\n" +" 如果你希望在非交互式登录shell中也能得到Cairo,也可以将这些命令添加到`~/.zprofile`或`~/.zlogin`。\n" +"\n" +"- 对于**Fish shell**:\n" +"\n" +" 如果你有Fish 3.2.0或更新版本,请以交互方式执行:\n" +"\n" +" ```fish\n" +" set -Ux CAIRO_ROOT $HOME/.cairo\n" +" fish_add_path $CAIRO_ROOT/target/release\n" +" ```\n" +"\n" +" 否则,执行下面的片段:\n" +"\n" +" ```fish\n" +" set -Ux CAIRO_ROOT $HOME/.cairo\n" +" set -U fish_user_paths $CAIRO_ROOT/target/release $fish_user_paths\n" +" ```" + +#: src/appendix-06-cairo-binaries.md:123 +msgid "" +"In MacOS, you might also want to install [Fig](https://fig.io/) which\n" +"provides alternative shell completions for many command line tools with an\n" +"IDE-like popup interface in the terminal window.\n" +"(Note that their completions are independent from Cairo's codebase\n" +"so they might be slightly out of sync for bleeding-edge interface changes.)" +msgstr "" +"在 MacOS 中,你可能还想安装[Fig](https://fig.io/)。它为许多命令行工具提供了替\n" +"代性的 shell 补全功能,并在终端窗口有一个类似于 IDE 的弹出式界面。(注意,他们\n" +"的命令补全功能与Cairo的代码库无关,所以他们有可能有点跟不上Cairo命令行界面的更新)。" + +#: src/appendix-06-cairo-binaries.md:129 +msgid "### Restart your shell" +msgstr "### 重新启动你的shell" + +#: src/appendix-06-cairo-binaries.md:131 +msgid "for the `PATH` changes to take effect." +msgstr "以使 `PATH`的改变生效。" + +#: src/appendix-06-cairo-binaries.md:133 +msgid "" +"```sh\n" +"exec \"$SHELL\"\n" +"```" +msgstr "" +"```sh\n" +"exec \"$SHELL\"\n" +"```" + +#: src/appendix-06-cairo-binaries.md:137 +msgid "## Installing Cairo Manually ([Guide](https://github.com/auditless/cairo-template) by [Abdel](https://github.com/abdelhamidbakhta))" +msgstr "## 手动安装Cairo([指南](https://github.com/auditless/cairo-template)由[Abdel](https://github.com/abdelhamidbakhta)提供)" + +#: src/appendix-06-cairo-binaries.md:139 +msgid "### Step 1: Install Cairo 1.0" +msgstr "### 第1步:安装Cairo 1.0" + +#: src/appendix-06-cairo-binaries.md:141 +msgid "If you are using an x86 Linux system and can use the release binary, download Cairo here: ." +msgstr "如果你使用的是 x86 Linux 系统,并且可以使用发布的二进制文件,请在这里下载Cairo:。" + +#: src/appendix-06-cairo-binaries.md:143 +msgid "For everyone else, we recommend compiling Cairo from source as follows:" +msgstr "对于其他用户,我们建议从源码编译 Cairo,如下所示:" + +#: src/appendix-06-cairo-binaries.md:145 +msgid "" +"```bash\n" +"# Start by defining environment variable CAIRO_ROOT\n" +"export CAIRO_ROOT=\"${HOME}/.cairo\"\n" +"\n" +"# Create .cairo folder if it doesn't exist yet\n" +"mkdir $CAIRO_ROOT\n" +"\n" +"# Clone the Cairo compiler in $CAIRO_ROOT (default root)\n" +"cd $CAIRO_ROOT && git clone git@github.com:starkware-libs/cairo.git .\n" +"\n" +"# OPTIONAL/RECOMMENDED: If you want to install a specific version of the compiler\n" +"# Fetch all tags (versions)\n" +"git fetch --all --tags\n" +"# View tags (you can also do this in the cairo compiler repository)\n" +"git describe --tags `git rev-list --tags`\n" +"# Checkout the version you want\n" +"git checkout tags/v2.2.0\n" +"\n" +"# Generate release binaries\n" +"cargo build --all --release\n" +"```" +msgstr "" +"```bash\n" +"# Start by defining environment variable CAIRO_ROOT\n" +"export CAIRO_ROOT=\"${HOME}/.cairo\"\n" +"\n" +"# Create .cairo folder if it doesn't exist yet\n" +"mkdir $CAIRO_ROOT\n" +"\n" +"# Clone the Cairo compiler in $CAIRO_ROOT (default root)\n" +"cd $CAIRO_ROOT && git clone git@github.com:starkware-libs/cairo.git .\n" +"\n" +"# OPTIONAL/RECOMMENDED: If you want to install a specific version of the compiler\n" +"# Fetch all tags (versions)\n" +"git fetch --all --tags\n" +"# View tags (you can also do this in the cairo compiler repository)\n" +"git describe --tags `git rev-list --tags`\n" +"# Checkout the version you want\n" +"git checkout tags/v2.2.0\n" +"\n" +"# Generate release binaries\n" +"cargo build --all --release\n" +"```" + +#: src/appendix-06-cairo-binaries.md:167 +msgid "." +msgstr "." + +#: src/appendix-06-cairo-binaries.md:169 +msgid "**NOTE: Keeping Cairo up to date**" +msgstr "**注意:保持Cairo已更新到最新版本**" + +#: src/appendix-06-cairo-binaries.md:171 +msgid "" +"Now that your Cairo compiler is in a cloned repository, all you will need to do\n" +"is pull the latest changes and rebuild as follows:" +msgstr "" +"现在你的Cairo编译器已经在一个克隆的仓库里了,你所需要做的是拉取最新的修改,\n" +"并按如下方式重新编译:" + +#: src/appendix-06-cairo-binaries.md:174 +msgid "" +"```bash\n" +"cd $CAIRO_ROOT && git fetch && git pull && cargo build --all --release\n" +"```" +msgstr "" +"```bash\n" +"cd $CAIRO_ROOT && git fetch && git pull && cargo build —all —release\n" +"```" + +#: src/appendix-06-cairo-binaries.md:178 +msgid "### Step 2: Add Cairo 1.0 executables to your path" +msgstr "### 第二步:将Cairo 1.0的可执行文件添加到你的路径中" + +#: src/appendix-06-cairo-binaries.md:180 +msgid "" +"```bash\n" +"export PATH=\"$CAIRO_ROOT/target/release:$PATH\"\n" +"```" +msgstr "" +"```bash\n" +"export PATH=\"$CAIRO_ROOT/target/release:$PATH\"\n" +"```" + +#: src/appendix-06-cairo-binaries.md:184 +msgid "**NOTE: If installing from a Linux binary, adapt the destination path accordingly.**" +msgstr "**注意:如果你是在Linux编译的二进制文件,请相应调整目标路径**" + +#: src/appendix-06-cairo-binaries.md:186 +msgid "### Step 3: Setup Language Server" +msgstr "### 第三步:设置语言服务器" + +#: src/appendix-06-cairo-binaries.md:188 +msgid "#### VS Code Extension" +msgstr "#### VS代码扩展" + +#: src/appendix-06-cairo-binaries.md:190 +msgid "" +"- If you have the previous Cairo 0 extension installed, you can disable/uninstall it.\n" +"- Install the Cairo 1 extension for proper syntax highlighting and code navigation. You can find the link to the extension [here](https://marketplace.visualstudio.com/items?" +"itemName=starkware.cairo1&ssr=false), or just search for \"Cairo 1.0\" in the VS Code marketplace.\n" +"- The extension will work out of the box once you will have [Scarb](./ch01-03-hello-scarb.md) installed." +msgstr "" +"- 如果你安装了以前的Cairo 0扩展,你可以禁用/卸载它。\n" +"- 安装Cairo 1扩展以获得正确的语法高亮和代码导航。你可以通过这个链接下载扩展[here](https://marketplace.visualstudio.com/items?itemName=starkware.cairo1&ssr=false),或者直接在VS Code市" +"场上搜索 \"Cairo 1.0\"。\n" +"- 一旦你安装了[Scarb](./ch01-03-hello-scarb.md),该扩展就可以立即工作了。" + +#: src/appendix-06-cairo-binaries.md:194 +msgid "#### Cairo Language Server without Scarb" +msgstr "#### Cairo语言服务器(不使用Scarb时)" + +#: src/appendix-06-cairo-binaries.md:196 +msgid "" +"If you don't want to depend on Scarb, you can still use the Cairo Language Server with the compiler binary.\n" +"From [Step 1](#installing-cairo-with-a-script-installer-by-fran), the `cairo-language-server` binary should be built and executing this command will copy its path into your clipboard." +msgstr "" +"如果你不想依赖Scarb,你仍然可以通过编译的二进制文件使用Cairo语言服务器。\n" +"在[Step 1](#installing-cairo-with-a-script-installer-by-fran) 中,`cairo-language-server`二进制文件应该已经编译完成,执行这个命令将复制其路径到你的剪贴板。" + +#: src/appendix-06-cairo-binaries.md:199 +msgid "" +"```bash\n" +"which cairo-language-server | pbcopy\n" +"```" +msgstr "" +"```bash\n" +"which cairo-language-server | pbcopy\n" +"```" + +#: src/appendix-06-cairo-binaries.md:203 +msgid "Update the `cairo1.languageServerPath` of the Cairo 1.0 extension by pasting the path." +msgstr "将上面复制的路径更新到Cairo 1.0扩展的`cairo1.languageServerPath`中。" + +#~ msgid "" +#~ "```rust,noplayground\n" +#~ " Option::Some(val) => Option::Some(val + 1),\n" +#~ "```" +#~ msgstr "" +#~ "```rust,noplayground\n" +#~ " Option::Some(val) => Option::Some(val + 1),\n" +#~ "```" + +#~ msgid "Hello, Scarb!" +#~ msgstr "Hello,Scarb!" + +#~ msgid "### Writing and Running a Cairo Program" +#~ msgstr "### 编写和运行Cairo程序" + +#~ msgid "" +#~ "Next, make a new source file and call it _main.cairo_. Cairo files always end with\n" +#~ "the _.cairo_ extension. If you’re using more than one word in your filename, the\n" +#~ "convention is to use an underscore to separate them. For example, use\n" +#~ "_hello_world.cairo_ rather than _helloworld.cairo_." +#~ msgstr "" +#~ "接下来,制作一个新的源代码文件,并将命名为 _main.cairo_ 。Cairo文件的扩展名为 _.cairo_ 。\n" +#~ "如果你在文件名中使用一个以上的单词,惯例是用下划线来分隔它们。\n" +#~ "例如,使用 _hello_world.cairo_ 而不是 _helloworld.cairo_ 。" + +#~ msgid "Now open the _main.cairo_ file you just created and enter the code in Listing 1-1." +#~ msgstr "现在打开你刚刚创建的 _main.cairo_ 文件,输入示例1-1中的代码。" + +#~ msgid "Filename: main.cairo" +#~ msgstr "文件名:main.cairo" + +#~ msgid "Listing 1-1: A program that prints `Hello, world!`" +#~ msgstr "示例1-1:一个打印 \"Hello,world\"的程序。" + +#~ msgid "" +#~ "Save the file and go back to your terminal window in the\n" +#~ "_~/cairo_projects/hello_world_ directory. Enter the following\n" +#~ "commands to compile and run the file:" +#~ msgstr "" +#~ "保存该文件,并回到你的终端窗口,在\n" +#~ " _~/cairo_projects/hello_world_ 目录。输入以下\n" +#~ "命令来编译和运行该文件:" + +#~ msgid "" +#~ "```console\n" +#~ "$ cairo-run main.cairo\n" +#~ "Hello, world!\n" +#~ "```" +#~ msgstr "" +#~ "```console\n" +#~ "$ cairo-run main.cairo\n" +#~ "Hello, world!\n" +#~ "```" + +#~ msgid "" +#~ "Just running with `cairo-run` is fine for simple programs, but as your project\n" +#~ "grows, you’ll want to manage all the options and make it easy to share your\n" +#~ "code. Next, we’ll introduce you to the Scarb tool, which will help you write\n" +#~ "real-world Cairo programs." +#~ msgstr "" +#~ "只用`cairo-run`运行简单的程序是可以的,但随着你的项目\n" +#~ "增长,你会希望管理所有的选项,并使之易于分享你的\n" +#~ "代码。接下来,我们将向你介绍Scarb工具,它将帮助你编写\n" +#~ "真实世界的Cairo程序。" + +#~ msgid "# Hello, Scarb" +#~ msgstr "# 你好,Scarb" + +#~ msgid "" +#~ "If we were to build the 'Hello, world!' project using Scarb, only the part of Scarb that handles building the code would be used, since the program doesn't require any external " +#~ "dependencies. As you write more complex Cairo programs, you’ll add dependencies, and if you start a project using Scarb, adding dependencies will be much easier to do." +#~ msgstr "" +#~ "如果我们使用 Scarb 构建 'Hello, world!' 项目,由于该程序不需要任何外部依赖,因此只会使用 Scarb 中处理代码构建的部分。当你编写更复杂的 Cairo 程序时,你需要添加依赖项,如果你使用 " +#~ "Scarb 启动一个项目,添加依赖项就会变得容易得多。" + +#~ msgid "Let’s create a new project using Scarb and look at how it differs from our original “Hello, world!” project." +#~ msgstr "让我们用Scarb创建一个新的项目,看看它与我们原来的 \"Hello, world!\"项目有什么不同。" + +#~ msgid "" +#~ "```rust,file=hello_scarb.cairo\n" +#~ "use debug::PrintTrait;\n" +#~ "fn main() {\n" +#~ " 'Hello, Scarb!'.print();\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust,file=hello_scarb.cairo\n" +#~ "use debug::PrintTrait;\n" +#~ "fn main() {\n" +#~ " 'Hello, Scarb!'.print();\n" +#~ "}\n" +#~ "```" + +#~ msgid "" +#~ "```bash\n" +#~ "$ cairo-run src/lib.cairo\n" +#~ "[DEBUG] Hello, Scarb! (raw: 5735816763073854913753904210465)\n" +#~ "\n" +#~ "Run completed successfully, returning []\n" +#~ "```" +#~ msgstr "" +#~ "```bash\n" +#~ "$ cairo-run src/lib.cairo\n" +#~ "[DEBUG] Hello, Scarb! (raw: 5735816763073854913753904210465)\n" +#~ "\n" +#~ "Run completed successfully, returning []\n" +#~ "```" + +#~ msgid "" +#~ "> Note: You will notice here that we didn't use a Scarb command, but rather a command from the Cairo binaries directly.\n" +#~ "> As Scarb doesn't have a command to execute Cairo code yet, we have to use the `cairo-run` command directly.\n" +#~ "> We will use this command in the rest of the tutorial, but we will also use Scarb commands to initialize projects." +#~ msgstr "" +#~ "> 注意:你会注意到这里我们没有使用Scarb的命令,而是直接使用了Cairo二进制文件的命令。\n" +#~ "> 由于Scarb还没有执行Cairo代码的命令,我们必须直接使用`cairo-run`命令来执行代码。\n" +#~ "> 在接下来的教程中我们将使用这个命令,但我们也将使用Scarb命令来初始化项目。" + +#~ msgid "### Defining Custom Scripts" +#~ msgstr "### 定义自定义脚本" + +#~ msgid "" +#~ "We can define Scarb scripts in `Scarb.toml` file, which can be used to execute custom shell scripts.\n" +#~ "Add the following line to your `Scarb.toml` file:" +#~ msgstr "" +#~ "我们可以在`Scarb.toml`文件中定义Scarb脚本,它可以用来执行自定义的shell脚本。\n" +#~ "在你的`Scarb.toml`文件中添加以下一行:" + +#~ msgid "" +#~ "```toml\n" +#~ "[scripts]\n" +#~ "run-lib = \"cairo-run src/lib.cairo\"\n" +#~ "```" +#~ msgstr "" +#~ "```toml\n" +#~ "[scripts]\n" +#~ "run-lib = \"cairo-run src/lib.cairo\"\n" +#~ "```" + +#~ msgid "Now you can run the following command to run the project:" +#~ msgstr "现在你可以运行以下命令来运行该项目:" + +#~ msgid "Using `scarb run` is a convenient way to run custom shell scripts that can be useful to run files and test your project." +#~ msgstr "使用 \"scarb run \"是运行自定义shell脚本的一种方便的方法,可以用来运行文件和测试你的项目。" + +#~ msgid "" +#~ "```toml\n" +#~ "\n" +#~ "[scripts]\n" +#~ "test = \"protostar test\"\n" +#~ "```" +#~ msgstr "" +#~ "```toml\n" +#~ "\n" +#~ "[scripts]\n" +#~ "test = \"protostar test\"\n" +#~ "```" + +#~ msgid "" +#~ "```console\n" +#~ "❯ cairo-run src/lib.cairo\n" +#~ "[DEBUG]\t \t(raw: 5)\n" +#~ "\n" +#~ "[DEBUG]\t \t(raw: 6)\n" +#~ "\n" +#~ "Run completed successfully, returning []\n" +#~ "```" +#~ msgstr "" +#~ "```console\n" +#~ "❯ cairo-run src/lib.cairo\n" +#~ "[DEBUG]\t \t(raw: 5)\n" +#~ "\n" +#~ "[DEBUG]\t \t(raw: 6)\n" +#~ "\n" +#~ "Run completed successfully, returning []\n" +#~ "```" + +#~ msgid "" +#~ "```rust,does_not_compile\n" +#~ "use debug::PrintTrait;\n" +#~ "use traits::Into;\n" +#~ "fn main() {\n" +#~ " let mut x = 2;\n" +#~ " x.print();\n" +#~ " x = x.into();\n" +#~ " x.print()\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust,does_not_compile\n" +#~ "use debug::PrintTrait;\n" +#~ "use traits::Into;\n" +#~ "fn main() {\n" +#~ " let mut x = 2;\n" +#~ " x.print();\n" +#~ " x = x.into();\n" +#~ " x.print()\n" +#~ "}\n" +#~ "```" + +#~ msgid "Filename: src/main.cairo" +#~ msgstr "文件名: src/main.cairo" + +#~ msgid "The snapshot type is always copyable and droppable, so that you can use it multiple times without worrying about ownership transfers." +#~ msgstr "快照类型始终是可复制和可删除的,因此你可以多次使用它而不必担心所有权的转移。" + +#~ msgid "Filename: structs.cairo" +#~ msgstr "文件名:structs.cairo" + +#~ msgid "" +#~ "> Note: You will notice here a `cairo_project.toml` file.\n" +#~ "> This is the configuration file for \"vanilla\" Cairo projects (i.e. not managed by Scarb),\n" +#~ "> which is required to run the `cairo-run .` command to run the code of the crate.\n" +#~ "> It is required until Scarb implements this feature. The content of the file is:\n" +#~ ">\n" +#~ "> ```toml\n" +#~ "> [crate_roots]\n" +#~ "> backyard = \"src\"\n" +#~ "> ```\n" +#~ ">\n" +#~ "> and indicates that the crate named \"backyard\" is located in the `src` directory." +#~ msgstr "" +#~ "> 注意:你会注意到这里有一个`cairo_project.toml`文件。\n" +#~ "> 这是 通常的Cairo项目的配置文件(即不由Scarb管理)、\n" +#~ "> 这是运行`cairo-run .`命令来运行crate的代码所需要的。\n" +#~ "> 在Scarb实现这一功能之前,它是必需的。该文件的内容是:\n" +#~ ">\n" +#~ "> ```toml\n" +#~ "> [crate_roots]\n" +#~ "> backyard = “src”\n" +#~ "> ```\n" +#~ ">\n" +#~ "> 它表示名为 \"backyard \"的板块位于`src`目录下。" + +#~ msgid "Filename: lib.cairo" +#~ msgstr "文件名:lib.cairo" + +#~ msgid "" +#~ "```rust\n" +#~ " balances.insert('Alex', 100_u64);\n" +#~ " balances.insert('Maria', 50_u64);\n" +#~ " balances.insert('Alex', 200_u64);\n" +#~ " balances.get('Maria');\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ " balances.insert('Alex', 100_u64);\n" +#~ " balances.insert('Maria', 50_u64);\n" +#~ " balances.insert('Alex', 200_u64);\n" +#~ " balances.get('Maria');\n" +#~ "```" + +#~ msgid "" +#~ "```rust\n" +#~ "fn main() {\n" +#~ " let mut dict: Felt252Dict = Default::default();\n" +#~ "\n" +#~ " custom_insert(ref dict, '0', 100);\n" +#~ "\n" +#~ " let val = custom_get(ref dict, '0');\n" +#~ "\n" +#~ " assert(val == 100, 'Expecting 100');\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "fn main() {\n" +#~ " let mut dict: Felt252Dict = Default::default();\n" +#~ "\n" +#~ " custom_insert(ref dict, '0', 100);\n" +#~ "\n" +#~ " let val = custom_get(ref dict, '0');\n" +#~ "\n" +#~ " assert(val == 100, 'Expecting 100');\n" +#~ "}\n" +#~ "```" + +#~ msgid "" +#~ "```rust\n" +#~ "fn main() {\n" +#~ " let mut db = UserDatabaseTrait::new();\n" +#~ "\n" +#~ " db.add_user('Alex', 100);\n" +#~ " db.add_user('Maria', 80);\n" +#~ "\n" +#~ " db.add_user('Alex', 40);\n" +#~ " db.add_user('Maria', 0);\n" +#~ "\n" +#~ " let alex_latest_balance = db.get_user('Alex');\n" +#~ " let maria_latest_balance = db.get_user('Maria');\n" +#~ "\n" +#~ " assert(alex_latest_balance == 40, 'Expected 40');\n" +#~ " assert(maria_latest_balance == 0, 'Expected 0');\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "fn main() {\n" +#~ " let mut db = UserDatabaseTrait::new();\n" +#~ "\n" +#~ " db.add_user('Alex', 100);\n" +#~ " db.add_user('Maria', 80);\n" +#~ "\n" +#~ " db.add_user('Alex', 40);\n" +#~ " db.add_user('Maria', 0);\n" +#~ "\n" +#~ " let alex_latest_balance = db.get_user('Alex');\n" +#~ " let maria_latest_balance = db.get_user('Maria');\n" +#~ "\n" +#~ " assert(alex_latest_balance == 40, 'Expected 40');\n" +#~ " assert(maria_latest_balance == 0, 'Expected 0');\n" +#~ "}\n" +#~ "```" + +#~ msgid "The ability of contracts to interact with other smart contracts on the blockchain is a common pattern found in smart contract development." +#~ msgstr "合约与区块链上其他智能合约的互动能力是智能合约开发中的一个常见模式。" + +#~ msgid "For your Cairo code to qualify as an interface, it must meet the following requirements:" +#~ msgstr "要使你的Cairo代码有资格成为一个接口,它必须满足以下要求:" + +#~ msgid "" +#~ "1. Must be appended with the `#[abi]` attribute.\n" +#~ "2. Your interface functions should have no implementations.\n" +#~ "3. You must explicitly declare the function's decorator.\n" +#~ "4. Your interface should not declare a constructor.\n" +#~ "5. Your interface should not declare state variables." +#~ msgstr "" +#~ "1. 必须附加 `#[abi]` 属性。\n" +#~ "2. 你的接口函数不应该有任何实现。\n" +#~ "3. 你必须明确地声明该函数的装饰器。\n" +#~ "4. 你的接口不应该声明一个构造函数。\n" +#~ "5. 你的接口不应该声明状态变量。" + +#~ msgid "Here's a sample interface for an ERC20 token contract:" +#~ msgstr "下面是一个ERC20代币合约的接口样本:" + +#~ msgid "## ABIs" +#~ msgstr "## ABI" + +#~ msgid "" +#~ "ABI stands for Application Binary Interface. ABIs gives a smart contract the ability to communicate and interact with external applications or other smart contracts. ABIs can be " +#~ "likened to APIs in traditional web development, which helps data flow between applications and servers." +#~ msgstr "ABI是指应用二进制接口。ABI使智能合约有能力与外部应用程序或其他智能合约进行沟通和互动。ABI可以比喻为传统网络开发中的API,它帮助数据在应用程序和服务器之间流动。" + +#~ msgid "Every contract on Starknet has an Application Binary Interface (ABI) that defines how to encode and decode data when calling its methods." +#~ msgstr "Starknet上的每个合约都有一个应用二进制接口(ABI),它定义了在调用其方法时如何对数据进行编码和解码。" + +#~ msgid "# Contract Dispatcher, Library Dispatcher and System calls" +#~ msgstr "# 合约调度器、库调度器和系统调用" + +#~ msgid "" +#~ "Traits annotated with the `#[abi]` attribute are programmed to automatically generate and export the relevant dispatcher logic on compilation. The compiler also generates a new " +#~ "trait, two new structs (one for contract calls, and the other for library calls) and their implementation of this trait. Our interface is expanded into something like this:" +#~ msgstr "" +#~ "用`#[abi]`属性注释的trait会在编译时自动生成并导出相关的调度器。编译器也会生成一个新的trait、两个新的结构体(一个用于合约调用,另一个用于库调用)以及它们对这个trait的实现。我们的接" +#~ "口被扩展为如下:" + +#~ msgid "" +#~ "The key difference between the contract dispatcher and the library dispatcher is that while the contract dispatcher calls an external contract's logic in the external contract's " +#~ "context, the library dispatcher calls the target contract's class hash, whilst executing the call in the calling contract's context.\n" +#~ "So unlike the contract dispatcher, calls made using the library dispatcher have no possibility of tampering with the target contract's state." +#~ msgstr "" +#~ "合约调度器和库调度器的关键区别在于,合约调度器是在外部合约的上下文中调用外部合约的逻辑,而库调度器则是在调用合约的上下文中执行调用,调用目标契约的classhash。\n" +#~ "因此,与合约调度器不同,使用库调度器进行的调用不可能修改目标合约的状态。" + +#~ msgid "" +#~ "As stated in the previous chapter, contracts annotated with the `#[abi]` macro on compilation generates a new trait, two new structs (one for contract calls, and the other for " +#~ "library calls) and their implementation of this trait. The expanded form of the library traits looks like:" +#~ msgstr "如前一章所述,在编译时用`#[abi]`宏标注的合约会生成一个新的trait、两个新的结构体(一个用于契约调用,另一个用于库调用)以及它们对该trait的实现。库特征的扩展形式看起来像:" + +#~ msgid "" +#~ "```rust\n" +#~ "#[starknet::contract]\n" +#~ "mod TokenWrapper {\n" +#~ " use super::IERC20DispatcherTrait;\n" +#~ " use super::IERC20LibraryDispatcher;\n" +#~ " use starknet::ContractAddress;\n" +#~ " use super::ITokenWrapper;\n" +#~ "\n" +#~ " #[storage]\n" +#~ " struct Storage {}\n" +#~ "\n" +#~ " impl TokenWrapper of ITokenWrapper {\n" +#~ " fn token_name(self: @ContractState) -> felt252 {\n" +#~ " IERC20LibraryDispatcher { class_hash: starknet::class_hash_const::<0x1234>() }.name()\n" +#~ " }\n" +#~ "\n" +#~ " fn transfer_token(\n" +#~ " ref self: ContractState, recipient: ContractAddress, amount: u256\n" +#~ " ) -> bool {\n" +#~ " IERC20LibraryDispatcher {\n" +#~ " class_hash: starknet::class_hash_const::<0x1234>()\n" +#~ " }.transfer(recipient, amount)\n" +#~ " }\n" +#~ " }\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "#[starknet::contract]\n" +#~ "mod TokenWrapper {\n" +#~ " use super::IERC20DispatcherTrait;\n" +#~ " use super::IERC20LibraryDispatcher;\n" +#~ " use starknet::ContractAddress;\n" +#~ " use super::ITokenWrapper;\n" +#~ "\n" +#~ " #[storage]\n" +#~ " struct Storage {}\n" +#~ "\n" +#~ " impl TokenWrapper of ITokenWrapper {\n" +#~ " fn token_name(self: @ContractState) -> felt252 {\n" +#~ " IERC20LibraryDispatcher { class_hash: starknet::class_hash_const::<0x1234>() }.name()\n" +#~ " }\n" +#~ "\n" +#~ " fn transfer_token(\n" +#~ " ref self: ContractState, recipient: ContractAddress, amount: u256\n" +#~ " ) -> bool {\n" +#~ " IERC20LibraryDispatcher {\n" +#~ " class_hash: starknet::class_hash_const::<0x1234>()\n" +#~ " }.transfer(recipient, amount)\n" +#~ " }\n" +#~ " }\n" +#~ "}\n" +#~ "```" + +#~ msgid "" +#~ "As you can see, we had to first import the `IERC20DispatcherTrait` and `IERC20LibraryDispatcher` which were generated and exported after compiling our interface, then we make " +#~ "calls to the methods implemented for the `IERC20LibraryDispatcher` struct (`name`, `transfer`, etc), passing in the `class_hash` of the contract we want to call." +#~ msgstr "" +#~ "如您所见,我们必须首先导入`IERC20DispatcherTrait`和`IERC20LibraryDispatcher`,它们是在编译我们的接口后生成并导出的,然后我们调用为`IERC20LibraryDispatcher`结构实现的方法(`name`、" +#~ "`transfer`等),并传入我们要调用的合约的`class_hash`。" + +#~ msgid "TODO (Not derivable yet ?)" +#~ msgstr "TODO (还不能派生?)" + +#~ msgid "" +#~ "```console\n" +#~ "cairo-format -r\n" +#~ "```" +#~ msgstr "" +#~ "```console\n" +#~ "cairo-format -r\n" +#~ "```" + +#~ msgid "" +#~ "Running this command reformats all the Cairo code in the current directory, recursively. This\n" +#~ "should only change the code style, not the code semantics." +#~ msgstr "" +#~ "运行这条命令可以递归式的重新格式化当前目录下的所有Cairo代码。这条命令\n" +#~ "只会改变代码的风格,而不会改变代码的语义。" + +#~ msgid "Writing Starknet Contracts" +#~ msgstr "编写Starknet智能合约" + +#~ msgid "" +#~ "```rust\n" +#~ "let rect = Rectangle { ... }; // Rectangle instantiation\n" +#~ "\n" +#~ "// First way, as a method on the struct instance\n" +#~ "let area1 = rect.area();\n" +#~ "// Second way, from the implementation\n" +#~ "let area2 = RectangleGeometry::area(rect);\n" +#~ "// `area1` has same value as `area2`\n" +#~ "area1.print();\n" +#~ "area2.print();\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "let rect = Rectangle { ... }; // Rectangle instantiation\n" +#~ "\n" +#~ "// First way, as a method on the struct instance\n" +#~ "let area1 = rect.area();\n" +#~ "// Second way, from the implementation\n" +#~ "let area2 = RectangleGeometry::area(rect);\n" +#~ "// `area1` has same value as `area2`\n" +#~ "area1.print();\n" +#~ "area2.print();\n" +#~ "```" + +#~ msgid "If the code was organised into modules like this," +#~ msgstr "如果代码被如下般组织成模块," + +#~ msgid "you might also need to use `CircleGeometry`," +#~ msgstr "你可能还需要使用`CircleGeometry`、" + +#~ msgid "" +#~ "Ethereum, being the most widely used and resilient smart-contract platform, became a victim of its own success. With the rapid adoption of some previously mentioned use cases, " +#~ "mainly DeFi, the cost of performing transactions became extremely high, rendering the network almost unusable. Engineers and researchers in the ecosystem began working on " +#~ "solutions to address this scalability issue. A famous theorem in the blockchain space states that it is impossible to achieve a high level of scalability, decentralization, and " +#~ "security simultaneously; trade-offs must be made. Ethereum is at the intersection of decentralization and security. Eventually, it was decided that Ethereum's purpose would be to " +#~ "serve as a secure settlement layer, while complex computations would be offloaded to other networks built on top of Ethereum. These are called Layer 2s (L2s). The two primary " +#~ "types of L2s are optimistic rollups and validity rollups. Both approaches involve compressing and batching numerous transactions together, computing the new state, and settling " +#~ "the result on Ethereum (L1). The difference lies in the way the result is settled on L1. For optimistic rollups, the new state is considered valid by default, but there is a 7-day " +#~ "window for nodes to identify malicious transactions. In contrast, validity rollups, such as Starknet, use cryptography to prove that the new state has been correctly computed. " +#~ "This is the purpose of STARKs, this cryptographic technology could permit validity rollups to scale significantly more than optimistic rollups. You can learn more about STARKs " +#~ "from Starkware's Medium [article](https://medium.com/starkware/starks-starkex-and-starknet-9a426680745a), which serves as a good primer." +#~ msgstr "" +#~ "以太坊作为使用最广泛、弹性最大的智能合约平台,成为了其自身成功的受害者。随着前面提到的一些用例的快速采用,主要是DeFi,执行交易的成本变得非常高,使网络几乎无法使用。生态系统中的工程" +#~ "师和研究人员开始研究解决这一可扩展性问题的方案。区块链领域的一个著名定理指出,不可能同时实现高水平的可扩展性、去中心化和安全性;必须做出权衡。以太坊正处于去中心化和安全的交叉点。最" +#~ "终,人们决定,以太坊的目的是作为一个安全的结算层,而复杂的计算将被卸载到建立在以太坊之上的其他网络。这些被称为第二层(L2)。L2的两种主要类型是optimistic-rollups和validity-rollups。" +#~ "这两种方法都涉及到将众多交易压缩和批量化,计算新的状态,并将结果在以太坊(L1)上结算。区别在于结果在L1上结算的方式。对于optimistic-rollups,新的状态默认被认为是有效的,但有一个7天" +#~ "的窗口供节点识别恶意交易。相比之下,validity-rollups,如Starknet,使用密码学来证明新的状态已经被正确计算出来。这是STARKs的目的,这种加密技术可以允许validity-rollups的规模大大超过" +#~ "optimistic-rollups。你可以从Starkware的Medium[文章](https://medium.com/starkware/starks-starkex-and-starknet-9a426680745a)中了解更多关于STARKs的信息,这可以作为一个很好的入门。" + +#~ msgid "# Writing Starknet Contracts" +#~ msgstr "# 撰写Starknet合约" + +#~ msgid "This chapter will guide you on how to create smart contracts in Cairo, and will clarify the distinction between Cairo programs and Starknet contracts." +#~ msgstr "本章将指导你如何在Cairo中创建智能合约,并将阐明Cairo程序和Starknet合约之间的区别。" + +#~ msgid "" +#~ "```rust\n" +#~ "#[contract]\n" +#~ "mod example {\n" +#~ " use starknet::get_caller_address;\n" +#~ " use starknet::ContractAddress;\n" +#~ "\n" +#~ " struct Storage {\n" +#~ " names: LegacyMap::, \n" +#~ " }\n" +#~ "\n" +#~ " #[event]\n" +#~ " fn StoredName(caller: ContractAddress, name: felt252) {}\n" +#~ "\n" +#~ " #[constructor]\n" +#~ " fn constructor(_name: felt252, _address: ContractAddress) {\n" +#~ " names::write(_address, _name);\n" +#~ " }\n" +#~ "\n" +#~ " #[external]\n" +#~ " fn store_name(_name: felt252) {\n" +#~ " let caller = get_caller_address();\n" +#~ " names::write(caller, _name);\n" +#~ " StoredName(caller, _name);\n" +#~ " }\n" +#~ "\n" +#~ " #[view]\n" +#~ " fn get_name(_address: ContractAddress) -> felt252 {\n" +#~ " let name = names::read(_address);\n" +#~ " return name;\n" +#~ " }\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "#[contract]\n" +#~ "mod example {\n" +#~ " use starknet::get_caller_address;\n" +#~ " use starknet::ContractAddress;\n" +#~ "\n" +#~ " struct Storage {\n" +#~ " names: LegacyMap::, \n" +#~ " }\n" +#~ "\n" +#~ " #[event]\n" +#~ " fn StoredName(caller: ContractAddress, name: felt252) {}\n" +#~ "\n" +#~ " #[constructor]\n" +#~ " fn constructor(_name: felt252, _address: ContractAddress) {\n" +#~ " names::write(_address, _name);\n" +#~ " }\n" +#~ "\n" +#~ " #[external]\n" +#~ " fn store_name(_name: felt252) {\n" +#~ " let caller = get_caller_address();\n" +#~ " names::write(caller, _name);\n" +#~ " StoredName(caller, _name);\n" +#~ " }\n" +#~ "\n" +#~ " #[view]\n" +#~ " fn get_name(_address: ContractAddress) -> felt252 {\n" +#~ " let name = names::read(_address);\n" +#~ " return name;\n" +#~ " }\n" +#~ "}\n" +#~ "```" + +#~ msgid "## Starknet Contract Attributes" +#~ msgstr "## Starknet合约的属性" + +#~ msgid "Attributes are special annotations that modify the behavior of certain functions or methods. They are placed preceding a function and are denoted by the `#[]` symbol." +#~ msgstr "属性是修改某些函数或方法的行为的特殊标注。它们被放在一个函数的前面,用`#[]`符号来表示。" + +#~ msgid "" +#~ msgstr "" + +#~ msgid "Here is a list of common attributes used in Starknet contracts:" +#~ msgstr "以下是Starknet合约中使用的常见属性列表:" + +#~ msgid "" +#~ "1. `#[contract]`: This attribute is used to annotate a module to be compiled as a Starknet contract.\n" +#~ " The compiler recognizes this attribute and prepares the module with necessary contract elements,\n" +#~ " such as the logic to handle external contract calls or how to access storage variables.\n" +#~ "\n" +#~ "2. `#[constructor]`: This attribute marks a function as a constructor. The constructor function is called only once upon deploying a contract, setting the initial state of the " +#~ "contract.\n" +#~ "\n" +#~ "3. `#[external]`: This attribute marks a function as an external function. External functions can be called by other contracts or externally and can modify the contract's state.\n" +#~ "\n" +#~ "4. `#[view]`: This attribute marks a function as a view function. View functions are read-only functions that allow you to access data from the contract, but prevent you from " +#~ "modifying the state of the blockchain.\n" +#~ "\n" +#~ "5. `#[event]`: This is used to define events that can be emitted by the contract.\n" +#~ "\n" +#~ "6. `#[l1_handler]`: This attribute is used to mark functions which can receive messages from L1s." +#~ msgstr "" +#~ "1. `#[contract]`:这个属性用来标注一个要被编译为Starknet合约的模块。\n" +#~ " 编译器会识别这个属性并为模块准备必要的合同元素、\n" +#~ " 例如,处理外部合同调用的逻辑或如何访问存储变量。\n" +#~ "\n" +#~ "2. `#[constructor]`:这个属性标志着一个函数是一个构造函数。构造函数在部署合约时只被调用一次,设置合约的初始状态。\n" +#~ "\n" +#~ "3. `#[external]`:这个属性标志着一个函数是一个外部函数。外部函数可以被其他合约或外部调用,可以修改合约的状态。\n" +#~ "\n" +#~ "4. `#[view]`:这个属性标志着一个函数是一个视图函数。视图函数是只读函数,允许你访问合约中的数据,但阻止你修改区块链的状态。\n" +#~ "\n" +#~ "5. `#[event]`:这是用来定义可由合约发出的事件。\n" +#~ "\n" +#~ "6. `#[l1_handler]`:这个属性用来标记可以接收L1消息的函数。" + +#~ msgid "" +#~ "An event is defined as an empty function annotated with the `#[event]` attribute. The parameters of this function\n" +#~ "are the data that will be emitted by the event." +#~ msgstr "" +#~ "一个事件被定义为一个用`#[event]`属性注释的空函数。这个函数的参数\n" +#~ "的参数是将由该事件发出的数据。" + +#~ msgid "In Listing 99-1, `StoredName` is an event that emits information when names are stored in the contract:" +#~ msgstr "在示例99-1中,`StoredName`是一个当名字被存储在合约中时,会被触发并发出信息的事件:" + +#~ msgid "" +#~ "```rust\n" +#~ " #[event]\n" +#~ " fn StoredName(caller: ContractAddress, name: felt252) {}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ " #[event]\n" +#~ " fn StoredName(caller: ContractAddress, name: felt252) {}\n" +#~ "```" + +#~ msgid "" +#~ "We pass in the emitted data types as parameters within the parentheses. In this example, our event will emit the contract address of the caller and the name stored within the " +#~ "contract." +#~ msgstr "我们在括号内传入作为把发射的数据类型参数传入。在这个例子中,我们的事件将发出调用者的合同地址和存储在合同中的名字的信息。" + +#~ msgid "" +#~ "After defining events, we can emit them by simply calling the event name like we'll call functions,\n" +#~ "passing in the values to be emitted as parameters:" +#~ msgstr "" +#~ "定义完事件后,我们可以像调用函数一样简单地调用事件名称来发射它们、\n" +#~ "作为参数传入要发射的值:" + +#~ msgid "" +#~ "```rust\n" +#~ "#[contract]\n" +#~ "mod contract {\n" +#~ " use array::ArrayTrait;\n" +#~ " #[external]\n" +#~ " fn transfer_token(\n" +#~ " address: starknet::ContractAddress, selector: felt252, calldata: Array\n" +#~ " ) -> Span:: {\n" +#~ " starknet::call_contract_syscall(address, selector, calldata.span()).unwrap_syscall()\n" +#~ " }\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "#[contract]\n" +#~ "mod contract {\n" +#~ " use array::ArrayTrait;\n" +#~ " #[external]\n" +#~ " fn transfer_token(\n" +#~ " address: starknet::ContractAddress, selector: felt252, calldata: Array\n" +#~ " ) -> Span:: {\n" +#~ " starknet::call_contract_syscall(address, selector, calldata.span()).unwrap_syscall()\n" +#~ " }\n" +#~ "}\n" +#~ "```" + +#~ msgid "" +#~ "- Disable previous Cairo 0.x extension\n" +#~ "- Install the Cairo 1 extension for proper syntax highlighting and code navigation.\n" +#~ " Just follow the steps indicated [here](https://github.com/starkware-libs/cairo/blob/main/vscode-cairo/README.md)." +#~ msgstr "" +#~ "- 禁用以前的 Cairo 0.x 扩展\n" +#~ "- 安装Cairo 1扩展以获得正确的语法高亮和代码导航。\n" +#~ "只要按照[这里](https://github.com/starkware-libs/cairo/blob/main/vscode-cairo/README.md)所示的步骤就可以了。" -#: src/appendix-03-derivable-traits.md:145 -msgid "## Drop and Destruct" -msgstr "## Drop 和 Destruct" +#~ msgid "As for now, Scarb needs manual installation with the following steps:" +#~ msgstr "就目前而言,Scarb需要手动安装,步骤如下:" -#: src/appendix-03-derivable-traits.md:147 -msgid "" -"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](ch03-01-what-is-ownership." -"md#the-drop-trait)." -msgstr "当离开作用域时,需要先移动变量。这就是 `Drop` trait起作用的地方。你可以在[这里](ch03-01-what-is-ownership.md#the-drop-trait)找到更多关于它的用法的细节。" +#~ msgid "" +#~ "- Download the release archive matching your operating system and CPU architecture, from [Scarb releases on GitHub](https://github.com/software-mansion/scarb/releases)\n" +#~ "- Extract it to a location where you would like to have Scarb installed, e.g. `~/scarb`\n" +#~ "- Add path to the `scarb/bin` directory to your `PATH` environment variable.\n" +#~ "\n" +#~ " This depend on what shell you are using. Let’s take the example of [zsh](https://ohmyz.sh/) and you have extracted Scarb to `~/scarb`:\n" +#~ "\n" +#~ " - Open `~/.zshrc` file in your favorite editor\n" +#~ " - Add the following line to the end of the file: `export PATH=\"$PATH:~/scarb/bin\"`\n" +#~ "\n" +#~ "- Verify installation by running the following command in new terminal session, it should print both Scarb and Cairo language versions, e.g:\n" +#~ "\n" +#~ " ```bash\n" +#~ " $ scarb --version\n" +#~ " scarb 0.3.0 (182a9019d 2023-05-29)\n" +#~ " cairo: 1.1.0 (https://crates.io/crates/cairo-lang-compiler/1.1.0)\n" +#~ " ```" +#~ msgstr "" +#~ "- 从[GitHub上的Scarb发布页](https://github.com/software-mansion/scarb/releases)下载与你的操作系统和CPU架构相匹配的Release档案。\n" +#~ "- 将其解压到你想安装Scarb的位置,例如`~/scarb`。\n" +#~ "- 将`scarb/bin`目录的路径添加到你的`PATH`环境变量中。\n" +#~ "\n" +#~ " 这取决于你使用的是什么shell。让我们以[zsh](https://ohmyz.sh/)为例,将Scarb解压到`~/scarb`后:\n" +#~ "\n" +#~ " - 用你爱用的编辑器打开`~/.zshrc`文件\n" +#~ " - 在文件的末尾添加以下行:`export PATH=\"$PATH:~/scarb/bin\"`。\n" +#~ "\n" +#~ "- 在新的终端会话中运行以下命令来验证安装是否成功,它应该同时打印Scarb和Cairo语言的版本,例如:\n" +#~ "\n" +#~ " ```bash\n" +#~ " $ scarb --version\n" +#~ " scarb 0.3.0 (182a9019d 2023-05-29)\n" +#~ " cairo: 1.1.0 (https://crates.io/crates/cairo-lang-compiler/1.1.0)\n" +#~ " ```" -#: src/appendix-03-derivable-traits.md:149 -msgid "" -"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](ch03-01-what-is-ownership.md#the-destruct-trait)." -msgstr "" -"此外,字典在离开作用域之前需要被squash(压缩)。在每个字典上手动调用`squash`方法很快就不再是必须操作。`Destruct` 特性允许字典在超出范围时被自动压缩。你也可以在[这里](ch03-01-what-is-" -"ownership.md#the-destruct-trait) 找到更多关于`Destruct`的信息。" +#~ msgid "" +#~ "```rs\n" +#~ "let direction = Direction::North(());\n" +#~ "```" +#~ msgstr "" +#~ "```rs\n" +#~ "let direction = Direction::North(());\n" +#~ "```" -#: src/appendix-03-derivable-traits.md:151 -msgid "## PartialOrd and Ord for Ordering Comparisons" -msgstr "## 用于排序比较的PartialOrd和Ord" +#~ msgid "" +#~ "```rust\n" +#~ "let msg: Message = Message::Quit(());\n" +#~ "msg.process();\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "let msg: Message = Message::Quit(());\n" +#~ "msg.process();\n" +#~ "```" -#: src/appendix-03-derivable-traits.md:153 -msgid "TODO (Not derivable yet ?)" -msgstr "TODO (还不能派生?)" +#~ msgid "" +#~ "```rs\n" +#~ "enum Option {\n" +#~ " Some: T,\n" +#~ " None: (),\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rs\n" +#~ "enum Option {\n" +#~ " Some: T,\n" +#~ " None: (),\n" +#~ "}\n" +#~ "```" -#: src/appendix-04-useful-development-tools.md:1 -msgid "## Appendix D - Useful Development Tools" -msgstr "## 附录D - 实用开发工具" +#~ msgid "Compiling the above code would error due to the `derive` macro not working well with generics. When using generic types is best to directly write the traits you want to use:" +#~ msgstr "由于`derive`宏在泛型中不能正常工作,编译上述代码会出错。当使用泛型时,最好直接编写你想使用的特性:" -#: src/appendix-04-useful-development-tools.md:3 -msgid "" -"In this appendix, we talk about some useful development tools that the Cairo\n" -"project provides. We’ll look at automatic formatting, quick ways to apply\n" -"warning fixes, a linter, and integrating with IDEs." -msgstr "" -"在本附录中,我们将提到由Cairo项目提供的一些有用的开发工具。\n" -"我们将看看自动格式化、快速应用警告修正,linter,以及与IDE的整合。" +#~ msgid "" +#~ msgstr "" -#: src/appendix-04-useful-development-tools.md:7 -msgid "### Automatic Formatting with `cairo-format`" -msgstr "### 用`cairo-format`自动格式化" +#~ msgid "" +#~ "```rust\n" +#~ "struct Wallet {\n" +#~ " balance: T,\n" +#~ " address: U,\n" +#~ "}\n" +#~ "\n" +#~ "impl WalletDrop, U, impl UDrop: Drop> of Drop>;\n" +#~ "\n" +#~ "fn main() {\n" +#~ " let w = Wallet { balance: 3, address: 14 };\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "struct Wallet {\n" +#~ " balance: T,\n" +#~ " address: U,\n" +#~ "}\n" +#~ "\n" +#~ "impl WalletDrop, U, impl UDrop: Drop> of Drop>;\n" +#~ "\n" +#~ "fn main() {\n" +#~ " let w = Wallet { balance: 3, address: 14 };\n" +#~ "}\n" +#~ "```" -#: src/appendix-04-useful-development-tools.md:9 -msgid "" -"The `cairo-format` tool reformats your code according to the community code style.\n" -"Many collaborative projects use `cairo-format` to prevent arguments about which\n" -"style to use when writing Cairo: everyone formats their code using the tool." -msgstr "" -"`cairo-format`工具根据Cairo社区的代码风格重新格式化你的代码。\n" -"在大多多人合作项目里,每个成员都会使用`cairo-format`以防止在编写Cairo时争论使用哪种代码风格。" +#~ msgid "Listing 8-1: A test module and function" +#~ msgstr "示例8-1:一个测试模块和函数" -#: src/appendix-04-useful-development-tools.md:13 -msgid "To format any Cairo project, enter the following:" -msgstr "要格式化任何Cairo项目,请输入以下命令:" +#~ msgid "Listing 8-2: The output from running a test" +#~ msgstr "示例8-2:运行一个测试的输出结果" -#: src/appendix-04-useful-development-tools.md:15 -msgid "" -"```console\n" -"cairo-format -r\n" -"```" -msgstr "" -"```console\n" -"cairo-format -r\n" -"```" +#~ msgid "" +#~ "```rust\n" +#~ "trait RectangleTrait {\n" +#~ " fn area(self: @Rectangle) -> u64;\n" +#~ " fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" +#~ "}\n" +#~ "\n" +#~ "impl RectangleImpl of RectangleTrait {\n" +#~ " fn area(self: @Rectangle) -> u64 {\n" +#~ " *self.width * *self.height\n" +#~ " }\n" +#~ " fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +#~ " *self.width > *other.width & *self.height > *other.height\n" +#~ " }\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "trait RectangleTrait {\n" +#~ " fn area(self: @Rectangle) -> u64;\n" +#~ " fn can_hold(self: @Rectangle, other: @Rectangle) -> bool;\n" +#~ "}\n" +#~ "\n" +#~ "impl RectangleImpl of RectangleTrait {\n" +#~ " fn area(self: @Rectangle) -> u64 {\n" +#~ " *self.width * *self.height\n" +#~ " }\n" +#~ " fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +#~ " *self.width > *other.width & *self.height > *other.height\n" +#~ " }\n" +#~ "}\n" +#~ "```" -#: src/appendix-04-useful-development-tools.md:19 -msgid "" -"Running this command reformats all the Cairo code in the current directory, recursively. This\n" -"should only change the code style, not the code semantics." -msgstr "" -"运行这条命令可以递归式的重新格式化当前目录下的所有Cairo代码。这条命令\n" -"只会改变代码的风格,而不会改变代码的语义。" +#~ msgid "" +#~ "```rust\n" +#~ "#[cfg(test)]\n" +#~ "mod tests {\n" +#~ " use super::Rectangle;\n" +#~ " use super::RectangleTrait;\n" +#~ "\n" +#~ " #[test]\n" +#~ " fn larger_can_hold_smaller() {\n" +#~ " let larger = Rectangle {\n" +#~ " height: 7,\n" +#~ " width: 8,\n" +#~ " };\n" +#~ " let smaller = Rectangle {\n" +#~ " height: 1,\n" +#~ " width: 5,\n" +#~ " };\n" +#~ "\n" +#~ " assert(larger.can_hold(@smaller), 'rectangle cannot hold');\n" +#~ " }\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "#[cfg(test)]\n" +#~ "mod tests {\n" +#~ " use super::Rectangle;\n" +#~ " use super::RectangleTrait;\n" +#~ "\n" +#~ " #[test]\n" +#~ " fn larger_can_hold_smaller() {\n" +#~ " let larger = Rectangle {\n" +#~ " height: 7,\n" +#~ " width: 8,\n" +#~ " };\n" +#~ " let smaller = Rectangle {\n" +#~ " height: 1,\n" +#~ " width: 5,\n" +#~ " };\n" +#~ "\n" +#~ " assert(larger.can_hold(@smaller), 'rectangle cannot hold');\n" +#~ " }\n" +#~ "}\n" +#~ "```" -#: src/appendix-04-useful-development-tools.md:22 -msgid "### IDE Integration Using `cairo-language-server`" -msgstr "### 使用`cairo-language-server`的IDE集成" +#~ msgid "" +#~ "```rust\n" +#~ "#[cfg(test)]\n" +#~ "mod tests {\n" +#~ " use super::Rectangle;\n" +#~ " use super::RectangleTrait;\n" +#~ "\n" +#~ " #[test]\n" +#~ " fn larger_can_hold_smaller() {\n" +#~ " // --snip--\n" +#~ " }\n" +#~ "\n" +#~ " #[test]\n" +#~ " fn smaller_cannot_hold_larger() {\n" +#~ " let larger = Rectangle {\n" +#~ " height: 7,\n" +#~ " width: 8,\n" +#~ " };\n" +#~ " let smaller = Rectangle {\n" +#~ " height: 1,\n" +#~ " width: 5,\n" +#~ " };\n" +#~ "\n" +#~ " assert(!smaller.can_hold(@larger), 'rectangle cannot hold');\n" +#~ " }\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "#[cfg(test)]\n" +#~ "mod tests {\n" +#~ " use super::Rectangle;\n" +#~ " use super::RectangleTrait;\n" +#~ "\n" +#~ " #[test]\n" +#~ " fn larger_can_hold_smaller() {\n" +#~ " // --snip--\n" +#~ " }\n" +#~ "\n" +#~ " #[test]\n" +#~ " fn smaller_cannot_hold_larger() {\n" +#~ " let larger = Rectangle {\n" +#~ " height: 7,\n" +#~ " width: 8,\n" +#~ " };\n" +#~ " let smaller = Rectangle {\n" +#~ " height: 1,\n" +#~ " width: 5,\n" +#~ " };\n" +#~ "\n" +#~ " assert(!smaller.can_hold(@larger), 'rectangle cannot hold');\n" +#~ " }\n" +#~ "}\n" +#~ "```" -#: src/appendix-04-useful-development-tools.md:24 -msgid "" -"To help IDE integration, the Cairo community recommends using the\n" -"[`cairo-language-server`][cairo-language-server]. This tool is a set of\n" -"compiler-centric utilities that speaks the [Language Server Protocol][lsp], which is a specification for IDEs and programming languages to\n" -"communicate with each other. Different clients can use `cairo-language-server`, such as\n" -"[the Cairo extension for Visual Studio Code][vscode-cairo]." -msgstr "" -"为了帮助IDE整合,Cairo社区建议使用\n" -"[`cairo-language-server`][cairo-language-server]。这是\n" -"[Language Server Protocol][lsp]的一套以编译器为中心的实用工具。\n" -"它是用于IDE和编程语言互相通信的规范。不同的客户端都可以使用`cairo-language-server`,例如\n" -"[Visual Studio Code的Cairo扩展][vscode-cairo]。" +#~ msgid "" +#~ "```rust\n" +#~ "// --snip--\n" +#~ "impl RectangleImpl of RectangleTrait {\n" +#~ " fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +#~ " *self.width < *other.width & *self.height > *other.height\n" +#~ " }\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "// —snip—\n" +#~ "impl RectangleImpl of RectangleTrait {\n" +#~ " fn can_hold(self: @Rectangle, other: @Rectangle) -> bool {\n" +#~ " *self.width < *other.width & *self.height > *other.height\n" +#~ " }\n" +#~ "}\n" +#~ "```" -#: src/appendix-04-useful-development-tools.md:34 -msgid "" -"Visit the `vscode-cairo` [page][vscode-cairo]\n" -"for installation instructions, You will gain abilities such as autocompletion, jump to\n" -"definition, and inline errors." -msgstr "" -"请访问 `vscode-cairo` [页面][vscode-cairo] \n" -"获取安装说明,你将得到自动完成、跳转到定义,以及内联错误等功能。" +#~ msgid "" +#~ "```rust\n" +#~ "// --snip--\n" +#~ "impl GuessImpl of GuessTrait {\n" +#~ " fn new(value: u64) -> Guess {\n" +#~ " if value < 1{\n" +#~ " let mut data = ArrayTrait::new();\n" +#~ " data.append('Guess must be >= 1 and <= 100');\n" +#~ " panic(data);\n" +#~ " }\n" +#~ "\n" +#~ " Guess { value, }\n" +#~ " }\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "// --snip--\n" +#~ "impl GuessImpl of GuessTrait {\n" +#~ " fn new(value: u64) -> Guess {\n" +#~ " if value < 1{\n" +#~ " let mut data = ArrayTrait::new();\n" +#~ " data.append('Guess must be >= 1 and <= 100');\n" +#~ " panic(data);\n" +#~ " }\n" +#~ "\n" +#~ " Guess { value, }\n" +#~ " }\n" +#~ "}\n" +#~ "```" -#: src/appendix-05-most-common-types-and-traits.md:1 -msgid "## Appendix E - Most Common Types and Traits Required To Write Contracts" -msgstr "## 附录 E - 编写合约所需最常见的类型 和Trait" +#~ msgid "" +#~ "```rust\n" +#~ "if value < 1{\n" +#~ " let mut data = ArrayTrait::new();\n" +#~ " data.append('Guess must be <= 100');\n" +#~ " panic(data);\n" +#~ "} else if value > 100{\n" +#~ " let mut data = ArrayTrait::new();\n" +#~ " data.append('Guess must be >= 1');\n" +#~ " panic(data);\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "if value < 1{\n" +#~ " let mut data = ArrayTrait::new();\n" +#~ " data.append('Guess must be <= 100');\n" +#~ " panic(data);\n" +#~ "} else if value > 100{\n" +#~ " let mut data = ArrayTrait::new();\n" +#~ " data.append('Guess must be >= 1');\n" +#~ " panic(data);\n" +#~ "}\n" +#~ "```" -#: src/appendix-05-most-common-types-and-traits.md:3 -msgid "This appendix provides a reference for common types and traits used in contract development, along with their corresponding imports, paths, and usage examples." -msgstr "本附录提供了合约开发中使用的常见类型和trait的参考,以及相应的导入方法、路径和使用方法的范例。" +#~ msgid "" +#~ "```rust\n" +#~ "#[test]\n" +#~ "fn test_function_2() {\n" +#~ " let number: felt252 = 258_felt252;\n" +#~ " match do_something_with_parse_u8(number) {\n" +#~ " Result::Ok(value) => value.print(),\n" +#~ " Result::Err(e) => e.print()\n" +#~ " }\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "#[test]\n" +#~ "fn test_function_2() {\n" +#~ " let number: felt252 = 258_felt252;\n" +#~ " match do_something_with_parse_u8(number) {\n" +#~ " Result::Ok(value) => value.print(),\n" +#~ " Result::Err(e) => e.print()\n" +#~ " }\n" +#~ "}\n" +#~ "```" -#: src/appendix-05-most-common-types-and-traits.md:5 -msgid "" -"| Import | Path | " -"Usage " -"|\n" -"| ------------------------- | ----------------------------------------------------- | " -"-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- " -"|\n" -"| `OptionTrait` | `std::option::OptionTrait` | `OptionTrait` defines a set of methods required to manipulate optional " -"value. |\n" -"| `ResultTrait` | `std::result::ResultTrait` | `ResultTrait` Type for Starknet contract address, a value in the range [0, 2 \\*\\* " -"251). |\n" -"| `ContractAddress` | `starknet::ContractAddress` | `ContractAddress` is a type to represent the smart contract " -"address |\n" -"| `ContractAddressZeroable` | `starknet::contract_address::ContractAddressZeroable` | `ContractAddressZeroable` is the implementation of the trait `Zeroable` for the " -"`ContractAddress` type. It is required to check whether a value of `t:ContractAddress` is zero or not. |\n" -"| `contract_address_const` | `starknet::contract_address_const` | The `contract_address_const!` it's a function that allows instantiating constant contract " -"address values. |\n" -"| `Into` | `traits::Into;` | `Into` is a trait used for conversion between types. If there is an implementation of Into for the types T and S, you can convert T into S. |\n" -"| `TryInto` | `traits::TryInto;` | `TryInto` is a trait used for conversion between types.If there is an implementation of " -"TryInto for the types T and S, you can convert T into S. |\n" -"| `get_caller_address` | `starknet::get_caller_address` | `get_caller_address()` is a function that returns the address of the caller of the contract. It " -"can be used to identify the caller of a contract function. |\n" -"| `get_contract_address` | `starknet::info::get_contract_address` | `get_contract_address()` is a function that returns the address of the current contract. It can " -"be used to obtain the address of the contract being executed. |" -msgstr "" -"| Import | Path | " -"Usage " -"|\n" -"| ------------------------- | ----------------------------------------------------- | " -"-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- " -"|\n" -"| `OptionTrait` | `std::option::OptionTrait` | `OptionTrait` defines a set of methods required to manipulate optional " -"value. |\n" -"| `ResultTrait` | `std::result::ResultTrait` | `ResultTrait` Type for Starknet contract address, a value in the range [0, 2 \\*\\* " -"251). |\n" -"| `ContractAddress` | `starknet::ContractAddress` | `ContractAddress` is a type to represent the smart contract " -"address |\n" -"| `ContractAddressZeroable` | `starknet::contract_address::ContractAddressZeroable` | `ContractAddressZeroable` is the implementation of the trait `Zeroable` for the " -"`ContractAddress` type. It is required to check whether a value of `t:ContractAddress` is zero or not. |\n" -"| `contract_address_const` | `starknet::contract_address_const` | The `contract_address_const!` it's a function that allows instantiating constant contract " -"address values. |\n" -"| `Into` | `traits::Into;` | `Into` is a trait used for conversion between types. If there is an implementation of Into for the types T and S, you can convert T into S. |\n" -"| `TryInto` | `traits::TryInto;` | `TryInto` is a trait used for conversion between types.If there is an implementation of " -"TryInto for the types T and S, you can convert T into S. |\n" -"| `get_caller_address` | `starknet::get_caller_address` | `get_caller_address()` is a function that returns the address of the caller of the contract. It " -"can be used to identify the caller of a contract function. |\n" -"| `get_contract_address` | `starknet::info::get_contract_address` | `get_contract_address()` is a function that returns the address of the current contract. It can " -"be used to obtain the address of the contract being executed. |" +#~ msgid "Starknet contracts are denoted by the `#[contract]` attribute. We'll dive deeper into this in the next sections." +#~ msgstr "Starknet合约是由`#[contract]`属性表示的。我们将在接下来的章节中更深入地探讨这个问题。" -#: src/appendix-05-most-common-types-and-traits.md:17 -msgid "" -"This is not an exhaustive list, but it covers some of the commonly used types and traits in contract development. For more details, refer to the official documentation and explore " -"the available libraries and frameworks." -msgstr "这并不是一个详尽的列表,但它涵盖了合约开发中一些常用的类型和trait。关于更多的细节,请参考官方文档并参考可用的库以及框架。" +#~ msgid "" +#~ "```rust\n" +#~ "//**** Specify interface here ****//\n" +#~ "\n" +#~ "#[contract]\n" +#~ "mod dispatcher {\n" +#~ " use super::IERC20DispatcherTrait;\n" +#~ " use super::IERC20Dispatcher;\n" +#~ " use starknet::ContractAddress;\n" +#~ "\n" +#~ " #[view]\n" +#~ " fn token_name(\n" +#~ " _contract_address: ContractAddress\n" +#~ " ) -> felt252 {\n" +#~ " IERC20Dispatcher {contract_address: _contract_address }.name()\n" +#~ " }\n" +#~ "\n" +#~ " #[external]\n" +#~ " fn transfer_token(\n" +#~ " _contract_address: ContractAddress, recipient: ContractAddress, amount: u256\n" +#~ " ) -> bool {\n" +#~ " IERC20Dispatcher {contract_address: _contract_address }.transfer(recipient, amount)\n" +#~ " }\n" +#~ "}\n" +#~ "```" +#~ msgstr "" +#~ "```rust\n" +#~ "//**** Specify interface here ****//\n" +#~ "\n" +#~ "#[contract]\n" +#~ "mod dispatcher {\n" +#~ " use super::IERC20DispatcherTrait;\n" +#~ " use super::IERC20Dispatcher;\n" +#~ " use starknet::ContractAddress;\n" +#~ "\n" +#~ " #[view]\n" +#~ " fn token_name(\n" +#~ " _contract_address: ContractAddress\n" +#~ " ) -> felt252 {\n" +#~ " IERC20Dispatcher {contract_address: _contract_address }.name()\n" +#~ " }\n" +#~ "\n" +#~ " #[external]\n" +#~ " fn transfer_token(\n" +#~ " _contract_address: ContractAddress, recipient: ContractAddress, amount: u256\n" +#~ " ) -> bool {\n" +#~ " IERC20Dispatcher {contract_address: _contract_address }.transfer(recipient, amount)\n" +#~ " }\n" +#~ "}\n" +#~ "```" + +#~ msgid "Listing 99-4: An expanded form of the IERC20 trait" +#~ msgstr "示例99-4:IERC20trait的扩展形式" #~ msgid "" #~ "```rust\n" @@ -14517,7 +20400,7 @@ msgstr "这并不是一个详尽的列表,但它涵盖了合约开发中一些 #~ " let mut i: usize = 0;\n" #~ " loop {\n" #~ " if i > 10 {\n" -#~ " break ();\n" +#~ " break;\n" #~ " }\n" #~ " 'again!'.print();\n" #~ " }\n" @@ -14530,28 +20413,13 @@ msgstr "这并不是一个详尽的列表,但它涵盖了合约开发中一些 #~ " let mut i: usize = 0;\n" #~ " loop {\n" #~ " if i > 10 {\n" -#~ " break ();\n" +#~ " break;\n" #~ " }\n" #~ " 'again!'.print();\n" #~ " }\n" #~ "}\n" #~ "```" -#~ msgid "" -#~ "```rust\n" -#~ " let mut a = ArrayTrait::new();\n" -#~ " a.append(10);\n" -#~ " a.append(1);\n" -#~ " a.append(2);\n" -#~ "```" -#~ msgstr "" -#~ "```rust\n" -#~ " let mut a = ArrayTrait::new();\n" -#~ " a.append(10);\n" -#~ " a.append(1);\n" -#~ " a.append(2);\n" -#~ "```" - #~ msgid "" #~ "```rust\n" #~ "let span = array.span();\n" @@ -14684,6 +20552,3 @@ msgstr "这并不是一个详尽的列表,但它涵盖了合约开发中一些 #~ " None,\n" #~ "}\n" #~ "```" - -#~ msgid "# Contract Development Appendix" -#~ msgstr "# 合约开发附录" diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 8f131546f..20caf9ee7 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -10,7 +10,6 @@ - [Installation](ch01-01-installation.md) - [Hello, World!](ch01-02-hello-world.md) - - [Hello, Scarb!](ch01-03-hello-scarb.md) ## Common Programming Concepts @@ -20,7 +19,12 @@ - [Functions](ch02-03-functions.md) - [Comments](ch02-04-comments.md) - [Control Flow](ch02-05-control-flow.md) - - [Common Collections](ch02-06-common-collections.md) + +## Common Collections + +- [Common Collections](ch02-99-00-common-collections.md) + - [Arrays](ch02-99-01-arrays.md) + - [Dictionaries](ch02-99-02-dictionaries.md) ## Understanding Ownership @@ -70,22 +74,33 @@ - [Error Handling](ch09-00-error-handling.md) - [Unrecoverable Errors with panic](ch09-01-unrecoverable-errors-with-panic.md) - - [Recoverable Errors with Result](ch09-02-error-handling.md) + - [Recoverable Errors with Result](ch09-02-recoverable-errors.md) ## Advanced Features - [Advanced Features](ch10-00-advanced-features.md) - [Operator Overloading](ch10-01-operator-overloading.md) + - [Macros](ch10-02-macros.md) ## Starknet smart contracts - [Starknet Smart Contracts](./ch99-00-starknet-smart-contracts.md) - [Introduction to smart-contracts](./ch99-01-01-introduction-to-smart-contracts.md) - - [Writing Starknet Contracts](./ch99-01-02-writing-starknet-contracts.md) + - [A simple contract](./ch99-01-02-a-simple-contract.md) + - [A deeper dive into contracts](./ch99-01-03-00-a-deeper-dive-into-contracts.md) + - [Storage Variables](./ch99-01-03-01-storage-variables.md) + - [Contract Functions](./ch99-01-03-02-contract-functions.md) + - [Contract Events](./ch99-01-03-03-contract-events.md) + - [Reducing boilerplate](./ch99-01-03-04-reducing-boilerplate.md) + - [Optimizing storage costs](./ch99-01-03-05-optimizing-storage.md) - [ABIs and Cross-contract Interactions](./ch99-02-00-abis-and-cross-contract-interactions.md) - [ABIs and Interfaces](./ch99-02-01-abis-and-interfaces.md) - [Contract Dispatchers, Library Dispachers and system calls](./ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md) + - [Other examples](./ch99-01-04-00-other-examples.md) + - [Deploying and Interacting with a Voting contract](./ch99-01-04-01-voting-contract.md) + - [L1 <> L2 Messaging](./ch99-04-00-L1-L2-messaging.md) + - [Security Considerations](./ch99-03-security-considerations.md) - [Appendix](appendix-00.md) - [A - Keywords](appendix-01-keywords.md) @@ -93,3 +108,4 @@ - [C - Derivable Traits](appendix-03-derivable-traits.md) - [D - Useful Development Tools](appendix-04-useful-development-tools.md) - [E - Cairo Most Common Types and Traits](appendix-05-most-common-types-and-traits.md) + - [F - Installing Cairo binaries](appendix-06-cairo-binaries.md) diff --git a/src/appendix-01-keywords.md b/src/appendix-01-keywords.md index b8937f0f7..f3f0faeae 100644 --- a/src/appendix-01-keywords.md +++ b/src/appendix-01-keywords.md @@ -36,8 +36,8 @@ They cannot be used as names of any items. - `mod` - Define a module - `mut` - Denote variable mutability - `nopanic` - Functions marked with this notation mean that the function will never panic. -- `of` - Implement a trait -- `ref` - Bind by reference +- `of` - Implementation a trait +- `ref` - Parameter passed implicitly returned at the end of a function - `return` - Return from function - `struct` - Define a structure - `trait` - Define a trait @@ -54,13 +54,18 @@ They have the same restrictions as strict keywords. The reasoning behind this is to make current programs forward compatible with future versions of Cairo by forbidding them to use these keywords. +- `Self` +- `assert` - `do` - `dyn` +- `for` +- `hint` +- `in` - `macro` - `move` -- `Self` -- `self` +- `pub` - `static_assert` +- `self` - `static` - `super` - `try` diff --git a/src/appendix-02-operators-and-symbols.md b/src/appendix-02-operators-and-symbols.md index 8b2b687b9..c7dca4962 100644 --- a/src/appendix-02-operators-and-symbols.md +++ b/src/appendix-02-operators-and-symbols.md @@ -15,6 +15,7 @@ Table B-1 contains the operators in Cairo, an example of how the operator would | `%` | `expr % expr` | Arithmetic remainder | `Rem` | | `%=` | `var %= expr` | Arithmetic remainder and assignment | `RemEq` | | `&` | `expr & expr` | Bitwise AND | `BitAnd` | +| `&&` | `expr && expr` | Short-circuiting logical AND | | | `*` | `expr * expr` | Arithmetic multiplication | `Mul` | | `*=` | `var *= expr` | Arithmetic multiplication and assignment | `MulEq` | | `@` | `@var` | Snapshot | | @@ -41,6 +42,7 @@ Table B-1 contains the operators in Cairo, an example of how the operator would | `>=` | `expr >= expr` | Greater than or equal to comparison | `PartialOrd` | | `^` | `expr ^ expr` | Bitwise exclusive OR | `BitXor` | | | | expr | expr | Bitwise OR | `BitOr` | +| || | expr || expr | Short-circuiting logical OR | | ## Non Operator Symbols @@ -117,4 +119,4 @@ Table B-8 shows the contexts in which curly braces are used. | Context | Explanation | |---------|-------------| | `{...}` | Block expression | -| `Type {...}` | `struct` literal | \ No newline at end of file +| `Type {...}` | `struct` literal | diff --git a/src/appendix-03-derivable-traits.md b/src/appendix-03-derivable-traits.md index ad385534b..5f13ece10 100644 --- a/src/appendix-03-derivable-traits.md +++ b/src/appendix-03-derivable-traits.md @@ -16,7 +16,7 @@ When `PartialEq` is derived on structs, two instances are equal only if all fiel Example: -```Rust +```rust #[derive(PartialEq, Drop)] struct A { item: felt252 @@ -41,7 +41,7 @@ Deriving `Clone` implements the `clone` method, which, in turn, calls clone on e Example: -```Rust +```rust use clone::Clone; #[derive(Clone, Drop)] @@ -62,7 +62,7 @@ The `Copy` trait allows for the duplication of values. You can derive `Copy` on Example: -```Rust +```rust #[derive(Copy, Drop)] struct A { item: felt252 @@ -84,7 +84,7 @@ fn main() { Example: -```Rust +```rust use serde::Serde; use array::ArrayTrait; @@ -117,7 +117,7 @@ Also, we can use `deserialize` function to convert the serialized array back int Example: -```Rust +```rust use serde::Serde; use array::ArrayTrait; use option::OptionTrait; @@ -148,6 +148,36 @@ When moving out of scope, variables need to be moved first. This is where the `D 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](ch03-01-what-is-ownership.md#the-destruct-trait). +## 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. + +Example: + +```rust, noplayground +#[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 -TODO (Not derivable yet ?) \ No newline at end of file +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. diff --git a/src/appendix-04-useful-development-tools.md b/src/appendix-04-useful-development-tools.md index 940520345..b0a7bebd9 100644 --- a/src/appendix-04-useful-development-tools.md +++ b/src/appendix-04-useful-development-tools.md @@ -4,21 +4,15 @@ In this appendix, we talk about some useful development tools that the Cairo project provides. We’ll look at automatic formatting, quick ways to apply warning fixes, a linter, and integrating with IDEs. -### Automatic Formatting with `cairo-format` +### Automatic Formatting with `scarb fmt` -The `cairo-format` tool reformats your code according to the community code style. -Many collaborative projects use `cairo-format` to prevent arguments about which +Scarb projects can be formatted using the `scarb fmt` command. +If you're using the cairo binaries directly, you can run `cairo-format` instead. +Many collaborative projects use `scarb fmt` to prevent arguments about which style to use when writing Cairo: everyone formats their code using the tool. To format any Cairo project, enter the following: -```console -cairo-format -r -``` - -Running this command reformats all the Cairo code in the current directory, recursively. This -should only change the code style, not the code semantics. - ### IDE Integration Using `cairo-language-server` To help IDE integration, the Cairo community recommends using the @@ -29,10 +23,12 @@ communicate with each other. Different clients can use `cairo-language-server`, [the Cairo extension for Visual Studio Code][vscode-cairo]. [lsp]: http://langserver.org/ -[vscode-cairo]: https://github.com/starkware-libs/cairo/tree/main/vscode-cairo +[vscode-cairo]: https://marketplace.visualstudio.com/items?itemName=starkware.cairo1 Visit the `vscode-cairo` [page][vscode-cairo] -for installation instructions, You will gain abilities such as autocompletion, jump to +to install it on VSCode. You will get abilities such as autocompletion, jump to definition, and inline errors. [cairo-language-server]: https://github.com/starkware-libs/cairo/tree/main/crates/cairo-lang-language-server + +> Note: If you have Scarb installed, it should work out of the box with the Cairo VSCode extension, without a manual installation of the language server. diff --git a/src/appendix-06-cairo-binaries.md b/src/appendix-06-cairo-binaries.md new file mode 100644 index 000000000..69327ebb0 --- /dev/null +++ b/src/appendix-06-cairo-binaries.md @@ -0,0 +1,203 @@ +# Appendix F: Installing the Cairo binaries + +If you want to have access to the Cairo binaries, for anything that you could not achieve by purely using Scarb you can install them by following the instructions below. + +The first step is to install Cairo. We will download Cairo manually, using cairo repository or with an installation script. You’ll need an internet connection for the download. + +### Prerequisites + +First you will need to have Rust and Git installed. + +```bash +# Install stable Rust +rustup override set stable && rustup update +``` + +Install [Git](https://git-scm.com/). + +## Installing Cairo with a Script ([Installer](https://github.com/franalgaba/cairo-installer) by [Fran](https://github.com/franalgaba)) + +### Install + +If you wish to install a specific release of Cairo rather than the latest head, set the `CAIRO_GIT_TAG` environment variable (e.g. `export CAIRO_GIT_TAG=v2.2.0`). + +```bash +curl -L https://github.com/franalgaba/cairo-installer/raw/main/bin/cairo-installer | bash +``` + +After installing, follow [these instructions](#set-up-your-shell-environment-for-cairo) to set up your shell environment. + +### Update + +``` +rm -fr ~/.cairo +curl -L https://github.com/franalgaba/cairo-installer/raw/main/bin/cairo-installer | bash +``` + +### Uninstall + +Cairo is installed within `$CAIRO_ROOT` (default: ~/.cairo). To uninstall, just remove it: + +```bash +rm -fr ~/.cairo +``` + +then remove these three lines from .bashrc: + +```bash +export PATH="$HOME/.cairo/target/release:$PATH" +``` + +and finally, restart your shell: + +```bash +exec $SHELL +``` + +### Set up your shell environment for Cairo + +- Define environment variable `CAIRO_ROOT` to point to the path where + Cairo will store its data. `$HOME/.cairo` is the default. + If you installed Cairo via Git checkout, we recommend + to set it to the same location as where you cloned it. +- Add the `cairo-*` executables to your `PATH` if it's not already there + +The below setup should work for the vast majority of users for common use cases. + +- For **bash**: + + Stock Bash startup files vary widely between distributions in which of them source + which, under what circumstances, in what order and what additional configuration they perform. + As such, the most reliable way to get Cairo in all environments is to append Cairo + configuration commands to both `.bashrc` (for interactive shells) + and the profile file that Bash would use (for login shells). + + First, add the commands to `~/.bashrc` by running the following in your terminal: + + ```bash + echo 'export CAIRO_ROOT="$HOME/.cairo"' >> ~/.bashrc + echo 'command -v cairo-compile >/dev/null || export PATH="$CAIRO_ROOT/target/release:$PATH"' >> ~/.bashrc + ``` + + Then, if you have `~/.profile`, `~/.bash_profile` or `~/.bash_login`, add the commands there as well. + If you have none of these, add them to `~/.profile`. + + - to add to `~/.profile`: + + ```bash + echo 'export CAIRO_ROOT="$HOME/.cairo"' >> ~/.profile + echo 'command -v cairo-compile >/dev/null || export PATH="$CAIRO_ROOT/target/release:$PATH"' >> ~/.profile + ``` + + - to add to `~/.bash_profile`: + ```bash + echo 'export CAIRO_ROOT="$HOME/.cairo"' >> ~/.bash_profile + echo 'command -v cairo-compile >/dev/null || export PATH="$CAIRO_ROOT/target/release:$PATH"' >> ~/.bash_profile + ``` + +- For **Zsh**: + + ```zsh + echo 'export CAIRO_ROOT="$HOME/.cairo"' >> ~/.zshrc + echo 'command -v cairo-compile >/dev/null || export PATH="$CAIRO_ROOT/target/release:$PATH"' >> ~/.zshrc + ``` + + If you wish to get Cairo in non-interactive login shells as well, also add the commands to `~/.zprofile` or `~/.zlogin`. + +- For **Fish shell**: + + If you have Fish 3.2.0 or newer, execute this interactively: + + ```fish + set -Ux CAIRO_ROOT $HOME/.cairo + fish_add_path $CAIRO_ROOT/target/release + ``` + + Otherwise, execute the snippet below: + + ```fish + set -Ux CAIRO_ROOT $HOME/.cairo + set -U fish_user_paths $CAIRO_ROOT/target/release $fish_user_paths + ``` + +In MacOS, you might also want to install [Fig](https://fig.io/) which +provides alternative shell completions for many command line tools with an +IDE-like popup interface in the terminal window. +(Note that their completions are independent from Cairo's codebase +so they might be slightly out of sync for bleeding-edge interface changes.) + +### Restart your shell + +for the `PATH` changes to take effect. + +```sh +exec "$SHELL" +``` + +## Installing Cairo Manually ([Guide](https://github.com/auditless/cairo-template) by [Abdel](https://github.com/abdelhamidbakhta)) + +### Step 1: Install Cairo 1.0 + +If you are using an x86 Linux system and can use the release binary, download Cairo here: . + +For everyone else, we recommend compiling Cairo from source as follows: + +```bash +# Start by defining environment variable CAIRO_ROOT +export CAIRO_ROOT="${HOME}/.cairo" + +# Create .cairo folder if it doesn't exist yet +mkdir $CAIRO_ROOT + +# Clone the Cairo compiler in $CAIRO_ROOT (default root) +cd $CAIRO_ROOT && git clone git@github.com:starkware-libs/cairo.git . + +# OPTIONAL/RECOMMENDED: If you want to install a specific version of the compiler +# Fetch all tags (versions) +git fetch --all --tags +# View tags (you can also do this in the cairo compiler repository) +git describe --tags `git rev-list --tags` +# Checkout the version you want +git checkout tags/v2.2.0 + +# Generate release binaries +cargo build --all --release +``` + +. + +**NOTE: Keeping Cairo up to date** + +Now that your Cairo compiler is in a cloned repository, all you will need to do +is pull the latest changes and rebuild as follows: + +```bash +cd $CAIRO_ROOT && git fetch && git pull && cargo build --all --release +``` + +### Step 2: Add Cairo 1.0 executables to your path + +```bash +export PATH="$CAIRO_ROOT/target/release:$PATH" +``` + +**NOTE: If installing from a Linux binary, adapt the destination path accordingly.** + +### Step 3: Setup Language Server + +#### VS Code Extension + +- If you have the previous Cairo 0 extension installed, you can disable/uninstall it. +- Install the Cairo 1 extension for proper syntax highlighting and code navigation. You can find the link to the extension [here](https://marketplace.visualstudio.com/items?itemName=starkware.cairo1&ssr=false), or just search for "Cairo 1.0" in the VS Code marketplace. +- The extension will work out of the box once you will have [Scarb](./ch01-03-hello-scarb.md) installed. + +#### Cairo Language Server without Scarb + +If you don't want to depend on Scarb, you can still use the Cairo Language Server with the compiler binary. +From [Step 1](#installing-cairo-with-a-script-installer-by-fran), the `cairo-language-server` binary should be built and executing this command will copy its path into your clipboard. + +```bash +which cairo-language-server | pbcopy +``` + +Update the `cairo1.languageServerPath` of the Cairo 1.0 extension by pasting the path. diff --git a/src/ch01-00-getting-started.md b/src/ch01-00-getting-started.md index e69de29bb..bad55622f 100644 --- a/src/ch01-00-getting-started.md +++ b/src/ch01-00-getting-started.md @@ -0,0 +1 @@ +# Getting Started diff --git a/src/ch01-01-installation.md b/src/ch01-01-installation.md index 314dece13..cf67670c6 100644 --- a/src/ch01-01-installation.md +++ b/src/ch01-01-installation.md @@ -1,200 +1,35 @@ # Installation -The first step is to install Cairo. We will download Cairo manually, using cairo repository or with an installation script. You’ll need an internet connection for the download. +Cairo can be installed by simply downloading [Scarb](https://docs.swmansion.com/scarb/docs). Scarb bundles the Cairo compiler and the Cairo language server together in an easy-to-install package so that you can start writing Cairo code right away. -### Prerequisites +Scarb is also Cairo's package manager and is heavily inspired by [Cargo](https://doc.rust-lang.org/cargo/), Rust’s build system and package manager. -First you will need to have Rust and Git installed. +Scarb handles a lot of tasks for you, such as building your code (either pure Cairo or Starknet contracts), downloading the libraries your code depends on, building those libraries, and provides LSP support for the VSCode Cairo 1 extension. -```bash -# Install stable Rust -rustup override set stable && rustup update -``` - -Install [Git](https://git-scm.com/). - -## Installing Cairo with a Script ([Installer](https://github.com/franalgaba/cairo-installer) by [Fran](https://github.com/franalgaba)) - -### Install +As you write more complex Cairo programs, you might add dependencies, and if you start a project using Scarb, managing external code and dependencies will be a lot easier to do. -If you wish to install a specific release of Cairo rather than the latest head, set the `CAIRO_GIT_TAG` environment variable (e.g. `export CAIRO_GIT_TAG=v1.1.0`). +Let's start by installing Scarb. -```bash -curl -L https://github.com/franalgaba/cairo-installer/raw/main/bin/cairo-installer | bash -``` - -After installing, follow [these instructions](#set-up-your-shell-environment-for-cairo) to set up your shell environment. +## Installing Scarb -### Update +### Requirements -``` -rm -fr ~/.cairo -curl -L https://github.com/franalgaba/cairo-installer/raw/main/bin/cairo-installer | bash -``` +Scarb requires a Git executable to be available in the `PATH` environment variable. -### Uninstall +### Installation -Cairo is installed within `$CAIRO_ROOT` (default: ~/.cairo). To uninstall, just remove it: +To install Scarb, please refer to the [installation instructions](https://docs.swmansion.com/scarb/download). +You can simply run the following command in your terminal, then follow the onscreen instructions. This will install the latest stable release. ```bash -rm -fr ~/.cairo +curl --proto '=https' --tlsv1.2 -sSf https://docs.swmansion.com/scarb/install.sh | sh ``` -then remove these three lines from .bashrc: - -```bash -export PATH="$HOME/.cairo/target/release:$PATH" -``` - -and finally, restart your shell: - -```bash -exec $SHELL -``` - -### Set up your shell environment for Cairo - -- Define environment variable `CAIRO_ROOT` to point to the path where - Cairo will store its data. `$HOME/.cairo` is the default. - If you installed Cairo via Git checkout, we recommend - to set it to the same location as where you cloned it. -- Add the `cairo-*` executables to your `PATH` if it's not already there - -The below setup should work for the vast majority of users for common use cases. - -- For **bash**: - - Stock Bash startup files vary widely between distributions in which of them source - which, under what circumstances, in what order and what additional configuration they perform. - As such, the most reliable way to get Cairo in all environments is to append Cairo - configuration commands to both `.bashrc` (for interactive shells) - and the profile file that Bash would use (for login shells). - - First, add the commands to `~/.bashrc` by running the following in your terminal: +- Verify installation by running the following command in new terminal session, it should print both Scarb and Cairo language versions, e.g: ```bash - echo 'export CAIRO_ROOT="$HOME/.cairo"' >> ~/.bashrc - echo 'command -v cairo-compile >/dev/null || export PATH="$CAIRO_ROOT/target/release:$PATH"' >> ~/.bashrc - ``` - - Then, if you have `~/.profile`, `~/.bash_profile` or `~/.bash_login`, add the commands there as well. - If you have none of these, add them to `~/.profile`. - - - to add to `~/.profile`: - - ```bash - echo 'export CAIRO_ROOT="$HOME/.cairo"' >> ~/.profile - echo 'command -v cairo-compile >/dev/null || export PATH="$CAIRO_ROOT/target/release:$PATH"' >> ~/.profile - ``` - - - to add to `~/.bash_profile`: - ```bash - echo 'export CAIRO_ROOT="$HOME/.cairo"' >> ~/.bash_profile - echo 'command -v cairo-compile >/dev/null || export PATH="$CAIRO_ROOT/target/release:$PATH"' >> ~/.bash_profile - ``` - -- For **Zsh**: - - ```zsh - echo 'export CAIRO_ROOT="$HOME/.cairo"' >> ~/.zshrc - echo 'command -v cairo-compile >/dev/null || export PATH="$CAIRO_ROOT/target/release:$PATH"' >> ~/.zshrc - ``` - - If you wish to get Cairo in non-interactive login shells as well, also add the commands to `~/.zprofile` or `~/.zlogin`. - -- For **Fish shell**: - - If you have Fish 3.2.0 or newer, execute this interactively: - - ```fish - set -Ux CAIRO_ROOT $HOME/.cairo - fish_add_path $CAIRO_ROOT/target/release - ``` - - Otherwise, execute the snippet below: - - ```fish - set -Ux CAIRO_ROOT $HOME/.cairo - set -U fish_user_paths $CAIRO_ROOT/target/release $fish_user_paths + $ scarb --version + scarb 0.7.0 (58cc88efb 2023-08-23) + cairo: 2.2.0 (https://crates.io/crates/cairo-lang-compiler/2.2.0) + sierra: 1.3.0 ``` - -In MacOS, you might also want to install [Fig](https://fig.io/) which -provides alternative shell completions for many command line tools with an -IDE-like popup interface in the terminal window. -(Note that their completions are independent from Cairo's codebase -so they might be slightly out of sync for bleeding-edge interface changes.) - -### Restart your shell - -for the `PATH` changes to take effect. - -```sh -exec "$SHELL" -``` - -## Installing Cairo Manually ([Guide](https://github.com/auditless/cairo-template) by [Abdel](https://github.com/abdelhamidbakhta)) - -### Step 1: Install Cairo 1.0 - -If you are using an x86 Linux system and can use the release binary, download Cairo here: . - -For everyone else, we recommend compiling Cairo from source as follows: - -```bash -# Start by defining environment variable CAIRO_ROOT -export CAIRO_ROOT="${HOME}/.cairo" - -# Create .cairo folder if it doesn't exist yet -mkdir $CAIRO_ROOT - -# Clone the Cairo compiler in $CAIRO_ROOT (default root) -cd $CAIRO_ROOT && git clone git@github.com:starkware-libs/cairo.git . - -# OPTIONAL/RECOMMENDED: If you want to install a specific version of the compiler -# Fetch all tags (versions) -git fetch --all --tags -# View tags (you can also do this in the cairo compiler repository) -git describe --tags `git rev-list --tags` -# Checkout the version you want -git checkout tags/v1.1.0 - -# Generate release binaries -cargo build --all --release -``` - -. - -**NOTE: Keeping Cairo up to date** - -Now that your Cairo compiler is in a cloned repository, all you will need to do -is pull the latest changes and rebuild as follows: - -```bash -cd $CAIRO_ROOT && git fetch && git pull && cargo build --all --release -``` - -### Step 2: Add Cairo 1.0 executables to your path - -```bash -export PATH="$CAIRO_ROOT/target/release:$PATH" -``` - -**NOTE: If installing from a Linux binary, adapt the destination path accordingly.** - -### Step 3: Setup Language Server - -#### VS Code Extension - -- Disable previous Cairo 0.x extension -- Install the Cairo 1 extension for proper syntax highlighting and code navigation. - Just follow the steps indicated [here](https://github.com/starkware-libs/cairo/blob/main/vscode-cairo/README.md). - -#### Cairo Language Server - -From [Step 1](#step-1-install-cairo-10-guide-by-abdel), the `cairo-language-server` binary should be built and executing this command will copy its path into your clipboard. - -```bash -which cairo-language-server | pbcopy -``` - -Update the `languageServerPath` of the Cairo 1.0 extension by pasting the path. diff --git a/src/ch01-02-hello-world.md b/src/ch01-02-hello-world.md index f8ea9850b..c02243702 100644 --- a/src/ch01-02-hello-world.md +++ b/src/ch01-02-hello-world.md @@ -1,6 +1,6 @@ ## Hello, World -Now that you’ve installed Cairo, it’s time to write your first Cairo program. +Now that you’ve installed Cairo through Scarb, it’s time to write your first Cairo program. It’s traditional when learning a new language to write a little program that prints the text `Hello, world!` to the screen, so we’ll do the same here! @@ -9,7 +9,7 @@ prints the text `Hello, world!` to the screen, so we’ll do the same here! > if you prefer to use an integrated development environment (IDE) instead of > the command line, feel free to use your favorite IDE. The Cairo team has developed > a VSCode extension for the Cairo language that you can use to get the features from -> the language server and code highlighting. See [Appendix B][devtools] +> the language server and code highlighting. See [Appendix D][devtools] > for more details. ### Creating a Project Directory @@ -22,51 +22,115 @@ your projects there. Open a terminal and enter the following commands to make a _cairo_projects_ directory and a directory for the “Hello, world!” project within the _cairo_projects_ directory. +> Note: From now on, for each example shown in the book, we assume that +> you will be working from a Scarb project directory. If you are not using Scarb, and try to run the examples from a different directory, you might need to adjust the commands accordingly or create a Scarb project. + For Linux, macOS, and PowerShell on Windows, enter this: -```console +```shell mkdir ~/cairo_projects cd ~/cairo_projects -mkdir hello_world -cd hello_world ``` For Windows CMD, enter this: ```cmd -> mkdir "%USERPROFILE%\projects" -> cd /d "%USERPROFILE%\projects" -> mkdir hello_world -> cd hello_world +> mkdir "%USERPROFILE%\cairo_projects" +> cd /d "%USERPROFILE%\cairo_projects" ``` -### Writing and Running a Cairo Program +### Creating a Project with Scarb + +Let’s create a new project using Scarb. + +Navigate to your projects directory (or wherever you decided to store your code). Then run the following: + +```bash +scarb new hello_world +``` + +It creates a new directory and project called `hello_world`. We’ve named our project `hello_world`, and Scarb creates its files in a directory of the same name. + +Go into the `hello_world` directory with the command `cd hello_world`. You’ll see that Scarb has generated two files and one directory for us: a `Scarb.toml` file and a src directory with a `lib.cairo` file inside. -Next, make a new source file and call it _main.cairo_. Cairo files always end with -the _.cairo_ extension. If you’re using more than one word in your filename, the -convention is to use an underscore to separate them. For example, use -_hello_world.cairo_ rather than _helloworld.cairo_. +It has also initialized a new Git repository along with a `.gitignore` file + +> Note: Git is a common version control system. You can stop using version control system by using the `--vcs` flag. +> Run `scarb new -help` to see the available options. + +Open _Scarb.toml_ in your text editor of choice. It should look similar to the code in Listing 1-2. + +Filename: Scarb.toml + +```toml +[package] +name = "hello_world" +version = "0.1.0" + +# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest + +[dependencies] +# foo = { path = "vendor/foo" } +``` -Now open the _main.cairo_ file you just created and enter the code in Listing 1-1. +Listing 1-2: Contents of Scarb.toml generated by `scarb new` -Filename: main.cairo +This file is in the [TOML](https://toml.io/) (Tom’s Obvious, Minimal Language) format, which is Scarb’s configuration format. + +The first line, `[package]`, is a section heading that indicates that the following statements are configuring a package. As we add more information to this file, we’ll add other sections. + +The next two lines set the configuration information Scarb needs to compile your program: the name and the version of Scarb to use. + +The last line, `[dependencies]`, is the start of a section for you to list any of your project’s dependencies. In Cairo, packages of code are referred to as crates. We won’t need any other crates for this project. + +> Note: If you're building contracts for Starknet, you will need to add the `starknet` dependency as mentioned in the [Scarb documentation](https://docs.swmansion.com/scarb/docs/extensions/starknet/starknet-package.html). + +The other file created by Scarb is `src/lib.cairo`, let's delete all the content and put in the following content, we will explain the reason later. + +```rust,noplayground +mod hello_world; +``` + +Then create a new file called `src/hello_world.cairo` and put the following code in it: + +Filename: src/hello_world.cairo ```rust,file=hello_world.cairo use debug::PrintTrait; fn main() { - 'Hello, world!'.print(); + 'Hello, World!'.print(); } ``` -Listing 1-1: A program that prints `Hello, world!` +We have just created a file called `lib.cairo`, which contains a module declaration referencing another module named `hello_world`, as well as the file `hello_world.cairo`, containing the implementation details of the `hello_world` module. + +Scarb requires your source files to be located within the `src` directory. + +The top-level project directory is reserved for README files, license information, configuration files, and any other non-code-related content. +Scarb ensures a designated location for all project components, maintaining a structured organization. + +If you started a project that doesn’t use Scarb, you can convert it to a project that does use Scarb. Move the project code into the src directory and create an appropriate `Scarb.toml` file. + +### Building a Scarb Project + +From your `hello_world` directory, build your project by entering the following command: + +```bash +$ scarb build + Compiling hello_world v0.1.0 (file:///projects/Scarb.toml) + Finished release target(s) in 0 seconds +``` + +This command creates a `sierra` file in `target/dev`, let's ignore the `sierra` file for now. -Save the file and go back to your terminal window in the -_~/cairo_projects/hello_world_ directory. Enter the following -commands to compile and run the file: +If you have installed Cairo correctly, you should be able to run and see the following output: -```console -$ cairo-run main.cairo -Hello, world! +```shell +$ scarb cairo-run +running hello_world ... +[DEBUG] Hello, World! (raw: 0x48656c6c6f2c20776f726c6421 + +Run completed successfully, returning [] ``` Regardless of your operating system, the string `Hello, world!` should print to @@ -80,7 +144,7 @@ program. That makes you a Cairo programmer—welcome! Let’s review this “Hello, world!” program in detail. Here’s the first piece of the puzzle: -```rust,ignore_format +```rust,noplayground fn main() { } @@ -96,9 +160,9 @@ function bodies. It’s good style to place the opening curly bracket on the sam line as the function declaration, adding one space in between. > Note: If you want to stick to a standard style across Cairo projects, you can -> use the automatic formatter tool called `cairo-format` to format your code in a -> particular style (more on `cairo-format` in -> [Appendix B][devtools]). The Cairo team has included this tool +> use the automatic formatter tool available with `scarb fmt` to format your code in a +> particular style (more on `scarb fmt` in +> [Appendix D][devtools]). The Cairo team has included this tool > with the standard Cairo distribution, as `cairo-run` is, so it should already be > installed on your computer! @@ -106,8 +170,8 @@ Prior to the main function declaration, The line `use debug::PrintTrait;` is res The body of the `main` function holds the following code: -```rust - 'Hello, world!'.print(); +```rust,noplayground + 'Hello, World!'.print(); ``` This line does all the work in this little program: it prints text to the @@ -117,16 +181,68 @@ First, Cairo style is to indent with four spaces, not a tab. Second, the `print()` function called is a method from the trait `PrintTrait`. This trait is imported from the Cairo core library, and it defines how to print values to the screen for different data types. In our case, our text is defined as a "short string", which is an ASCII string that can fit in Cairo's basic data type, which is the `felt252` type. By calling `Hello, world!'.print()`, we're calling the `print()` method of the `felt252` implementation of the `PrintTrait` trait. -Third, you see the `'Hello, world!'` short string. We pass this short string as an argument +Third, you see the `'Hello, World!'` short string. We pass this short string as an argument to `print()`, and the short string is printed to the screen. Fourth, we end the line with a semicolon (`;`), which indicates that this expression is over and the next one is ready to begin. Most lines of Cairo code end with a semicolon. -Just running with `cairo-run` is fine for simple programs, but as your project -grows, you’ll want to manage all the options and make it easy to share your -code. Next, we’ll introduce you to the Scarb tool, which will help you write -real-world Cairo programs. - [devtools]: appendix-04-useful-development-tools.md + +### Running tests + +To run all the tests associated with a particular package, you can use the `scarb test` command. +It is not a test runner by itself, but rather delegates work to a testing solution of choice. Scarb comes with preinstalled `scarb cairo-test` extension, which bundles Cairo's native test runner. It is the default test runner used by scarb test. +To use third-party test runners, please refer to [Scarb's documentation](https://docs.swmansion.com/scarb/docs/extensions/testing.html#using-third-party-test-runners). + +Test functions are marked with the `#[test]` attributes, and running `scarb test` will run all test functions in your codebase under the `src/` directory. + +```txt +├── Scarb.toml +├── src +│   ├── lib.cairo +│   └── file.cairo +``` + + A sample Scarb project structure + +Let’s recap what we’ve learned so far about Scarb: + +- We can create a project using `scarb new`. +- We can build a project using `scarb build` to generate the compiled Sierra code. +- We can define custom scripts in `Scarb.toml` and call them with the `scarb run` command. +- We can run tests using the `scarb test` command. + +An additional advantage of using Scarb is that the commands are the same no matter which operating system you’re working on. So, at this point, we’ll no longer provide specific instructions for Linux and macOS versus Windows. + +### Starknet support + +Scarb supports smart contract development for Starknet. To enable this functionality, you'll need to make some configurations in your `Scarb.toml` file. +You have to add the `starknet` dependency and add a `[[target.starknet-contract]]` section to enable contract compilation. + +Below is the minimal Scarb.toml file required for a Starknet contract: + +```toml +[package] +name = "hello_starknet" +version = "0.1.0" + +[dependencies] +starknet = ">=2.2.0" + +[[target.starknet-contract]] +``` + +For additional configuration, such as external contract dependencies, please refer to the [Scarb documentation](https://docs.swmansion.com/scarb/docs/extensions/starknet/contract-target.html#compiling-external-contracts). + +# Summary + +You’re already off to a great start on your Cairo journey! In this chapter, you’ve learned how to: + +- Install the latest stable version of Cairo +- Write and run a “Hello, Scarb!” program using `scarb` directly +- Create and run a new project using the conventions of Scarb +- Execute tests using the `scarb test` command + +This is a great time to build a more substantial program to get used to reading and writing Cairo code. diff --git a/src/ch01-03-hello-scarb.md b/src/ch01-03-hello-scarb.md index afe94254b..e69de29bb 100644 --- a/src/ch01-03-hello-scarb.md +++ b/src/ch01-03-hello-scarb.md @@ -1,170 +0,0 @@ -# Hello, Scarb - -Scarb is the Cairo package manager and heavily inspired by [Cargo](https://doc.rust-lang.org/cargo/), Rust’s build system and package manager. - -Scarb handles a lot of tasks for you, such as building your code (either pure Cairo or Starknet contracts), downloading the libraries your code depends on, and building those libraries. - -If we were to build the 'Hello, world!' project using Scarb, only the part of Scarb that handles building the code would be utilized, since the program doesn't require any external dependencies. As you write more complex Cairo programs, you’ll add dependencies, and if you start a project using Scarb, adding dependencies will be much easier to do. - -Let's start by installing Scarb. - -## Installing Scarb - -### Requirements - -Scarb requires a Git executable to be available in the `PATH` environment variable. - -### Installation - -As for now, Scarb needs manual installation with the following steps: - -- Download the release archive matching your operating system and CPU architecture, from [Scarb releases on GitHub](https://github.com/software-mansion/scarb/releases) -- Extract it to a location where you would like to have Scarb installed, e.g. `~/scarb` -- Add path to the `scarb/bin` directory to your `PATH` environment variable. - - This depend on what shell you are using. Let’s take the example of [zsh](https://ohmyz.sh/) and you have extracted Scarb to `~/scarb`: - - - Open `~/.zshrc` file in your favorite editor - - Add the following line to the end of the file: `export PATH="$PATH:~/scarb/bin"` - -- Verify installation by running the following command in new terminal session, it should print both Scarb and Cairo language versions, e.g: - - ```bash - $ scarb --version - scarb 0.3.0 (182a9019d 2023-05-29) - cairo: 1.1.0 (https://crates.io/crates/cairo-lang-compiler/1.1.0) - ``` - -### Creating a Project with Scarb - -Let’s create a new project using Scarb and look at how it differs from our original “Hello, world!” project. - -Navigate back to your projects directory (or wherever you decided to store your code). Then run the following: - -```bash -$ scarb new hello_scarb -``` - -It creates a new directory and project called hello_scarb. We’ve named our project hello_scarb, and Scarb creates its files in a directory of the same name. - -Go into the hello_scarb directory with the command `cd hello_scarb`. You’ll see that Scarb has generated two files and one directory for us: a `Scarb.toml` file and a src directory with a `lib.cairo` file inside. - -It has also initialized a new Git repository along with a `.gitignore` file - -> Note: Git is a common version control system. You can stop using version control system by using the `--vcs` flag. -> Run `scarb new -help` to see the available options. - -Open _Scarb.toml_ in your text editor of choice. It should look similar to the code in Listing 1-2. - -Filename: Scarb.toml - -```toml -[package] -name = "hello_scarb" -version = "0.1.0" - -# See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest - -[dependencies] -# foo = { path = "vendor/foo" } -``` - -Listing 1-2: Contents of Scarb.toml generated by `scarb new` - -This file is in the [TOML](https://toml.io/) (Tom’s Obvious, Minimal Language) format, which is Scarb’s configuration format. - -The first line, `[package]`, is a section heading that indicates that the following statements are configuring a package. As we add more information to this file, we’ll add other sections. - -The next two lines set the configuration information Scarb needs to compile your program: the name and the version of Scarb to use. - -The last line, `[dependencies]`, is the start of a section for you to list any of your project’s dependencies. In Cairo, packages of code are referred to as crates. We won’t need any other crates for this project. - -The other file created by Scarb is `src/lib.cairo`, let's delete all the content and put in the following content, we will explain the reason later. - -```rust -mod hello_scarb; -``` - -Then create a new file called `src/hello_scarb.cairo` and put the following code in it: - -Filename: src/hello_scarb.cairo - -```rust,file=hello_scarb.cairo -use debug::PrintTrait; -fn main() { - 'Hello, Scarb!'.print(); -} -``` - -We have just created a file called `lib.cairo`, which contains a module declaration referencing another module named "hello_scarb", as well as the file `hello_scarb.cairo`, containing the implementation details of the "hello_scarb" module. - -Scarb requires your source files to be located within the src directory. - -The top-level project directory is reserved for README files, license information, configuration files, and any other non-code-related content. -Scarb ensures a designated location for all project components, maintaining a structured organization. - -If you started a project that doesn’t use Scarb, as we did with the “Hello, world!” project, you can convert it to a project that does use Scarb. Move the project code into the src directory and create an appropriate `Scarb.toml` file. - -### Building a Scarb Project - -From your hello_scarb directory, build your project by entering the following command: - -```bash -$ scarb build - Compiling hello_scarb v0.1.0 (file:///projects/Scarb.toml) - Finished release target(s) in 0 seconds -``` - -This command creates a `sierra` file in `target/release`, let's ignore the `sierra` file for now. - -If you have installed Cairo correctly, you should be able to run and see the following output: - -```bash -$ cairo-run src/lib.cairo -[DEBUG] Hello, Scarb! (raw: 5735816763073854913753904210465) - -Run completed successfully, returning [] -``` - -> Note: You will notice here that we didn't use a Scarb command, but rather a command from the Cairo binaries directly. -> As Scarb doesn't have a command to execute Cairo code yet, we have to use the `cairo-run` command directly. -> We will use this command in the rest of the tutorial, but we will also use Scarb commands to initialize projects. - -### Defining Custom Scripts - -We can define Scarb scripts in `Scarb.toml` file, which can be used to execute custom shell scripts. -Add the following line to your `Scarb.toml` file: - -```toml -[scripts] -run-lib = "cairo-run src/lib.cairo" -``` - -Now you can run the following command to run the project: - -```bash -$ scarb run run-lib -[DEBUG] Hello, Scarb! (raw: 5735816763073854913753904210465) - -Run completed successfully, returning [] -``` - -Using `scarb run` is a convenient way to run custom shell scripts that can be useful to run files and test your project. - -Let’s recap what we’ve learned so far about Scarb: - -- We can create a project using `scarb new`. -- We can build a project using `scarb build` to generate the compiled Sierra code. -- We can define custom scripts in `Scarb.toml` and call them with the `scarb run` command. - -An additional advantage of using Scarb is that the commands are the same no matter which operating system you’re working on. So, at this point, we’ll no longer provide specific instructions for Linux and macOS versus Windows. - -# Summary - -You’re already off to a great start on your Cairo journey! In this chapter, you’ve learned how to: - -- Install the latest stable version of Cairo -- Write and run a “Hello, world!” program using `cairo-run` directly -- Create and run a new project using the conventions of Scarb - -This is a great time to build a more substantial program to get used to reading and writing Cairo code. diff --git a/src/ch02-01-variables-and-mutability.md b/src/ch02-01-variables-and-mutability.md index fc76b2f3a..b7907ca02 100644 --- a/src/ch02-01-variables-and-mutability.md +++ b/src/ch02-01-variables-and-mutability.md @@ -17,14 +17,14 @@ code with the following code, which won’t compile just yet: Filename: src/lib.cairo ```rust,does_not_compile -{{#include ../listings/ch02-common-programming-concepts/no_listing_01_variables_are_immutable.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_01_variables_are_immutable/src/lib.cairo}} ``` -Save and run the program using `cairo-run src/lib.cairo`. You should receive an error message +Save and run the program using `scarb cairo-run`. You should receive an error message regarding an immutability error, as shown in this output: -```console +```shell error: Cannot assign to an immutable variable. --> lib.cairo:5:5 x = 6; @@ -71,16 +71,16 @@ For example, let’s change _src/lib.cairo_ to the following: Filename: src/lib.cairo ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_02_adding_mut.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_02_adding_mut/src/lib.cairo}} ``` When we run the program now, we get this: -```console -❯ cairo-run src/lib.cairo -[DEBUG] (raw: 5) +```shell +$ scarb cairo-run +[DEBUG] (raw: 5) -[DEBUG] (raw: 6) +[DEBUG] (raw: 6) Run completed successfully, returning [] ``` @@ -111,7 +111,7 @@ are currently supported. Here’s an example of a constant declaration: -```rust +```rust, noplayground const ONE_HOUR_IN_SECONDS: u32 = 3600; ``` @@ -143,7 +143,7 @@ use of the `let` keyword as follows: Filename: src/lib.cairo ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_03_shadowing.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_03_shadowing/src/lib.cairo}} ``` This program first binds `x` to a value of `5`. Then it creates a new variable @@ -154,16 +154,16 @@ variable, multiplying the previous value by `2` to give `x` a value of `12`. When that scope is over, the inner shadowing ends and `x` returns to being `6`. When we run this program, it will output the following: -```console -cairo-run src/lib.cairo -[DEBUG] Inner scope x value is: (raw: 7033328135641142205392067879065573688897582790068499258) +```shell +scarb cairo-run +[DEBUG] Inner scope x value is: (raw: 7033328135641142205392067879065573688897582790068499258) [DEBUG] - (raw: 12) + (raw: 12) -[DEBUG] Outer scope x value is: (raw: 7610641743409771490723378239576163509623951327599620922) +[DEBUG] Outer scope x value is: (raw: 7610641743409771490723378239576163509623951327599620922) -[DEBUG] (raw: 6) +[DEBUG] (raw: 6) Run completed successfully, returning [] ``` @@ -183,7 +183,7 @@ if you change its type. For example, say our program performs a type conversion `u64` and `felt252` types. ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_04_shadowing_different_type.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_04_shadowing_different_type/src/lib.cairo}} ``` The first `x` variable has a `u64` type while the second `x` variable has a `felt252` type. @@ -192,17 +192,17 @@ and `x_felt252`; instead, we can reuse the simpler `x` name. However, if we try `mut` for this, as shown here, we’ll get a compile-time error: ```rust,does_not_compile -{{#include ../listings/ch02-common-programming-concepts/no_listing_05_mut_cant_change_type.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_05_mut_cant_change_type/src/lib.cairo}} ``` The error says we were expecting a `u64` (the original type) but we got a different type: -```console -❯ cairo-run src/lib.cairo +```shell +$ scarb cairo-run error: Unexpected argument type. Expected: "core::integer::u64", found: "core::felt252". - --> lib.cairo:6:9 - x = x.into(); - ^******^ + --> lib.cairo:9:9 + x = 100_felt252; + ^*********^ Error: failed to compile: src/lib.cairo ``` diff --git a/src/ch02-02-data-types.md b/src/ch02-02-data-types.md index 673b84e24..a599a7db8 100644 --- a/src/ch02-02-data-types.md +++ b/src/ch02-02-data-types.md @@ -8,7 +8,7 @@ must know the types of all variables at compile time. The compiler can usually i when many types are possible, we can use a cast method where we specify the desired output type. ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_06_data_types.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_06_data_types/src/lib.cairo}} ``` You’ll see different type annotations for other data types. @@ -57,7 +57,7 @@ Each variant has an explicit size. Note that for now, the `usize` type is just a As variables are unsigned, they can't contain a negative number. This code will cause the program to panic: ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_07_integer_types.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_07_integer_types/src/lib.cairo}} ``` You can write integer literals in any of the forms shown in Table 3-2. Note @@ -84,7 +84,7 @@ division truncates toward zero to the nearest integer. The following code shows how you’d use each numeric operation in a `let` statement: ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_08_numeric_operations.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_08_numeric_operations/src/lib.cairo}} ``` Each expression in these statements uses a mathematical operator and evaluates @@ -99,7 +99,7 @@ values: `true` and `false`. Booleans are one felt252 in size. The Boolean type i Cairo is specified using `bool`. For example: ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_09_boolean_type.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_09_boolean_type/src/lib.cairo}} ``` The main way to use Boolean values is through conditionals, such as an `if` @@ -112,7 +112,7 @@ Cairo doesn't have a native type for strings, but you can store characters formi Here are some examples of declaring values by putting them between single quotes: ```rust -{{#rustdoc_include ../listings/ch02-common-programming-concepts/no_listing_10_short_string_type.cairo:2:3}} +{{#rustdoc_include ../listings/ch02-common-programming-concepts/no_listing_10_short_string_type/src/lib.cairo:2:3}} ``` ### Type casting @@ -126,7 +126,7 @@ On the other hand, the `into` method can be used for type casting when success i To perform the conversion, call `var.into()` or `var.try_into()` on the source value to cast it to another type. The new variable's type must be explicitly defined, as demonstrated in the example below. ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_11_type_casting.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_11_type_casting/src/lib.cairo}} ``` ### The Tuple Type @@ -141,7 +141,7 @@ different values in the tuple don’t have to be the same. We’ve added optiona type annotations in this example: ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_12_tuple_type.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_12_tuple_type/src/lib.cairo}} ``` The variable `tup` binds to the entire tuple because a tuple is considered a @@ -149,7 +149,7 @@ single compound element. To get the individual values out of a tuple, we can use pattern matching to destructure a tuple value, like this: ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_13_tuple_destructuration.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_13_tuple_destructuration/src/lib.cairo}} ``` This program first creates a tuple and binds it to the variable `tup`. It then @@ -162,7 +162,7 @@ We can also declare the tuple with value and types at the same time. For example: ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_14_tuple_types.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_14_tuple_types/src/lib.cairo}} ``` ### The unit type () diff --git a/src/ch02-03-functions.md b/src/ch02-03-functions.md index dd8bc19c0..8baa58dbd 100644 --- a/src/ch02-03-functions.md +++ b/src/ch02-03-functions.md @@ -10,7 +10,7 @@ names, in which all letters are lowercase and underscores separate words. Here’s a program that contains an example function definition: ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_15_functions.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_15_functions/src/lib.cairo}} ``` We define a function in Cairo by entering `fn` followed by a function name and a @@ -28,8 +28,8 @@ Let’s start a new project with Scarb named _functions_ to explore functions further. Place the `another_function` example in _src/lib.cairo_ and run it. You should see the following output: -```console -$ cairo-run src/lib.cairo +```shell +$ scarb cairo-run [DEBUG] Hello, world! (raw: 5735816763073854953388147237921) [DEBUG] Another function. (raw: 22265147635379277118623944509513687592494) ``` @@ -51,13 +51,13 @@ function. In this version of `another_function` we add a parameter: ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_16_single_param.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_16_single_param/src/lib.cairo}} ``` Try running this program; you should get the following output: -```console -$ cairo-run src/lib.cairo +```shell +$ scarb cairo-run [DEBUG] (raw: 5) ``` @@ -75,7 +75,7 @@ When defining multiple parameters, separate the parameter declarations with commas, like this: ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_17_multiple_params.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_17_multiple_params/src/lib.cairo}} ``` This example creates a function named `another_function` with two @@ -83,10 +83,10 @@ parameters. The first parameter is named `x` and is an `felt252`. The second is named `y` and is type `felt252` too. The function then prints the content of the felt `x` and then the content of the felt `y`. Let’s try running this code. Replace the program currently in your _functions_ -project’s _src/lib.cairo_ file with the preceding example and run it using `cairo-run src/lib.cairo`: +project’s _src/lib.cairo_ file with the preceding example and run it using `scarb cairo-run`: -```console -$ cairo-run src/lib.cairo +```shell +$ scarb cairo-run [DEBUG] (raw: 5) [DEBUG] (raw: 6) ``` @@ -94,6 +94,17 @@ $ cairo-run src/lib.cairo Because we called the function with `5` as the value for `x` and `6` as the value for `y`, the program output contains those values. +#### Named parameters + +In Cairo, named parameters allow you to specify the names of arguments when you call a function. This makes the function calls more readable and self-descriptive. +If you want to use named parameters, you need to specify the name of the parameter and the value you want to pass to it. The syntax is `parameter_name: value`. If you pass a variable that has the same name as the parameter, you can simply write `:parameter_name` instead of `parameter_name: variable_name`. + +Here is an example: + +```rust +{{#include ../listings/ch02-common-programming-concepts/no_listing_30_named_parameters/src/lib.cairo}} +``` + ### Statements and Expressions Function bodies are made up of a series of statements optionally ending in an @@ -113,7 +124,7 @@ assigning a value to it with the `let` keyword is a statement. In Listing 2-1, `let y = 6;` is a statement. ```rust -{{#include ../listings/ch02-common-programming-concepts/listing_01_statement.cairo}} +{{#include ../listings/ch02-common-programming-concepts/listing_01_statement/src/lib.cairo}} ``` Listing 2-1: A `main` function declaration containing one statement @@ -124,14 +135,14 @@ statement in itself. Statements do not return values. Therefore, you can’t assign a `let` statement to another variable, as the following code tries to do; you’ll get an error: -```rust,does_not_compile,ignore_format -{{#include ../listings/ch02-common-programming-concepts/no_listing_18_statements_dont_return_values.cairo}} +```rust, noplayground +{{#include ../listings/ch02-common-programming-concepts/no_listing_18_statements_dont_return_values/src/lib.cairo}} ``` When you run this program, the error you’ll get looks like this: -```console -$ cairo-run src/lib.cairo +```shell +$ scarb cairo-run error: Missing token TerminalRParen. --> src/lib.cairo:2:14 let x = (let y = 6); @@ -167,14 +178,14 @@ expression. A new scope block created with curly brackets is an expression, for example: ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_19_blocks_are_expressions.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_19_blocks_are_expressions/src/lib.cairo}} ``` This expression: -```rust, does_not_compile, ignore_format +```rust, noplayground { -{{#include ../listings/ch02-common-programming-concepts/no_listing_19_blocks_are_expressions.cairo:4:5}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_19_blocks_are_expressions/src/lib.cairo:4:5}} } ``` @@ -197,7 +208,7 @@ functions return the last expression implicitly. Here’s an example of a function that returns a value: ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_20_function_return_values.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_20_function_return_values/src/lib.cairo}} ``` There are no function calls, or even `let` statements in the `five` @@ -205,8 +216,8 @@ function—just the number `5` by itself. That’s a perfectly valid function in Cairo. Note that the function’s return type is specified too, as `-> u32`. Try running this code; the output should look like this: -```console -$ cairo-run src/lib.cairo +```shell +$ scarb cairo-run [DEBUG] (raw: 5) ``` @@ -216,7 +227,7 @@ first, the line `let x = five();` shows that we’re using the return value of a function to initialize a variable. Because the function `five` returns a `5`, that line is the same as the following: -```rust, does_not_compile +```rust, noplayground let x = 5; ``` @@ -226,7 +237,7 @@ because it’s an expression whose value we want to return. Let’s look at another example: ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_21_function_return_values_2.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_21_function_return_values_2/src/lib.cairo}} ``` Running this code will print `[DEBUG] (raw: 6)`. But if we place a @@ -234,12 +245,12 @@ semicolon at the end of the line containing `x + 1`, changing it from an expression to a statement, we’ll get an error: ```rust,does_not_compile -{{#include ../listings/ch02-common-programming-concepts/no_listing_22_function_return_invalid.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_22_function_return_invalid/src/lib.cairo}} ``` Compiling this code produces an error, as follows: -```console +```shell error: Unexpected return type. Expected: "core::integer::u32", found: "()". ``` diff --git a/src/ch02-04-comments.md b/src/ch02-04-comments.md index 572cc5d99..f06fd05a6 100644 --- a/src/ch02-04-comments.md +++ b/src/ch02-04-comments.md @@ -3,5 +3,5 @@ In Cairo programs, you can include explanatory text within the code using comments. To create a comment, use the // syntax, after which any text on the same line will be ignored by the compiler. ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_23_comments.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_23_comments/src/lib.cairo}} ``` diff --git a/src/ch02-05-control-flow.md b/src/ch02-05-control-flow.md index 230816df7..2ecf61bcf 100644 --- a/src/ch02-05-control-flow.md +++ b/src/ch02-05-control-flow.md @@ -6,10 +6,10 @@ The ability to run some code depending on whether a condition is true and to run An if expression allows you to branch your code depending on conditions. You provide a condition and then state, “If this condition is met, run this block of code. If the condition is not met, do not run this block of code.” -Filename: main.cairo +Filename: src/lib.cairo ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_24_if.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_24_if/src/lib.cairo}} ``` All `if` expressions start with the keyword `if`, followed by a condition. In this case, the condition checks whether or not the variable `number` has a value equal to 5. We place the block of code to execute if the condition is `true` immediately after the condition inside curly brackets. @@ -18,25 +18,25 @@ Optionally, we can also include an `else` expression, which we chose to do here, Try running this code; you should see the following output: -```console +```shell $ cairo-run main.cairo [DEBUG] condition was false ``` Let’s try changing the value of `number` to a value that makes the condition `true` to see what happens: -```rust, does_not_compile +```rust, noplayground let number = 5; ``` -```console +```shell $ cairo-run main.cairo condition was true ``` It’s also worth noting that the condition in this code must be a bool. If the condition isn’t a bool, we’ll get an error. -```console +```shell $ cairo-run main.cairo thread 'main' panicked at 'Failed to specialize: `enum_match`. Error: Could not specialize libfunc `enum_match` with generic_args: [Type(ConcreteTypeId { id: 1, debug_name: None })]. Error: Provided generic argument is unsupported.', crates/cairo-lang-sierra-generator/src/utils.rs:256:9 ``` @@ -45,15 +45,15 @@ thread 'main' panicked at 'Failed to specialize: `enum_match`. Error: C You can use multiple conditions by combining if and else in an else if expression. For example: -Filename: main.cairo +Filename: src/lib.cairo ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_25_else_if.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_25_else_if/src/lib.cairo}} ``` This program has four possible paths it can take. After running it, you should see the following output: -```console +```shell [DEBUG] number is 3 ``` @@ -63,13 +63,13 @@ When this program executes, it checks each `if` expression in turn and executes Because if is an expression, we can use it on the right side of a let statement to assign the outcome to a variable. -Filename: main.cairo +Filename: src/lib.cairo ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_26_if_let.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_26_if_let/src/lib.cairo}} ``` -```console +```shell $ cairo-run main.cairo [DEBUG] condition was true ``` @@ -93,7 +93,7 @@ like this: Filename: src/lib.cairo ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_27_loop.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_27_loop/src/lib.cairo}} ``` When we run this program, we’ll see `again!` printed over and over continuously @@ -103,8 +103,8 @@ the stop condition might never be reached, resulting in an infinite loop. Most terminals support the keyboard shortcut ctrl-c to interrupt a program that is stuck in a continual loop. Give it a try: -```console -❯ cairo-run src/lib.cairo --available-gas=20000000 +```shell +$ scarb cairo-run --available-gas=20000000 [DEBUG] again (raw: 418346264942) [DEBUG] again (raw: 418346264942) @@ -125,7 +125,7 @@ To break out of a loop, you can place the `break` statement within the loop to t executing the loop. Let's fix the infinite loop by adding a making the stop condition `i > 10` reachable. ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_28_loop_break.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_28_loop_break/src/lib.cairo}} ``` The `continue` keyword tells the program to go to the next iteration of the loop and to skip the rest of the code in this iteration. Let's add a `continue` statement to our loop to skip the `print` statement when `i` is equal to `5`. @@ -136,7 +136,7 @@ fn main() { let mut i: usize = 0; loop { if i > 10 { - break (); + break; } if i == 5 { i += 1; @@ -160,7 +160,7 @@ use to stop the loop; that value will be returned out of the loop so you can use it, as shown here: ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_29_loop_return_values.cairo}} +{{#include ../listings/ch02-common-programming-concepts/no_listing_29_loop_return_values/src/lib.cairo}} ``` Before the loop, we declare a variable named `counter` and initialize it to @@ -169,3 +169,14 @@ the loop. On every iteration of the loop, we check whether the `counter` is equa When the condition is met, we use the `break` keyword with the value `counter * 2`. After the loop, we use a semicolon to end the statement that assigns the value to `result`. Finally, we print the value in `result`, which in this case is `20`. + +## Summary + +You made it! This was a sizable chapter: you learned about variables, data types, functions, comments, +`if` expressions and loops! To practice with the concepts discussed in this chapter, +try building programs to do the following: + +- Generate the _n_-th Fibonacci number. +- Compute the factorial of a number _n_. + +Now, we’ll review the common collection types in Cairo in the next chapter. diff --git a/src/ch02-99-00-common-collections.md b/src/ch02-99-00-common-collections.md new file mode 100644 index 000000000..c59e9039c --- /dev/null +++ b/src/ch02-99-00-common-collections.md @@ -0,0 +1,3 @@ +## Common Collections + +Cairo provides a set of common collection types that can be used to store and manipulate data. These collections are designed to be efficient, flexible, and easy to use. This section introduces the primary collection types available in Cairo: Arrays and Dictionaries. diff --git a/src/ch02-06-common-collections.md b/src/ch02-99-01-arrays.md similarity index 67% rename from src/ch02-06-common-collections.md rename to src/ch02-99-01-arrays.md index 198c6f324..08cbcd00d 100644 --- a/src/ch02-06-common-collections.md +++ b/src/ch02-99-01-arrays.md @@ -1,52 +1,52 @@ -## Common Collections - -Cairo1 provides a set of common collection types that can be used to store and manipulate data. These collections are designed to be efficient, flexible, and easy to use. This section introduces the primary collection types available in Cairo1: `Array` and `Felt252Dict` (coming soon). - -### Array +## Arrays An array is a collection of elements of the same type. You can create and use array methods by importing the `array::ArrayTrait` trait. An important thing to note is that arrays have limited modifications options. Arrays are, in fact, queues whose values can't be modified. This has to do with the fact that once a memory slot is written to, it cannot be overwritten, but only read from it. You can only append items to the end of an array and remove items from the front using `pop_front`. -#### Creating an Array +### Creating an Array Creating an Array is done with the `ArrayTrait::new()` call. Here is an example of the creation of an array to which we append 3 elements: ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_30_array_new_append.cairo}} +{{#include ../listings/ch02-99-common-collections/no_listing_00_array_new_append/src/lib.cairo}} ``` -You can pass the expected type of items inside the array when instantiating the array like this +When required, you can pass the expected type of items inside the array when instantiating the array like this, or explicitly define the type the variable. -```rust, does_not_compile +```rust, noplayground let mut arr = ArrayTrait::::new(); ``` -#### Updating an Array +```rust, noplayground +let mut arr:Array = ArrayTrait::new(); +``` -##### Adding Elements +### Updating an Array + +#### Adding Elements To add an element to the end of an array, you can use the `append()` method: ```rust -{{#rustdoc_include ../listings/ch02-common-programming-concepts/no_listing_30_array_new_append.cairo:5}} +{{#rustdoc_include ../listings/ch02-99-common-collections/no_listing_00_array_new_append/src/lib.cairo:5}} ``` -##### Removing Elements +#### Removing Elements You can only remove elements from the front of an array by using the `pop_front()` method. This method returns an `Option` containing the removed element, or `Option::None` if the array is empty. ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_31_array_pop_front.cairo}} +{{#include ../listings/ch02-99-common-collections/no_listing_01_array_pop_front/src/lib.cairo}} ``` The above code will print `10` as we remove the first element that was added. In Cairo, memory is immutable, which means that it is not possible to modify the elements of an array once they've been added. You can only add elements to the end of an array and remove elements from the front of an array. These operations do not require memory mutation, as they involve updating pointers rather than directly modifying the memory cells. -#### Reading Elements from an Array +### Reading Elements from an Array To access array elements, you can use `get()` or `at()` array methods that return different types. Using `arr.at(index)` is equivalent to using the subscripting operator `arr[index]`. @@ -57,7 +57,7 @@ The `at` function, on the other hand, directly returns a snapshot to the element In summary, use `at` when you want to panic on out-of-bounds access attempts, and use `get` when you prefer to handle such cases gracefully without panicking. ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_32_array_at.cairo}} +{{#include ../listings/ch02-99-common-collections/no_listing_02_array_at/src/lib.cairo}} ``` In this example, the variable named `first` will get the value `0` because that @@ -66,46 +66,34 @@ the value `1` from index `1` in the array. Here is an example with the `get()` method: -```rust,ignore_format -{{#include ../listings/ch02-common-programming-concepts/no_listing_33_array_get.cairo}} +```rust +{{#include ../listings/ch02-99-common-collections/no_listing_03_array_get/src/lib.cairo}} ``` -#### Size related methods +### Size related methods To determine the number of elements in an array, use the `len()` method. The return is of type `usize`. If you want to check if an array is empty or not, you can use the `is_empty()` method, which returns `true` if the array is empty and `false` otherwise. -#### Storing multiple types with Enums +### Storing multiple types with Enums If you want to store elements of different types in an array, you can use an `Enum` to define a custom data type that can hold multiple types. ```rust -{{#include ../listings/ch02-common-programming-concepts/no_listing_34_array_with_enums.cairo}} +{{#include ../listings/ch02-99-common-collections/no_listing_04_array_with_enums/src/lib.cairo}} ``` -#### Span +### Span `Span` is a struct that represents a snapshot of an `Array`. It is designed to provide safe and controlled access to the elements of an array without modifying the original array. Span is particularly useful for ensuring data integrity and avoiding borrowing issues when passing arrays between functions or when performing read-only operations (cf. [References and Snapshots](ch03-02-references-and-snapshots.md)) All methods provided by `Array` can also be used with `Span`, with the exception of the `append()` method. -##### Turning an Array into span +#### Turning an Array into span To create a `Span` of an `Array`, call the `span()` method: ```rust -{{#rustdoc_include ../listings/ch02-common-programming-concepts/no_listing_35_array_span.cairo:5}} +{{#rustdoc_include ../listings/ch02-99-common-collections/no_listing_05_array_span/src/lib.cairo:5}} ``` - -## Summary - -You made it! This was a sizable chapter: you learned about variables, data types, functions, comments, -`if` expressions, loops, and common collections! To practice with the concepts discussed in this chapter, -try building programs to do the following: - -- Generate the _n_-th Fibonacci number. -- Compute the factorial of a number _n_. - -When you’re ready to move on, we’ll talk about a concept that Cairo shares with Rust and that _doesn’t_ -commonly exist in other programming languages: ownership. diff --git a/src/ch02-99-02-dictionaries.md b/src/ch02-99-02-dictionaries.md new file mode 100644 index 000000000..1ba9e75ca --- /dev/null +++ b/src/ch02-99-02-dictionaries.md @@ -0,0 +1,273 @@ +## Dictionaries + +Cairo provides in its core library a dictionary-like type. The `Felt252Dict` data type represents a collection of key-value pairs where each key is unique and associated with a corresponding value. This type of data structure is known differently across different programming languages such as maps, hash tables, associative arrays and many others. + +The `Felt252Dict` type is useful when you want to organize your data in a certain way for which using an `Array` and indexing doesn't suffice. Cairo dictionaries also allow the programmer to easily simulate the existence of mutable memory when there is none. + +### Basic Use of Dictionaries + +It is normal in other languages when creating a new dictionary to define the data types of both key and value. In Cairo, the key type is restricted to `felt252` leaving only the possibility to specify the value data type, represented by `T` in `Felt252Dict`. + +The core functionality of a `Felt252Dict` is implemented in the trait `Felt252DictTrait` which includes all basic operations. Among them we can find: + +1. `insert(felt252, T) -> ()` to write values to a dictionary instance and +2. `get(felt252) -> T` to read values from it. + +These functions allow us to manipulate dictionaries like in any other language. In the following example, we create a dictionary to represent a mapping between individuals and their balance: + +```rust +{{#include ../listings/ch02-99-common-collections/no_listing_07_intro/src/lib.cairo}} +``` + +The first thing we do is import `Felt252DictTrait` which brings to scope all the methods we need to interact with the dictionary. Next, we create a new instance of `Felt252Dict` by using the `default` method of the `Default` trait and added two individuals, each one with their own balance, using the `insert` method. Finally, we checked the balance of our users with the `get` method. + +Throughout the book we have talked about how Cairo's memory is immutable, meaning you can only write to a memory cell once but the `Felt252Dict` type represents a way to overcome this obstacle. We will explain how this is implemented later on in [Dictionaries Underneath](#dictionaries-underneath). + +Building upon our previous example, let us show a code example where the balance of the same user changes: + +```rust +{{#include ../listings/ch02-99-common-collections/no_listing_08_intro_rewrite/src/lib.cairo}} +``` + +Notice how in this example we added the _Alex_ individual twice, each time using a different balance and each time that we checked for its balance it had the last value inserted! `Felt252Dict` effectively allows us to "rewrite" the stored value for any given key. + +Before heading on and explaining how dictionaries are implemented it is worth mentioning that once you instantiate a `Felt252Dict`, behind the scenes all keys have their associated values initialized as zero. This means that if for example, you tried to get the balance of an inexistent user you will get 0 instead of an error or an undefined value. This also means there is no way to delete data from a dictionary. Something to take into account when incorporating this structure into your code. + +Until this point, we have seen all the basic features of `Felt252Dict` and how it mimics the same behavior as the corresponding data structures in any other language, that is, externally of course. Cairo is at its core a non-deterministic Turing-complete programming language, very different from any other popular language in existence, which as a consequence means that dictionaries are implemented very differently as well! + +In the following sections, we are going to give some insights about `Felt252Dict` inner mechanisms and the compromises that were taken to make them work. After that, we are going to take a look at how to use dictionaries with other data structures as well as use the `entry` method as another way to interact with them. + +### Dictionaries Underneath + +One of the constraints of Cairo's non-deterministic design is that its memory system is immutable, so in order to simulate mutability, the language implements `Felt252Dict` as a list of entries. Each of the entries represents a time when a dictionary was accessed for reading/updating/writing purposes. An entry has three fields: + +1. A `key` field that identifies the value for this key-value pair of the dictionary. +2. A `previous_value` field that indicates which previous value was held at `key`. +3. A `new_value` field that indicates the new value that is held at `key`. + +If we try implementing `Felt252Dict` using high-level structures we would internally define it as `Array>` where each `Entry` has information about what key-value pair it represents and the previous and new values it holds. The definition of `Entry` would be: + +```rust,noplayground +{{#include ../listings/ch02-99-common-collections/no_listing_09_entries/src/lib.cairo:struct}} +``` + +For each time we interact with a `Felt252Dict` a new `Entry` will be registered: + +- A `get` would register an entry where there is no change in state, and previous and new values are stored with the same value. +- An `insert` would register a new `Entry` where the `new_value` would be the element being inserted, and the `previous_value` the last element inserted before this. In case it is the first entry for a certain key, then the previous value will be zero. + +The use of this entry list shows how there isn't any rewriting, just the creation of new memory cells per `Felt252Dict` interaction. Let's show an example of this using the `balances` dictionary from the previous section and inserting the users 'Alex' and 'Maria': + +```rust +{{#rustdoc_include ../listings/ch02-99-common-collections/no_listing_09_entries/src/lib.cairo:inserts}} +``` + +These instructions would then produce the following list of entries: + +| key | previous | new | +| :---: | -------- | --- | +| Alex | 0 | 100 | +| Maria | 0 | 50 | +| Alex | 100 | 200 | +| Maria | 50 | 50 | + +Notice that since 'Alex' was inserted twice, it appears twice and the `previous` and `current` values are set properly. Also reading from 'Maria' registered an entry with no change from previous to current values. + +This approach to implementing `Felt252Dict` means that for each read/write operation, there is a scan for the whole entry list in search of the last entry with the same `key`. Once the entry has been found, its `new_value` is extracted and used on the new entry to be added as the `previous_value`. This means that interacting with `Felt252Dict` has a worst-case time complexity of `O(n)` where `n` is the number of entries in the list. + +If you pour some thought into alternate ways of implementing `Felt252Dict` you'd surely find them, probably even ditching completely the need for a `previous_value` field, nonetheless, since Cairo is not your normal language this won't work. +One of the purposes of Cairo is, with the STARK proof system, to generate proofs of computational integrity. This means that you need to verify that program execution is correct and inside the boundaries of Cairo restrictions. One of those boundary checks consists of "dictionary squashing" and that requires information on both previous and new values for every entry. + +### Squashing Dictionaries + +To verify that the proof generated by a Cairo program execution that used a `Felt252Dict` is correct we need to check that there wasn't any illegal tampering with the dictionary. This is done through a method called `squash_dict` that reviews each entry of the entry list and checks that access to the dictionary remains coherent throughout the execution. + +The process of squashing is as follows: given all entries with certain key `k`, taken in the same order as they were inserted, verify that the ith entry `new_value` is equal to the ith + 1 entry `previous_value`. + +For example, given the following entry list: + +| key | previous | new | +| :-----: | -------- | --- | +| Alex | 0 | 150 | +| Maria | 0 | 100 | +| Charles | 0 | 70 | +| Maria | 100 | 250 | +| Alex | 150 | 40 | +| Alex | 40 | 300 | +| Maria | 250 | 190 | +| Alex | 300 | 90 | + +After squashing, the entry list would be reduced to: + +| key | previous | new | +| :-----: | -------- | --- | +| Alex | 0 | 90 | +| Maria | 0 | 190 | +| Charles | 0 | 70 | + +In case of a change on any of the values of the first table, squashing would have failed during runtime. + +### Dictionary Destruction + +If you run the examples from [Basic Use of Dictionaries](#basic-use-of-dictionaries) you'd notice that there was never a call to squash dictionary, but the program compiled successfully nonetheless. What happened behind the scene was that squash was called automatically via the `Felt252Dict` implementation of the `Destruct` trait. This call occurred just before the `balance` dictionary went out of scope. + +The `Destruct` trait represents another way of removing instances out of scope apart from `Drop`. The main difference between these two is that `Drop` is treated as a no-op operation, meaning it does not generate new CASM while `Destruct` does not have this restriction. The only type which actively uses the `Destruct` trait is `Felt252Dict`, for every other type `Destruct` and `Drop` are synonyms. You can read more about these traits in [Drop and Destruct](/appendix-03-derivable-traits.md#drop-and-destruct). + +Later in [Dictionaries as Struct Members](#dictionaries-as-struct-members), we will have a hands-on example where we implement the `Destruct` trait for a custom type. + +### More Dictionaries + +Up to this point, we have given a comprehensive overview of the functionality of `Felt252Dict` as well as how and why it is implemented in a certain way. If you haven't understood all of it, don't worry because in this section we will have some more examples using dictionaries. + +We will start by explaining the `entry` method which is part of a dictionary basic functionality included in `Felt252DictTrait` which we didn't mention at the beginning. Soon after, we will see examples of how `Felt252Dict` [interacts](#dictionaries-of-complex-types) with other complex types such as `Array` and how to [implement](#dictionaries-as-struct-members) a struct with a dictionary as a member. + +### Entry and Finalize + +In the [Dictionaries Underneath](#dictionaries-underneath) section, we explained how `Felt252Dict` internally worked. It was a list of entries for each time the dictionary was accessed in any manner. It would first find the last entry given a certain `key` and then update it accordingly to whatever operation it was executing. The Cairo language gives us the tools to replicate this ourselves through the `entry` and `finalize` methods. + +The `entry` method comes as part of `Felt252DictTrait` with the purpose of creating a new entry given a certain key. Once called, this method takes ownership of the dictionary and returns the entry to update. The method signature is as follows: + +```rust,noplayground +fn entry(self: Felt252Dict, key: felt252) -> (Felt252DictEntry, T) nopanic +``` + +The first input parameter takes ownership of the dictionary while the second one is used to create the appropriate entry. It returns a tuple containing a `Felt252DictEntry`, which is the type used by Cairo to represent dictionary entries, and a `T` representing the value held previously. + +The next thing to do is to update the entry with the new value. For this, we use the `finalize` method which inserts the entry and returns ownership of the dictionary: + +```rust,noplayground +fn finalize(self: Felt252DictEntry, new_value: T) -> Felt252Dict { +``` + +This method receives the entry and the new value as a parameter and returns the updated dictionary. + +Let us see an example using `entry` and `finalize`. Imagine we would like to implement our own version of the `get` method from a dictionary. We should then do the following: + +1. Create the new entry to add using the `entry` method +2. Insert back the entry where the `new_value` equals the `previous_value`. +3. Return the value. + +Implementing our custom get would look like this: + +```rust,noplayground +{{#include ../listings/ch02-99-common-collections/no_listing_10_custom_methods/src/lib.cairo:imports}} + +{{#include ../listings/ch02-99-common-collections/no_listing_10_custom_methods/src/lib.cairo:custom_get}} +``` + +Implementing the `insert` method would follow a similar workflow, except for inserting a new value when finalizing. If we were to implement it, it would look like the following: + +```rust,noplayground +{{#include ../listings/ch02-99-common-collections/no_listing_10_custom_methods/src/lib.cairo:imports}} + +{{#include ../listings/ch02-99-common-collections/no_listing_10_custom_methods/src/lib.cairo:custom_insert}} +``` + +As a finalizing note, these two methods are implemented in a similar way to how `insert` and `get` are implemented for `Felt252Dict`. This code shows some example usage: + +```rust +{{#rustdoc_include ../listings/ch02-99-common-collections/no_listing_10_custom_methods/src/lib.cairo:main}} +``` + +### Dictionaries of types not supported natively + +One restriction of `Felt252Dict` that we haven't talked about is the trait `Felt252DictValue`. +This trait defines the `zero_default` method which is the one that gets called when a value does not exist in the dictionary. +This is implemented by some common data types, such as most unsigned integers, `bool` and `felt252` - but it is not implemented for more complex ones types such as arrays, structs (including `u256`), and other types from the core library. +This means that making a dictionary of types not natively supported is not a straightforward task, because you would need to write a couple of trait implementations in order to make the data type a valid dictionary value type. +To compensate this, you can wrap your type inside a `Nullable`. + +`Nullable` is a smart pointer type that can either point to a value or be `null` in the absence of value. It is usually used in Object Oriented Programming Languages when a reference doesn't point anywhere. The difference with `Option` is that the wrapped value is stored inside a `Box` data type. The `Box` type, inspired by Rust, allows us to allocate a new memory segment for our type, and access this segment using a pointer that can only be manipulated in one place at a time. + +Let's show using an example. We will try to store a `Span` inside a dictionary. For that, we will use `Nullable` and `Box`. Also, we are storing a `Span` and not an `Array` because the latter does not implement the `Copy` trait which is required for reading from a dictionary. + +```rust,noplayground +{{#include ../listings/ch02-99-common-collections/no_listing_11_dict_of_complex/src/lib.cairo:imports}} + +{{#include ../listings/ch02-99-common-collections/no_listing_11_dict_of_complex/src/lib.cairo:header}} + +//... +``` + +In this code snippet, the first thing we did was to create a new dictionary `d`. We want it to hold a `Nullable`. After that, we created an array and filled it with values. + +The last step is inserting the array as a span inside the dictionary. Notice that we didn't do that directly, but instead, we took some steps in between: + +1. We wrapped the array inside a `Box` using the `new` method from `BoxTrait`. +2. We wrapped the `Box` inside a nullable using the `nullable_from_box` function. +3. Finally, we inserted the result. + +Once the element is inside the dictionary, and we want to get it, we follow the same steps but in reverse order. The following code shows how to achieve that: + +```rust,noplayground +//... + +{{#include ../listings/ch02-99-common-collections/no_listing_11_dict_of_complex/src/lib.cairo:footer}} +``` + +Here we: + +1. Read the value using `get`. +2. Verified it is non-null using the `match_nullable` function. +3. Unwrapped the value inside the box and asserted it was correct. + +The complete script would look like this: + +```rust +{{#include ../listings/ch02-99-common-collections/no_listing_11_dict_of_complex/src/lib.cairo:all}} +``` + +### Dictionaries as Struct Members + +Defining dictionaries as struct members is possible in Cairo but correctly interacting with them may not be entirely seamless. Let's try implementing a custom _user database_ that will allow us to add users and query them. We will need to define a struct to represent the new type and a trait to define its functionality: + +```rust,noplayground +{{#include ../listings/ch02-99-common-collections/no_listing_12_dict_struct_member/src/lib.cairo:struct}} + +{{#include ../listings/ch02-99-common-collections/no_listing_12_dict_struct_member/src/lib.cairo:trait}} +``` + +Our new type `UserDatabase` represents a database of users. It is generic over the balances of the users, giving major flexibility to whoever uses our data type. Its two members are: + +- `users_amount`, the number of users currently inserted and +- `balances`, a mapping of each user to its balance. + +The database core functionality is defined by `UserDatabaseTrait`. The following methods are defined: + +- `new` for easily creating new `UserDatabase` types. +- `add_user` to insert users in the database. +- `get_user` to find users in the database. + +The only remaining step is to implement each of the methods in `UserDatabaseTrait`, but since we are working with [generic types](/src/ch07-00-generic-types-and-traits.md) we also need to correctly establish the requirements of `T` so it can be a valid `Felt252Dict` value type: + +1. `T` should implement the `Copy` since it's required for getting values from a `Felt252Dict`. +2. All value types of a dictionary implement the `Felt252DictValue`, our generic type should do as well. +3. To insert values, `Felt252DictTrait` requires all value types to be destructible. + +The implementation, with all restriction in place, would be as follow: + +```rust,noplayground +{{#include ../listings/ch02-99-common-collections/no_listing_12_dict_struct_member/src/lib.cairo:imports}} + +{{#include ../listings/ch02-99-common-collections/no_listing_12_dict_struct_member/src/lib.cairo:impl}} +``` + +Our database implementation is almost complete, except for one thing: the compiler doesn't know how to make a `UserDatabase` go out of scope, since it doesn't implement the `Drop` trait, nor the `Destruct` trait. +Since it has a `Felt252Dict` as a member, it cannot be dropped, so we are forced to implement the `Destruct` trait manually (refer to the [Ownership](ch03-01-what-is-ownership.md#the-drop-trait) chapter for more information). +Using `#[derive(Destruct)]` on top of the `UserDatabase` definition won't work because of the use of [genericity](/src/ch07-00-generic-types-and-traits.md) in the struct definition. We need to code the `Destruct` trait implementation by ourselves: + +```rust,noplayground +{{#include ../listings/ch02-99-common-collections/no_listing_12_dict_struct_member/src/lib.cairo:destruct}} +``` + +Implementing `Destruct` for `UserDatabase` was our last step to get a fully functional database. We can now try it out: + +```rust +{{#rustdoc_include ../listings/ch02-99-common-collections/no_listing_12_dict_struct_member/src/lib.cairo:main}} +``` + +## Summary + +Well done! You finished this chapter on arrays and dictionaries in Cairo. These data structures may be a bit challenging to grasp, but they are really useful. + +When you’re ready to move on, we’ll talk about a concept that Cairo shares with Rust and that _doesn’t_ commonly exist in other programming languages: ownership. diff --git a/src/ch03-01-what-is-ownership.md b/src/ch03-01-what-is-ownership.md index 2a093e5ff..96d0d0146 100644 --- a/src/ch03-01-what-is-ownership.md +++ b/src/ch03-01-what-is-ownership.md @@ -27,7 +27,7 @@ As a first example of ownership, we’ll look at the _scope_ of some variables. scope is the range within a program for which an item is valid. Take the following variable: -```rust +```rust,noplayground let s = 'hello'; ``` @@ -37,7 +37,7 @@ which it’s declared until the end of the current _scope_. Listing 3-1 shows a program with comments annotating where the variable `s` would be valid. ```rust -{{#rustdoc_include ../listings/ch03-understanding-ownership/listing_03_01.cairo:here}} +{{#rustdoc_include ../listings/ch03-understanding-ownership/listing_03_01/src/lib.cairo:here}} ``` Listing 3-1: A variable and the scope in which it is @@ -65,7 +65,7 @@ is unknown at compile time and which can't be trivially copied? Here is a short reminder of what an array looks like: ```rust -{{#rustdoc_include ../listings/ch03-understanding-ownership/no_listing_01_array.cairo:3:5}} +{{#rustdoc_include ../listings/ch03-understanding-ownership/no_listing_01_array/src/lib.cairo:3:5}} ``` So, how does the ownership system ensure that each cell is never written to more than once? @@ -73,7 +73,7 @@ Consider the following code, where we try to pass the same instance of an array function calls: ```rust,does_not_compile -{{#include ../listings/ch03-understanding-ownership/no_listing_02_pass_array_by_value.cairo}} +{{#include ../listings/ch03-understanding-ownership/no_listing_02_pass_array_by_value/src/lib.cairo}} ``` In this case, we try to pass the same array instance `arr` by value to the functions `foo` and `bar`, which means @@ -86,7 +86,7 @@ system thus prevents us from using the same instance of `arr` in `foo`. Running the code above will result in a compile-time error: -```console +```shell error: Variable was previously moved. Trait has no implementation in context: core::traits::Copy::> --> array.cairo:6:9 let mut arr = ArrayTrait::::new(); @@ -100,7 +100,7 @@ You can implement the `Copy` trait on your type by adding the `#[derive(Copy)]` While Arrays and Dictionaries can't be copied, custom types that don't contain either of them can be. ```rust,ignore_format -{{#include ../listings/ch03-understanding-ownership/no_listing_03_copy_trait.cairo}} +{{#include ../listings/ch03-understanding-ownership/no_listing_03_copy_trait/src/lib.cairo}} ``` In this example, we can pass `p1` twice to the foo function because the `Point` type implements the `Copy` trait. This means that when we pass `p1` to `foo`, we are actually passing a copy of `p1`, and the ownership of `p1` remains with the main function. @@ -114,7 +114,7 @@ You may have noticed that the `Point` type in the previous example also implemen For example, the following code will not compile, because the struct `A` is not moved before it goes out of scope: ```rust,does_not_compile -{{#include ../listings/ch03-understanding-ownership/no_listing_04_no_drop_derive_fails.cairo}} +{{#include ../listings/ch03-understanding-ownership/no_listing_04_no_drop_derive_fails/src/lib.cairo}} ``` This is to ensure the soundness of Cairo programs. Soundness refers to the fact that if a @@ -132,7 +132,7 @@ The `Drop` implementation can be derived for all types, allowing them to be drop For example, the following code compiles: ```rust -{{#include ../listings/ch03-understanding-ownership/no_listing_05_drop_derive_compiles.cairo}} +{{#include ../listings/ch03-understanding-ownership/no_listing_05_drop_derive_compiles/src/lib.cairo}} ``` ### The `Destruct` Trait @@ -142,12 +142,12 @@ Manually calling the `squash` method on a dictionary is not very convenient, and Consider the following example, in which we define a custom type that contains a dictionary: ```rust,does_not_compile -{{#include ../listings/ch03-understanding-ownership/no_listing_06_no_destruct_compile_fails.cairo}} +{{#include ../listings/ch03-understanding-ownership/no_listing_06_no_destruct_compile_fails/src/lib.cairo}} ``` If you try to run this code, you will get a compile-time error: -```console +```shell error: Variable not dropped. Trait has no implementation in context: core::traits::Drop::. Trait has no implementation in context: core::traits::Destruct::. --> temp7.cairo:7:5 A { @@ -157,7 +157,7 @@ error: Variable not dropped. Trait has no implementation in context: core::trait When A goes out of scope, it can't be dropped as it implements neither the `Drop` (as it contains a dictionary and can't `derive(Drop)`) nor the `Destruct` trait. To fix this, we can derive the `Destruct` trait implementation for the `A` type: ```rust -{{#include ../listings/ch03-understanding-ownership/no_listing_07_destruct_compiles.cairo}} +{{#include ../listings/ch03-understanding-ownership/no_listing_07_destruct_compiles/src/lib.cairo}} ``` Now, when `A` goes out of scope, its dictionary will be automatically `squashed`, and the program will compile. @@ -172,10 +172,10 @@ Here’s an example of the `clone` method in action. > Note: in the following example, we need to import the `Clone` trait from the corelib `clone` module, and its implementation for the array type from the `array` module. ```rust -{{#include ../listings/ch03-understanding-ownership/no_listing_08_array_clone.cairo}} +{{#include ../listings/ch03-understanding-ownership/no_listing_08_array_clone/src/lib.cairo}} ``` -> Note: you will need to run `cairo-run` with the `--available-gas=2000000` option to run this example, because it uses a loop and must be ran with a gas limit. +> Note: you will need to run `scarb cairo-run` with the `--available-gas=2000000` option to run this example, because it uses a loop and must be ran with a gas limit. When you see a call to `clone`, you know that some arbitrary code is being executed and that code may be expensive. It’s a visual indicator that something @@ -188,10 +188,10 @@ Passing a variable to a function will either move it or copy it. As seen in the Listing 3-3 has an example with some annotations showing where variables go into and out of scope. -Filename: src/main.cairo +Filename: src/lib.cairo -```rust,ignore_format -{{#include ../listings/ch03-understanding-ownership/listing_03_03.cairo}} +```rust +{{#include ../listings/ch03-understanding-ownership/listing_03_03/src/lib.cairo}} ``` Listing 3-3: Functions with ownership and scope @@ -208,10 +208,10 @@ Returning values can also transfer ownership. Listing 3-4 shows an example of a function that returns some value, with similar annotations as those in Listing 4-3. -Filename: src/main.cairo +Filename: src/lib.cairo -```rust,ignore_format -{{#include ../listings/ch03-understanding-ownership/listing_03_04.cairo}} +```rust +{{#include ../listings/ch03-understanding-ownership/listing_03_04/src/lib.cairo}} ``` Listing 3-4: Transferring ownership of return @@ -227,10 +227,10 @@ from the body of the function that we might want to return as well. Cairo does let us return multiple values using a tuple, as shown in Listing 3-5. -Filename: src/main.cairo +Filename: src/lib.cairo ```rust -{{#include ../listings/ch03-understanding-ownership/listing_03_05.cairo}} +{{#include ../listings/ch03-understanding-ownership/listing_03_05/src/lib.cairo}} ``` Listing 3-5: Returning ownership of parameters diff --git a/src/ch03-02-references-and-snapshots.md b/src/ch03-02-references-and-snapshots.md index 62a2053c3..f01d99378 100644 --- a/src/ch03-02-references-and-snapshots.md +++ b/src/ch03-02-references-and-snapshots.md @@ -22,15 +22,15 @@ the `calculate_length` function will not mutate the array, and ownership of the Filename: src/lib.cairo -```rust,ignore_format -{{#include ../listings/ch03-understanding-ownership/no_listing_09_snapshots.cairo}} +```rust +{{#include ../listings/ch03-understanding-ownership/no_listing_09_snapshots/src/lib.cairo}} ``` > Note: It is only possible to call the `len()` method on an array snapshot because it is defined as such in the `ArrayTrait` trait. If you try to call a method that is not defined for snapshots on a snapshot, you will get a compilation error. However, you can call methods expecting a snapshot on non-snapshot types. The output of this program is: -```console +```shell [DEBUG] (raw: 0) [DEBUG] (raw: 1) @@ -44,14 +44,14 @@ that we pass `@arr1` into `calculate_length` and, in its definition, we take `@A Let’s take a closer look at the function call here: ```rust -{{#rustdoc_include ../listings/ch03-understanding-ownership/no_listing_09_snapshots.cairo:11}} +{{#rustdoc_include ../listings/ch03-understanding-ownership/no_listing_09_snapshots/src/lib.cairo:11}} ``` The `@arr1` syntax lets us create a snapshot of the value in `arr1`. Because a snapshot is an immutable view of a value, the value it points to cannot be modified through the snapshot, and the value it refers to will not be dropped once the snapshot stops being used. Similarly, the signature of the function uses `@` to indicate that the type of the parameter `arr` is a snapshot. Let’s add some explanatory annotations: -```rust +```rust, noplayground fn calculate_length( array_snapshot: @Array ) -> usize { // array_snapshot is a snapshot of an Array @@ -62,12 +62,16 @@ fn calculate_length( The scope in which the variable `array_snapshot` is valid is the same as any function parameter’s scope, but the underlying value of the snapshot is not dropped when `array_snapshot` stops being used. When functions have snapshots as parameters instead of the actual values, we won’t need to return the values in order to give back ownership of the original value, because we never had it. -Snapshots can be converted back into regular values using the `desnap` operator `*`, as long as the value type is copyable (which is not the case for Arrays, as they don't implement `Copy`). In the following example, we want to calculate the area of a rectangle, but we don't want to take ownership of the rectangle in the `calculate_area` function, because we might want to use the rectangle again after the function call. Since our function doesn't mutate the rectangle instance, we can pass the snapshot of the rectangle to the function, and then transform the snapshots back into values using the `desnap` operator `*`. +#### Desnap Operator + +To convert a snapshot back into a regular value, you can use the `desnap` operator `*`, which serves as the opposite of the `@` operator: the snapshot value is copied to a new variable. + +It's important to note that during this conversion process, the value it points to is copied into a new variable. This enables multiple uses of the underlying value without concerns about ownership transfers. This also means that the value pointed to by the snapshot must be copyable (which is not the case for Arrays, as they don't implement `Copy`). -The snapshot type is always copyable and droppable, so that you can use it multiple times without worrying about ownership transfers. +In the following example, we want to calculate the area of a rectangle, but we don't want to take ownership of the rectangle in the `calculate_area` function, because we might want to use the rectangle again after the function call. Since our function doesn't mutate the rectangle instance, we can pass the snapshot of the rectangle to the function, and then transform the snapshots back into values using the `desnap` operator `*`. ```rust -{{#include ../listings/ch03-understanding-ownership/no_listing_10_desnap.cairo}} +{{#include ../listings/ch03-understanding-ownership/no_listing_10_desnap/src/lib.cairo}} ``` But, what happens if we try to modify something we’re passing as snapshot? Try the code in @@ -76,14 +80,14 @@ Listing 3-6. Spoiler alert: it doesn’t work! Filename: src/lib.cairo ```rust,does_not_compile -{{#include ../listings/ch03-understanding-ownership/listing_03_06.cairo}} +{{#include ../listings/ch03-understanding-ownership/listing_03_06/src/lib.cairo}} ``` Listing 3-6: Attempting to modify a snapshot value Here’s the error: -```console +```shell error: Invalid left-hand side of assignment. --> ownership.cairo:15:5 rec.height = rec.width; @@ -102,7 +106,7 @@ In Cairo, a parameter can be passed as _mutable reference_ using the `ref` modif In Listing 3-7, we use a mutable reference to modify the value of the `height` and `width` fields of the `Rectangle` instance in the `flip` function. ```rust -{{#include ../listings/ch03-understanding-ownership/listing_03_07.cairo}} +{{#include ../listings/ch03-understanding-ownership/listing_03_07/src/lib.cairo}} ``` Listing 3-7: Use of a mutable reference to modify a value @@ -111,7 +115,7 @@ First, we change `rec` to be `mut`. Then we pass a mutable reference of `rec` in The output of the program is: -```console +```shell [DEBUG] (raw: 10) diff --git a/src/ch04-01-defining-and-instantiating-structs.md b/src/ch04-01-defining-and-instantiating-structs.md index 515ac1fab..8ebd3fb67 100644 --- a/src/ch04-01-defining-and-instantiating-structs.md +++ b/src/ch04-01-defining-and-instantiating-structs.md @@ -4,10 +4,10 @@ Structs are similar to tuples, discussed in [The Data Types](ch02-02-data-types. To define a struct, we enter the keyword `struct` and name the entire struct. A struct’s name should describe the significance of the pieces of data being grouped together. Then, inside curly brackets, we define the names and types of the pieces of data, which we call fields. For example, Listing 4-1 shows a struct that stores information about a user account. -Filename: structs.cairo +Filename: src/lib.cairo -```rust -{{#include ../listings/ch04-using-structs-to-structure-related-data/listing_04_01_user_struct.cairo:user}} +```rust, noplayground +{{#include ../listings/ch04-using-structs-to-structure-related-data/listing_04_01_user_struct/src/lib.cairo:user}} ``` Listing 4-1: A `User` struct definition @@ -17,20 +17,20 @@ We create an instance by stating the name of the struct and then add curly brack For example, we can declare a particular user as shown in Listing 4-2. -Filename: structs.cairo +Filename: src/lib.cairo ```rust -{{#include ../listings/ch04-using-structs-to-structure-related-data/listing_04_01_user_struct.cairo:all}} +{{#include ../listings/ch04-using-structs-to-structure-related-data/listing_04_01_user_struct/src/lib.cairo:all}} ``` Listing 4-2: Creating an instance of the `User` struct To get a specific value from a struct, we use dot notation. For example, to access this user’s email address, we use `user1.email`. If the instance is mutable, we can change a value by using the dot notation and assigning into a particular field. Listing 4-3 shows how to change the value in the `email` field of a mutable `User` instance. -Filename: structs.cairo +Filename: src/lib.cairo ```rust -{{#rustdoc_include ../listings/ch04-using-structs-to-structure-related-data/listing_04_03_mut_struct.cairo:main}} +{{#rustdoc_include ../listings/ch04-using-structs-to-structure-related-data/listing_04_03_mut_struct/src/lib.cairo:main}} ``` Listing 4-3: Changing the value in the email field of a `User` instance @@ -41,10 +41,10 @@ As with any expression, we can construct a new instance of the struct as the las Listing 4-4 shows a `build_user` function that returns a `User` instance with the given email and username. The `active` field gets the value of `true`, and the `sign_in_count` gets a value of `1`. -Filename: structs.cairo +Filename: src/lib.cairo ```rust -{{#rustdoc_include ../listings/ch04-using-structs-to-structure-related-data/listing_04_03_mut_struct.cairo:build_user}} +{{#rustdoc_include ../listings/ch04-using-structs-to-structure-related-data/listing_04_03_mut_struct/src/lib.cairo:build_user}} ``` Listing 4-4: A `build_user` function that takes an email and username and returns a `User` instance @@ -55,10 +55,10 @@ It makes sense to name the function parameters with the same name as the struct Because the parameter names and the struct field names are exactly the same in Listing 4-4, we can use the field init shorthand syntax to rewrite `build_user` so it behaves exactly the same but doesn’t have the repetition of `username` and `email`, as shown in Listing 4-5. -Filename: structs.cairo +Filename: src/lib.cairo ```rust -{{#rustdoc_include ../listings/ch04-using-structs-to-structure-related-data/listing_04_03_mut_struct.cairo:build_user2}} +{{#rustdoc_include ../listings/ch04-using-structs-to-structure-related-data/listing_04_03_mut_struct/src/lib.cairo:build_user2}} ``` Listing 4-5: A `build_user` function that uses field init shorthand because the `username` and `email` parameters have the same name as struct fields diff --git a/src/ch04-02-an-example-program-using-structs.md b/src/ch04-02-an-example-program-using-structs.md index 716f54cd5..01ee87a24 100644 --- a/src/ch04-02-an-example-program-using-structs.md +++ b/src/ch04-02-an-example-program-using-structs.md @@ -7,15 +7,15 @@ Let’s make a new project with Scarb called _rectangles_ that will take the wid Filename: src/lib.cairo ```rust -{{#include ../listings/ch04-using-structs-to-structure-related-data/listing_04_06_no_struct.cairo}} +{{#include ../listings/ch04-using-structs-to-structure-related-data/listing_04_06_no_struct/src/lib.cairo}} ``` Listing 4-6: Calculating the area of a rectangle specified by separate width and height variables -Now run the program with `cairo-run src/lib.cairo`: +Now run the program with `scarb cairo-run`: ```bash -$ cairo-run src/lib.cairo +$ scarb cairo-run [DEBUG] , (raw: 300) Run completed successfully, returning [] @@ -25,8 +25,8 @@ This code succeeds in figuring out the area of the rectangle by calling the `are The issue with this code is evident in the signature of `area`: -```rust -{{#include ../listings/ch04-using-structs-to-structure-related-data/listing_04_06_no_struct.cairo:9}} +```rust,noplayground +{{#include ../listings/ch04-using-structs-to-structure-related-data/listing_04_06_no_struct/src/lib.cairo:9}} ``` The `area` function is supposed to calculate the area of one rectangle, but the function we wrote has two parameters, and it’s not clear anywhere in our program that the parameters are related. It would be more readable and more manageable to group width and height together. We’ve already discussed one way we might do that in [Chapter 3](ch02-02-data-types.html#the-tuple-type): using tuples. @@ -38,7 +38,7 @@ Listing 4-7 shows another version of our program that uses tuples. Filename: src/lib.cairo ```rust -{{#include ../listings/ch04-using-structs-to-structure-related-data/listing_04_07_w_tuples.cairo}} +{{#include ../listings/ch04-using-structs-to-structure-related-data/listing_04_07_w_tuples/src/lib.cairo}} ``` Listing 4-7: Specifying the width and height of the rectangle with a tuple @@ -53,8 +53,8 @@ We use structs to add meaning by labeling the data. We can transform the tuple w Filename: src/lib.cairo -```rust,ignore_format -{{#include ../listings/ch04-using-structs-to-structure-related-data/listing_04_08_w_structs.cairo}} +```rust +{{#include ../listings/ch04-using-structs-to-structure-related-data/listing_04_08_w_structs/src/lib.cairo}} ``` Listing 4-8: Defining a `Rectangle` struct @@ -68,14 +68,14 @@ It’d be useful to be able to print an instance of `Rectangle` while we’re de Filename: src/lib.cairo ```rust -{{#include ../listings/ch04-using-structs-to-structure-related-data/listing_04_10_print_rectangle.cairo:0:11}} +{{#include ../listings/ch04-using-structs-to-structure-related-data/listing_04_10_print_rectangle/src/lib.cairo:0:11}} ``` Listing 4-9: Attempting to print a `Rectangle` instance When we compile this code, we get an error with this message: -```bash +```text $ cairo-compile src/lib.cairo error: Method `print` not found on type "../src::Rectangle". Did you import the correct trait and impl? --> lib.cairo:16:15 @@ -90,8 +90,8 @@ To learn more about traits, see [Traits in Cairo](ch07-02-traits-in-cairo.md). Filename: src/lib.cairo -```rust,ignore_format -{{#rustdoc_include ../listings/ch04-using-structs-to-structure-related-data/listing_04_10_print_rectangle.cairo}} +```rust +{{#rustdoc_include ../listings/ch04-using-structs-to-structure-related-data/listing_04_10_print_rectangle/src/lib.cairo}} ``` Listing 4-10: Implementing the `PrintTrait` trait on `Rectangle` diff --git a/src/ch04-03-method-syntax.md b/src/ch04-03-method-syntax.md index ebeb077a7..7228024eb 100644 --- a/src/ch04-03-method-syntax.md +++ b/src/ch04-03-method-syntax.md @@ -18,7 +18,7 @@ in Listing 4-13. Filename: src/lib.cairo ```rust -{{#include ../listings/ch04-using-structs-to-structure-related-data/listing_04_13_area_method.cairo}} +{{#include ../listings/ch04-using-structs-to-structure-related-data/listing_04_13_area_method/src/lib.cairo}} ``` Listing 4-13: Defining an `area` method to use on the @@ -72,7 +72,7 @@ fields. For example, we can define a method on `Rectangle` that is also named Filename: src/lib.cairo ```rust -{{#include ../listings/ch04-using-structs-to-structure-related-data/listing_04_14_width_method.cairo}} +{{#include ../listings/ch04-using-structs-to-structure-related-data/listing_04_14_width_method/src/lib.cairo}} ``` Here, we’re choosing to make the `width` method return `true` if the value in @@ -94,7 +94,7 @@ the program shown in Listing 4-14. Filename: src/lib.cairo ```rust,does_not_compile -{{#include ../listings/ch04-using-structs-to-structure-related-data/listing_04_15_can_hold.cairo:no_method}} +{{#include ../listings/ch04-using-structs-to-structure-related-data/listing_04_15_can_hold/src/lib.cairo:no_method}} ``` Listing 4-14: Using the as-yet-unwritten `can_hold` @@ -105,7 +105,7 @@ The expected output would look like the following because both dimensions of `rect1`: ```text -❯ cairo-run src/lib.cairo +$ scarb cairo-run [DEBUG] Can rec1 hold rect2? (raw: 384675147322001379018464490539350216396261044799) [DEBUG] true (raw: 1953658213) @@ -134,7 +134,7 @@ Listing 4-13, shown in Listing 4-15. Filename: src/lib.cairo ```rust -{{#include ../listings/ch04-using-structs-to-structure-related-data/listing_04_15_can_hold.cairo:trait_impl}} +{{#include ../listings/ch04-using-structs-to-structure-related-data/listing_04_15_can_hold/src/lib.cairo:trait_impl}} ``` Listing 4-15: Implementing the `can_hold` method on @@ -159,8 +159,8 @@ value twice: Filename: src/lib.cairo -```rust -{{#include ../listings/ch04-using-structs-to-structure-related-data/no_listing_01_implementation_functions.cairo:here}} +```rust,noplayground +{{#include ../listings/ch04-using-structs-to-structure-related-data/no_listing_01_implementation_functions/src/lib.cairo:here}} ``` To call this function, we use the `::` syntax with the implementation name; @@ -176,8 +176,8 @@ Each struct is allowed to have multiple `trait` and `impl` blocks. For example, 5-15 is equivalent to the code shown in Listing 4-16, which has each method in its own `trait` and `impl` blocks. -```rust -{{#include ../listings/ch04-using-structs-to-structure-related-data/no_listing_02_multiple_impls.cairo:here}} +```rust,noplayground +{{#include ../listings/ch04-using-structs-to-structure-related-data/no_listing_02_multiple_impls/src/lib.cairo:here}} ``` Listing 4-16: Rewriting Listing 4-15 using multiple `impl` diff --git a/src/ch05-01-enums.md b/src/ch05-01-enums.md index 7cb233cb6..82aaaa31e 100644 --- a/src/ch05-01-enums.md +++ b/src/ch05-01-enums.md @@ -6,14 +6,14 @@ Enums, short for "enumerations," are a way to define a custom data type that con Here's a simple example of an enum: -```rust -{{#include ../listings/ch05-enums-and-pattern-matching/no_listing_01_enum_example.cairo:enum_example}} +```rust,noplayground +{{#include ../listings/ch05-enums-and-pattern-matching/no_listing_01_enum_example/src/lib.cairo:enum_example}} ``` -Unlike other languages like Rust, every variant has a type. In this example, we've defined an enum called `Direction` with four variants: `North`, `East`, `South`, and `West`. The naming convention is to use PascalCase for enum variants. Each variant represents a distinct value of the Direction type and is associated with a unit type `()`. One variant can be instantiated using this syntax: +In this example, we've defined an enum called `Direction` with four variants: `North`, `East`, `South`, and `West`. The naming convention is to use PascalCase for enum variants. Each variant represents a distinct value of the Direction type. In this particular example, variants don't have any associated value. One variant can be instantiated using this syntax: ```rust -{{#rustdoc_include ../listings/ch05-enums-and-pattern-matching/no_listing_01_enum_example.cairo:here}} +{{#rustdoc_include ../listings/ch05-enums-and-pattern-matching/no_listing_01_enum_example/src/lib.cairo:here}} ``` It's easy to write code that acts differently depending on the variant of an enum instance, in this example to run specific code according to a Direction. You can learn more about it on [The Match Control Flow Construct page](ch05-02-the-match-control-flow-construct.md). @@ -22,13 +22,13 @@ It's easy to write code that acts differently depending on the variant of an enu Enums can also be used to store more interesting data associated with each variant. For example: -```rust -{{#include ../listings/ch05-enums-and-pattern-matching/no_listing_02_enum_message.cairo:message}} +```rust,noplayground +{{#include ../listings/ch05-enums-and-pattern-matching/no_listing_02_enum_message/src/lib.cairo:message}} ``` In this example, the `Message` enum has three variants: `Quit`, `Echo` and `Move`, all with different types: -- `Quit` is the unit type - it has no data associated with it at all. +- `Quit` doesn't have any associated value. - `Echo` is a single felt. - `Move` is a tuple of two u128 values. @@ -38,14 +38,14 @@ You could even use a Struct or another Enum you defined inside one of your Enum In Cairo, you can define traits and implement them for your custom enums. This allows you to define methods and behaviors associated with the enum. Here's an example of defining a trait and implementing it for the previous `Message` enum: -```rs -{{#include ../listings/ch05-enums-and-pattern-matching/no_listing_02_enum_message.cairo:trait_impl}} +```rust,noplayground +{{#include ../listings/ch05-enums-and-pattern-matching/no_listing_02_enum_message/src/lib.cairo:trait_impl}} ``` In this example, we implemented the `Processing` trait for `Message`. Here is how it could be used to process a Quit message: ```rust -{{#rustdoc_include ../listings/ch05-enums-and-pattern-matching/no_listing_02_enum_message.cairo:main}} +{{#rustdoc_include ../listings/ch05-enums-and-pattern-matching/no_listing_02_enum_message/src/lib.cairo:main}} ``` Running this code would print `quitting`. @@ -54,7 +54,7 @@ Running this code would print `quitting`. The Option enum is a standard Cairo enum that represents the concept of an optional value. It has two variants: `Some: T` and `None: ()`. `Some: T ` indicates that there's a value of type `T`, while `None` represents the absence of a value. -```rust +```rust,noplayground enum Option { Some: T, None: (), @@ -72,8 +72,8 @@ We are demonstrating two approaches for the above function: > Note: in the future it would be nice to replace this example by something simpler using a loop and without gas related code. -```rust -{{#include ../listings/ch05-enums-and-pattern-matching/no_listing_03_enum_option.cairo}} +```rust,noplayground +{{#include ../listings/ch05-enums-and-pattern-matching/no_listing_03_enum_option/src/lib.cairo}} ``` diff --git a/src/ch05-02-the-match-control-flow-construct.md b/src/ch05-02-the-match-control-flow-construct.md index 656ecd17d..daab26de6 100644 --- a/src/ch05-02-the-match-control-flow-construct.md +++ b/src/ch05-02-the-match-control-flow-construct.md @@ -8,8 +8,8 @@ Think of a match expression as being like a coin-sorting machine: coins slide do Speaking of coins, let’s use them as an example using match! We can write a function that takes an unknown US coin and, in a similar way as the counting machine, determines which coin it is and returns its value in cents, as shown in Listing 5-3. -```rust -{{#include ../listings/ch05-enums-and-pattern-matching/listing_05_03.cairo:all}} +```rust,noplayground +{{#include ../listings/ch05-enums-and-pattern-matching/listing_05_03/src/lib.cairo:all}} ``` Listing 5-3: An enum and a match expression that has the variants of the enum as its patterns @@ -26,8 +26,8 @@ The code associated with each arm is an expression, and the resultant value of t We don’t typically use curly brackets if the match arm code is short, as it is in our example where each arm just returns a value. If you want to run multiple lines of code in a match arm, you must use curly brackets, with a comma following the arm. For example, the following code prints “Lucky penny!” every time the method is called with a `Coin::Penny(())`, but still returns the last value of the block, `1`: -```rust -{{#include ../listings/ch05-enums-and-pattern-matching/no_listing_04_match_arms.cairo:here}} +```rust,noplayground +{{#include ../listings/ch05-enums-and-pattern-matching/no_listing_04_match_arms/src/lib.cairo:here}} ``` ## Patterns That Bind to Values @@ -36,8 +36,8 @@ Another useful feature of match arms is that they can bind to the parts of the v As an example, let’s change one of our enum variants to hold data inside it. From 1999 through 2008, the United States minted quarters with different designs for each of the 50 states on one side. No other coins got state designs, so only quarters have this extra value. We can add this information to our `enum` by changing the `Quarter` variant to include a `UsState` value stored inside it, which we’ve done in Listing 5-4. -```rust -{{#include ../listings/ch05-enums-and-pattern-matching/listing_05_04.cairo}} +```rust,noplayground +{{#include ../listings/ch05-enums-and-pattern-matching/listing_05_04/src/lib.cairo}} ``` Listing 5-4: A `Coin` enum in which the `Quarter` variant also holds a `UsState` value @@ -46,14 +46,14 @@ Let’s imagine that a friend is trying to collect all 50 state quarters. While In the match expression for this code, we add a variable called `state` to the pattern that matches values of the variant `Coin::Quarter`. When a `Coin::Quarter` matches, the `state` variable will bind to the value of that quarter’s state. Then we can use `state` in the code for that arm, like so: -```rust -{{#include ../listings/ch05-enums-and-pattern-matching/no_listing_05_print_enum.cairo:function}} +```rust,noplayground +{{#include ../listings/ch05-enums-and-pattern-matching/no_listing_05_print_enum/src/lib.cairo:function}} ``` To print the value of a variant of an enum in Cairo, we need to add an implementation for the `print` function for the `debug::PrintTrait`: -```rust -{{#include ../listings/ch05-enums-and-pattern-matching/no_listing_05_print_enum.cairo:print_impl}} +```rust,noplayground +{{#include ../listings/ch05-enums-and-pattern-matching/no_listing_05_print_enum/src/lib.cairo:print_impl}} ``` If we were to call `value_in_cents(Coin::Quarter(UsState::Alaska(())))`, `coin` would be `Coin::Quarter(UsState::Alaska())`. When we compare that value with each of the match arms, none of them match until we reach `Coin::Quarter(state)`. At that point, the binding for state will be the value `UsState::Alaska()`. We can then use that binding in the `PrintTrait`, thus getting the inner state value out of the `Coin` enum variant for `Quarter`. @@ -67,14 +67,15 @@ Let’s say we want to write a function that takes an `Option` and, if there This function is very easy to write, thanks to match, and will look like Listing 5-5. ```rust -{{#include ../listings/ch05-enums-and-pattern-matching/listing_05_05.cairo}} +{{#include ../listings/ch05-enums-and-pattern-matching/listing_05_05/src/lib.cairo}} ``` -Listing 5-5: A function that uses a match expression on an `Option` +Listing 5-5: A function that uses a match +expression on an `Option` Note that your arms must respect the same order as the enum defined in the `OptionTrait` of the core Cairo lib. -```rust +```rust,noplayground enum Option { Some: T, None: (), @@ -83,22 +84,22 @@ enum Option { Let’s examine the first execution of `plus_one` in more detail. When we call `plus_one(five)`, the variable `x` in the body of `plus_one` will have the value `Some(5)`. We then compare that against each match arm: -```rust -{{#include ../listings/ch05-enums-and-pattern-matching/listing_05_05.cairo:6}} +```rust,noplayground +{{#include ../listings/ch05-enums-and-pattern-matching/listing_05_05/src/lib.cairo:6}} ``` Does `Option::Some(5)` value match the pattern `Option::Some(val)`? It does! We have the same variant. The `val` binds to the value contained in `Option::Some`, so `val` takes the value `5`. The code in the match arm is then executed, so we add `1` to the value of `val` and create a new `Option::Some` value with our total `6` inside. Because the first arm matched, no other arms are compared. Now let’s consider the second call of `plus_one` in our main function, where `x` is `Option::None(())`. We enter the match and compare to the first arm: -```rust -{{#include ../listings/ch05-enums-and-pattern-matching/listing_05_05.cairo:6}} +```rust,noplayground +{{#include ../listings/ch05-enums-and-pattern-matching/listing_05_05/src/lib.cairo:6}} ``` The `Option::Some(val)` value doesn’t match the pattern `Option::None`, so we continue to the next arm: ```rust -{{#include ../listings/ch05-enums-and-pattern-matching/listing_05_05.cairo:7}} +{{#include ../listings/ch05-enums-and-pattern-matching/listing_05_05/src/lib.cairo:7}} ``` It matches! There’s no value to add to, so the program stops and returns the `Option::None(())` value on the right side of `=>`. @@ -109,8 +110,12 @@ Combining `match` and enums is useful in many situations. You’ll see this patt There’s one other aspect of match we need to discuss: the arms’ patterns must cover all possibilities. Consider this version of our `plus_one` function, which has a bug and won’t compile: +```rust,noplayground +{{#include ../listings/ch05-enums-and-pattern-matching/no_listing_07_missing_match_arm/src/lib.cairo:here}} +``` + ```bash -$ cairo-run src/test.cairo +$ scarb cairo-run error: Unsupported match. Currently, matches require one arm per variant, in the order of variant definition. --> test.cairo:34:5 @@ -127,8 +132,8 @@ Using enums, we can also take special actions for a few particular values, but f Imagine we’re implementing a game where, you get a random number between 0 and 7. If you have 0, you win. For all other values you lose. Here's a match that implements that logic, with the number hardcoded rather than a random value. -```rust -{{#include ../listings/ch05-enums-and-pattern-matching/no_listing_06_match_zero.cairo:here}} +```rust,noplayground +{{#include ../listings/ch05-enums-and-pattern-matching/no_listing_06_match_zero/src/lib.cairo:here}} ``` The first arm, the pattern is the literal values 0. For the last arm that covers every other possible value, the pattern is the character `_`. This code compiles, even though we haven’t listed all the possible values a `felt252` can have, because the last pattern will match all values not specifically listed. This catch-all pattern meets the requirement that `match` must be exhaustive. Note that we have to put the catch-all arm last because the patterns are evaluated in order. If we put the catch-all arm earlier, the other arms would never run, so Cairo will warn us if we add arms after a catch-all! diff --git a/src/ch06-01-packages-and-crates.md b/src/ch06-01-packages-and-crates.md index a66154a4f..75618feda 100644 --- a/src/ch06-01-packages-and-crates.md +++ b/src/ch06-01-packages-and-crates.md @@ -1,12 +1,15 @@ # Packages and Crates ## What is a crate? + A crate is the smallest amount of code that the Cairo compiler considers at a time. Even if you run `cairo-compile` rather than `scarb build` and pass a single source code file, the compiler considers that file to be a crate. Crates can contain modules, and the modules may be defined in other files that get compiled with the crate, as will be discussed in the subsequent sections. ## What is the crate root? + The crate root is the `lib.cairo` source file that the Cairo compiler starts from and makes up the root module of your crate (we’ll explain modules in depth in the [“Defining Modules to Control Scope”](./ch06-02-defining-modules-to-control-scope.md) section). ## What is a package? + A cairo package is a bundle of one or more crates with a Scarb.toml file that describes how to build those crates. This enables the splitting of code into smaller, reusable parts and facilitates more structured dependency management. ## Creating a Package with Scarb @@ -27,8 +30,8 @@ my_package/ ``` - `src/` is the main directory where all the Cairo source files for the package will be stored. -- `lib.cairo` is the default root module of the crate, which is also the main entry point of the package. By default, it is empty. -- `Scarb.toml` is the package manifest file, which contains metadata and configuration options for the package, such as dependencies, package name, version, and authors. You can find documentation about it on the [scarb reference](https://docs.swmansion.com/scarb/docs/reference/manifest). +- `lib.cairo` is the default root module of the crate, which is also the main entry point of the package. +- `Scarb.toml` is the package manifest file, which contains metadata and configuration options for the package, such as dependencies, package name, version, and authors. You can find documentation about it on the [scarb reference](https://docs.swmansion.com/scarb/docs/reference/manifest.html). ```toml [package] @@ -39,4 +42,4 @@ version = "0.1.0" # foo = { path = "vendor/foo" } ``` -As you develop your package, you may want to organize your code into multiple Cairo source files. You can do this by creating additional `.cairo` files within the `src` directory or its subdirectories. \ No newline at end of file +As you develop your package, you may want to organize your code into multiple Cairo source files. You can do this by creating additional `.cairo` files within the `src` directory or its subdirectories. diff --git a/src/ch06-02-defining-modules-to-control-scope.md b/src/ch06-02-defining-modules-to-control-scope.md index 06b39a15a..b0a2e5e66 100644 --- a/src/ch06-02-defining-modules-to-control-scope.md +++ b/src/ch06-02-defining-modules-to-control-scope.md @@ -24,14 +24,15 @@ work. You can create a new Scarb project with `scarb new backyard` to follow alo - Inline, within curly brackets that replace the semicolon following `mod garden;`. - ```rust - // crate root file (lib.cairo) + ```rust,noplayground + // crate root file (src/lib.cairo) mod garden { // code defining the garden module goes here } ``` -- In the file _src/garden.cairo_ + - In the file _src/garden.cairo_ + - **Declaring submodules**: In any file other than the crate root, you can declare submodules. For example, you might declare `mod vegetables;` in _src/garden.cairo_. The compiler will look for the submodule’s code within the @@ -40,7 +41,7 @@ work. You can create a new Scarb project with `scarb new backyard` to follow alo - Inline, directly following `mod vegetables`, within curly brackets instead of the semicolon. - ```rust + ```rust,noplayground // src/garden.cairo file mod vegetables { // code defining the vegetables submodule goes here @@ -65,7 +66,6 @@ crate’s directory, also named `backyard`, contains these files and directories ```text backyard/ ├── Scarb.toml -├── cairo_project.toml └── src ├── garden │   └── vegetables.cairo @@ -73,39 +73,27 @@ backyard/ └── lib.cairo ``` -> Note: You will notice here a `cairo_project.toml` file. -> This is the configuration file for "vanilla" Cairo projects (i.e. not managed by Scarb), -> which is required to run the `cairo-run .` command to run the code of the crate. -> It is required until Scarb implements this feature. The content of the file is: -> -> ```toml -> [crate_roots] -> backyard = "src" -> ``` -> -> and indicates that the crate named "backyard" is located in the `src` directory. - The crate root file in this case is _src/lib.cairo_, and it contains: Filename: src/lib.cairo ```rust -{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_01_lib.cairo}} +{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_01_lib/src/lib.cairo}} ``` The `mod garden;` line tells the compiler to include the code it finds in _src/garden.cairo_, which is: Filename: src/garden.cairo -```rust +```rust,noplayground mod vegetables; ``` Here, `mod vegetables;` means the code in _src/garden/vegetables.cairo_ is included too. That code is: -```rust -{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_02_garden.cairo}} +```rust,noplayground +{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/no_listing_02_garden/src/lib.cairo}} ``` The line `use garden::vegetables::Asparagus;` lets us use bring the `Asparagus` type into scope, @@ -134,8 +122,8 @@ define some modules and function signatures. Here’s the front of house section Filename: src/lib.cairo -```rust -{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_01.cairo}} +```rust,noplayground +{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_01/src/lib.cairo}} ``` Listing 6-1: A `front_of_house` module containing other diff --git a/src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md b/src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md index 573a2dffa..b8f6f2050 100644 --- a/src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md +++ b/src/ch06-03-paths-for-referring-to-an-item-in-the-module-tree.md @@ -14,8 +14,8 @@ To illustrate this notion let's take back our example Listing 6-1 for the restau Filename: src/lib.cairo -```rust -{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_03.cairo}} +```rust,noplayground +{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_03/src/lib.cairo}} ``` Listing 6-3: Calling the `add_to_waitlist` function using absolute and relative paths @@ -38,8 +38,8 @@ definition code separately from or together with the code that uses the item. Filename: src/lib.cairo -```rust -{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_04.cairo}} +```rust,noplayground +{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_04/src/lib.cairo}} ``` Listing 6-4: Calling a function using a relative path starting with super diff --git a/src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md b/src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md index 8bf83b7fa..9e3c75365 100644 --- a/src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md +++ b/src/ch06-04-bringing-paths-into-scope-with-the-use-keyword.md @@ -10,7 +10,7 @@ scope of the `eat_at_restaurant` function so we only have to specify Filename: src/lib.cairo ```rust -{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_05.cairo}} +{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_05/src/lib.cairo}} ``` Listing 6-5: Bringing a module into scope with @@ -25,7 +25,7 @@ statement, so the function body won’t compile: Filename: src/lib.cairo ```rust -{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_06.cairo}} +{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_06/src/lib.cairo}} ``` Listing 6-6: A `use` statement only applies in the scope @@ -34,7 +34,7 @@ it’s in The compiler error shows that the shortcut no longer applies within the `customer` module: -```console +```shell ❯ scarb build error: Identifier not found. --> lib.cairo:11:9 @@ -52,7 +52,7 @@ the `add_to_waitlist` function to achieve the same result, as in Listing 6-7. Filename: src/lib.cairo ```rust -{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_07.cairo}} +{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_07/src/lib.cairo}} ``` Listing 6-7: Bringing the `add_to_waitlist` function @@ -71,7 +71,7 @@ it’s idiomatic to specify the full path. Listing 6-8 shows the idiomatic way to bring the core library’s `ArrayTrait` trait into the scope. ```rust -{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_08.cairo}} +{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_08/src/lib.cairo}} ``` Listing 6-8: Bringing `ArrayTrait` into scope in an @@ -93,7 +93,7 @@ local name, or _alias_, for the type. Listing 6-9 shows how you can rename an im Filename: src/lib.cairo ```rust -{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_09.cairo}} +{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_09/src/lib.cairo}} ``` Listing 6-9: Renaming a trait when it’s brought into @@ -117,7 +117,7 @@ use module::{item1, item2, item3}; Here is an example where we import three structures from the same module: ```rust -{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_10.cairo}} +{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_10/src/lib.cairo}} ``` Listing 6-10: Importing multiple items from the same module @@ -134,7 +134,7 @@ For example, let's re-export the `add_to_waitlist` function in the restaurant ex Filename: src/lib.cairo ```rust -{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_11.cairo}} +{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_11/src/lib.cairo}} ``` Listing 6-11: Making a name available for any code to use @@ -159,4 +159,4 @@ the library and programmers calling the library. You might need to use external packages to leverage the functionality provided by the community. To use an external package in your project with Scarb, follow these steps: -> The dependencies system is still a work in progress. You can check the official [documentation](https://docs.swmansion.com/scarb/docs/guides/dependencies). +> The dependencies system is still a work in progress. You can check the official [documentation](https://docs.swmansion.com/scarb/docs/guides/dependencies.html). diff --git a/src/ch06-05-separating-modules-into-different-files.md b/src/ch06-05-separating-modules-into-different-files.md index 356850950..06999a2e2 100644 --- a/src/ch06-05-separating-modules-into-different-files.md +++ b/src/ch06-05-separating-modules-into-different-files.md @@ -17,8 +17,8 @@ _src/front_of_house.cairo_ file in Listing 6-13. Filename: src/lib.cairo -```rust -{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_12.cairo}} +```rust,noplayground +{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_12/src/lib.cairo}} ``` Listing 6-12: Declaring the `front_of_house` module whose @@ -31,8 +31,8 @@ with the name `front_of_house`. Filename: src/front_of_house.cairo -```rust, -{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_13.cairo}} +```rust,noplayground +{{#include ../listings/ch06-managing-cairo-projects-with-packages-crates-and-modules/listing_06_13/src/lib.cairo}} ``` Listing 6-13: Definitions inside the `front_of_house` @@ -57,7 +57,7 @@ declaration of the `hosting` module: Filename: src/front_of_house.cairo -```rust +```rust,noplayground mod hosting; ``` @@ -66,7 +66,7 @@ contain the definitions made in the `hosting` module: Filename: src/front_of_house/hosting.cairo -```rust +```rust,noplayground fn add_to_waitlist() {} ``` diff --git a/src/ch07-01-generic-data-types.md b/src/ch07-01-generic-data-types.md index 72cdb5fe0..ba93c2af1 100644 --- a/src/ch07-01-generic-data-types.md +++ b/src/ch07-01-generic-data-types.md @@ -7,13 +7,13 @@ We use generics to create definitions for item declarations, such as structs and When defining a function that uses generics, we place the generics in the function signature, where we would usually specify the data types of the parameter and return value. For example, imagine we want to create a function which given two `Array` of items, will return the largest one. If we need to perform this operation for lists of different types, then we would have to redefine the function each time. Luckily we can implement the function once using generics and move on to other tasks. ```rust -{{#include ../listings/ch07-generic-types-and-traits/no_listing_01_missing_tdrop.cairo}} +{{#include ../listings/ch07-generic-types-and-traits/no_listing_01_missing_tdrop/src/lib.cairo}} ``` The `largest_list` function compares two lists of the same type and returns the one with more elements and drops the other. If you compile the previous code, you will notice that it will fail with an error saying that there are no traits defined for dropping an array of a generic type. This happens because the compiler has no way to guarantee that an `Array` is droppable when executing the `main` function. In order to drop an array of `T`, the compiler must first know how to drop `T`. This can be fixed by specifying in the function signature of `largest_list` that `T` must implement the drop trait. The correct function definition of `largest_list` is as follows: ```rust -{{#include ../listings/ch07-generic-types-and-traits/no_listing_02_with_tdrop.cairo}} +{{#rustdoc_include ../listings/ch07-generic-types-and-traits/no_listing_02_with_tdrop/src/lib.cairo}} ``` The new `largest_list` function includes in its definition the requirement that whatever generic type is placed there, it must be droppable. The `main` function remains unchanged, the compiler is smart enough to deduct which concrete type is being used and if it implements the `Drop` trait. @@ -25,15 +25,15 @@ When defining generic types, it is useful to have information about them. Knowin Imagine that we want, given a list of elements of some generic type `T`, find the smallest element among them. Initially, we know that for an element of type `T` to be comparable, it must implement the `PartialOrd` trait. The resulting function would be: ```rust -{{#include ../listings/ch07-generic-types-and-traits/no_listing_03_missing_tcopy.cairo}} +{{#include ../listings/ch07-generic-types-and-traits/no_listing_03_missing_tcopy/src/lib.cairo}} ``` The `smallest_element` function uses a generic type `T` that implements the `PartialOrd` trait, takes a snapshot of an `Array` as a parameter and returns a copy of the smallest element. Because the parameter is of type `@Array`, we no longer need to drop it at the end of the execution and so we don't require to implement the `Drop` trait for `T` as well. Why it does not compile then? When indexing on `list`, the value results in a snap of the indexed element, unless `PartialOrd` is implemented for `@T` we need to desnap the element using `*`. The `*` operation requires a copy from `@T` to`T`, which means that `T` needs to implement the `Copy` trait. After copying an element of type `@T` to `T`, there are now variables with type `T` that need to be dropped, requiring for `T` to implement the `Drop` trait as well. We must then add both `Drop` and `Copy` traits implementation for the function to be correct. After updating the`smallest_element` function the resulting code would be: -```rs -{{#include ../listings/ch07-generic-types-and-traits/no_listing_04_with_tcopy.cairo}} +```rust +{{#rustdoc_include ../listings/ch07-generic-types-and-traits/no_listing_04_with_tcopy/src/lib.cairo}} ``` ## Structs @@ -41,13 +41,13 @@ When indexing on `list`, the value results in a snap of the indexed element, unl We can also define structs to use a generic type parameter for one or more fields using the `<>` syntax, similar to function definitions. First we declare the name of the type parameter inside the angle brackets just after the name of the struct. Then we use the generic type in the struct definition where we would otherwise specify concrete data types. The next code example shows the definition `Wallet` which has a `balance` field of type `T`. ```rust -{{#include ../listings/ch07-generic-types-and-traits/no_listing_05_derive_generics.cairo}} +{{#include ../listings/ch07-generic-types-and-traits/no_listing_05_derive_generics/src/lib.cairo}} ``` The above code derives the `Drop` trait for the `Wallet` type automatically. It is equivalent to writing the following code: ```rust -{{#include ../listings/ch07-generic-types-and-traits/no_listing_06_drop_explicit.cairo}} +{{#include ../listings/ch07-generic-types-and-traits/no_listing_06_drop_explicit/src/lib.cairo}} ``` We avoid using the `derive` macro for `Drop` implementation of `Wallet` and instead define our own `WalletDrop` implementation. Notice that we must define, just like functions, an additional generic type for `WalletDrop` saying that `T` implements the `Drop` trait as well. We are basically saying that the struct `Wallet` is droppable as long as `T` is also droppable. @@ -55,7 +55,7 @@ We avoid using the `derive` macro for `Drop` implementation of `Wallet` and inst Finally, if we want to add a field to `Wallet` representing its address and we want that field to be different than `T` but generic as well, we can simply add another generic type between the `<>`: ```rust -{{#include ../listings/ch07-generic-types-and-traits/no_listing_07_two_generics.cairo}} +{{#include ../listings/ch07-generic-types-and-traits/no_listing_07_two_generics/src/lib.cairo}} ``` We add to `Wallet` struct definition a new generic type `U` and then assign this type to the new field member `address`. Notice that the derive attribute for the `Drop` trait works for `U` as well. @@ -64,16 +64,16 @@ We add to `Wallet` struct definition a new generic type `U` and then assign this As we did with structs, we can define enums to hold generic data types in their variants. For example the `Option` enum provided by the Cairo core library: -```rust -{{#include ../listings/ch07-generic-types-and-traits/no_listing_08_option.cairo}} +```rust,noplayground +{{#include ../listings/ch07-generic-types-and-traits/no_listing_08_option/src/lib.cairo}} ``` The `Option` enum is generic over a type `T` and has two variants: `Some`, which holds one value of type `T` and `None` that doesn't hold any value. By using the `Option` enum, it is possible for us to express the abstract concept of an optional value and because the value has a generic type `T` we can use this abstraction with any type. Enums can use multiple generic types as well, like definition of the `Result` enum that the core library provides: -```rust -{{#include ../listings/ch07-generic-types-and-traits/no_listing_09_result.cairo}} +```rust,noplayground +{{#include ../listings/ch07-generic-types-and-traits/no_listing_09_result/src/lib.cairo}} ``` The `Result` enum has two generic types, `T` and `E`, and two variants: `Ok` which holds the value of type `T` and `Err` which holds the value of type `E`. This definition makes it convenient to use the `Result` enum anywhere we have an operation that might succeed (by returning a value of type `T`) or fail (by returning a value of type `E`). @@ -83,7 +83,7 @@ The `Result` enum has two generic types, `T` and `E`, and two variants: `O We can implement methods on structs and enums, and use the generic types in their definition, too. Using our previous definition of `Wallet` struct, we define a `balance` method for it: ```rust -{{#include ../listings/ch07-generic-types-and-traits/no_listing_10_generic_methods.cairo}} +{{#include ../listings/ch07-generic-types-and-traits/no_listing_10_generic_methods/src/lib.cairo}} ``` We first define `WalletTrait` trait using a generic type `T` which defines a method that returns a snapshot of the field `address` from `Wallet`. Then we give an implementation for the trait in `WalletImpl`. Note that you need to include a generic type in both definitions of the trait and the implementation. @@ -91,34 +91,34 @@ We first define `WalletTrait` trait using a generic type `T` which defines a We can also specify constraints on generic types when defining methods on the type. We could, for example, implement methods only for `Wallet` instances rather than `Wallet`. In the code example we define an implementation for wallets which have a concrete type of `u128` for the `balance` field. ```rust -{{#include ../listings/ch07-generic-types-and-traits/no_listing_11_constrained_generics.cairo}} +{{#include ../listings/ch07-generic-types-and-traits/no_listing_11_constrained_generics/src/lib.cairo}} ``` The new method `receive` increments the size of the balance of any instance of a `Wallet`. Notice that we changed the `main` function making `w` a mutable variable in order for it to be able to update its balance. If we were to change the initialization of `w` by changing the type of `balance` the previous code wouldn't compile. Cairo allows us to define generic methods inside generic traits as well. Using the past implementation from `Wallet` we are going to define a trait that picks two wallets of different generic types and create a new one with a generic type of each. First, let's rewrite the struct definition: -```rust -{{#include ../listings/ch07-generic-types-and-traits/no_listing_12_not_compiling.cairo:1:4}} +```rust,noplayground +{{#include ../listings/ch07-generic-types-and-traits/no_listing_12_not_compiling/src/lib.cairo:1:4}} ``` Next we are going to naively define the mixup trait and implementation: -```rust -{{#include ../listings/ch07-generic-types-and-traits/no_listing_12_not_compiling.cairo:6:15}} +```rust,noplayground +{{#include ../listings/ch07-generic-types-and-traits/no_listing_12_not_compiling/src/lib.cairo:6:15}} ``` We are creating a trait `WalletMixTrait` with the `mixup` methods which given an instance of `Wallet` and `Wallet` creates a new `Wallet`. As `mixup` signature specify, both `self` and `other` are getting dropped at the end of the function, which is the reason for this code not to compile. If you have been following from the start until now you would know that we must add a requirement for all the generic types specifying that they will implement the `Drop` trait in order for the compiler to know how to drop instances of `Wallet`. The updated implementation is as follow: ```rust -{{#include ../listings/ch07-generic-types-and-traits/no_listing_13_compiling.cairo:trait_impl}} +{{#include ../listings/ch07-generic-types-and-traits/no_listing_13_compiling/src/lib.cairo:trait_impl}} ``` We add the requirements for `T1` and `U1` to be droppable on `WalletMixImpl` declaration. Then we do the same for `T2` and `U2`, this time as part of `mixup` signature. We can now try the `mixup` function: -```rust -{{#include ../listings/ch07-generic-types-and-traits/no_listing_13_compiling.cairo:main}} +```rust,noplayground +{{#include ../listings/ch07-generic-types-and-traits/no_listing_13_compiling/src/lib.cairo:main}} ``` We first create two instances: one of `Wallet` and the other of `Wallet`. Then, we call `mixup` and create a new `Wallet` instance. diff --git a/src/ch07-02-traits-in-cairo.md b/src/ch07-02-traits-in-cairo.md index dc294341f..c64cc1543 100644 --- a/src/ch07-02-traits-in-cairo.md +++ b/src/ch07-02-traits-in-cairo.md @@ -8,11 +8,8 @@ To define a trait, you use the keyword `trait` followed by the name of the trait For example, let's say that we have multiple structs representing shapes. We want our application to be able to perform geometry operations on these shapes, So we define a trait `ShapeGeometry` that contains a blueprint to implement geometry operations on a shape like this: -```rust -trait ShapeGeometry { - fn boundary(self: Rectangle) -> u64; - fn area(self: Rectangle) -> u64; -} +```rust,noplayground +{{#include ../listings/ch07-generic-types-and-traits/no_listing_14_traits/src/lib.cairo:trait}} ``` Here our trait `ShapeGeometry` declares signatures for two methods `boundary` and `area`. When implemented, both these functions should return a `u64` and accept parameters as specified by the trait. @@ -21,19 +18,22 @@ Here our trait `ShapeGeometry` declares signatures for two methods `boundary` an A trait can be implemented using `impl` keyword with the name of your implementation followed by `of` then the name of trait being implemented. Here's an example implementing `ShapeGeometry` trait. -```rust -impl RectangleGeometry of ShapeGeometry { - fn boundary(self: Rectangle) -> u64 { - 2 * (self.height + self.width) - } - fn area(self: Rectangle) -> u64 { - self.height * self.width - } -} +```rust,noplayground +{{#include ../listings/ch07-generic-types-and-traits/no_listing_14_traits/src/lib.cairo:impl}} ``` In the code above, `RectangleGeometry` implements the trait `ShapeGeometry` defining what the methods `boundary` and `area` should do. Note that the function parameters and return value types are identical to the trait specification. +## Implementing a trait, without writing its declaration. + +You can write implementations directly without definining the corresponding trait. This is made possible by using the `#[generate_trait]` attribute with on the implementation, which will make the compiler generate the trait corresponding to the implementation automatically. Remember to add `Trait` as a suffix to your trait name, as the compiler will create the trait by adding a `Trait` suffix to the implementation name. + +```rust,noplayground +{{#include ../listings/ch07-generic-types-and-traits/no_listing_15_generate_trait/src/lib.cairo}} +``` + +In the aforementioned code, there is no need to manually define the trait. The compiler will automatically handle its definition, dynamically generating and updating it as new functions are introduced. + ## Parameter `self` In the example above, `self` is a special parameter. When a parameter with name `self` is used, the implemented functions are also [attached to the instances of the type as methods](ch04-03-method-syntax.md#defining-methods). Here's an illustration, @@ -41,15 +41,7 @@ In the example above, `self` is a special parameter. When a parameter with name When the `ShapeGeometry` trait is implemented, the function `area` from the `ShapeGeometry` trait can be called in two ways: ```rust -let rect = Rectangle { ... }; // Rectangle instantiation - -// First way, as a method on the struct instance -let area1 = rect.area(); -// Second way, from the implementation -let area2 = RectangleGeometry::area(rect); -// `area1` has same value as `area2` -area1.print(); -area2.print(); +{{#rustdoc_include ../listings/ch07-generic-types-and-traits/no_listing_14_traits/src/lib.cairo:main}} ``` And the implementation of the `area` method will be accessed via the `self` parameter. @@ -61,56 +53,7 @@ Usually we want to write a trait when we want multiple types to implement a func In the example below, we use generic type `T` and our method signatures can use this alias which can be provided during implementation. ```rust -use debug::PrintTrait; - -#[derive(Copy, Drop)] -struct Rectangle { - height: u64, - width: u64, -} - -#[derive(Copy, Drop)] -struct Circle { - radius: u64 -} - -// Here T is an alias type which will be provided during implementation -trait ShapeGeometry { - fn boundary(self: T) -> u64; - fn area(self: T) -> u64; -} - -// Implementation RectangleGeometry passes in -// to implement the trait for that type -impl RectangleGeometry of ShapeGeometry { - fn boundary(self: Rectangle) -> u64 { - 2 * (self.height + self.width) - } - fn area(self: Rectangle) -> u64 { - self.height * self.width - } -} - -// We might have another struct Circle -// which can use the same trait spec -impl CircleGeometry of ShapeGeometry { - fn boundary(self: Circle) -> u64 { - (2 * 314 * self.radius) / 100 - } - fn area(self: Circle) -> u64 { - (314 * self.radius * self.radius) / 100 - } -} - -fn main() { - let rect = Rectangle { height: 5, width: 7 }; - rect.area().print(); // 35 - rect.boundary().print(); // 24 - - let circ = Circle { radius: 5 }; - circ.area().print(); // 78 - circ.boundary().print(); // 31 -} +{{#include ../listings/ch07-generic-types-and-traits/no_listing_16_generic_traits/src/lib.cairo}} ``` ## Managing and using external trait implementations @@ -120,9 +63,9 @@ To use traits methods, you need to make sure the correct traits/implementation(s In some cases you might need to import not only the trait but also the implementation if they are declared in separate modules. If `CircleGeometry` was in a separate module/file `circle` then to use `boundary` on `circ: Circle`, we'd need to import `CircleGeometry` in addition to `ShapeGeometry`. -If the code was organised into modules like this, +If the code was organised into modules like this, where the implementation of a trait was defined in a different module than the trait itself, explicitly importing the relevant implementation is required. -```rust,does_not_compile,ignore_format +```rust,noplayground use debug::PrintTrait; // struct Circle { ... } and struct Rectangle { ... } @@ -163,7 +106,7 @@ To make it work, in addition to, use geometry::ShapeGeometry; ``` -you might also need to use `CircleGeometry`, +you will need to import `CircleGeometry` explicitly. Note that you do not need to import `RectangleGeometry`, as it is defined in the same module as the imported trait, and thus is automatically resolved. ```rust use circle::CircleGeometry diff --git a/src/ch08-01-how-to-write-tests.md b/src/ch08-01-how-to-write-tests.md index b6135cccb..ffad7a660 100644 --- a/src/ch08-01-how-to-write-tests.md +++ b/src/ch08-01-how-to-write-tests.md @@ -40,10 +40,10 @@ adder In _lib.cairo_, let's add a first test, as shown in Listing 8-1. -Filename: lib.cairo +Filename: src/lib.cairo ```rust -{{#include ../listings/ch08-testing-cairo-programs/listing_08_01_03.cairo:it_works}} +{{#include ../listings/ch08-testing-cairo-programs/listing_08_01_02/src/lib.cairo:it_works}} ``` Listing 8-1: A test module and function @@ -69,10 +69,10 @@ It’s possible to mark a test as ignored so it doesn’t run in a particular in Let’s start to customize the test to our own needs. First change the name of the `it_works` function to a different name, such as `exploration`, like so: -Filename: lib.cairo +Filename: src/lib.cairo ```rust -{{#include ../listings/ch08-testing-cairo-programs/listing_08_01_03.cairo:exploration}} +{{#include ../listings/ch08-testing-cairo-programs/listing_08_01_02/src/lib.cairo:exploration}} ``` Then run `cairo-test -- --path src` again. The output now shows `exploration` instead of `it_works`: @@ -87,7 +87,7 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out; Now we’ll add another test, but this time we’ll make a test that fails! Tests fail when something in the test function panics. Each test is run in a new thread, and when the main thread sees that a test thread has died, the test is marked as failed. Enter the new test as a function named `another`, so your _src/lib.cairo_ file looks like Listing 8-3. ```rust -{{#include ../listings/ch08-testing-cairo-programs/listing_08_01_03.cairo:another}} +{{#include ../listings/ch08-testing-cairo-programs/listing_08_03/src/lib.cairo:another}} ``` @@ -117,20 +117,20 @@ The `assert` function, provided by Cairo, is useful when you want to ensure that In [Chapter 4, Listing 5-15](ch04-03-method-syntax.md#multiple-impl-blocks), we used a `Rectangle` struct and a `can_hold` method, which are repeated here in Listing 8-5. Let’s put this code in the _src/lib.cairo_ file, then write some tests for it using the `assert` function. -Filename: lib.cairo +Filename: src/lib.cairo ```rust -{{#include ../listings/ch08-testing-cairo-programs/listing_08_06.cairo:trait_impl}} +{{#include ../listings/ch08-testing-cairo-programs/listing_08_06/src/lib.cairo:trait_impl}} ``` Listing 8-5: Using the `Rectangle` struct and its `can_hold` method from Chapter 5 The `can_hold` method returns a `bool`, which means it’s a perfect use case for the assert function. In Listing 8-6, we write a test that exercises the `can_hold` method by creating a `Rectangle` instance that has a width of `8` and a height of `7` and asserting that it can hold another `Rectangle` instance that has a width of `5` and a height of `1`. -Filename: lib.cairo +Filename: src/lib.cairo ```rust -{{#rustdoc_include ../listings/ch08-testing-cairo-programs/listing_08_06.cairo:test1}} +{{#rustdoc_include ../listings/ch08-testing-cairo-programs/listing_08_06/src/lib.cairo:test1}} ``` Listing 8-6: A test for `can_hold` that checks whether a larger rectangle can indeed hold a smaller rectangle @@ -148,10 +148,10 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out; It does pass! Let’s add another test, this time asserting that a smaller rectangle cannot hold a larger rectangle: -Filename: lib.cairo +Filename: src/lib.cairo ```rust -{{#rustdoc_include ../listings/ch08-testing-cairo-programs/listing_08_06.cairo:test2}} +{{#rustdoc_include ../listings/ch08-testing-cairo-programs/listing_08_06/src/lib.cairo:test2}} ``` Because the correct result of the `can_hold` function in this case is `false`, we need to negate that result before we pass it to the assert function. As a result, our test will pass if `can_hold` returns false: @@ -167,7 +167,7 @@ $ cairo-test . Two tests that pass! Now let’s see what happens to our test results when we introduce a bug in our code. We’ll change the implementation of the `can_hold` method by replacing the greater-than sign with a less-than sign when it compares the widths: ```rust -{{#include ../listings/ch08-testing-cairo-programs/no_listing_02_wrong_can_hold_impl.cairo:wrong_impl}} +{{#include ../listings/ch08-testing-cairo-programs/no_listing_02_wrong_can_hold_impl/src/lib.cairo:wrong_impl}} ``` Running the tests now produces the following: @@ -193,10 +193,10 @@ We do this by adding the attribute `should_panic` to our test function. The test Listing 8-8 shows a test that checks that the error conditions of `GuessTrait::new` happen when we expect them to. -Filename: lib.cairo +Filename: src/lib.cairo ```rust -{{#include ../listings/ch08-testing-cairo-programs/listing_08_08.cairo}} +{{#include ../listings/ch08-testing-cairo-programs/listing_08_08/src/lib.cairo}} ``` Listing 8-8: Testing that a condition will cause a panic @@ -213,7 +213,7 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out; Looks good! Now let’s introduce a bug in our code by removing the condition that the new function will panic if the value is greater than `100`: ```rust -{{#rustdoc_include ../listings/ch08-testing-cairo-programs/no_listing_03_wrong_new_impl.cairo:here}} +{{#rustdoc_include ../listings/ch08-testing-cairo-programs/no_listing_03_wrong_new_impl/src/lib.cairo:here}} ``` When we run the test in Listing 8-8, it will fail: @@ -231,10 +231,10 @@ We don’t get a very helpful message in this case, but when we look at the test Tests that use `should_panic` can be imprecise. A `should_panic` test would pass even if the test panics for a different reason from the one we were expecting. To make `should_panic` tests more precise, we can add an optional expected parameter to the `should_panic` attribute. The test harness will make sure that the failure message contains the provided text. For example, consider the modified code for `Guess` in Listing 8-9 where the new function panics with different messages depending on whether the value is too small or too large. -Filename: lib.cairo +Filename: src/lib.cairo ```rust -{{#rustdoc_include ../listings/ch08-testing-cairo-programs/listing_08_09.cairo:test_panic}} +{{#rustdoc_include ../listings/ch08-testing-cairo-programs/listing_08_09/src/lib.cairo:test_panic}} ``` Listing 8-9: Testing for a panic with a panic message containing the error message string @@ -244,7 +244,7 @@ This test will pass because the value we put in the `should_panic` attribute’s To see what happens when a `should_panic` test with an expected message fails, let’s again introduce a bug into our code by swapping the bodies of the if `value < 1` and the else if `value > 100` blocks: ```rust -{{#include ../listings/ch08-testing-cairo-programs/no_listing_04_new_bug.cairo:here}} +{{#include ../listings/ch08-testing-cairo-programs/no_listing_04_new_bug/src/lib.cairo:here}} ``` This time when we run the `should_panic` test, it will fail: @@ -270,7 +270,7 @@ To demonstrate how to run a single test, we’ll first create two tests function Filename: src/lib.cairo ```rust -{{#include ../listings/ch08-testing-cairo-programs/listing_08_10.cairo}} +{{#include ../listings/ch08-testing-cairo-programs/listing_08_10/src/lib.cairo}} ``` Listing 8-10: Two tests with two different names @@ -295,7 +295,7 @@ Sometimes a few specific tests can be very time-consuming to execute, so you mig Filename: src/lib.cairo ```rust -{{#include ../listings/ch08-testing-cairo-programs/no_listing_05_ignore_tests.cairo}} +{{#include ../listings/ch08-testing-cairo-programs/no_listing_05_ignore_tests/src/lib.cairo}} ``` After `#[test]` we add the `#[ignore]` line to the test we want to exclude. Now when we run our tests, `it_works` runs, but `expensive_test` doesn’t: diff --git a/src/ch08-02-test-organization.md b/src/ch08-02-test-organization.md index be66d48d8..f62adde35 100644 --- a/src/ch08-02-test-organization.md +++ b/src/ch08-02-test-organization.md @@ -16,10 +16,10 @@ The `#[cfg(test)]` annotation on the tests module tells Cairo to compile and run Recall that when we created the new `adder` project in the first section of this chapter, we wrote this first test: -Filename: lib.cairo +Filename: src/lib.cairo ```rust -{{#include ../listings/ch08-testing-cairo-programs/no_listing_06_cfg_attr.cairo}} +{{#include ../listings/ch08-testing-cairo-programs/no_listing_06_cfg_attr/src/lib.cairo}} ``` The attribute `cfg` stands for configuration and tells Cairo that the following item should only be included given a certain configuration option. In this case, the configuration option is `test`, which is provided by Cairo for compiling and running tests. By using the `cfg` attribute, Cairo compiles our test code only if we actively run the tests with `cairo-test`. This includes any helper functions that might be within this module, in addition to the functions annotated with `#[test]`. @@ -65,7 +65,7 @@ Enter the code in Listing 8-11 into the _tests/integration_test.cairo_ file: Filename: tests/integration_test.cairo ```rust -{{#include ../listings/ch08-testing-cairo-programs/no_listing_07_integration_test.cairo:here}} +{{#include ../listings/ch08-testing-cairo-programs/no_listing_07_integration_test/src/lib.cairo:here}} ``` Listing 8-11: Testing functions from other modules diff --git a/src/ch09-01-unrecoverable-errors-with-panic.md b/src/ch09-01-unrecoverable-errors-with-panic.md index 38ea4f699..a58cf4d3d 100644 --- a/src/ch09-01-unrecoverable-errors-with-panic.md +++ b/src/ch09-01-unrecoverable-errors-with-panic.md @@ -6,16 +6,16 @@ When a panic occurs, it leads to an abrupt termination of the program. The `pani Here is how we can `panic` from inside a program and return the error code `2`: -Filename: lib.cairo +Filename: src/lib.cairo ```rust -{{#include ../listings/ch09-error-handling/no_listing_01_panic.cairo}} +{{#include ../listings/ch09-error-handling/no_listing_01_panic/src/lib.cairo}} ``` Running the program will produce the following output: -```console -$ cairo-run test.cairo +```shell +$ scarb cairo-run Run panicked with [2 (''), ]. ``` @@ -26,7 +26,7 @@ An alternative and more idiomatic approach to panic in Cairo would be to use the Let's consider an example: ```rust -{{#include ../listings/ch09-error-handling/no_listing_02_with_felt252.cairo}} +{{#include ../listings/ch09-error-handling/no_listing_02_with_felt252/src/lib.cairo}} ``` Executing this program will yield the same error message as before. In that case, if there is no need for an array and multiple values to be returned within the error, so `panic_with_felt252` is a more succinct alternative. @@ -37,19 +37,19 @@ You can use the `nopanic` notation to indicate that a function will never panic. Example: -```rust -{{#include ../listings/ch09-error-handling/no_listing_03_nopanic.cairo}} +```rust,noplayground +{{#include ../listings/ch09-error-handling/no_listing_03_nopanic/src/lib.cairo}} ``` Wrong example: -```rust -{{#include ../listings/ch09-error-handling/no_listing_04_nopanic_wrong.cairo}} +```rust,noplayground +{{#include ../listings/ch09-error-handling/no_listing_04_nopanic_wrong/src/lib.cairo}} ``` If you write the following function that includes a function that may panic you will get the following error: -```console +```shell error: Function is declared as nopanic but calls a function that may panic. --> test.cairo:2:12 assert(1 == 1, 'what'); @@ -62,14 +62,14 @@ Function is declared as nopanic but calls a function that may panic. Note that there are two functions that may panic here, assert and equality. -## panic_with macro +## panic_with attribute -You can use the `panic_with` macro to mark a function that returns an `Option` or `Result`. This macro takes two arguments, which are the data that is passed as the panic reason as well as the name for a wrapping function. It will create a wrapper for your annotated function which will panic if the function returns `None` or `Err`, the panic function will be called with the given data. +You can use the `panic_with` attribute to mark a function that returns an `Option` or `Result`. This attribute takes two arguments, which are the data that is passed as the panic reason as well as the name for a wrapping function. It will create a wrapper for your annotated function which will panic if the function returns `None` or `Err`, the panic function will be called with the given data. Example: ```rust -{{#include ../listings/ch09-error-handling/no_listing_05_panic_with.cairo}} +{{#include ../listings/ch09-error-handling/no_listing_05_panic_with/src/lib.cairo}} ``` ## Using assert @@ -79,7 +79,7 @@ The assert function from the Cairo core library is actually a utility function b Here is an example of its usage: ```rust -{{#include ../listings/ch09-error-handling/no_listing_06_assert.cairo}} +{{#include ../listings/ch09-error-handling/no_listing_06_assert/src/lib.cairo}} ``` We are asserting in main that `my_number` is not zero to ensure that we're not performing a division by 0. diff --git a/src/ch09-02-error-handling.md b/src/ch09-02-recoverable-errors.md similarity index 93% rename from src/ch09-02-error-handling.md rename to src/ch09-02-recoverable-errors.md index 1b23e2ba3..77a17f943 100644 --- a/src/ch09-02-error-handling.md +++ b/src/ch09-02-recoverable-errors.md @@ -8,8 +8,8 @@ Most errors aren’t serious enough to require the program to stop entirely. Som Recall from [“Generic data types”](ch07-01-generic-data-types.md#enums) in Chapter 7 that the `Result` enum is defined as having two variants, `Ok` and `Err`, as follows: -```rust -{{#include ../listings/ch09-error-handling/no_listing_07_result_enum.cairo}} +```rust,noplayground +{{#include ../listings/ch09-error-handling/no_listing_07_result_enum/src/lib.cairo}} ``` The `Result` enum has two generic types, `T` and `E`, and two variants: `Ok` which holds the value of type `T` and `Err` which holds the value of type `E`. This definition makes it convenient to use the `Result` enum anywhere we have an operation that might succeed (by returning a value of type `T`) or fail (by returning a value of type `E`). @@ -18,8 +18,8 @@ The `Result` enum has two generic types, `T` and `E`, and two variants: `O The `ResultTrait` trait provides methods for working with the `Result` enum, such as unwrapping values, checking whether the `Result` is `Ok` or `Err`, and panicking with a custom message. The `ResultTraitImpl` implementation defines the logic of these methods. -```rust -{{#include ../listings/ch09-error-handling/no_listing_08_result_trait.cairo}} +```rust,noplayground +{{#include ../listings/ch09-error-handling/no_listing_08_result_trait/src/lib.cairo}} ``` The `expect` and `unwrap` methods are similar in that they both attempt to extract the value of type `T` from a `Result` when it is in the `Ok` variant. If the `Result` is `Ok(x)`, both methods return the value `x`. However, the key difference between the two methods lies in their behavior when the `Result` is in the `Err` variant. The `expect` method allows you to provide a custom error message (as a `felt252` value) that will be used when panicking, giving you more control and context over the panic. On the other hand, the `unwrap` method panics with a default error message, providing less information about the cause of the panic. @@ -44,7 +44,7 @@ It is always easier to understand with examples. Have a look at this function signature: -```rust +```rust,noplayground fn u128_overflowing_add(a: u128, b: u128) -> Result; ``` @@ -52,7 +52,7 @@ It takes two u128 integers, a and b, and returns a `Result` where th Now, we can use this function elsewhere. For instance: -```rust +```rust,noplayground fn u128_checked_add(a: u128, b: u128) -> Option { match u128_overflowing_add(a, b) { Result::Ok(r) => Option::Some(r), @@ -66,7 +66,7 @@ Here, it accepts two u128 integers, a and b, and returns an `Option`. It u Let's take another example demonstrating the use of `unwrap`. First we import the necessary modules: -```rust +```rust,noplayground use core::traits::Into; use traits::TryInto; use option::OptionTrait; @@ -76,16 +76,16 @@ use result::ResultTraitImpl; In this example, the `parse_u8` function takes a `felt252` integer and tries to convert it into a `u8` integer using the `try_into` method. If successful, it returns `Result::Ok(value)`, otherwise it returns `Result::Err('Invalid integer')`. -```rust -{{#include ../listings/ch09-error-handling/listing_01.cairo:function}} +```rust,noplayground +{{#include ../listings/ch09-error-handling/listing_01/src/lib.cairo:function}} ``` Listing 9-1: Using the Result type Our two test cases are: -```rust -{{#rustdoc_include ../listings/ch09-error-handling/listing_01.cairo:tests}} +```rust,noplayground +{{#rustdoc_include ../listings/ch09-error-handling/listing_01/src/lib.cairo:tests}} ``` The first one tests a valid conversion from `felt252` to `u8`, expecting the `unwrap` method not to panic. The second test function attempts to convert a value that is out of the `u8` range, expecting the `unwrap` method to panic with the error message 'Invalid integer'. @@ -103,8 +103,8 @@ The `?` operator is useful when you want to handle errors implicitly and let the Here is an example. -```rust -{{#include ../listings/ch09-error-handling/listing_02.cairo:function}} +```rust,noplayground +{{#include ../listings/ch09-error-handling/listing_02/src/lib.cairo:function}} ``` Listing 9-1: Using the `?` operator @@ -113,8 +113,8 @@ Here is an example. And with a little test case: -```rust -{{#rustdoc_include ../listings/ch09-error-handling/listing_02.cairo:tests}} +```rust,noplayground +{{#rustdoc_include ../listings/ch09-error-handling/listing_02/src/lib.cairo:tests}} ``` The console will print the error "Invalid Integer". diff --git a/src/ch10-00-advanced-features.md b/src/ch10-00-advanced-features.md index 8e9730d9e..0e2f824aa 100644 --- a/src/ch10-00-advanced-features.md +++ b/src/ch10-00-advanced-features.md @@ -1 +1,3 @@ -# Advanced Features \ No newline at end of file +# Advanced Features + +Now, let's learn about more advanced features offered by Cairo. diff --git a/src/ch10-01-operator-overloading.md b/src/ch10-01-operator-overloading.md index 00fce79fd..39a55dc16 100644 --- a/src/ch10-01-operator-overloading.md +++ b/src/ch10-01-operator-overloading.md @@ -8,7 +8,7 @@ However, it's essential to use operator overloading judiciously. Misuse can lead Consider an example where two `Potions` need to be combined. `Potions` have two data fields, mana and health. Combining two `Potions` should add their respective fields. ```rust -{{#include ../listings/ch10-advanced-features/no_listing_01_potions.cairo}} +{{#include ../listings/ch10-advanced-features/no_listing_01_potions/src/lib.cairo}} ``` In the code above, we're implementing the `Add` trait for the `Potion` type. The add function takes two arguments: `lhs` and `rhs` (left and right-hand side). The function body returns a new `Potion` instance, its field values being a combination of `lhs` and `rhs`. diff --git a/src/ch10-02-macros.md b/src/ch10-02-macros.md new file mode 100644 index 000000000..f6818a1ba --- /dev/null +++ b/src/ch10-02-macros.md @@ -0,0 +1,32 @@ +# Macros + +The Cairo language has some plugins that allows developers to simplify their code. They are called `inline_macros` and are a way of writing code that generates other code. In Cairo, there are only two `macros`: `array![]` and `consteval_int!()`. + +### Let's start by `array!` + +Sometimes, we need to create arrays with values that are already known at compile time. The basic way of doing that is redundant. You would first declare the array and then append each value one by one. `array!` is a simpler way of doing this task by combining the two steps. +At compile-time, the compiler will create an array and append all values passed to the `array!` macro sequentially. + +Without `array!`: + +```rust +{{#include ../listings/ch10-advanced-features/no_listing_02_array_macro/src/lib.cairo:2:7}} +``` + +With `array!`: + +```rust +{{#include ../listings/ch10-advanced-features/no_listing_02_array_macro/src/lib.cairo:9:9}} +``` + +### `consteval_int!` + +In some situtations, a developer might need to declare a constant that is the result of a computation of integers. To compute a constant expression and use its result at compile time, it is required to use the `consteval_int!` macro. + +Here is an example of `consteval_int!`: + +```rust +const a: felt252 = consteval_int!(2 * 2 * 2); +``` + +This will be interprated as `const a: felt252 = 8;` by the compiler. diff --git a/src/ch99-00-starknet-smart-contracts.md b/src/ch99-00-starknet-smart-contracts.md index 8967d0116..7855f481d 100644 --- a/src/ch99-00-starknet-smart-contracts.md +++ b/src/ch99-00-starknet-smart-contracts.md @@ -2,7 +2,13 @@ All through the previous sections, you've mostly written programs with a `main` entrypoint. In the coming sections, you will learn to write and deploy Starknet contracts. +One of the applications of the Cairo language is to write smart contracts for the Starknet network. Starknet is a permissionless network that leverages zk-STARKs technology for scalability. As a Layer-2 scalability solution for Ethereum, Starknet's goal is to offer fast, secure, and low-cost transactions. It functions as a Validity Rollup (commonly known as a zero-knowledge Rollup) and is built on top of the Cairo language and the StarkNet VM. + Starknet contracts, in simple words, are programs that can run on the Starknet VM. Since they run on the VM, they have access to Starknet’s persistent state, can alter or modify variables in Starknet’s states, communicate with other contracts, and interact seamlessly with the underlying L1. Starknet contracts are denoted by the `#[contract]` attribute. We'll dive deeper into this in the next sections. If you want to learn more about the Starknet network itself, its architecture and the tooling available, you should read the [Starknet Book](https://book.starknet.io/). This section will focus on writing smart contracts in Cairo. + +#### Scarb + +You can set up a Starknet development environment using Scarb as stated in the [Hello, Scarb! - Starknet Support](ch01-03-hello-scarb.md#starknet-support) section. Each example in this chapter can be used with Scarb. diff --git a/src/ch99-01-01-introduction-to-smart-contracts.md b/src/ch99-01-01-introduction-to-smart-contracts.md index 62600dc6b..63cb80900 100644 --- a/src/ch99-01-01-introduction-to-smart-contracts.md +++ b/src/ch99-01-01-introduction-to-smart-contracts.md @@ -43,6 +43,29 @@ As Ethereum continues to mature, we can expect the use cases and applications of ## The rise of Starknet and Cairo -Ethereum, being the most widely used and resilient smart-contract platform, became a victim of its own success. With the rapid adoption of some previously mentioned use cases, mainly DeFi, the cost of performing transactions became extremely high, rendering the network almost unusable. Engineers and researchers in the ecosystem began working on solutions to address this scalability issue. A famous theorem in the blockchain space states that it is impossible to achieve a high level of scalability, decentralization, and security simultaneously; trade-offs must be made. Ethereum is at the intersection of decentralization and security. Eventually, it was decided that Ethereum's purpose would be to serve as a secure settlement layer, while complex computations would be offloaded to other networks built on top of Ethereum. These are called Layer 2s (L2s). The two primary types of L2s are optimistic rollups and validity rollups. Both approaches involve compressing and batching numerous transactions together, computing the new state, and settling the result on Ethereum (L1). The difference lies in the way the result is settled on L1. For optimistic rollups, the new state is considered valid by default, but there is a 7-day window for nodes to identify malicious transactions. In contrast, validity rollups, such as Starknet, use cryptography to prove that the new state has been correctly computed. This is the purpose of STARKs, this cryptographic technology could permit validity rollups to scale significantly more than optimistic rollups. You can learn more about STARKs from Starkware's Medium [article](https://medium.com/starkware/starks-starkex-and-starknet-9a426680745a), which serves as a good primer. +Ethereum, being the most widely used and resilient smart-contract platform, became a victim of its own success. With the rapid adoption of some previously mentioned use cases, mainly DeFi, the cost of performing transactions became extremely high, rendering the network almost unusable. Engineers and researchers in the ecosystem began working on solutions to address this scalability issue. -Remember Cairo? It is, in fact, a language developed specifically to work with STARKs and make them general-purpose. With Cairo, we can write **provable code**. In the context of Starknet, this allows proving the correctness of computations from one state to another. Unlike most (if not all) of Starknet's competitors that chose to use the EVM (either as-is or adapted) as a base layer, Starknet employs its own VM. This frees developers from the constraints of the EVM, opening up a broader range of possibilities. Coupled with decreased transaction costs, the combination of Starknet and Cairo creates an exciting playground for developers. Native account abstraction enables more complex logic for accounts and transaction flows. Emerging use cases include **transparent AI** and artificial intelligence and machine learning applications. Finally, **blockchain games** can be developed entirely **on-chain**. Starknet has been specifically designed to maximize the capabilities of STARK proofs for optimal scalability. +A famous trilemma ([The Blockchain Trilemma](https://vitalik.ca/general/2021/04/07/sharding.html#the-scalability-trilemma)) in the blockchain space states that it is impossible to achieve a high level of scalability, decentralization, and security simultaneously; trade-offs must be made. Ethereum is at the intersection of decentralization and security. Eventually, it was decided that Ethereum's purpose would be to serve as a secure settlement layer, while complex computations would be offloaded to other networks built on top of Ethereum. These are called Layer 2s (L2s). + +The two primary types of L2s are optimistic rollups and validity rollups. Both approaches involve compressing and batching numerous transactions together, computing the new state, and settling the result on Ethereum (L1). The difference lies in the way the result is settled on L1. For optimistic rollups, the new state is considered valid by default, but there is a 7-day window for nodes to identify malicious transactions. + +In contrast, validity rollups, such as Starknet, use cryptography to prove that the new state has been correctly computed. This is the purpose of STARKs, this cryptographic technology could permit validity rollups to scale significantly more than optimistic rollups. You can learn more about STARKs from Starkware's Medium [article](https://medium.com/starkware/starks-starkex-and-starknet-9a426680745a), which serves as a good primer. + +> Starknet's architecture is thoroughly described in the [Starknet Book](https://book.starknet.io/chapter_4/index.html), which is a great resource to learn more about the Starknet network. + +Remember Cairo? It is, in fact, a language developed specifically to work with STARKs and make them general-purpose. With Cairo, we can write **provable code**. In the context of Starknet, this allows proving the correctness of computations from one state to another. + +Unlike most (if not all) of Starknet's competitors that chose to use the EVM (either as-is or adapted) as a base layer, Starknet employs its own VM. This frees developers from the constraints of the EVM, opening up a broader range of possibilities. Coupled with decreased transaction costs, the combination of Starknet and Cairo creates an exciting playground for developers. Native account abstraction enables more complex logic for accounts, that we call "Smart Accounts", and transaction flows. Emerging use cases include **transparent AI** and machine learning applications. Finally, **blockchain games** can be developed entirely **on-chain**. Starknet has been specifically designed to maximize the capabilities of STARK proofs for optimal scalability. + +> Learn more about Account Abstraction in the [Starknet Book](https://book.starknet.io/chapter_5/index.html). + +## Cairo programs and Starknet contracts: what is the difference? + +Starknet contracts are a special superset of Cairo programs, so the concepts previously learned in this book are still applicable to write Starknet contracts. +As you may have already noticed, a Cairo program must always have a function `main` that serves as the entry point for this program: + +```rust +fn main() {} +``` + +Starknet contracts are essentially programs that can run on the Starknet OS, and as such, have access to Starknet's state. For a module to be handled as a contract by the compiler, it must be annotated with the `#[starknet::contract]` attribute. diff --git a/src/ch99-01-02-a-simple-contract.md b/src/ch99-01-02-a-simple-contract.md new file mode 100644 index 000000000..e2839f7f9 --- /dev/null +++ b/src/ch99-01-02-a-simple-contract.md @@ -0,0 +1,77 @@ +# A simple contract + +This chapter will introduce you to the basics of Starknet contracts with an example of a basic contract. You will learn how to write a simple contract that stores a single number on the blockchain. + +## Anatomy of a simple Starknet Contract + +Let's consider the following contract to present the basics of a Starknet contract. It might not be easy to understand it all at once, but we will go through it step by step: + +```rust +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_01/src/lib.cairo:all}} +``` + +Listing 99-1: A simple storage contract + +> Note: Starknet contracts are defined within [modules](./ch06-02-defining-modules-to-control-scope.md). + +### What is this contract? + +In this example, the `Storage` struct declares a storage variable called `stored_data` of type `u128` (unsigned integer of 128 bits). +You can think of it as a single slot in a database that you can query and alter by calling functions of the code that manages the database. +The contract defines and exposes publically the functions `set` and `get` that can be used to modify or retrieve the value of that variable. + +### The Interface: the contract's blueprint + +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_01/src/lib.cairo:interface}} +``` + +The interface of a contract represents the functions this contract exposes to the outside world. Here, the interface exposes two functions: `set` and `get`. By leveraging the [traits & impls](./ch07-02-traits-in-cairo.md) mechanism from Cairo, we can make sure that the actual implementation of the contract matches its interface. In fact, you will get a compilation error if your contract doesn’t conform with the declared interface. + +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_01_bis_wrong_impl/src/lib.cairo:impl}} +``` + +Listing 99-1-bis: A wrong implementation of the interface of the contract. This does not compile. + +In the interface, note the generic type `TContractState` of the `self` argument which is passed by reference to the `set` function. The `self` parameter represents the contract state. Seeing the `self` argument passed to `set` tells us that this function might access the state of the contract, as it is what gives us access to the contract’s storage. The `ref` modifier implies that `self` may be modified, meaning that the storage variables of the contract may be modified inside the `set` function. + +On the other hand, `get` takes a _snapshot_ of `TContractState`, which immediately tells us that it does not modify the state (and indeed, the compiler will complain if we try to modify storage inside the `get` function). + +### Public functions are defined in an implementation block + +Before we explore things further down, let's define some terminology. + +- In the context of Starknet, a _public function_ is a function that is exposed to the outside world. In the example above, `set` and `get` are public functions. A public function can be called by anyone, and can be called from outside the contract, or from within the contract. In the example above, `set` and `get` are public functions. + +- What we call an _external_ function is a public function that is invoked through a transaction and that can mutate the state of the contract. `set` is an external function. + +- A _view_ function is a public function that can be called from outside the contract, but that cannot mutate the state of the contract. `get` is a view function. + +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_01/src/lib.cairo:impl}} +``` + +Since the contract interface is defined as the `ISimpleStorage` trait, in order to match the interface, the external functions of the contract +must be defined in an implementation of this trait — which allows us to make sure that the implementation of the contract matches its interface. + +However, simply defining the functions in the implementation is not enough. The implementation block must be annotated with the `#[external(v0)]` attribute. This attribute exposes the functions defined in this implementation to the outside world — forget to add it and your functions will not be callable from the outside. All functions defined in a block marked as `#[external(v0)]` are consequently _public functions_. + +When writing the implementation of the interface, the generic parameter corresponding to the `self` argument in the trait must be `ContractState`. The `ContractState` type is generated by the compiler, and gives access to the storage variables defined in the `Storage` struct. +Additionally, `ContractState` gives us the ability to emit events. The name `ContractState` is not surprising, as it’s a representation of the contract’s state, which is what we think of `self` in the contract interface trait. + +### Modifying the contract's state + +As you can notice, all functions that need to access the state of the contract are defined under the implementation of a trait that has a `TContractState` generic parameter, and take a `self: ContractState` parameter. +This allows us to explicitly pass the `self: ContractState` parameter to the function, allowing access the storage variables of the contract. +To access a storage variable of the current contract, you add the `self` prefix to the storage variable name, which allows you to use the `read` and `write` methods to either read or write the value of the storage variable. + +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_01/src/lib.cairo:write_state}} +``` + +Using `self` and the `write` method to modify the value of a storage variable + +> Note: if the contract state is passed as a snapshot instead of `ref`, attempting to modify will result in a compilation error. + +This contract does not do much yet apart from allowing anyone to store a single number that is accessible by anyone in the world. Anyone could call `set` again with a different value and overwrite your number, but the number is still stored in the history of the blockchain. Later, you will see how you can impose access restrictions so that only you can alter the number. diff --git a/src/ch99-01-02-writing-starknet-contracts.md b/src/ch99-01-02-writing-starknet-contracts.md deleted file mode 100644 index 23f398eb6..000000000 --- a/src/ch99-01-02-writing-starknet-contracts.md +++ /dev/null @@ -1,166 +0,0 @@ -# Writing Starknet Contracts - -This chapter will guide you on how to create smart contracts in Cairo, and will clarify the distinction between Cairo programs and Starknet contracts. - -## Cairo programs and Starknet contracts - -Starknet contracts are a special subset of Cairo programs, so the concepts previously learned in this book are still applicable to write Starknet contracts. -As you may have already noticed, a Cairo program must always have a function `main` that serves as the entry point for this program: - -```rust -fn main() {} -``` - -Starknet contracts are essentially programs that can run on the Starknet OS, and as such, have access to Starknet's state. For a module to be handled as a contract by the compiler, it must be annotated with the `#[contract]` attribute: - -```rust -{{#include ../listings/ch99-starknet-smart-contracts/listing_99_03_example_contract.cairo:all}} -``` - -Listing 99-1: A simple naming service contract - -> Note: Starknet contracts are defined within [modules](./ch06-02-defining-modules-to-control-scope.md). - -## Starknet Contract Attributes - -Attributes are special annotations that modify the behavior of certain functions or methods. They are placed preceding a function and are denoted by the `#[]` symbol. - - - -Here is a list of common attributes used in Starknet contracts: - -1. `#[contract]`: This attribute is used to annotate a module to be compiled as a Starknet contract. - The compiler recognizes this attribute and prepares the module with necessary contract elements, - such as the logic to handle external contract calls or how to access storage variables. - -2. `#[constructor]`: This attribute marks a function as a constructor. The constructor function is called only once upon deploying a contract, setting the initial state of the contract. - -3. `#[external]`: This attribute marks a function as an external function. External functions can be called by other contracts or externally and can modify the contract's state. - -4. `#[view]`: This attribute marks a function as a view function. View functions are read-only functions that allow you to access data from the contract, but prevent you from modifying the state of the blockchain. - -5. `#[event]`: This is used to define events that can be emitted by the contract. - -6. `#[l1_handler]`: This attribute is used to mark functions which can receive messages from L1s. - -## Storage Variables - -Storage variables allow you to store data that will be stored on the blockchain in the contract's storage. These data are persistent and can be accessed and modified anytime once the contract is deployed. - -Storage variables in Starknet contracts are stored in a special struct called `Storage`: - -```rust -{{#rustdoc_include ../listings/ch99-starknet-smart-contracts/listing_99_02.cairo:here}} -``` - -Listing 99-2: A Storage Struct - -The storage struct is a [struct](./ch04-00-using-structs-to-structure-related-data.md) like any other, -except that it allows you to define mappings using the `LegacyMap` type. - -### Storage Mappings - -Mappings are a key-value data structure that you can use to store data within a smart contract. They are essentially hash tables that allow you to associate a unique key with a corresponding value. Mappings are also useful to store sets of data, as it's impossible to store arrays in storage. - -A mapping is a variable of type LegacyMap, in which the key and value types are specified within angular brackets <>. -It is important to note that the `LegacyMap` type can only be used inside the `Storage` struct, and can't be used to define mappings in user-defined structs. -The syntax for declaring a mapping is as follows in Listing 99-2. - -You can also create more complex mappings than that found in Listing 99-2 like the popular `allowances` storage variable in the ERC20 Standard which maps the `owner` and `spender` to the `allowance` using tuples: - -```rust -{{#include ../listings/ch99-starknet-smart-contracts/no_listing_01_storage_mapping.cairo:here}} -``` - -In mappings, the address of the value at key `k_1,...,k_n` is `h(...h(h(sn_keccak(variable_name),k_1),k_2),...,k_n)` where ℎ -is the Pedersen hash and the final value is taken `mod2251−256`. You can learn more about the contract storage layout in the [Starknet Documentation](https://docs.starknet.io/documentation/architecture_and_concepts/Contracts/contract-storage/#storage_variables) - -### Reading from Storage - -To read the value of the storage variable `names`, we call the `read` function on the `names` storage variable, passing in the key `_address` as a parameter. - -```rust -{{#include ../listings/ch99-starknet-smart-contracts/listing_99_03_example_contract.cairo:read}} -``` - -Listing 99-3: Calling the `read` function on the `names` variable - -> Note: When the storage variable does not store a mapping, its value is accessed without passing any parameters to the read method - -### Writing to Storage - -To write a value to the storage variable `names`, we call the `write` function on the `names` storage variable, passing in the key and values as arguments. - -```rust -{{#include ../listings/ch99-starknet-smart-contracts/listing_99_03_example_contract.cairo:write}} -``` - -Listing 99-4: Writing to the `names` variable - -## Functions - -In this section, we are going to be looking at some popular function types you'd encounter with most contracts: - -### 1. Constructors - -Constructors are a special type of function that runs only once when deploying a contract, and can be used to initialize the state of the contract. - -```rust -{{#include ../listings/ch99-starknet-smart-contracts/listing_99_03_example_contract.cairo:constructor}} -``` - -Some important rules to note: - -1. Your contract can't have more than one constructor. -2. Your constructor function must be named `constructor`. -3. Lastly, it must be annotated with the `#[constructor]` attribute. - -### 2. External functions - -External functions are functions that can modify the state of a contract. They are public and can be called by any other contract or externally. -You can define external functions by annotating them with the `#[external]` attribute: - -```rust -{{#include ../listings/ch99-starknet-smart-contracts/listing_99_03_example_contract.cairo:external}} -``` - -### 3. View functions - -View functions are read-only functions allowing you to access data from the contract while ensuring that the state of the contract is not modified. They can be called by other contracts or externally. -You can define view functions by annotating them with the `#[view]` attribute: - -```rust -{{#include ../listings/ch99-starknet-smart-contracts/listing_99_03_example_contract.cairo:view}} -``` - -> **Note:** It's important to note that, both external and view functions are public. To create an internal function in a contract, you simply don't annotate it with any attribute. - -## Events - -Events are custom data structures that are emitted by smart contracts during execution. -They provide a way for smart contracts to communicate with the external world by logging information -about specific occurrences in a contract. - -Events play a crucial role in the creation of smart contracts. Take, for instance, the Non-Fungible Tokens (NFTs) minted on Starknet. All of these are indexed and stored in a database, then displayed to users through the use of these events. Neglecting to include an event within your NFT contract could lead to a bad user experience. This is because users may not see their NFTs appear in their wallets (wallets use these indexers to display a user's NFTs). - -### Defining events - -An event is defined as an empty function annotated with the `#[event]` attribute. The parameters of this function -are the data that will be emitted by the event. - -In Listing 99-1, `StoredName` is an event that emits information when names are stored in the contract: - -```rust -{{#include ../listings/ch99-starknet-smart-contracts/listing_99_03_example_contract.cairo:event}} -``` - -We pass in the emitted data types as parameters within the parentheses. In this example, our event will emit the contract address of the caller and the name stored within the contract. - -### Emitting events - -After defining events, we can emit them by simply calling the event name like we'll call functions, -passing in the values to be emitted as parameters: - -```rust -{{#include ../listings/ch99-starknet-smart-contracts/listing_99_03_example_contract.cairo:emit_event}} -``` diff --git a/src/ch99-01-03-00-a-deeper-dive-into-contracts.md b/src/ch99-01-03-00-a-deeper-dive-into-contracts.md new file mode 100644 index 000000000..6d4792cd7 --- /dev/null +++ b/src/ch99-01-03-00-a-deeper-dive-into-contracts.md @@ -0,0 +1,21 @@ +# A deeper dive into contracts + +In the previous section, we gave an introductory example of a smart contract written in Cairo. In this section, we'll be taking a deeper look at all the components of a smart contract, step by step. + +When we discussed [_interfaces_](./ch99-01-02-a-simple-contract.md), we specified the difference between _public functions, external functions and view functions_, and we mentioned how to interact with _storage_. + +At this point, you should have multiple questions that come to mind: + +- How do I define internal/private functions? +- How can I emit events? How can I index them? +- Where should I define functions that do not need to access the contract's state? +- Is there a way to reduce the boilerplate? +- How can I store more complex data types? + +Luckily, we'll be answering all these questions in this chapter. Let's consider the following example contract that we'll be using throughout this chapter: + +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_03_example_contract/src/lib.cairo:all}} +``` + +Listing 99-1bis: Our reference contract for this chapter diff --git a/src/ch99-01-03-01-storage-variables.md b/src/ch99-01-03-01-storage-variables.md new file mode 100644 index 000000000..958106223 --- /dev/null +++ b/src/ch99-01-03-01-storage-variables.md @@ -0,0 +1,63 @@ +## Storage Variables + +As stated previously, storage variables allow you to store data that will be stored in the contract's storage that is itself stored on the blockchain. These data are persistent and can be accessed and modified anytime once the contract is deployed. + +Storage variables in Starknet contracts are stored in a special struct called `Storage`: + +```rust, noplayground +{{#rustdoc_include ../listings/ch99-starknet-smart-contracts/listing_99_02/src/lib.cairo:here}} +``` + +Listing 99-2: A Storage Struct + +The storage struct is a [struct](./ch04-00-using-structs-to-structure-related-data.md) like any other, +except that it **must** be annotated with `#[storage]` allowing you to store mappings using the `LegacyMap` type. + +### Storing Mappings + +Mappings are a key-value data structure that you can use to store data within a smart contract. They are essentially hash tables that allow you to associate a unique key with a corresponding value. Mappings are also useful to store sets of data, as it's impossible to store arrays in storage. + +A mapping is a variable of type `LegacyMap`, in which the key and value types are specified within angular brackets `<>`. +It is important to note that the `LegacyMap` type can only be used inside the `Storage` struct, and can't be used to define mappings in user-defined structs. + +You can also create more complex mappings than that; you can find one in Listing 99-2bis like the popular `allowances` storage variable in the ERC20 Standard which maps the `owner` and `spender` to the `allowance` using tuples: + +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/no_listing_01_storage_mapping/src/lib.cairo:here}} +``` + +Listing 99-2bis: Storing mappings + +In mappings, the address of the value at key `k_1,...,k_n` is `h(...h(h(sn_keccak(variable_name),k_1),k_2),...,k_n)` where ℎ +is the Pedersen hash and the final value is taken `mod2251−256`. You can learn more about the contract storage layout in the [Starknet Documentation](https://docs.starknet.io/documentation/architecture_and_concepts/Contracts/contract-storage/#storage_variables) + +### Storing custom structs + +The compiler knows how to store basic data types, such as unsigned integers (`u8`, `u128`, `u256`...), `felt252`, `ContractAddress`, etc. But what if you want to store a custom struct in storage? In that case, you have to explicitly tell the compiler how to store your struct in storage. +In our example, we want to store a `Person` struct in storage, so we have to tell the compiler how to store it in storage by adding a derive attribute of the `starknet::Store` trait to our struct definition. + +```rust, noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_03_example_contract/src/lib.cairo:person}} +``` + +### Reading from Storage + +To read the value of the storage variable `names`, we call the `read` function on the `names` storage variable, passing in the key `address` as a parameter. + +```rust, noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_03_example_contract/src/lib.cairo:read}} +``` + +Listing 99-3: Calling the `read` function on the `names` variable + +> Note: When the storage variable does not store a mapping, its value is accessed without passing any parameters to the read method + +### Writing to Storage + +To write a value to the storage variable `names`, we call the `write` function on the `names` storage variable, passing in the key and values as arguments. + +```rust, noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_03_example_contract/src/lib.cairo:write}} +``` + +Listing 99-4: Writing to the `names` variable diff --git a/src/ch99-01-03-02-contract-functions.md b/src/ch99-01-03-02-contract-functions.md new file mode 100644 index 000000000..9f0148047 --- /dev/null +++ b/src/ch99-01-03-02-contract-functions.md @@ -0,0 +1,61 @@ +## Contract Functions + +In this section, we are going to be looking at the different types of functions you could encounter in contracts: + +### 1. Constructors + +Constructors are a special type of function that only runs once when deploying a contract, and can be used to initialize the state of a contract. + +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_03_example_contract/src/lib.cairo:constructor}} +``` + +Some important rules to note: + +1. Your contract can't have more than one constructor. +2. Your constructor function must be named `constructor`. +3. It must be annotated with the `#[constructor]` attribute. + +### 2. Public functions + +As stated previously, public functions are accessible from outside of the contract. They must be defined inside an implementation block annotated with the `#[external(v0)]` attribute. This attribute only affects the visibility (public vs private/internal), but it doesn't inform us on the ability of these functions to modify the state of the contract. + +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_03_example_contract/src/lib.cairo:impl_public}} +``` + +#### External functions + +External functions are functions that can modify the state of a contract. They are public and can be called by any other contract or externally. +External functions are _public_ functions where the `self: ContractState` is passed as reference with the `ref` keyword, allowing you to modify the state of the contract. + +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_03_example_contract/src/lib.cairo:external}} +``` + +#### View functions + +View functions are read-only functions allowing you to access data from the contract while ensuring that the state of the contract is not modified. They can be called by other contracts or externally. +View functions are _public_ functions where the `self: ContractState` is passed as snapshot, preventing you from modifying the state of the contract. + +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_03_example_contract/src/lib.cairo:view}} +``` + +> **Note:** It's important to note that both external and view functions are public. To create an internal function in a contract, you will need to define it outside of the implementation block annotated with the `#[external(v0)]` attribute. + +### 3. Private functions + +Functions that are not defined in a block annotated with the `#[external(v0)]` attribute are private functions (also called internal functions). They can only be called from within the contract. + +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_03_example_contract/src/lib.cairo:state_internal}} +``` + +> Wait, what is this `#[generate_trait]` attribute? Where is the trait definition for this implementation? Well, the `#[generate_trait]` attribute is a special attribute that tells the compiler to generate a trait definition for the implementation block. This allows you to get rid of the boilerplate code of defining a trait and implementing it for the implementation block. We will see more about this in the [next section](./ch99-01-03-04-reducing-boilerplate.md). + +At this point, you might still be wondering if all of this is really necessary if you don't need to access the contract's state in your function (for example, a helper/library function). As a matter of fact, you can also define internal functions outside of implementation blocks. The only reason why we _need_ to define functions inside impl blocks is if we want to access the contract's state. + +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_03_example_contract/src/lib.cairo:stateless_internal}} +``` diff --git a/src/ch99-01-03-03-contract-events.md b/src/ch99-01-03-03-contract-events.md new file mode 100644 index 000000000..cf1a51f34 --- /dev/null +++ b/src/ch99-01-03-03-contract-events.md @@ -0,0 +1,40 @@ +## Events + +Events are custom data structures that are emitted by smart contracts during execution. +They provide a way for smart contracts to communicate with the external world by logging information +about specific occurrences in a contract. + +Events play a crucial role in the creation of smart contracts. Take, for instance, the Non-Fungible Tokens (NFTs) minted on Starknet. All of these are indexed and stored in a database, then displayed to users through the use of these events. Neglecting to include an event within your NFT contract could lead to a bad user experience. This is because users may not see their NFTs appear in their wallets (wallets use these indexers to display a user's NFTs). + +### Defining events + +All the different events in the contract are defined under the `Event` enum, which implements the `starknet::Event` trait, as enum variants. This trait is defined in the core library as follows: + +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/no_listing_event_trait/src/lib.cairo}} +``` + +The `#[derive(starknet::Event)]` attribute causes the compiler to generate an implementation for the above trait, +instantiated with the Event type, which in our example is the following enum: + +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_03_example_contract/src/lib.cairo:event}} +``` + +Each event variant has to be a struct of the same name as the variant, and each variant needs to implement the `starknet::Event` trait itself. +Moreover, the members of these variants must implement the `Serde` trait (_c.f._ [Appendix C: Serializing with Serde](./appendix-03-derivable-traits.md)), as keys/data are added to the event using a serialization process. + +The auto implementation of the `starknet::Event` trait will implement the `append_keys_and_data` function for each variant of our `Event` enum. The generated implementation will append a single key based on the variant name (`StoredName`), and then recursively call `append_keys_and_data` in the impl of the Event trait for the variant’s type . + +In our contract, we define an event named `StoredName` that emits the contract address of the caller and the name stored within the contract, where the `user` field is serialized as a key and the `name` field is serialized as data. +To index the key of an event, simply annotate it with the `#[key]` as demonstrated in the example for the `user` key. + +When emitting the event with `self.emit(StoredName { user: user, name: name })`, a key corresponding to the name ` StoredName`, specifically `sn_keccak(StoredName)`, is appended to the keys list. `user`is serialized as key, thanks to the `#[key]` attribute, while address is serialized as data. After everything is processed, we end up with the following keys and data: `keys = [sn_keccak("StoredName"),user]` and `data = [address]`. + +### Emitting events + +After defining events, we can emit them using `self.emit`, with the following syntax: + +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_03_example_contract/src/lib.cairo:emit_event}} +``` diff --git a/src/ch99-01-03-04-reducing-boilerplate.md b/src/ch99-01-03-04-reducing-boilerplate.md new file mode 100644 index 000000000..476bff2ef --- /dev/null +++ b/src/ch99-01-03-04-reducing-boilerplate.md @@ -0,0 +1,18 @@ +# Reducing boilerplate + +In a previous section, we saw this example of an implementation block in a contract that didn't have any corresponding trait. + +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_03_example_contract/src/lib.cairo:state_internal}} +``` + +It's not the first time that we encounter this attribute, we already talked about in it [Traits in Cairo](./ch07-02-traits-in-cairo.md). In this section, we'll be taking a deeper look at it and see how it can be used in contracts. + +Recall that in order to access the ContractState in a function, this function must be defined in an implementation block whose generic parameter is `ContractState`. This implies that we first need to define a generic trait that takes a `TContractState`, and then implement this trait for the `ContractState` type. +But by using the `#[generate_trait]` attribute, this whole process can be skipped and we can simply define the implementation block directly, without any generic parameter, and use `self: ContractState` in our functions. + +If we had to manually define the trait for the `InternalFunctions` implementation, it would look something like this: + +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/no_listing_99_02_explicit_internal_fn/src/lib.cairo:state_internal}} +``` diff --git a/src/ch99-01-03-05-optimizing-storage.md b/src/ch99-01-03-05-optimizing-storage.md new file mode 100644 index 000000000..cfd613f79 --- /dev/null +++ b/src/ch99-01-03-05-optimizing-storage.md @@ -0,0 +1,35 @@ +## Storage Optimization with `StorePacking` + +Bit-packing is a simple concept: Use as few bit as possible to store a piece of data. When done well, it can significantly reduce the size of the data you need to store. This is especially important in smart contracts, where storage is expensive. + +When writing Cairo smart contracts, it is important to optimize storage usage to reduce gas costs. Indeed, most of the cost associated to a transaction is related to storage updates; and each storage slot costs gas to write to. +This means that by packing multiple values into fewer slots, you can decrease the gas cost incurred to the users of your smart contract. + +Cairo provides the `StorePacking` trait to enable packing struct fields into a fewer number of storage slots. For example, consider a `Sizes` struct with 3 fields of different types. The total size is 8 + 32 + 64 = 104 bits. This is less than the 128 bits of a single `u128`. This means we can pack all 3 fields into a single `u128` variable. Since a storage slot can hold up to 251 bits, our packed value will take only one storage slot instead of 3. + +```rust +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_13_storage_packing/src/lib.cairo:here}} +``` + +Optimizing storage by implementing the `StorePacking` trait + +The `pack` function combines all three fields into a single `u128` value by performing bitshift and additions. The `unpack` reverses this process to extract the original fields back into a struct. + +If you're not familiar with bit operations, here's an explanation of the operations performed in the example: +The goal is to pack the `tiny`, `small`, and `medium` fields into a single `u128` value. +First, when packing: + +- `tiny` is a `u8` so we just convert it directly to a `u128` with `.into()`. This creates a `u128` value with the low 8 bits set to `tiny`'s value. +- `small` is a `u32` so we first shift it left by 8 bits (add 8 bits with the value 0 to the left) to create room for the 8 bites taken by `tiny`. Then we add `tiny` to `small` to combine them into a single `u128` value. The value of `tiny` now takes bits 0-7 and the value of small takes bits 8-39. +- Similarly `medium` is a `u64` so we shift it left by 40 (8 + 32) bits (`TWO_POW_40`) to make space for the previous fields. This takes bits 40-103. + +When unpacking: + +- First we extract `tiny` by bitwise ANDing (&) with a bitmask of 8 ones (`& MASK_8`). This isolates the lowest 8 bits of the packed value, which is `tiny`'s value. +- For `small`, we right shift by 8 bits (`/ TWO_POW_8`) to align it with the bitmask, then use bitwise AND with the 32 ones bitmask. +- For `medium` we right shift by 40 bits. Since it is the last value packed, we don't need to apply a bitmask as the higher bits are already 0. + +This technique can be used for any group of fields that fit within the bit size of the packed storage type. For example, if you have a struct with multiple fields whose bit sizes add up to 256 bits, you can pack them into a single `u256` variable. If the bit sizes add up to 512 bits, you can pack them into a single `u512` variable, and so on. You can define your own structs and logic to pack and unpack them. + +The rest of the work is done magically by the compiler - if a type implements the `StorePacking` trait, then the compiler will know it can use the `StoreUsingPacking` implementation of the `Store` trait in order to pack before writing and unpack after reading from storage. +One important details, however, is that the type that `StorePacking::pack` spits out also has to implement `Store` for `StoreUsingPacking` to work. Most of the time, we will want to pack into a felt252 or u256 - but if you want to pack into a type of your own, make sure that this one implements the `Store` trait. diff --git a/src/ch99-01-04-00-other-examples.md b/src/ch99-01-04-00-other-examples.md new file mode 100644 index 000000000..5a37ef27f --- /dev/null +++ b/src/ch99-01-04-00-other-examples.md @@ -0,0 +1,3 @@ +# Other examples + +This section contains additional examples of Starknet smart contracts, utilizing various features of the Cairo programming language. Your contributions are welcome and encouraged, as we aim to gather as many diverse examples as possible. diff --git a/src/ch99-01-04-01-voting-contract.md b/src/ch99-01-04-01-voting-contract.md new file mode 100644 index 000000000..ab6bae50b --- /dev/null +++ b/src/ch99-01-04-01-voting-contract.md @@ -0,0 +1,253 @@ +# Deploying and Interacting with a Voting contract + +The **`Vote`** contract in Starknet begins by registering voters through the contract's constructor. Three voters are initialized at this stage, and their addresses are passed to an internal function **`_register_voters`**. This function adds the voters to the contract's state, marking them as registered and eligible to vote. + +Within the contract, the constants **`YES`** and **`NO`** are defined to represent the voting options (1 and 0, respectively). These constants facilitate the voting process by standardizing the input values. + +Once registered, a voter is able to cast a vote using the **`vote`** function, selecting either the 1 (YES) or 0 (NO) as their vote. When voting, the state of the contract is updated, recording the vote and marking the voter as having voted. This ensures that the voter is not able to cast a vote again within the same proposal. The casting of a vote triggers the **`VoteCast`** event, logging the action. + +The contract also monitors unauthorized voting attempts. If an unauthorized action is detected, such as a non-registered user attempting to vote or a user trying to vote again, the **`UnauthorizedAttempt`** event is emitted. + +Together, these functions, states, constants, and events create a structured voting system, managing the lifecycle of a vote from registration to casting, event logging, and result retrieval within the Starknet environment. Constants like **`YES`** and **`NO`** help streamline the voting process, while events play a vital role in ensuring transparency and traceability. + +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_12_vote_contract/src/lib.cairo}} +``` + +Voting smart contract + +## Deploying, calling and invoking the Voting Contract + +Part of the Starknet experience is deploying and interacting with smart contracts. + +Once the contract is deployed, we can interact with it by calling and invoking its functions: + +- Calling contracts: Interacting with external functions that only read from the state. These functions do not alter the state of the network, so they don't require fees or signing. +- Invoking contracts: Interacting with external functions that can write to the state. These functions do alter the state of the network and require fees and signing. + +We will setup a local development node using `katana` to deploy the voting contract. Then, we'll interact with the contract by calling and invoking its functions. You can also use the Goerli Testnet instead of `katana`. However, we recommend using `katana` for local development and testing. You can find the complete tutorial for `katana` on [Chapter 3](https://book.starknet.io/chapter_3/katana.html) of the Starknet Book. + +### The `katana` local Starknet node + +`katana` is designed to support local development by the [Dojo team](https://github.com/dojoengine/dojo/blob/main/crates/katana/README.md). It will allow you to do everything you need to do with Starknet, but locally. It is a great tool for development and testing. + +To install `katana` from the source code, please refer to the [katana subchapter in Chapter 3](https://book.starknet.io/chapter_3/katana.html) of the Starknet Book. + +Once you have `katana` installed, you can start the local Starknet node with: + +```bash +katana --accounts 3 --seed 0 --gas-price 250 +``` + +This command will start a local Starknet node with 3 deployed accounts. We will use these accounts to deploy and interact with the voting contract: + +```bash +... +PREFUNDED ACCOUNTS +================== + +| Account address | 0x03ee9e18edc71a6df30ac3aca2e0b02a198fbce19b7480a63a0d71cbd76652e0 +| Private key | 0x0300001800000000300000180000000000030000000000003006001800006600 +| Public key | 0x01b7b37a580d91bc3ad4f9933ed61f3a395e0e51c9dd5553323b8ca3942bb44e + +| Account address | 0x033c627a3e5213790e246a917770ce23d7e562baa5b4d2917c23b1be6d91961c +| Private key | 0x0333803103001800039980190300d206608b0070db0012135bd1fb5f6282170b +| Public key | 0x04486e2308ef3513531042acb8ead377b887af16bd4cdd8149812dfef1ba924d + +| Account address | 0x01d98d835e43b032254ffbef0f150c5606fa9c5c9310b1fae370ab956a7919f5 +| Private key | 0x07ca856005bee0329def368d34a6711b2d95b09ef9740ebf2c7c7e3b16c1ca9c +| Public key | 0x07006c42b1cfc8bd45710646a0bb3534b182e83c313c7bc88ecf33b53ba4bcbc +... +``` + +Before we can interact with the voting contract, we need to prepare the voter and admin accounts on Starknet. Each voter account must be registered and sufficiently funded for voting. For a more detailed understanding of how accounts operate with Account Abstraction, refer to the [Account Abstraction](https://book.starknet.io/chapter_5/index.html) chapter of the Starknet Book. + +### Smart wallets for voting + +Aside from Scarb you will need to have Starkli installed. Starkli is a command line tool that allows you to interact with Starknet. You can find the installation instructions in the [Chapter 1](https://book.starknet.io/chapter_1/environment_setup.html) of the Starknet Book. + +For each smart wallet we'll use, we must create a Signer within the encrypted keystore and an Account Descriptor. This process is detailed in the [first chapter of the Starknet Book](https://book.starknet.io/chapter_1/first_contract.html). + +We can create Signers and Account Descriptors for the accounts we want to use for voting. Let's create a smart wallet for voting in our smart contract. + +Firstly, we create a signer from a private key: + +```bash +starkli signer keystore from-key ~/.starkli-wallets/deployer/account0_keystore.json +``` + +Then, we create the Account Descriptor: + +```bash +touch ~/.starkli-wallets/deployer/account0_account.json +``` + +The Account Descriptor will look like this. You can get the public key and the smart wallet address from the output of the initial `katana` command: + +```bash +{ + "version": 1, + "variant": { + "type": "open_zeppelin", + "version": 1, + "public_key": "" + }, + "deployment": { + "status": "deployed", + "class_hash": "", + "address": "" + } +} +``` + +You can retrieve the smart wallet class hash (it will be the same for all your smart wallets) with the following command. Notice the use of the `--rpc` flag and the RPC endpoint provided by `katana`: + +``` +starkli class-hash-at --rpc http://0.0.0.0:5050 +``` + +For the public key, you can use the `starkli signer keystore inspect` command with the directory of the keystore json file: + +```bash +starkli signer keystore inspect ~/.starkli-wallets/deployer/account0_keystore.json +``` + +This process is identical for `account_1` and `account_2` in case you want to have a second and a third voter. + +### Contract Deployment + +Before deploying, we need to declare the contract. We can do this with the `starkli declare` command: + +```bash +starkli declare target/dev/starknetbook_chapter_2_Vote.sierra.json --compiler-version 2.0.1 --rpc http://0.0.0.0:5050 --account ~/.starkli-wallets/deployer/account0_account.json --keystore ~/.starkli-wallets/deployer/account0_keystore.json +``` + +The class hash of the contract is: `0x06974677a079b7edfadcd70aa4d12aac0263a4cda379009fca125e0ab1a9ba52`. You can find it [on any block explorer](https://goerli.voyager.online/class/0x06974677a079b7edfadcd70aa4d12aac0263a4cda379009fca125e0ab1a9ba52). + +The `--rpc` flag specifies the RPC endpoint to use (the one provided by `katana`). The `--account` flag specifies the account to use for signing the transaction. The account we use here is the one we created in the previous step. The `--keystore` flag specifies the keystore file to use for signing the transaction. + +Since we are using a local node, the transaction will achieve finality immediately. If you are using the Goerli Testnet, you will need to wait for the transaction to be final, which usually takes a few seconds. + +The following command deploys the voting contract and registers voter_0, voter_1, and voter_2 as eligible voters. These are the constructor arguments, so add a voter account that you can later vote with. + +```bash +starkli deploy --rpc http://0.0.0.0:5050 --account ~/.starkli-wallets/deployer/account0_account.json --keystore ~/.starkli-wallets/deployer/account0_keystore.json +``` + +An example command: + +```bash +starkli deploy 0x06974677a079b7edfadcd70aa4d12aac0263a4cda379009fca125e0ab1a9ba52 0x03ee9e18edc71a6df30ac3aca2e0b02a198fbce19b7480a63a0d71cbd76652e0 0x033c627a3e5213790e246a917770ce23d7e562baa5b4d2917c23b1be6d91961c 0x01d98d835e43b032254ffbef0f150c5606fa9c5c9310b1fae370ab956a7919f5 --rpc http://0.0.0.0:5050 --account ~/.starkli-wallets/deployer/account0_account.json --keystore ~/.starkli-wallets/deployer/account0_keystore.json +``` + +In this case, the contract has been deployed at an specific address: `0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349`. This address will be different for you. We will use this address to interact with the contract. + +### Voter Eligibility Verification + +In our voting contract, we have two functions to validate voter eligibility, `voter_can_vote` and `is_voter_registered`. These are external read functions, which mean they don't alter the state of the contract but only read the current state. + +The `is_voter_registered` function checks whether a particular address is registered as an eligible voter in the contract. The `voter_can_vote` function, on the other hand, checks whether the voter at a specific address is currently eligible to vote, i.e., they are registered and haven't voted already. + +You can call these functions using the `starkli call` command. Note that the `call` command is used for read functions, while the `invoke` command is used for functions that can also write to storage. The `call` command does not require signing, while the `invoke` command does. + +```bash+ +starkli call 0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349 voter_can_vote 0x03ee9e18edc71a6df30ac3aca2e0b02a198fbce19b7480a63a0d71cbd76652e0 --rpc http://0.0.0.0:5050 +``` + +First we added the address of the contract, then the function we want to call, and finally the input for the function. In this case, we are checking whether the voter at the address `0x03ee9e18edc71a6df30ac3aca2e0b02a198fbce19b7480a63a0d71cbd76652e0` can vote. + +Since we provided a registered voter address as an input, the result is 1 (boolean true), indicating the voter is eligible to vote. + +Next, let's call the `is_voter_registered` function using an unregistered account address to observe the output: + +```bash +starkli call 0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349 is_voter_registered 0x44444444444444444 --rpc http://0.0.0.0:5050 +``` + +With an unregistered account address, the terminal output is 0 (i.e., false), confirming that the account is not eligible to vote. + +### Casting a Vote + +Now that we have established how to verify voter eligibility, we can vote! To vote, we interact with the `vote` function, which is flagged as external, necessitating the use of the `starknet invoke` command. + +The `invoke` command syntax resembles the `call` command, but for voting, we submit either `1` (for Yes) or `0` (for No) as our input. When we invoke the `vote` function, we are charged a fee, and the transaction must be signed by the voter; we are writing to the contract's storage. + +```bash +//Voting Yes +starkli invoke 0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349 vote 1 --rpc http://0.0.0.0:5050 --account ~/.starkli-wallets/deployer/account0_account.json --keystore ~/.starkli-wallets/deployer/account0_keystore.json + +//Voting No +starkli invoke 0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349 vote 0 --rpc http://0.0.0.0:5050 --account ~/.starkli-wallets/deployer/account0_account.json --keystore ~/.starkli-wallets/deployer/account0_keystore.json +``` + +You will be prompted to enter the password for the signer. Once you enter the password, the transaction will be signed and submitted to the Starknet network. You will receive the transaction hash as output. With the starkli transaction command, you can get more details about the transaction: + +```bash +starkli transaction --rpc http://0.0.0.0:5050 +``` + +This returns: + +```bash +{ + "transaction_hash": "0x5604a97922b6811060e70ed0b40959ea9e20c726220b526ec690de8923907fd", + "max_fee": "0x430e81", + "version": "0x1", + "signature": [ + "0x75e5e4880d7a8301b35ff4a1ed1e3d72fffefa64bb6c306c314496e6e402d57", + "0xbb6c459b395a535dcd00d8ab13d7ed71273da4a8e9c1f4afe9b9f4254a6f51" + ], + "nonce": "0x3", + "type": "INVOKE", + "sender_address": "0x3ee9e18edc71a6df30ac3aca2e0b02a198fbce19b7480a63a0d71cbd76652e0", + "calldata": [ + "0x1", + "0x5ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349", + "0x132bdf85fc8aa10ac3c22f02317f8f53d4b4f52235ed1eabb3a4cbbe08b5c41", + "0x0", + "0x1", + "0x1", + "0x1" + ] +} +``` + +If you try to vote twice with the same signer you will get an error: + +```bash +Error: code=ContractError, message="Contract error" +``` + +The error is not very informative, but you can get more details when looking at the output in the terminal where you started `katana` (our local Starknet node): + +```bash +... +Transaction execution error: "Error in the called contract (0x03ee9e18edc71a6df30ac3aca2e0b02a198fbce19b7480a63a0d71cbd76652e0): + Error at pc=0:81: + Got an exception while executing a hint: Custom Hint Error: Execution failed. Failure reason: \"USER_ALREADY_VOTED\". + ... +``` + +The key for the error is `USER_ALREADY_VOTED`. + +```bash +assert(can_vote == true, 'USER_ALREADY_VOTED'); +``` + +We can repeat the process to create Signers and Account Descriptors for the accounts we want to use for voting. Remember that each Signer must be created from a private key, and each Account Descriptor must be created from a public key, a smart wallet address, and the smart wallet class hash (which is the same for each voter). + +```bash +starkli invoke 0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349 vote 0 --rpc http://0.0.0.0:5050 --account ~/.starkli-wallets/deployer/account1_account.json --keystore ~/.starkli-wallets/deployer/account1_keystore.json + +starkli invoke 0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349 vote 1 --rpc http://0.0.0.0:5050 --account ~/.starkli-wallets/deployer/account2_account.json --keystore ~/.starkli-wallets/deployer/account2_keystore.json +``` + +### Visualizing Vote Outcomes + +To examine the voting results, we invoke the `get_vote_status` function, another view function, through the `starknet call` command. + +```bash +starkli call 0x05ea3a690be71c7fcd83945517f82e8861a97d42fca8ec9a2c46831d11f33349 get_vote_status --rpc http://0.0.0.0:5050 +``` + +The output reveals the tally of "Yes" and "No" votes along with their relative percentages. diff --git a/src/ch99-02-00-abis-and-cross-contract-interactions.md b/src/ch99-02-00-abis-and-cross-contract-interactions.md index e6a76c3b8..639984788 100644 --- a/src/ch99-02-00-abis-and-cross-contract-interactions.md +++ b/src/ch99-02-00-abis-and-cross-contract-interactions.md @@ -1,5 +1,5 @@ # Starknet contracts: ABIs and cross-contract interactions -The ability of contracts to interact with other smart contracts on the blockchain is a common pattern found in smart contract development. +Interactions between smart contracts are an important feature when creating complex decentralized applications, as it allows for composability and separation of concerns. This chapter sheds light on how to make contracts interact with each other. -This chapter covers how cross-contract interactions between Starknet contracts can be achieved. Specifically, you'll learn about ABIs, contract interfaces, the contract and library dispatchers and their low-level system call equivalents! +Specifically, you'll learn about ABIs, contract interfaces, the contract and library dispatchers and their low-level system call equivalents! diff --git a/src/ch99-02-01-abis-and-interfaces.md b/src/ch99-02-01-abis-and-interfaces.md index ecfabfcbf..317d7112b 100644 --- a/src/ch99-02-01-abis-and-interfaces.md +++ b/src/ch99-02-01-abis-and-interfaces.md @@ -4,34 +4,31 @@ Cross-contract interactions between smart contracts on a blockchain is a common Achieving this on Starknet requires something we call an interface. -## Interface +## ABI - Application Binary Interface -An interface is a list of a contract's function definitions without implementations. In other words, an interface specifies the function declarations (name, parameters, visibility and return value) contained in a smart contract without including the function body. +On Starknet, the ABI of a contract is a JSON representation of the contract's functions and structures, giving anyone (or any other contract) the ability to form encoded calls to it. It is a blueprint that instructs how functions should be called, what input parameters they expect, and in what format. -Interfaces in Cairo are traits with the `#[abi]` attribute. If you are new to traits, check out the dedicated chapter on [traits](./ch07-02-traits-in-cairo.md). +While we write our smart contract logics in high-level Cairo, they are stored on the VM as executable bytecodes which are in binary formats. Since this bytecode is not human readable, it requires interpretation to be understood. This is where ABIs come into play, defining specific methods which can be called to a smart contract for execution. Without an ABI, it becomes practically impossible for external actors to understand how to interact with a contract. -For your Cairo code to qualify as an interface, it must meet the following requirements: +ABIs are typically used in dApps frontends, allowing it to format data correctly, making it understandable by the smart contract and vice versa. When you interact with a smart contract through a block explorer like [Voyager](https://voyager.online/) or [Starkscan](https://starkscan.co/), they use the contract's ABI to format the data you send to the contract and the data it returns. -1. Must be appended with the `#[abi]` attribute. -2. Your interface functions should have no implementations. -3. You must explicitly declare the function's decorator. -4. Your interface should not declare a constructor. -5. Your interface should not declare state variables. +## Interface -Here's a sample interface for an ERC20 token contract: +The interface of a contract is a list of the functions it exposes publically. +It specifies the function signatures (name, parameters, visibility and return value) contained in a smart contract without including the function body. -```rust -{{#include ../listings/ch99-starknet-smart-contracts/listing_99_04_interface.cairo}} -``` +Contract interfaces in Cairo are traits annotated with the `#[starknet::interface]` attribute. If you are new to traits, check out the dedicated chapter on [traits](./ch07-02-traits-in-cairo.md). -Listing 99-4: A simple ERC20 Interface +One important specification is that this trait must be generic over the `TContractState` type. This is required for functions to access the contract's storage, so that they can read and write to it. -## ABIs +> Note: The contract constructor is not part of the interface. Nor are internal functions part of the interface. -ABI stands for Application Binary Interface. ABIs gives a smart contract the ability to communicate and interact with external applications or other smart contracts. ABIs can be likened to APIs in traditional web development, which helps data flow between applications and servers. +Here's a sample interface for an ERC20 token contract. As you can see, it's a generic trait over the `TContractState` type. `view` functions have a self parameter of type `@TContractState`, while `external` functions have a self parameter of type passed by reference `ref self: TContractState`. -While we write our smart contract logics in high-level Cairo, they are stored on the VM as executable bytecodes which are in binary formats. Since this bytecode is not human readable, it requires interpretation to be understood. This is where ABIs come into play, defining specific methods which can be called to a smart contract for execution. +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_04_interface/src/lib.cairo}} +``` -Every contract on Starknet has an Application Binary Interface (ABI) that defines how to encode and decode data when calling its methods. +Listing 99-4: A simple ERC20 Interface -In the next chapter, we are going to be looking into how we can call other smart contracts using a `Contract Dispatcher`, `Library Dispatcher`, and `System calls`. +In the next chapter, we will see how we can call contracts from other smart contracts using _dispatchers_ and _syscalls_ . diff --git a/src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md b/src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md index 451278874..6ed3a2dbc 100644 --- a/src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md +++ b/src/ch99-02-02-contract-dispatcher-library-dispatcher-and-system-calls.md @@ -1,75 +1,87 @@ -# Contract Dispatcher, Library Dispatcher and System calls +# Interacting with other contracts and classes using Dispatchers and syscalls -Each time a contract interface is created on Starknet, two dispatchers are automatically created and exported: +Each time a contract interface is defined, two dispatchers are automatically created and exported by the compiler. Let's consider an interface that we named IERC20, these would be: -1. The Contract Dispatcher -2. The Library Dispatcher +1. The Contract Dispatcher `IERC20Dispatcher` +2. The Library Dispatcher `IERC20LibraryDispatcher` -In this chapter, we are going to extensively discuss how these dispatchers work and their usage. +The compiler also generates a trait `IERC20DispatcherTrait`, allowing us to call the functions defined in the interface on the dispatcher struct. + +In this chapter, we are going to discuss what these are, how they work and how to use them. To effectively break down the concepts in this chapter, we are going to be using the IERC20 interface from the previous chapter (refer to Listing 99-4): ## Contract Dispatcher -Traits annotated with the `#[abi]` attribute are programmed to automatically generate and export the relevant dispatcher logic on compilation. The compiler also generates a new trait, two new structs (one for contract calls, and the other for library calls) and their implementation of this trait. Our interface is expanded into something like this: +As mentioned previously, traits annotated with the `#[starknet::interface]` attribute automatically generate a dispatcher and a trait on compilation. +Our `IERC20` interface is expanded into something like this: -**Note:** The expanded code for our IERC20 interface is a lot longer, but to keep this chapter concise and straight to the point, we focused on one view function `get_name`, and one external function `transfer`. +**Note:** The expanded code for our IERC20 interface is a lot longer, but to keep this chapter concise and straight to the point, we focused on one view function `name`, and one external function `transfer`. -```rust -{{#include ../listings/ch99-starknet-smart-contracts/listing_99_05_dispatcher_trait.cairo}} +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_05_dispatcher_trait/src/lib.cairo}} ``` Listing 99-5: An expanded form of the IERC20 trait +As you can see, the "classic" dispatcher is just a struct that wraps a contract address and implements the `DispatcherTrait` generated by the compiler, allowing us to call functions from another contract. This means that we can instantiate a struct with the address of the contract we want to call, and then simply call the functions defined in the interface on the dispatcher struct as if they were methods of that type. + It's also worthy of note that all these are abstracted behind the scenes thanks to the power of Cairo plugins. ### Calling Contracts using the Contract Dispatcher -This is an example of a contract named `Dispatcher` using the Contract interface dispatcher to call an ERC-20 contract in the ERC-20 contract's context and, in the case of `transfer_token`, altering the state of the ERC-20 contract: +This is an example of a contract named `TokenWrapper` using a dispatcher to call functions defined on an ERC-20 token. Calling `transfer_token` will modify the state of the contract deployed at `contract_address`. -```rust -{{#rustdoc_include ../listings/ch99-starknet-smart-contracts/listing_99_06_sample_contract.cairo:here}} +```rust,noplayground +{{#rustdoc_include ../listings/ch99-starknet-smart-contracts/listing_99_06_sample_contract/src/lib.cairo:here}} ``` Listing 99-6: A sample contract which uses the Contract Dispatcher -As you can see, we had to first import the `IERC20DispatcherTrait` and `IERC20Dispatcher` which was generated and exported on compiling our interface, then we make calls to the methods implemented for the `IERC20Dispatcher` struct (`name`, `transfer`, etc), passing in the `contract_address` parameter which represents the address of the contract we want to call. +As you can see, we had to first import `IERC20DispatcherTrait` and `IERC20Dispatcher` generated by the compiler, which allows us to make calls to the methods implemented for the `IERC20Dispatcher` struct (`name`, `transfer`, etc), passing in the `contract_address` of the contract we want to call in the `IERC20Dispatcher` struct. ## Library Dispatcher -The key difference between the contract dispatcher and the library dispatcher is that while the contract dispatcher calls an external contract's logic in the external contract's context, the library dispatcher calls the target contract's classhash, whilst executing the call in the calling contract's context. -So unlike the contract dispatcher, calls made using the library dispatcher have no possibility of tampering with the target contract's state. +The key difference between the contract dispatcher and the library dispatcher lies in the execution context of the logic defined in the class. While regular dispatchers are used to call functions from **contracts** (with an associated state), library dispatchers are used to call **classes** (stateless). + +Let's consider two contracts A and B. -As stated in the previous chapter, contracts annotated with the `#[abi]` macro on compilation generates a new trait, two new structs (one for contract calls, and the other for library calls) and their implementation of this trait. The expanded form of the library traits looks like: +When A uses `IBDispatcher` to call functions from the **contract** B, the execution context of the logic defined in B is that of B. This means that the value returned by `get_caller_address()` in B will return the address of A, and updating a storage variable in B will update the storage of B. -```rust -{{#include ../listings/ch99-starknet-smart-contracts/listing_99_07_library_dispatcher.cairo}} +When A uses `IBLibraryDispatcher` to call functions from the **class** of B, the execution context of the logic defined in B's class is that of A. This means that the value returned by `get_caller_address()` variable in B will return the address of the caller of A, and updating a storage variable in B's class will update the storage of A (remember that the **class** of B is stateless; there is no state that can be updated!) + +The expanded form of the struct and trait generated by the compiler look like: + +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_07_library_dispatcher/src/lib.cairo}} ``` +Notice that the main difference between the regular contract dispatcher and the library dispatcher is that the former uses `call_contract_syscall` while the latter uses `library_call_syscall`. + Listing 99-7: An expanded form of the IERC20 trait ### Calling Contracts using the Library Dispatcher -Below's a sample code on calling contracts using the Library Dispatcher: +Below's a sample code for calling contracts using the Library Dispatcher. -```rust -{{#include ../listings/ch99-starknet-smart-contracts/listing_99_08_using_library_dispatcher.cairo:here}} +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_08_using_library_dispatcher/src/lib.cairo:here}} ``` Listing 99-8: A sample contract using the Library Dispatcher -As you can see, we had to first import the `IERC20DispatcherTrait` and `IERC20LibraryDispatcher` which was generated and exported on compiling our interface, then we make calls to the methods implemented for the `IERC20LibraryDispatcher` struct (`name`, `transfer`, etc), passing in the `class_hash` parameter which represents the class of the contract we want to call. +As you can see, we had to first import in our contract the `IContractBDispatcherTrait` and `IContractBLibraryDispatcher` which were generated from our interface by the compiler. Then, we can create an instance of `IContractBLibraryDispatcher` passing in the `class_hash` of the class we want to make library calls to. From there, we can call the functions defined in that class, executing its logic in the context of our contract. When we call `set_value` on ContractA, it will make a library call to the `set_value` function in ContractB, updating the value of the storage variable `value` in ContractA. -## Calling Contracts using low-level System calls +## Using low-level syscalls -Another way to call other contracts is to use the `starknet::call_contract_syscall` system call. The Dispatchers we described in the previous sections are high-level syntaxes for this low-level system call. +Another way to call other contracts and classes is to use the `starknet::call_contract_syscall`and `starknet::library_call_syscall` system calls. The dispatchers we described in the previous sections are high-level syntaxes for these low-level system calls. -Using the system call `starknet::call_contract_syscall` can be handy for customized error handling or possessing more control over the serialization/deserialization of the call data and the returned data. Here's an example demonstrating a low-level `transfer` call: +Using these syscalls can be handy for customized error handling or to get more control over the serialization/deserialization of the call data and the returned data. Here's an example demonstrating how to use a `call_contract_sycall` to call the `transfer` function of an ERC20 contract: -```rust -{{#include ../listings/ch99-starknet-smart-contracts/listing_99_09_call_contract_syscall.cairo}} +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_09_call_contract_syscall/src/lib.cairo}} ``` -Listing 99-9: A sample contract implementing system calls +Listing 99-9: A sample contract using syscalls -As you can see, rather than pass our function arguments directly, we passed in the contract address, function selector (which is a keccak hash of the function name), and the calldata (function arguments). At the end, we get returned a serialized value which we'll need to deserialize ourselves! +To use this syscall, we passed in the contract address, the function selector (which is the `starknet_keccak` hash of the function name), and the calldata (function arguments). At the end, we get returned a serialized value which we'll need to deserialize ourselves! diff --git a/src/ch99-03-security-considerations.md b/src/ch99-03-security-considerations.md new file mode 100644 index 000000000..2e21b8fcf --- /dev/null +++ b/src/ch99-03-security-considerations.md @@ -0,0 +1,78 @@ +# Security Considerations + +When developing software, ensuring it functions as intended is usually straightforward. However, preventing unintended usage and vulnerabilities can be more challenging. + +In smart contract development, security is very important. A single error can result in the loss of valuable assets or the improper functioning of certain features. + +Smart contracts are executed in a public environment where anyone can examine the code and interact with it. Any errors or vulnerabilities in the code can be exploited by malicious actors. + +This chapter presents general recommendations for writing secure smart contracts. By incorporating these concepts during development, you can create robust and reliable smart contracts. This reduces the chances of unexpected behavior or vulnerabilities. + +## Disclaimer + +This chapter does not provide an exhaustive list of all possible security issues, and it does not guarantee that your contracts will be completely secure. + +If you are developing smart contracts for production use, it is highly recommended to conduct external audits performed by security experts. + +## Mindset + +Cairo is a highly safe language inspired by rust. It is designed in a way that force you to cover all possible cases. Security issues on Starknet mostly arise from the way smart contracts flows are designed, not much from the language itself. + +Adopting a security mindset is the initial step in writing secure smart contracts. Try to always consider all possible scenarios when writing code. + +### Viewing smart contract as Finite State Machines + +Transactions in smart contracts are atomic, meaning they either succeed or fail without making any changes. + +Think of smart contracts as state machines: they have a set of initial states defined by the constructor constraints, and external function represents a set of possible state transitions. A transaction is nothing more than a state transition. + +The `assert` or `panic` functions can be used to validate conditions before performing specific actions. You can learn more about these on the [Unrecoverable Errors with panic](./ch09-01-unrecoverable-errors-with-panic.md) page. + +These validations can include: + +- Inputs provided by the caller +- Execution requirements +- Invariants (conditions that must always be true) +- Return values from other function calls + +For example, you could use the `assert` function to validate that a user has enough funds to perform a withdraw transaction. If the condition is not met, the transaction will fail and the state of the contract will not change. + +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_10_assert_balance/src/lib.cairo:withdraw}} +``` + +Using these functions to check conditions adds constraints that help clearly define the boundaries of possible state transitions for each function in your smart contract. These checks ensure that the behavior of the contract stays within the expected limits. + +## Recommendations + +### Checks Effects Interactions Pattern + +The Checks Effects Interactions pattern is a common design pattern used to prevent reentrancy attacks on Ethereum. While reentrancy is harder to achieve in Starknet, it is still recommended to use this pattern in your smart contracts. + + + +The pattern consists of following a specific order of operations in your functions: + +1. **Checks**: Validate all conditions and inputs before performing any state changes. +2. **Effects**: Perform all state changes. +3. **Interactions**: All external calls to other contracts should be made at the end of the function. + +### Access control + +Access control is the process of restricting access to certain features or resources. It is a common security mechanism used to prevent unauthorized access to sensitive information or actions. In smart contracts, some functions may often be restricted to specific users or roles. + +You can implement the access control pattern to easily manage permissions. This pattern consists of defining a set of roles and assigning them to specific users. Each function can then be restricted to specific roles. + +```rust,noplayground +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_11_simple_access_control/src/lib.cairo}} +``` + +### Static analysis tool + +Static analysis refers to the process of examining code without its execution, focusing on its structure, syntax, and properties. It involves analyzing the source code to identify potential issues, vulnerabilities, or violations of specified rules. + +By defining rules, such as coding conventions or security guidelines, developers can utilize static analysis tools to automatically check the code against these standards. + +Reference: + +- [Semgrep Cairo 1.0 support](https://semgrep.dev/blog/2023/semgrep-now-supports-cairo-1-0) diff --git a/src/ch99-04-00-L1-L2-messaging.md b/src/ch99-04-00-L1-L2-messaging.md new file mode 100644 index 000000000..1a6782870 --- /dev/null +++ b/src/ch99-04-00-L1-L2-messaging.md @@ -0,0 +1,134 @@ +# L1-L2 Messaging + +A crucial feature of a Layer 2 is its ability to interact with Layer 1. + +Starknet has its own L1 <> L2 Messaging system, which is different from its consensus mechanism and the submission of state updates on L1. Messaging is a way for smart-contracts on L1 to interact with smart-contracts on L2 (or the other way around), allowing us to do "cross-chain" transactions. For example, we can do some computations on a chain and use the result of this computation on the other chain. + +Bridges on Staknet all use L1-L2 messaging. Let's say that you want to bridge tokens from Ethereum to Starknet. You will simply have to deposit your tokens in the L1 bridge contract, which will automatically trigger the minting of the same token on L2. Another good use case for L1-L2 messaging would be [DeFi pooling](https://starkware.co/resource/defi-pooling/). + +Let's dive into the details. + +## The StarknetMessaging Contract + +The crucial component of the L1 <> L2 Messaging system is the [`StarknetCore`](https://etherscan.io/address/0xc662c410C0ECf747543f5bA90660f6ABeBD9C8c4) contract. It is a set of Solidity contracts deployed on Ethereum that allows Starknet to function properly. One of the contracts of `StarknetCore` is called `StarknetMessaging` and it is the contract responsible for passing messages between Starknet and Ethereum. `StarknetMessaging` follows an [interface](https://github.com/starkware-libs/cairo-lang/blob/4e233516f52477ad158bc81a86ec2760471c1b65/src/starkware/starknet/eth/IStarknetMessaging.sol#L6) with functions allowing to send message to L2, receiving messages on L1 from L2 and canceling messages. + +```js +interface IStarknetMessaging is IStarknetMessagingEvents { + + function sendMessageToL2( + uint256 toAddress, + uint256 selector, + uint256[] calldata payload + ) external returns (bytes32); + + function consumeMessageFromL2(uint256 fromAddress, uint256[] calldata payload) + external + returns (bytes32); + + function startL1ToL2MessageCancellation( + uint256 toAddress, + uint256 selector, + uint256[] calldata payload, + uint256 nonce + ) external; + + function cancelL1ToL2Message( + uint256 toAddress, + uint256 selector, + uint256[] calldata payload, + uint256 nonce + ) external; +} +``` + + Starknet messaging contract interface + +The Starknet sequencer can receive the messages sent from Ethereum to the `StarknetMessaging` contract and trigger the appropriate functions on L2, or send messages to `StarknetCore` on L1. + +## Sending messages from Ethereum to Starknet + +If you want to send messages from Ethereum to Starknet, your Solidity contracts must call the `sendMessageToL2` function of the `StarknetMessaging` contract. To receive these messages on Starknet, you will need to annotate functions that can be called from L1 with the `#[l1_handler]` attribute. + +Let's take an example. It is adapted from the [starknet-edu L1-L2 exercises](https://github.com/starknet-edu/starknet-messaging-bridge/tree/main). It's a contract that can receive a message sent from L1 and store it, and also send a message to L1. + +To give a bit of context, here we have two contracts, one on Ethereum and the other on Starknet. Both interact with each other. The goal of the workshop is to find a way to earn points by sending messages from one chain to the other. + +Here is a snippet of the solidity code to send a simple message from Ethereum to Starknet: + +```rust +function ex01SendMessageToL2(uint256 value) external payable{ + + // This function call requires money to send L2 messages, we check there is enough + require(msg.value>=10000000000, "Message fee missing"); + + // Sending the message to the l2 contract + // Creating the payload + uint256[] memory payload = new uint256[](1); + // Adding the value to the payload + payload[0] = value; + // Sending the message + starknetCore.sendMessageToL2{value: 10000000000}(l2Evaluator, ex01_selector, payload); +} +``` + +The signature of `StarknetCore.sendMessageToL2` is: + +```js +function sendMessageToL2( + uint256 toAddress, + uint256 selector, + uint256[] calldata payload + ) external override returns (bytes32); +``` + +In `ex01SendMessageToL2`, we first construct the message (the payload). It is an array of `uint256`. Then we call `StarknetCore.sendMessageToL2`. The first parameter is the L2 contract address. The second is the selector (or the `sn_keccak` hash of the name of the function we want to call on L2), followed by the payload. We add a fee to it as a `msg.value` because we need to pay the transaction on L2. + +On the Starknet side, to receive this message, we have: + +```rust +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_04_L1_L2_messaging/src/lib.cairo:here}} +``` + +We need to add the `#[l1_handler]` attribute to our function. L1 handlers are special functions that can only be triggered by the sequencer following a message sent from L1. There is nothing particular to do to receive transactions from L1, as the message is relayed by the sequencer automatically. In your `#[l1_handler]` functions, it is important to verify the sender of the L1 message to ensure that our contract can only receive messages from a trusted L1 contract. + +## Sending messages from Starknet to Ethereum + +When sending messages from Starknet to Ethereum, you will have to use the `send_message_to_l1` syscall in your Cairo contracts. This syscall allows you to send messages to the `StarknetMessaging` contract on L1. Unlike L1-to-L2 messages, L2-to-L1 messages are not automatically consumed, which means that you will need your Solidity contract to call the `consumeMessageFromL2` function explicitly in order to consume the message. + +To send a message from L2 to L1, what we would do on Starknet is: + +```rust +{{#include ../listings/ch99-starknet-smart-contracts/listing_99_04_L1_L2_messaging/src/lib.cairo:l2l1}} +``` + +We simply build the payload and pass it, along with the L1 contract address, to the syscall function. + +On L1, the important part is to build the same payload as on L2. Then you call `starknetCore.consumeMessageFromL2` by passing the L2 contract address and the payload. + +```js +function ex02ReceiveMessageFromL2(uint256 player_l2_address, uint256 message) external payable{ + + require(msg.value>=10000000000, "Message fee missing"); + // Consuming the message + // Reconstructing the payload of the message we want to consume + uint256[] memory payload = new uint256[](2); + // Adding the address of the player on L2 + payload[0] = caller_l2_address; + // Adding the message + payload[1] = message; + // Adding a constraint on the message, to make sure players read BOTH contracts ;-) + require(message>3121906, 'Message too small'); + require(message<4230938, 'Message too big'); + + // If the message constructed above was indeed sent by starknet, this returns the hash of the message + // If the message was NOT sent by starknet, the cal will revert + starknetCore.consumeMessageFromL2(l2Evaluator, payload); + + // Firing an event, for fun + emit MessageReceived(message); + } +``` + +It is important to remember that on L1 we are sending a payload of `uint256`, but the basic data type on Starknet is `felt252`; however, `felt252` are approximatively 4 bits smaller than `uint256`. So we have to pay attention to the values contained in the payload of the messages we are sending. If, on L1, we build a message with values above the maximum `felt252`, the message will be stuck and never consumed on L2. + +If you want to learn more about the messaging mechanism, you can visit the [Starknet documentation](https://docs.starknet.io/documentation/architecture_and_concepts/L1-L2_Communication/messaging-mechanism/). diff --git a/src/title-page.md b/src/title-page.md index 95483997c..7ace60e30 100644 --- a/src/title-page.md +++ b/src/title-page.md @@ -2,4 +2,4 @@ by the Cairo Community and its [contributors](https://github.com/cairo-book/cairo-book.github.io). Special thanks to [Starkware](https://starkware.co/) through [OnlyDust](https://www.onlydust.xyz/), and [Voyager](https://voyager.online/) for supporting the creation of this book. -This version of the text assumes you’re using Cairo v1.1.0. See the “Installation” section of Chapter 1 to install or update Cairo. +This version of the text assumes you’re using the [Cairo Compiler](https://github.com/starkware-libs/cairo) [version 2.2.0](https://github.com/starkware-libs/cairo/releases). See the “Installation” section of Chapter 1 to install or update Cairo. diff --git a/theme/book.js b/theme/book.js index e303ebb45..e6a8cbc2b 100644 --- a/theme/book.js +++ b/theme/book.js @@ -61,7 +61,7 @@ function playground_text(playground, hidden = true) { win: "Ctrl-Enter", mac: "Ctrl-Enter" }, - exec: _editor => run_rust_code(playground_block) + exec: _editor => run_cairo_code(playground_block) }); } } @@ -99,6 +99,30 @@ function playground_text(playground, hidden = true) { } } + function run_cairo_code(code_block) { + var result_block = code_block.querySelector(".result"); + if (!result_block) { + result_block = document.createElement('code'); + result_block.className = 'result hljs language-bash'; + + code_block.append(result_block); + } + + let text = playground_text(code_block); + + result_block.innerText = "Running..."; + window.runFunc(text).then(data => { + if (data.trim() === '') { + result_block.innerText = "No output"; + result_block.classList.add("result-no-output"); + } else { + result_block.innerText = data; + result_block.classList.remove("result-no-output"); + } + }) + .catch(error => result_block.innerText = "Playground Communication: " + error.message); + } + function run_rust_code(code_block) { var result_block = code_block.querySelector(".result"); if (!result_block) { @@ -253,7 +277,8 @@ function playground_text(playground, hidden = true) { buttons.insertBefore(runCodeButton, buttons.firstChild); runCodeButton.addEventListener('click', function (e) { - run_rust_code(pre_block); + // run_rust_code(pre_block); + run_cairo_code(pre_block); }); if (window.playground_copyable) { diff --git a/theme/fonts/OPEN-SANS-LICENSE.txt b/theme/fonts/OPEN-SANS-LICENCE.txt similarity index 99% rename from theme/fonts/OPEN-SANS-LICENSE.txt rename to theme/fonts/OPEN-SANS-LICENCE.txt index d64569567..7a4a3ea24 100644 --- a/theme/fonts/OPEN-SANS-LICENSE.txt +++ b/theme/fonts/OPEN-SANS-LICENCE.txt @@ -199,4 +199,4 @@ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and - limitations under the License. + limitations under the License. \ No newline at end of file diff --git a/theme/index.hbs b/theme/index.hbs index f9bb7c7bb..15b30f8bf 100644 --- a/theme/index.hbs +++ b/theme/index.hbs @@ -336,6 +336,7 @@ + {{#each additional_js}} diff --git a/theme/js/index.mjs b/theme/js/index.mjs new file mode 100644 index 000000000..161f9688c --- /dev/null +++ b/theme/js/index.mjs @@ -0,0 +1,22 @@ +const maxWorkers = 1 +const worker = new Worker('js/worker.cjs') + +window.runFunc = async (cairo_program) => { + return new Promise((resolve, reject) => { + worker.postMessage({ + data: cairo_program, + availableGas: undefined, + printFullMemory: false, + useDBGPrintHint: true, + functionToRun: "runCairoProgram" + }); + + worker.onmessage = function(e) { + resolve(e.data.substring(e.data.indexOf('\n') + 1)); + }; + + worker.onerror = function(error) { + reject(error); + }; + }); +} diff --git a/theme/js/worker.cjs b/theme/js/worker.cjs new file mode 100644 index 000000000..7b1194fef --- /dev/null +++ b/theme/js/worker.cjs @@ -0,0 +1,29 @@ +importScripts("../pkg/wasm-cairo.js") +const { greet, compileCairoProgram, runCairoProgram } = wasm_bindgen; + +(async () => { + await wasm_bindgen("../pkg/wasm-cairo_bg.wasm") + + console.log(greet("Wasm-cairo ready.")) +})(); + +onmessage = function (e) { + const { data, functionToRun } = e.data; + wasm_bindgen("../pkg/wasm-cairo_bg.wasm").then(() => { + let result; + switch (functionToRun) { + case "runCairoProgram": + const { availableGas, printFullMemory, useDBGPrintHint } = e.data; + result = runCairoProgram(data, availableGas, printFullMemory, useDBGPrintHint); + break; + case "compileCairoProgram": + const { replaceIds } = e.data; + result = compileCairoProgram(data, replaceIds); + break; + default: + console.error(`Unexpected function: ${functionToRun}`); + return; + } + postMessage(result); + }); +} diff --git a/theme/pkg/README.md b/theme/pkg/README.md new file mode 100644 index 000000000..7410ac8ca --- /dev/null +++ b/theme/pkg/README.md @@ -0,0 +1,89 @@ + + + +## 🚴 Usage + + +### 🛠️ Build WASM-bindgen's WASM-Cairo Toolkit +With Modules + +``` +wasm-pack build --release --target web --out-dir ./pkg/module --out-name wasm-cairo +``` + +No Modules + +``` +wasm-pack build --release --target no-modules --out-dir ./pkg/no_module --out-name wasm-cairo +``` + +You will find `wasm-cairo_bg.wasm` and `wasm-cairo.js` in `pkg` folder. + + +### 🛠️ Build Astro Editor + +``` +wasm-pack build --release --target no-modules --out-dir ./dist/pkg --out-name wasm-cairo +``` + +Then run +``` +node app.js +``` +For local web instance. + +### 🛠️ Build WASMTIME's WASM-Cairo Toolkit + +``` +cargo build --target wasm32-wasi --release +``` + +You can test it by using: + +Compile Cairo + +``` +./wasmtime_test.sh compileCairoProgram ./cairo_files/HelloStarknetAstro.cairo ./cairo_files/HelloStarknetAstro.sierra +``` + +Run +``` +./wasmtime_test.sh runCairoProgram ./cairo_files/HelloStarknetAstro.cairo +``` + +Compile Contract + +``` +./wasmtime_test.sh compileStarknetContract ./cairo_files/erc20.cairo ./cairo_files/erc20.json +``` + +## 🔋 Batteries Included + +* [`wasm-bindgen`](https://github.com/rustwasm/wasm-bindgen) for communicating + between WebAssembly and JavaScript. +* [`console_error_panic_hook`](https://github.com/rustwasm/console_error_panic_hook) + for logging panic messages to the developer console. +* [`wee_alloc`](https://github.com/rustwasm/wee_alloc), an allocator optimized + for small code size. +* [`Cairo`](https://github.com/starkware-libs/cairo) for Cairo-lang support. +* `LICENSE-APACHE` and `LICENSE-MIT`: most Rust projects are licensed this way, so these are included for you + +## License + +* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. \ No newline at end of file diff --git a/theme/pkg/package.json b/theme/pkg/package.json new file mode 100644 index 000000000..0a90b2a9c --- /dev/null +++ b/theme/pkg/package.json @@ -0,0 +1,14 @@ +{ + "name": "wasm-cairo", + "collaborators": [ + "cryptonerdcn " + ], + "version": "0.2.1", + "files": [ + "wasm-cairo_bg.wasm", + "wasm-cairo.js", + "wasm-cairo.d.ts" + ], + "browser": "wasm-cairo.js", + "types": "wasm-cairo.d.ts" +} \ No newline at end of file diff --git a/theme/pkg/wasm-cairo.d.ts b/theme/pkg/wasm-cairo.d.ts new file mode 100644 index 000000000..c4a8e1ebd --- /dev/null +++ b/theme/pkg/wasm-cairo.d.ts @@ -0,0 +1,54 @@ +declare namespace wasm_bindgen { + /* tslint:disable */ + /* eslint-disable */ + /** + * @param {string} s + * @returns {string} + */ + export function greet(s: string): string; + /** + * @param {string} cairo_program + * @param {boolean} replace_ids + * @returns {string} + */ + export function compileCairoProgram(cairo_program: string, replace_ids: boolean): string; + /** + * @param {string} cairo_program + * @param {number | undefined} available_gas + * @param {boolean} print_full_memory + * @param {boolean} use_dbg_print_hint + * @returns {string} + */ + export function runCairoProgram(cairo_program: string, available_gas: number | undefined, print_full_memory: boolean, use_dbg_print_hint: boolean): string; + /** + * @param {string} starknet_contract + * @param {boolean} replace_ids + * @returns {string} + */ + export function compileStarknetContract(starknet_contract: string, replace_ids: boolean): string; + +} + +declare type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembly.Module; + +declare interface InitOutput { + readonly memory: WebAssembly.Memory; + readonly greet: (a: number, b: number, c: number) => void; + readonly compileCairoProgram: (a: number, b: number, c: number, d: number) => void; + readonly runCairoProgram: (a: number, b: number, c: number, d: number, e: number, f: number, g: number) => void; + readonly compileStarknetContract: (a: number, b: number, c: number, d: number) => void; + readonly __wbindgen_add_to_stack_pointer: (a: number) => number; + readonly __wbindgen_export_0: (a: number, b: number) => number; + readonly __wbindgen_export_1: (a: number, b: number, c: number, d: number) => number; + readonly __wbindgen_export_2: (a: number, b: number, c: number) => void; +} + +/** +* If `module_or_path` is {RequestInfo} or {URL}, makes a request and +* for everything else, calls `WebAssembly.instantiate` directly. +* +* @param {InitInput | Promise} module_or_path +* +* @returns {Promise} +*/ +declare function wasm_bindgen (module_or_path?: InitInput | Promise): Promise; diff --git a/theme/pkg/wasm-cairo.js b/theme/pkg/wasm-cairo.js new file mode 100644 index 000000000..af5f09935 --- /dev/null +++ b/theme/pkg/wasm-cairo.js @@ -0,0 +1,326 @@ +let wasm_bindgen; +(function() { + const __exports = {}; + let script_src; + if (typeof document !== 'undefined' && document.currentScript !== null) { + script_src = new URL(document.currentScript.src, location.href).toString(); + } + let wasm = undefined; + + const cachedTextDecoder = (typeof TextDecoder !== 'undefined' ? new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }) : { decode: () => { throw Error('TextDecoder not available') } } ); + + if (typeof TextDecoder !== 'undefined') { cachedTextDecoder.decode(); }; + + let cachedUint8Memory0 = null; + + function getUint8Memory0() { + if (cachedUint8Memory0 === null || cachedUint8Memory0.byteLength === 0) { + cachedUint8Memory0 = new Uint8Array(wasm.memory.buffer); + } + return cachedUint8Memory0; + } + + function getStringFromWasm0(ptr, len) { + ptr = ptr >>> 0; + return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); + } + + let WASM_VECTOR_LEN = 0; + + const cachedTextEncoder = (typeof TextEncoder !== 'undefined' ? new TextEncoder('utf-8') : { encode: () => { throw Error('TextEncoder not available') } } ); + + const encodeString = (typeof cachedTextEncoder.encodeInto === 'function' + ? function (arg, view) { + return cachedTextEncoder.encodeInto(arg, view); + } + : function (arg, view) { + const buf = cachedTextEncoder.encode(arg); + view.set(buf); + return { + read: arg.length, + written: buf.length + }; + }); + + function passStringToWasm0(arg, malloc, realloc) { + + if (realloc === undefined) { + const buf = cachedTextEncoder.encode(arg); + const ptr = malloc(buf.length, 1) >>> 0; + getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf); + WASM_VECTOR_LEN = buf.length; + return ptr; + } + + let len = arg.length; + let ptr = malloc(len, 1) >>> 0; + + const mem = getUint8Memory0(); + + let offset = 0; + + for (; offset < len; offset++) { + const code = arg.charCodeAt(offset); + if (code > 0x7F) break; + mem[ptr + offset] = code; + } + + if (offset !== len) { + if (offset !== 0) { + arg = arg.slice(offset); + } + ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; + const view = getUint8Memory0().subarray(ptr + offset, ptr + len); + const ret = encodeString(arg, view); + + offset += ret.written; + } + + WASM_VECTOR_LEN = offset; + return ptr; + } + + let cachedInt32Memory0 = null; + + function getInt32Memory0() { + if (cachedInt32Memory0 === null || cachedInt32Memory0.byteLength === 0) { + cachedInt32Memory0 = new Int32Array(wasm.memory.buffer); + } + return cachedInt32Memory0; + } + /** + * @param {string} s + * @returns {string} + */ + __exports.greet = function(s) { + let deferred2_0; + let deferred2_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0(s, wasm.__wbindgen_export_0, wasm.__wbindgen_export_1); + const len0 = WASM_VECTOR_LEN; + wasm.greet(retptr, ptr0, len0); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + deferred2_0 = r0; + deferred2_1 = r1; + return getStringFromWasm0(r0, r1); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_export_2(deferred2_0, deferred2_1, 1); + } + }; + + const heap = new Array(128).fill(undefined); + + heap.push(undefined, null, true, false); + +function getObject(idx) { return heap[idx]; } + +let heap_next = heap.length; + +function dropObject(idx) { + if (idx < 132) return; + heap[idx] = heap_next; + heap_next = idx; +} + +function takeObject(idx) { + const ret = getObject(idx); + dropObject(idx); + return ret; +} +/** +* @param {string} cairo_program +* @param {boolean} replace_ids +* @returns {string} +*/ +__exports.compileCairoProgram = function(cairo_program, replace_ids) { + let deferred3_0; + let deferred3_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0(cairo_program, wasm.__wbindgen_export_0, wasm.__wbindgen_export_1); + const len0 = WASM_VECTOR_LEN; + wasm.compileCairoProgram(retptr, ptr0, len0, replace_ids); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r2 = getInt32Memory0()[retptr / 4 + 2]; + var r3 = getInt32Memory0()[retptr / 4 + 3]; + var ptr2 = r0; + var len2 = r1; + if (r3) { + ptr2 = 0; len2 = 0; + throw takeObject(r2); + } + deferred3_0 = ptr2; + deferred3_1 = len2; + return getStringFromWasm0(ptr2, len2); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_export_2(deferred3_0, deferred3_1, 1); + } +}; + +function isLikeNone(x) { + return x === undefined || x === null; +} +/** +* @param {string} cairo_program +* @param {number | undefined} available_gas +* @param {boolean} print_full_memory +* @param {boolean} use_dbg_print_hint +* @returns {string} +*/ +__exports.runCairoProgram = function(cairo_program, available_gas, print_full_memory, use_dbg_print_hint) { + let deferred3_0; + let deferred3_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0(cairo_program, wasm.__wbindgen_export_0, wasm.__wbindgen_export_1); + const len0 = WASM_VECTOR_LEN; + wasm.runCairoProgram(retptr, ptr0, len0, !isLikeNone(available_gas), isLikeNone(available_gas) ? 0 : available_gas, print_full_memory, use_dbg_print_hint); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r2 = getInt32Memory0()[retptr / 4 + 2]; + var r3 = getInt32Memory0()[retptr / 4 + 3]; + var ptr2 = r0; + var len2 = r1; + if (r3) { + ptr2 = 0; len2 = 0; + throw takeObject(r2); + } + deferred3_0 = ptr2; + deferred3_1 = len2; + return getStringFromWasm0(ptr2, len2); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_export_2(deferred3_0, deferred3_1, 1); + } +}; + +/** +* @param {string} starknet_contract +* @param {boolean} replace_ids +* @returns {string} +*/ +__exports.compileStarknetContract = function(starknet_contract, replace_ids) { + let deferred3_0; + let deferred3_1; + try { + const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); + const ptr0 = passStringToWasm0(starknet_contract, wasm.__wbindgen_export_0, wasm.__wbindgen_export_1); + const len0 = WASM_VECTOR_LEN; + wasm.compileStarknetContract(retptr, ptr0, len0, replace_ids); + var r0 = getInt32Memory0()[retptr / 4 + 0]; + var r1 = getInt32Memory0()[retptr / 4 + 1]; + var r2 = getInt32Memory0()[retptr / 4 + 2]; + var r3 = getInt32Memory0()[retptr / 4 + 3]; + var ptr2 = r0; + var len2 = r1; + if (r3) { + ptr2 = 0; len2 = 0; + throw takeObject(r2); + } + deferred3_0 = ptr2; + deferred3_1 = len2; + return getStringFromWasm0(ptr2, len2); + } finally { + wasm.__wbindgen_add_to_stack_pointer(16); + wasm.__wbindgen_export_2(deferred3_0, deferred3_1, 1); + } +}; + +async function __wbg_load(module, imports) { + if (typeof Response === 'function' && module instanceof Response) { + if (typeof WebAssembly.instantiateStreaming === 'function') { + try { + return await WebAssembly.instantiateStreaming(module, imports); + + } catch (e) { + if (module.headers.get('Content-Type') != 'application/wasm') { + console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n", e); + + } else { + throw e; + } + } + } + + const bytes = await module.arrayBuffer(); + return await WebAssembly.instantiate(bytes, imports); + + } else { + const instance = await WebAssembly.instantiate(module, imports); + + if (instance instanceof WebAssembly.Instance) { + return { instance, module }; + + } else { + return instance; + } + } +} + +function __wbg_get_imports() { + const imports = {}; + imports.wbg = {}; + imports.wbg.__wbg_log_65d0b624a75fcb22 = function(arg0, arg1) { + console.log(getStringFromWasm0(arg0, arg1)); + }; + + return imports; +} + +function __wbg_init_memory(imports, maybe_memory) { + +} + +function __wbg_finalize_init(instance, module) { + wasm = instance.exports; + __wbg_init.__wbindgen_wasm_module = module; + cachedInt32Memory0 = null; + cachedUint8Memory0 = null; + + + return wasm; +} + +function initSync(module) { + if (wasm !== undefined) return wasm; + + const imports = __wbg_get_imports(); + + __wbg_init_memory(imports); + + if (!(module instanceof WebAssembly.Module)) { + module = new WebAssembly.Module(module); + } + + const instance = new WebAssembly.Instance(module, imports); + + return __wbg_finalize_init(instance, module); +} + +async function __wbg_init(input) { + if (wasm !== undefined) return wasm; + + if (typeof input === 'undefined' && script_src !== 'undefined') { + input = script_src.replace(/\.js$/, '_bg.wasm'); + } + const imports = __wbg_get_imports(); + + if (typeof input === 'string' || (typeof Request === 'function' && input instanceof Request) || (typeof URL === 'function' && input instanceof URL)) { + input = fetch(input); + } + + __wbg_init_memory(imports); + + const { instance, module } = await __wbg_load(await input, imports); + + return __wbg_finalize_init(instance, module); +} + +wasm_bindgen = Object.assign(__wbg_init, { initSync }, __exports); + +})(); diff --git a/theme/pkg/wasm-cairo_bg.wasm b/theme/pkg/wasm-cairo_bg.wasm new file mode 100644 index 000000000..c4b1bd15d Binary files /dev/null and b/theme/pkg/wasm-cairo_bg.wasm differ diff --git a/theme/pkg/wasm-cairo_bg.wasm.d.ts b/theme/pkg/wasm-cairo_bg.wasm.d.ts new file mode 100644 index 000000000..b3b006706 --- /dev/null +++ b/theme/pkg/wasm-cairo_bg.wasm.d.ts @@ -0,0 +1,11 @@ +/* tslint:disable */ +/* eslint-disable */ +export const memory: WebAssembly.Memory; +export function greet(a: number, b: number, c: number): void; +export function compileCairoProgram(a: number, b: number, c: number, d: number): void; +export function runCairoProgram(a: number, b: number, c: number, d: number, e: number, f: number, g: number): void; +export function compileStarknetContract(a: number, b: number, c: number, d: number): void; +export function __wbindgen_add_to_stack_pointer(a: number): number; +export function __wbindgen_export_0(a: number, b: number): number; +export function __wbindgen_export_1(a: number, b: number, c: number, d: number): number; +export function __wbindgen_export_2(a: number, b: number, c: number): void;