From d2ea4ebcc0d4f26e018ef086d55187a34bc40c86 Mon Sep 17 00:00:00 2001 From: Luke Zhang Date: Thu, 18 Jan 2018 17:16:39 -0500 Subject: [PATCH] updates to lesson 2 --- zh/2/00-overview.md | 5 +++-- zh/2/1-overview.md | 20 ++++++++++---------- zh/2/10-interactingcontracts.md | 32 +++++++++++++++++--------------- zh/2/11-interactingcontracts2.md | 9 +++++---- zh/2/12-multiplereturns.md | 8 ++++---- zh/2/13-kittygenes.md | 7 ++----- zh/2/14-wrappingitup.md | 6 +++--- zh/2/2-mappings.md | 18 +++++++----------- zh/2/3-msgsender.md | 16 ++++++++-------- zh/2/4-require.md | 22 +++++++++++----------- zh/2/5-inheritance.md | 12 +++++------- zh/2/6-importfiles.md | 4 ++-- zh/2/7-storage.md | 23 ++++++++++++----------- zh/2/8-feedandmultiply2.md | 6 +++--- zh/2/9-internalfunctions.md | 12 ++++++------ zh/2/template.md | 6 ++++-- 16 files changed, 102 insertions(+), 104 deletions(-) diff --git a/zh/2/00-overview.md b/zh/2/00-overview.md index 20652a8062..8318c5c254 100644 --- a/zh/2/00-overview.md +++ b/zh/2/00-overview.md @@ -3,6 +3,7 @@ title: 僵尸攻击人类 header: 所以,你需要晋级至第二课! roadmap: roadmap2.jpg --- + 厉害了,我的人类! 你比我设想的更会编程! -第二课中你会学到如何通过喂养其他生物,增加你僵尸军团的数量 -在这一课中,我们会使用到一些高级的Solidity概念,所以你一定要先完成第一课。 +第二课中,你会学到如何通过吞噬其他生物,扩张你的僵尸军团 +在这一课里,我们会使用到一些高级的Solidity概念,所以你一定要先完成第一课。 diff --git a/zh/2/1-overview.md b/zh/2/1-overview.md index e5068e994e..c71fe2fbf1 100644 --- a/zh/2/1-overview.md +++ b/zh/2/1-overview.md @@ -11,21 +11,21 @@ material: answer: 1 --- -在第一课中,我们创建了一个命名的函数用来生成僵尸 ,并且将它放置在我们区块链的僵尸数据库中。 -在第二课里,我们会让我们的app更加像一个游戏: 让它支持多用户,并且采用更加有趣--而不仅仅随机--的方式,来生成僵尸, +在第一课中,我们创建了一个命名函数用来生成僵尸,并且将它放入区块链上的僵尸数据库中。 +在第二课里,我们会让我们的app看起来更像一个游戏: 它得支持多用户,并且采用更加有趣--而不仅仅随机--的方式,来生成新的僵尸。 -我们如何生成新的僵尸呢?通过让僵尸“喂食”其他生物! +如何生成新的僵尸呢?通过让现有的僵尸猎食其他生物! -## 僵尸喂食 +## 僵尸猎食 -僵尸喂食的时候, 它会用病毒侵入宿主, 这些病毒会将宿主变为新的僵尸,加入你的军团。系统会通过宿主和侵入僵尸的DNA计算出新僵尸的DNA。 +僵尸猎食的时候, 僵尸病毒侵入猎物, 这些病毒会将猎物变为新的僵尸,加入你的Solidity。系统会通过猎物和猎食者僵尸的DNA计算出新僵尸的DNA。 -僵尸最喜欢喂食什么样的物种呢? +僵尸最喜欢猎食什么物种呢? 等你学完第二课就知道了! -# 小测试 +# 实战演习 -右边是一个简单的喂食展示。点击一个“人”,试试看僵尸喂食的时候会发生什么? -可见,新僵尸的DNA是通过从原来的僵尸的DNA, 加上宿主的DNA计算得来的。 +右边是一个简单的猎食演示。点击一个“人”,看看僵尸猎食的时候会发生什么? +可见,新僵尸的DNA是通过从原来的僵尸的DNA, 加上猎物的DNA计算得来的。 -学完这一章,请点击“下一章”, 我们让游戏支持多玩家模式。 \ No newline at end of file +学完这一章,请点击“下一章”, 我们该让游戏支持多玩家模式了。 \ No newline at end of file diff --git a/zh/2/10-interactingcontracts.md b/zh/2/10-interactingcontracts.md index eb031d363a..3a4656d014 100644 --- a/zh/2/10-interactingcontracts.md +++ b/zh/2/10-interactingcontracts.md @@ -95,7 +95,7 @@ material: } --- -是时候喂喂我们的僵尸了! 那僵尸最喜欢吃什么呢? +是时候让我们的僵尸去捕猎! 那僵尸最喜欢的食物是什么呢? Crypto僵尸喜欢吃的是... @@ -103,13 +103,13 @@ Crypto僵尸喜欢吃的是... (正经点,我可不是开玩笑😆) -为了做到这一点,我们要读出CryptoKitties智能合约中的kittyDna。这些数据是公开存储在区块链中的。区块链是不是很酷? +为了做到这一点,我们要读出CryptoKitties智能合约中的kittyDna。这些数据是公开存储在区块链上的。区块链是不是很酷? -别担心 - 我们的游戏并不会伤害到任何真正的CryptoKitty。 我们只读取* CryptoKitties数据,但是无法物理上删除它 +别担心 - 我们的游戏并不会伤害到任何真正的CryptoKitty。 我们只读取* CryptoKitties*数据,但却无法物理上删除它。 -##与其他合约交互 +##与其他合约的交互 -如果我们的合约需要和区块链上的其他的合约对话,则需要先定义一个** _interface_ **(接口)。 +如果我们的合约需要和区块链上的其他的合约会话,则需先定义一个** _interface_ **(接口)。 先举一个简单的栗子。 假设在区块链上有这么一个合约: @@ -128,9 +128,9 @@ contract LuckyNumber { } ``` -这是个简单的合约,您可以用它存储自己的幸运号码,并与您的以太坊地址关联。 这样其他人就可以使用这个地址查找您的幸运号码了。 +这是个很简单的合约,您可以用它存储自己的幸运号码,并将其与您的以太坊地址关联。 这样其他人就可以通过您的地址查找您的幸运号码了。 -现在假设我们有一个外部合约,使用`getNum`函数来读取其中的数据。 +现在假设我们有一个外部合约,使用`getNum`函数可读取其中的数据。 首先,我们定义“LuckyNumber”合约的** _interface_ **: @@ -141,17 +141,19 @@ contract NumberInterface { } ``` -请注意,这个过程看起来像在定义一个合同,不同的是,首先,我们只声明了要与之交互的函数 - 在本例中为`getNum` - 而且,我们没有使用到任何关于函数或状态的变量。 +请注意,这个过程虽然看起来像在定义一个合约,但其实内里不同: -其次,我们并没有用大括号(`{`和`}`)定义函数体,我们只是用分号(`;`)来结束函数声明。这使它看起来像一个合约框架。 +首先,我们只声明了要与之交互的函数 - 在本例中为`getNum` - 在其中我们没有使用到任何关于函数或状态的变量。 -编译器就是靠这些特征知道它是一个接口的。 +其次,我们并没有使用大括号(`{`和`}`)定义函数体,我们单单用分号(`;`)结束了函数声明。这使它看起来像一个合约框架。 -在我们的app代码中使用这个接口,我们的合约就知道其他合约的函数是怎么样的,如何调用它们,以及期待什么类型的响应。 +编译器就是靠这些特征认出它是一个接口的。 -在下一课中,我们将真实地调用其他合约的函数。目前我们只要声明一个为调用CryptoKitties合约而准备的接口就行了。 +在我们的app代码中使用这个接口,合约就知道其他合约的函数是怎样的,应该如何调用,以及可期待什么类型的返回。 -# 小测试 +在下一课中,我们将真正调用其他合约的函数。目前我们只要声明一个接口,用于调用CryptoKitties合约就行了。 + +# 实战演习 我们已经为你查看过了CryptoKitties的源代码,并且找到了一个名为`getKitty`的函数,它返回所有的加密猫的数据,包括它的“基因”(我们的僵尸游戏要用它生成新的僵尸)。 @@ -186,9 +188,9 @@ function getKitty(uint256 _id) external view returns ( } ``` -这个函数看起来跟我们习惯的函数不太一样。 它竟然返回了...一堆不同的值! 如果您使用过Javascript之类的编程语言,一定会感到奇怪 - 在Solidity中,您可以让一个函数返回多个值。 +这个函数看起来跟我们习惯的函数不太一样。 它竟然返回了...一堆不同的值! 如果您用过Javascript之类的编程语言,一定会感到奇怪 - 在Solidity中,您可以让一个函数返回多个值。 -现在我们知道这个函数章什么样的,我们可以用它来创建一个接口: +现在我们知道这个函数长什么样的了,就可以用它来创建一个接口: 1.定义一个名为`KittyInterface`的接口。 请注意,因为我们使用了`contract`关键字, 这过程看起来就像创建一个新的合同一样。 diff --git a/zh/2/11-interactingcontracts2.md b/zh/2/11-interactingcontracts2.md index 6b7bed8f9d..b373ed7436 100644 --- a/zh/2/11-interactingcontracts2.md +++ b/zh/2/11-interactingcontracts2.md @@ -121,7 +121,8 @@ contract NumberInterface { function getNum(address _myAddress) public view returns (uint); } ``` -我们可以在合同中这样使用: + +我们可以在合约中这样使用: ``` contract MyContract { @@ -138,10 +139,10 @@ contract MyContract { } ``` -通过这种方式,只要将您合约的功能设置为“公共”或“外部”,它们就可以与以太坊区块链上的任何其他合同进行交互。 +通过这种方式,只要将您合约的可见性设置为“公共”或“外部”,它们就可以与以太坊区块链上的任何其他合同进行交互。 #小测验 -我们来建个自己的合约去读取智能CryptoKitties合约的内容吧! +我们来建个自己的合约去读取另一个智能合约--CryptoKitties的内容吧! -1.我已经将代码中CryptoKitties合约的地址保存在一个名为`ckAddress`的变量中。在下一行中,请创建一个名为`kittyContract`的KittyInterface,并用`ckAddress`初始化 - 就像我们为`numberContract`所做的一样。 +1.我已经将代码中CryptoKitties合约的地址保存在一个名为`ckAddress`的变量中。在下一行中,请创建一个名为`kittyContract`的KittyInterface,并用`ckAddress`为它初始化 - 就像我们为`numberContract`所做的一样。 diff --git a/zh/2/12-multiplereturns.md b/zh/2/12-multiplereturns.md index ae3668246a..94e1ac9dec 100644 --- a/zh/2/12-multiplereturns.md +++ b/zh/2/12-multiplereturns.md @@ -145,18 +145,18 @@ function getLastReturnValue() external { } ``` -# 小测试 +# 实战演习 是时候与CryptoKitties合约交互起来了! -让我们定义一个函数,从kitty 合约中获取它的基因: +我们来定义一个函数,从kitty 合约中获取它的基因: 1.创建一个名为`feedOnKitty`的函数。它需要2个`uint`类型的参数,`_zombieId`和`_kittyId`,这是一个`public`类型的函数。 2.函数首先要声明一个名为`kittyDna`的`uint`。 -  >注意:在我们的KittyInterface中,`genes`是一个`uint256`类型的变量,但是如果你记得,我们在第一课中提到过,`uint`是`uint256`的别名,也就是说,它们是一回事。 +  >注意:在我们的KittyInterface中,`genes`是一个`uint256`类型的变量,但是如果你记得,我们在第一课中提到过,`uint`是`uint256`的别名,也就是说它们是一回事。 3.这个函数接下来使用了 _kittyId 参数,去调用`kittyContract.getKitty`函数,并将返回的 `genes`存储在`kittyDna`中。记住 - `getKitty`会返回一大堆变量。 (确切地说10个 - 我已经为你数过了,不错吧!)。但是我们只关心最后一个--“基因”。数逗号的时候小心点哦! -4.最后,函数调用了`feedAndMultiply`,传了`_zombieId`和`kittyDna`两个参数。 +4.最后,函数调用了`feedAndMultiply`,并传入了`_zombieId`和`kittyDna`两个参数。 diff --git a/zh/2/13-kittygenes.md b/zh/2/13-kittygenes.md index dbcdb7e368..b3ece5195e 100644 --- a/zh/2/13-kittygenes.md +++ b/zh/2/13-kittygenes.md @@ -149,15 +149,14 @@ material: if语句的语法在 Solidity中,与在javascript差不多: ``` function eatBLT(string sandwich) public { - // Remember with strings, we have to compare their keccak256 hashes - // to check equality + // 看清楚了,当我们比较字符串的时候,需要比较他们的 keccak256 哈希码 if (keccak256(sandwich) == keccak256("BLT")) { eat(); } } ``` -# 小测试 +# 实战演习 让我们在我们的僵尸代码中实现小猫的基因。 @@ -171,6 +170,4 @@ function eatBLT(string sandwich) public {  >解释:假设`newDna`是`334455`。那么`newDna%100`是`55`,所以`newDna - newDna%100`得到`334400`。最后加上`99`可得到`334499`。 -4. Lastly, we need to change the function call inside `feedOnKitty`. When it calls `feedAndMultiply`, add the parameter `"kitty"` to the end. - 4.最后,我们修改了`feedOnKitty`中的函数调用。当它调用`feedAndMultiply`时,增加了`“kitty”`作为最后一个参数。 diff --git a/zh/2/14-wrappingitup.md b/zh/2/14-wrappingitup.md index 892e8914d9..1056f32972 100644 --- a/zh/2/14-wrappingitup.md +++ b/zh/2/14-wrappingitup.md @@ -17,7 +17,7 @@ material: ## Javascript 实现 -我们只用编译和部署`ZombieFeeding`,就可以将这个合约部署到以太坊了。 - 因为我们最终完成的这个合约继承自`ZombieFactory`,并且它可以访问自己和父辈合约中的所有public方法。 +我们只用编译和部署`ZombieFeeding`,就可以将这个合约部署到以太坊了。 - 我们最终完成的这个合约继承自`ZombieFactory`,因此它可以访问自己和父辈合约中的所有public方法。 我们来看一个与我们的刚部署的合约进行交互的例子, 这个例子使用了Javascript和web3.js: @@ -56,8 +56,8 @@ ZombieFactory.NewZombie(function(error, result) { }) ``` -选择一只你想吃的小猫。你自家僵尸的DNA会和小猫的DNA结合,生成一个新的小猫僵尸加入你的军团! +选择一只你想猎食的小猫。你自家僵尸的DNA会和小猫的DNA结合,生成一个新的小猫僵尸,加入你的军团! 看到新僵尸上那可爱的猫咪腿了么?这是新僵尸最后DNA中最后两位数字“99”的功劳! -你想要的话随时可以重新开始。能捕获一只猫咪僵尸,你一定很高兴吧!(不过你只能持有一只),继续前进到下一章,完成第二课吧! +你想要的话随时可以重新开始。捕获了一只猫咪僵尸,你一定很高兴吧!(不过你只能持有一只),继续前进到下一章,完成第二课吧! diff --git a/zh/2/2-mappings.md b/zh/2/2-mappings.md index ce3d03c7b9..f5bed695f0 100644 --- a/zh/2/2-mappings.md +++ b/zh/2/2-mappings.md @@ -80,33 +80,29 @@ material: 我们通过给数据库中的僵尸指定“主人”, 来支持“多玩家”模式。 -要做到这一点,我们需要2个新的数据类型:“映射”和“地址”。 +如此一来,我们需要引入2个新的数据类型:“映射”和“地址”。 ## 地址 -以太坊区块链由** _ 账户号 _ **组成,您可以把它想象成银行账户。一个帐户的余额是** _以太_ **(在以太坊区块链上使用的币种),您可以和其他帐户之间支付和接受以太币,就像您的银行帐户可以电汇资金到其他银行帐户一样。 +以太坊区块链由** _ account _ **(账户号)组成,您可以把它想象成银行账户。一个帐户的余额是** _以太_ **(在以太坊区块链上使用的币种),您可以和其他帐户之间支付和接受以太币,就像您的银行帐户可以电汇资金到其他银行帐户一样。 -每个帐户都有一个“地址”,您可以把它想象成银行账号。这是一个账户唯一的标识符,它看起来是这样的: +每个帐户都有一个“地址”,您可以把它想象成银行账号。这是账户唯一的标识符,它看起来长这样: `0x0cE446255506E92DF41614C46F1d6df9Cc969183` -(这个地址属于CryptoZombies团队,如果你喜欢CryptoZombies,可以给我们一些以太币!😉) +(这是CryptoZombies团队的地址,如果你喜欢CryptoZombies的话,请打赏我们一些以太币!😉) 我们将在后面的课程中介绍地址的细节,现在您只需要了解**地址属于特定用户(或智能合约)的**。 -所以我们可以指定“地址”作为僵尸拥有者的ID。当用户通过与我们的应用程序交互来创建新的僵尸时,我们将把这些僵尸的所有权设置到调用者的太坊地址名下。 +所以我们可以指定“地址”作为僵尸主人的ID。当用户通过与我们的应用程序交互来创建新的僵尸时,新僵尸的所有权被设置到调用者的太坊地址名下。 ##映射 在第1课中,我们看了** _ structs _ ** 和 ** _ arrays _ **。 ** _映射_ **是另一种在Solidity中存储有组织数据的方法。 -这样可以定义一个映射: +映射是这样定义的: ``` -// For a financial app, storing a uint that holds the user's account balance: -mapping (address => uint) public accountBalance; -// Or could be used to store / lookup usernames based on userId -mapping (uint => string) userIdToName; //对于金融应用程序,用以保存用户账户余额的单元: mapping (address => uint) public accountBalance; //或者可以用来通过userId 存储/查找的用户名 @@ -116,7 +112,7 @@ mapping (uint => string) userIdToName; 映射本质上是存储和查找数据所用的键-值对。在第一个例子中,键是一个“地址”,值是一个“单元”,在第二个例子中,键是一个“单元”,值是一个“字符串”。 -# 小测试 +# 实战演习 为了存储僵尸的所有权,我们会使用到两个映射:一个记录僵尸拥有者的地址,另一个记录某ID所拥有僵尸的数量。 diff --git a/zh/2/3-msgsender.md b/zh/2/3-msgsender.md index cc47f9407b..e8c975a66a 100644 --- a/zh/2/3-msgsender.md +++ b/zh/2/3-msgsender.md @@ -81,9 +81,9 @@ material: } --- -现在我们有了一套映射来记录僵尸的拥有者,我们可以修改`_createZombie`方法来使用它们。 +现在有了一套映射来记录僵尸的所有权了,我们可以修改`_createZombie`方法来运用它们。 -为了做到这一点,我们需要使用“msg.sender”。 +为了做到这一点,我们要用到“msg.sender”。 ## msg.sender @@ -113,15 +113,15 @@ function whatIsMyNumber() public view returns (uint) { 使用“msg.sender”很安全,因为它具有以太坊区块链的安全保障 - 除非窃取与以太坊地址相关联的私钥,否则是没有办法修改其他人的数据的。 -# 小测验 +# 实战演习 -让我们修改第1课的`_createZombie`方法,将僵尸的所有权分配给函数调用者。 +我们来修改第1课的`_createZombie`方法,将僵尸分配给函数调用者吧。 -1.首先,在我们得到新的僵尸`id`后,更新`zombieToOwner`映射,在`id`下面存入`msg.sender`。 +1.首先,在得到新的僵尸`id`后,更新`zombieToOwner`映射,在`id`下面存入`msg.sender`。 -第二,我们为这个“msg.sender”增加`ownerZombieCount`。 +然后,我们为这个“msg.sender”名下的`ownerZombieCount`加1。 -跟在javascript中一样, 在Solidity中你也可以用`++`增加`uint`。 +跟在javascript中一样, 在Solidity中你也可以用`++`使`uint`递增。 ``` uint number = 0; @@ -129,4 +129,4 @@ number++; // `number` 现在是 `1`了 ``` -本章答案,修改两行代码就可以了。 +修改两行代码即可。 diff --git a/zh/2/4-require.md b/zh/2/4-require.md index 2b41051553..c5e7b5f7c4 100644 --- a/zh/2/4-require.md +++ b/zh/2/4-require.md @@ -85,13 +85,13 @@ material: } --- -在第一课中,我们做到了让用户通过调用`createRandomZombie`并输入一个名字来创建新的僵尸。 但是,如果用户持续调用这个功能,并创建出无限多个僵尸加入他们的军团,这个游戏就太没意思了! +在第一课中,我们成功让用户通过调用`createRandomZombie`并输入一个名字来创建新的僵尸。 但是,如果用户持续调用这个函数,并创建出无限多个僵尸加入他们的军团,这游戏就太没意思了! -于是,我们做出限定:每个玩家只能调用一次这个功能。 这样一来,新玩家可以在刚开始玩游戏时调用它,以便在他们的军队中创建初始僵尸。 +于是,我们作出限定:每个玩家仅允许一次调用随机创建函数。 这样一来,新玩家可以在刚开始玩游戏时通过调用它,为其军团创建初始僵尸。 -我们怎样才能限定每个玩家只调用一次创建功能呢? +我们怎样才能限定每个玩家只调用一次随机创建函数呢? -我们使用`require`。 `require`使得函数在某些状况下运行时候会抛出一个错误,迫使程序终止: +答案是使用`require`。 `require`使得函数在某些状况下运行时候抛出异常,迫使程序终止: ``` function sayHiToVitalik(string _name) public returns (string) { @@ -106,18 +106,18 @@ function sayHiToVitalik(string _name) public returns (string) { 如果你使用参数`sayHiToVitalik(“Vitalik”)`调用创建函数 -,它会返回“Hi!”。而如果你用任何其他的参数来调用它,它都会抛出一个错误并停止运行。 +,它会返回“Hi!”。而如果调用时候使用了其他参数,它则会抛出异常并停止运行。 因此,在调用一个函数之前,用`require`验证前置条件是非常有必要的。 -#小测试 +#实战演习 -在我们的僵尸游戏中,我们不希望用户通过反复调用`createRandomZombie`来給他们的军队创建无限多个僵尸 - 这会让我们的游戏变得无聊。 +在我们的僵尸游戏中,我们不希望用户通过反复调用`createRandomZombie`来給他们的军队创建无限多个僵尸 - 这将使得游戏非常无聊。 -我们使用了`require`来确保这个函数只有在每个用户第一次执行的时候运行,用以创建初始僵尸。 +我们使用了`require`来确保这个函数只有在每个用户第一次调用它的时候运行,用以创建初始僵尸。 -1.在`createRandomZombie`的前面放置`require`语句。 该函数检查`ownerZombieCount [msg.sender]`是不是等于`0`,否则就抛出一个错误。 +1.在`createRandomZombie`的前面放置`require`语句。 使得函数先检查`ownerZombieCount [msg.sender]`是否等于`0`,不然就抛出一个错误。 >注意:在Solidity中,关键词放置的顺序并不重要 -- 两个位置是等效的。 但是,由于我们的答案检查器比较呆板,它只能认定其中一个为正确答案 -- 于是在这里,我们规定把`ownerZombieCount [msg.sender]`放前面吧 \ No newline at end of file +- 虽然参数的两个位置是等效的。 但是,由于我们的答案检查器比较呆板,它只能认定其中一个为正确答案 +- 于是在这里,我们就约定把`ownerZombieCount [msg.sender]`放前面吧 \ No newline at end of file diff --git a/zh/2/5-inheritance.md b/zh/2/5-inheritance.md index 06e1fbaa0c..1d682bdfdb 100644 --- a/zh/2/5-inheritance.md +++ b/zh/2/5-inheritance.md @@ -95,9 +95,7 @@ material: 我们的游戏代码越来越长。 当代码过于冗长的时候,最好将代码和逻辑分拆到多个不同的合约中,以便于管理。 -有个让Solidity的更易于管理的功能,就是** _继承_ **合约: - - +有个让Solidity的易于管理的功能,就是** _inheritance_ **(集成)合约: ``` contract Doge { @@ -113,13 +111,13 @@ contract BabyDoge is Doge { } ``` -由于 `BabyDoge` 是从 “Doge”哪里 **_ _inherits__** (继承)过来的。 这意味着当您编译和部署了`BabyDoge`,它将可以访问`catchphrase()`和`anotherCatchphrase()`以及我们在`Doge`中定义的其他公共函数。 +由于 `BabyDoge` 是从 “Doge”哪里 **_inherits_** (继承)过来的。 这意味着当您编译和部署了`BabyDoge`,它将可以访问`catchphrase()`和`anotherCatchphrase()`和其他我们在`Doge`中定义的其他公共函数。 这可以用于逻辑继承(比如表达子类的时候,`Cat`是一种`Animal`)。 但也可以简单地将类似的逻辑组合到不同的类中以组织代码。 -#小测试 +#实战演习 -在接下来的章节中,我们将要为僵尸实现各种功能,让它可以“饲养”和“繁殖”。 我们把这些运算放到父类“ZombieFactory”中,这样所有继承自“ZombieFactory”的类都可以使用这些方法了。 +在接下来的章节中,我们将要为僵尸实现各种功能,让它可以“猎食”和“繁殖”。 通过将这些运算放到父类“ZombieFactory”中,使得所有“ZombieFactory”的继承者类都可以使用这些方法。 -1.在ZombieFactory下创建一个叫“ZombieFeeding”的合约,使它继承自“ZombieFactory”合约。 +1.在ZombieFactory下创建一个叫“ZombieFeeding”的合约,它是继承自“ZombieFactory”合约的。 diff --git a/zh/2/6-importfiles.md b/zh/2/6-importfiles.md index 4c4dcce86c..5852bc87d6 100644 --- a/zh/2/6-importfiles.md +++ b/zh/2/6-importfiles.md @@ -79,8 +79,8 @@ contract newContract is SomeOtherContract { 这样当我们在合约(contract)目录下有一个名为`someothercontract.sol`的文件(`./`就是同一目录的意思),它就会被编译器导入。 -#小测验 +#实战演习 -现在我们已经建立了一个多文件架构,并且使用`import`来读取来自另一个文件中合约的内容: +现在我们已经建立了一个多文件架构,并用`import`来读取来自另一个文件中合约的内容: 1.将`zombiefactory.sol`导入到我们的新文件`zombiefeeding.sol`中。 \ No newline at end of file diff --git a/zh/2/7-storage.md b/zh/2/7-storage.md index 58d368abb8..bf2038bf17 100644 --- a/zh/2/7-storage.md +++ b/zh/2/7-storage.md @@ -68,13 +68,14 @@ material: } --- + 在Solidity中,有两个地方可以存储变量 - “存储”或“内存”。 -** _存储_ **变量是指永久存储在区块链中的变量。 ** _内存_ ** 变量则是临时的,当外部函数对某合约调用完成时,内存型变量即被移除。 您可以把它想象成存储在你电脑的硬盘或是RAM中数据的关系。 +**_Storage_**(存储)变量是指永久存储在区块链中的变量。 **_Memory_**(内存) 变量则是临时的,当外部函数对某合约调用完成时,内存型变量即被移除。 您可以把它想象成存储在你电脑的硬盘或是RAM中数据的关系。 -大多数情况下,您都用不到这些关键字,默认情况下Solidity会自动处理它们。 状态变量(在函数之外声明的变量)默认为“存储”形式,并永久写入区块链;而在函数内部声明的变量是“内存”型的,它们函数调用结束后消失。 +大多数时候您都用不到这些关键字,默认情况下Solidity会自动处理它们。 状态变量(在函数之外声明的变量)默认为“存储”形式,并永久写入区块链;而在函数内部声明的变量是“内存”型的,它们函数调用结束后消失。 -然而也有一些时候,您需要手动声明存储类型,主要用于处理函数内的** _ structs _ **和** _ arrays _ ** 时: +然而也有一些情况下,您需要手动声明存储类型,主要用于处理函数内的** _ structs _ **和** _ arrays _ ** 时: ``` @@ -112,23 +113,23 @@ contract SandwichFactory { } ``` -如果您还没有完全理解究竟应该使用哪一个,也不用担心 - 在本教程中,我们将告诉您何时使用“存储”以及何时使用“内存”,并且当您不得不使用到这些关键字的时候,Solidity编译器也发警示提醒您的。 +如果您还没有完全理解究竟应该使用哪一个,也不用担心 -- 在本教程中,我们将告诉您何时使用“存储”或是“内存”,并且当您不得不使用到这些关键字的时候,Solidity编译器也发警示提醒您的。 -现在,只要知道在某些场合下您需要显式地声明“存储”或“内存”就够了! +现在,只要知道在某些场合下也需要您显式地声明“存储”或“内存”就够了! -# 小测试 +# 实战演习 -是时候给我们的僵尸增加“喂养”和“繁殖”功能了! +是时候给我们的僵尸增加“猎食”和“繁殖”功能了! -当一个僵尸吞噬其他生物体时,它自身的DNA将与被吞噬生物的DNA结合在一起,形成一个新的僵尸DNA。 +当一个僵尸猎食其他生物体时,它自身的DNA将与猎物生物的DNA结合在一起,形成一个新的僵尸DNA。 1.创建一个名为`feedAndMultiply`的函数。 使用两个参数:`_zombieId`(`单元(uint)`)和`_targetDna`(也是`uint`类型)。 设置属性为“public”(公开)的。 -2.我们不希望别人用我们的僵尸喂食。 首先,我们确保对自己僵尸的拥有权。 通过添加一个`require`语句来确保`msg.sender`和这个僵尸的所有者是同一个人(类似于我们在`createRandomZombie`函数中所做的)。 +2.我们不希望别人用我们的僵尸去捕猎。 首先,我们确保对自己僵尸的所有权。 通过添加一个`require`语句来确保`msg.sender`只能是这个僵尸的主人(类似于我们在`createRandomZombie`函数中做过的那样)。 ->注意:同样,因为我们的答案检查器比较原始,所以只能接收“msg.sender”在前的答案,如果您切换了参数的顺序,它就不认了。 但通常当您编码时,如何安排参数顺序都是正确的。 +>注意:同样,因为我们的答案检查器比较呆萌,只认识把“msg.sender”在前的答案,如果您切换了参数的顺序,它就不认得了。 但您正常编码时,如何安排参数顺序都是正确的。 -3. 我们需要获取这个僵尸的DNA。 所以我们的函数接下来声明一个名为myZombie的本地`僵尸'(这是一个“存储”形的指针)。 在我们的`zombies`数组中将这个变量设置为索引`_zombieId`。 +3. 为了获取这个僵尸的DNA,我们的函数需要声明一个名为myZombie的本地`僵尸'(这是一个“存储”形的指针)。 在我们的`zombies`数组中将这个变量设置为索引`_zombieId`。 到目前为止,包括关闭`}`的那一行, 你该一共写了4行代码。 diff --git a/zh/2/8-feedandmultiply2.md b/zh/2/8-feedandmultiply2.md index ce016dcf38..97b7683668 100644 --- a/zh/2/8-feedandmultiply2.md +++ b/zh/2/8-feedandmultiply2.md @@ -91,15 +91,15 @@ function testDnaSplicing() public { } ``` -以后,我们也可以让公式变得更复杂些,比方给新的僵尸的DNA增加一些随机性之类的。但现在先从最简单的开始 - 以后还可以回来完善它嘛。 +以后,我们也可以让函数变得更复杂些,比方给新的僵尸的DNA增加一些随机性之类的。但现在先从最简单的开始 - 以后还可以回来完善它嘛。 -# 小测试 +# 实战演习 1.首先我们确保`_targetDna`不长于16位。要做到这一点,我们可以设置`_targetDna`为`_targetDna%dnaModulus`,并且只取其最后16位数字。 2.接下来为我们的函数声明一个名叫 `newDna`的单元(uint),并将其值设置为myZombie的DNA和_targetDna的平均值(如上例所示)。   - >注意:您可以通过myZombie.name 或 myZombie.dna访问myZombie的属性。 + >注意:您可以用 myZombie.name 或 myZombie.dna 访问 myZombie的属性。 计算出新的DNA,再调用 `_createZombie`就可以生成新的僵尸了。如果你忘了调用这个函数所需要的参数,您可以查看`zombiefactory.sol`选项卡。请注意,需要先给他命名,所以现在我们把新的僵尸的名字设为“NoName” - 我们回头可以编写一个函数来更改僵尸的名字。 diff --git a/zh/2/9-internalfunctions.md b/zh/2/9-internalfunctions.md index 0d2c297e4a..fb69d2aafa 100644 --- a/zh/2/9-internalfunctions.md +++ b/zh/2/9-internalfunctions.md @@ -25,7 +25,7 @@ material: mapping (uint => address) public zombieToOwner; mapping (address => uint) ownerZombieCount; - // edit function definition below + // 在这里修改函数的功能 function _createZombie(string _name, uint _dna) private { uint id = zombies.push(Zombie(_name, _dna)) - 1; zombieToOwner[id] = msg.sender; @@ -110,13 +110,13 @@ material: ## 内部和外部 -除了“public”和“private”属性之外,Solidity还使用了另外两类可见性的函数:`internal`(内部)和`external`(外部)。 +除“public”和“private”属性之外,Solidity还使用了另外两个描述函数可见性的修饰词:`internal`(内部)和`external`(外部)。 `internal`和 “private” 类似,不过, 如果某个合约继承自其父合约,这个合约即可以访问父合约中定义的“内部”函数。(嘿,这听起来正式我们想要的那样!)。 -`external`与`public`类似,只不过这些函数只能在合约之外调用 - 它们不能被合约内的其他函数调用。稍后我们将讨论什么时候你需要使用`external`和`public`。 +`external`与`public`类似,只不过这些函数只能在合约之外调用 - 它们不能被合约内的其他函数调用。稍后我们将讨论什么时候使用`external`和`public`。 -声明`internal`或`external`类型函数的语法,与声明`private`和`public`相同: +声明函数`internal`或`external`类型的语法,与声明`private`和`public`类型相同: ``` contract Sandwich { @@ -138,8 +138,8 @@ contract BLT is Sandwich { } ``` -# 小测试 +# 实战演习 -1. 将 `_createZombie()`函数的属性从 `private`改为 `internal` , 是的其他的合约也能访问到它。 +1. 将 `_createZombie()`函数的属性从 `private`改为 `internal` , 使得其他的合约也能访问到它。 我们已经成功把你的注意力集中在到`zombiefactory.sol`这个选项卡上啦。 diff --git a/zh/2/template.md b/zh/2/template.md index 4f58c99052..750cce6986 100644 --- a/zh/2/template.md +++ b/zh/2/template.md @@ -8,12 +8,14 @@ material: answer: > --- -Solidity's code is encapsulated in contracts. A contract is basically... +Solidity 代码封装在一种叫“合约(contracts)”的数据结构中。 + +合约看起来是这样的... ``` contract HelloWorld ``` -# Put it to the test +# 实战演练