summaryrefslogtreecommitdiffhomepage
path: root/zh-cn
diff options
context:
space:
mode:
Diffstat (limited to 'zh-cn')
-rw-r--r--zh-cn/awk-cn.html.markdown3
-rw-r--r--zh-cn/dart-cn.html.markdown44
-rw-r--r--zh-cn/git-cn.html.markdown2
-rw-r--r--zh-cn/lambda-calculus-cn.html.markdown223
-rw-r--r--zh-cn/make-cn.html.markdown13
-rw-r--r--zh-cn/markdown-cn.html.markdown58
-rw-r--r--zh-cn/python-cn.html.markdown2
-rw-r--r--zh-cn/ruby-cn.html.markdown160
-rw-r--r--zh-cn/solidity-cn.html.markdown825
-rw-r--r--zh-cn/sql.html.markdown105
10 files changed, 1348 insertions, 87 deletions
diff --git a/zh-cn/awk-cn.html.markdown b/zh-cn/awk-cn.html.markdown
index 3fea782b..8ee2db2c 100644
--- a/zh-cn/awk-cn.html.markdown
+++ b/zh-cn/awk-cn.html.markdown
@@ -1,5 +1,6 @@
---
-language: awk
+category: tool
+tool: awk
contributors:
- ["Marshall Mason", "http://github.com/marshallmason"]
translators:
diff --git a/zh-cn/dart-cn.html.markdown b/zh-cn/dart-cn.html.markdown
index b0287f0c..79db8e5c 100644
--- a/zh-cn/dart-cn.html.markdown
+++ b/zh-cn/dart-cn.html.markdown
@@ -176,23 +176,47 @@ example13() {
match(s2);
}
-// 布尔表达式必需被解析为 true 或 false,
-// 因为不支持隐式转换。
+// 布尔表达式支持隐式转换以及动态类型
example14() {
- var v = true;
- if (v) {
- print("Example14 value is true");
+ var a = true;
+ if (a) {
+ print("Example14 true, a is $a");
}
- v = null;
+ a = null;
+ if (a) {
+ print("Example14 true, a is $a");
+ } else {
+ print("Example14 false, a is $a"); // 执行到这里
+ }
+
+ // 动态类型的null可以转换成bool型
+ var b;// b是动态类型
+ b = "abc";
try {
- if (v) {
- // 不会执行
+ if (b) {
+ print("Example14 true, b is $b");
} else {
- // 不会执行
+ print("Example14 false, b is $b");
}
} catch (e) {
- print("Example14 null value causes an exception: '${e}'");
+ print("Example14 error, b is $b"); // 这段代码可以执行但是会报错
}
+ b = null;
+ if (b) {
+ print("Example14 true, b is $b");
+ } else {
+ print("Example14 false, b is $b"); // 这行到这里
+ }
+
+ // 静态类型的null不能转换成bool型
+ var c = "abc";
+ c = null;
+ // 编译出错
+ // if (c) {
+ // print("Example14 true, c is $c");
+ // } else {
+ // print("Example14 false, c is $c");
+ // }
}
// try/catch/finally 和 throw 语句用于异常处理。
diff --git a/zh-cn/git-cn.html.markdown b/zh-cn/git-cn.html.markdown
index 4ef3ffb8..d471ab5d 100644
--- a/zh-cn/git-cn.html.markdown
+++ b/zh-cn/git-cn.html.markdown
@@ -131,7 +131,7 @@ $ git help init
```bash
-# 显示分支,为跟踪文件,更改和其他不同
+# 显示分支,未跟踪文件,更改和其他不同
$ git status
# 查看其他的git status的用法
diff --git a/zh-cn/lambda-calculus-cn.html.markdown b/zh-cn/lambda-calculus-cn.html.markdown
new file mode 100644
index 00000000..7719ee71
--- /dev/null
+++ b/zh-cn/lambda-calculus-cn.html.markdown
@@ -0,0 +1,223 @@
+---
+category: Algorithms & Data Structures
+name: Lambda Calculus
+lang: zh-cn
+contributors:
+ - ["Max Sun", "http://github.com/maxsun"]
+ - ["Yan Hui Hang", "http://github.com/yanhh0"]
+translators:
+ - ["Maoyin Sun", "https://github.com/simonmysun"]
+---
+
+# Lambda 演算
+
+Lambda 演算(lambda calculus, λ-calculus),
+最初由[阿隆佐·邱奇][]([Alonzo Church][])提出,
+是世界上最小的编程语言.
+尽管没有数字, 字符串, 布尔或者任何非函数的数据类型,
+lambda 演算仍可以表示任何图灵机.
+
+[阿隆佐·邱奇]: https://zh.wikipedia.org/wiki/%E9%98%BF%E9%9A%86%E4%BD%90%C2%B7%E9%82%B1%E5%A5%87
+[Alonzo Church]: https://en.wikipedia.org/wiki/Alonzo_Church
+
+Lambda 演算由三种元素组成: **变量**(variables)、**函数**(functions)和**应用**(applications)。
+
+| 名称 | 语法 | 示例 | 解释 |
+|------|----------------------|-----------|--------------------------------------------------|
+| 变量 | `<变量名>` | `x` | 一个名为"x"的变量 |
+| 函数 | `λ<参数>.<函数体>` | `λx.x` | 一个以"x"(前者)为参数、以"x"(后者)为函数体的函数 |
+| 应用 | `<函数><变量或函数>` | `(λx.x)a` | 以"a"为参数调用函数"λx.x" |
+
+最基本的函数为恒等函数: `λx.x`, 它等价于`f(x) = x`.
+第一个"x"为函数的参数, 第二个为函数体.
+
+## 自由变量和约束变量:
+
+- 在函数`λx.x`中, "x"被称作约束变量因为它同时出现在函数体和函数参数中.
+- 在`λx.y`中, "y"被称作自由变量因为它没有被预先声明.
+
+## 求值:
+
+求值操作是通过[β-归约][]([β-Reduction][])完成的,
+它本质上是词法层面上的替换.
+
+[β-归约]: https://zh.wikipedia.org/wiki/%CE%9B%E6%BC%94%E7%AE%97#'%22%60UNIQ--postMath-0000006F-QINU%60%22'-%E6%AD%B8%E7%B4%84
+[β-Reduction]: https://en.wikipedia.org/wiki/Lambda_calculus#Beta_reduction
+
+当对表达式`(λx.x)a`求值时, 我们将函数体中所有出现的"x"替换为"a".
+
+- `(λx.x)a`计算结果为: `a`
+- `(λx.y)a`计算结果为: `y`
+
+你甚至可以创建高阶函数:
+
+- `(λx.(λy.x))a`计算结果为: `λy.a`
+
+尽管 lambda 演算传统上仅支持单个参数的函数,
+但我们可以通过一种叫作[柯里化][]([Currying][])的技巧创建多个参数的函数.
+
+[柯里化]: https://zh.wikipedia.org/wiki/%E6%9F%AF%E9%87%8C%E5%8C%96
+[Currying]: https://en.wikipedia.org/wiki/Currying
+
+- `(λx.λy.λz.xyz)`等价于`f(x, y, z) = ((x y) z)`
+
+有时`λxy.<body>`与`λx.λy.<body>`可以互换使用.
+
+----
+
+认识到传统的 **lambda 演算没有数字, 字符或者任何非函数的数据类型**很重要.
+
+## 布尔逻辑:
+
+在 lambda 演算中没有"真"或"假". 甚至没有 1 或 0.
+
+作为替换:
+
+`T`表示为: `λx.λy.x`
+
+`F`表示为: `λx.λy.y`
+
+首先, 我们可以定义一个"if"函数`λbtf`, 它当`b`为真时返回`t`,
+`b`为假时返回`f`
+
+`IF`等价于: `λb.λt.λf.b t f`
+
+通过`IF`, 我们可以定义基本的布尔逻辑运算符:
+
+`a AND b`等价于: `λab.IF a b F`
+
+`a OR b`等价于: `λab.IF a T b`
+
+`NOT a`等价于: `λa.IF a F T`
+
+*注意: `IF a b c`本质上指: `IF((a b) c)`*
+
+## 数字:
+
+尽管 lambda 演算中没有数字,
+我们还可以用[邱奇编码][]([Church numerals][])将数字嵌入到 lambda 演算中.
+
+[邱奇编码]: https://zh.wikipedia.org/wiki/%E9%82%B1%E5%A5%87%E7%BC%96%E7%A0%81
+[Church numerals]: https://en.wikipedia.org/wiki/Church_encoding
+
+对于任意数字 n: <code>n = λf.f<sup>n</sup></code> 所以:
+
+`0 = λf.λx.x`
+
+`1 = λf.λx.f x`
+
+`2 = λf.λx.f(f x)`
+
+`3 = λf.λx.f(f(f x))`
+
+要增加一个邱奇数, 我们使用后继函数`S(n) = n + 1`:
+
+`S = λn.λf.λx.f((n f) x)`
+
+使用后继函数, 我们可以定义加法:
+
+`ADD = λab.(a S)b`
+
+**挑战**: 试定义乘法函数!
+
+## 变得更小: SKI, SK 和 Iota
+
+### SKI 组合子演算
+
+令 S, K, I 为下列函数:
+
+`I x = x`
+
+`K x y = x`
+
+`S x y z = x z (y z)`
+
+我们可以将 lambda 演算中的表达式转换为 SKI 组合子演算中的表达式:
+
+1. `λx.x = I`
+2. `λx.c = Kc`
+3. `λx.(y z) = S (λx.y) (λx.z)`
+
+以邱奇数 2 为例:
+
+`2 = λf.λx.f(f x)`
+
+对于里面的部分 `λx.f(f x)`:
+
+```
+ λx.f(f x)
+= S (λx.f) (λx.(f x)) (case 3)
+= S (K f) (S (λx.f) (λx.x)) (case 2, 3)
+= S (K f) (S (K f) I) (case 2, 1)
+```
+
+所以:
+
+```
+ 2
+= λf.λx.f(f x)
+= λf.(S (K f) (S (K f) I))
+= λf.((S (K f)) (S (K f) I))
+= S (λf.(S (K f))) (λf.(S (K f) I)) (case 3)
+```
+
+对于第一个参数`λf.(S (K f))`有:
+
+```
+ λf.(S (K f))
+= S (λf.S) (λf.(K f)) (case 3)
+= S (K S) (S (λf.K) (λf.f)) (case 2, 3)
+= S (K S) (S (K K) I) (case 2, 3)
+```
+
+对于第二个参数`λf.(S (K f) I)`有:
+
+```
+ λf.(S (K f) I)
+= λf.((S (K f)) I)
+= S (λf.(S (K f))) (λf.I) (case 3)
+= S (S (λf.S) (λf.(K f))) (K I) (case 2, 3)
+= S (S (K S) (S (λf.K) (λf.f))) (K I) (case 1, 3)
+= S (S (K S) (S (K K) I)) (K I) (case 1, 2)
+```
+
+综上:
+
+```
+ 2
+= S (λf.(S (K f))) (λf.(S (K f) I))
+= S (S (K S) (S (K K) I)) (S (S (K S) (S (K K) I)) (K I))
+```
+
+如果展开这个表达式, 我们最终又会得到邱奇数 2 的相同的表达式.
+
+### SK 组合子演算
+
+SKI 组合子演算还可以进一步简化. 我们可以通过`I = SKK`移除 I 组合子.
+我们可以将所有的 `I` 替换为 `SKK`.
+
+### ι 组合子
+
+SK 组合子仍不是最简的. 定义:
+
+```
+ι = λf.((f S) K)
+```
+
+我们有:
+
+```
+I = ιι
+K = ι(ιI) = ι(ι(ιι))
+S = ι(K) = ι(ι(ι(ιι)))
+```
+
+## 更多阅读:
+
+1. [A Tutorial Introduction to the Lambda Calculus](http://www.inf.fu-berlin.de/lehre/WS03/alpi/lambda.pdf)(英文)
+2. [Cornell CS 312 Recitation 26: The Lambda Calculus](https://courses.cs.cornell.edu/cs312/2008sp/recitations/rec26.html)(英文)
+3. [Wikipedia - Lambda Calculus](https://en.wikipedia.org/wiki/Lambda_calculus)(英文)
+4. [Wikipedia - SKI combinator calculus](https://en.wikipedia.org/wiki/SKI_combinator_calculus)(英文)
+5. [Wikipedia - Iota and Jot](https://en.wikipedia.org/wiki/Iota_and_Jot)(英文)
+6. [λ演算 - 维基百科,自由的百科全书](https://zh.wikipedia.org/wiki/SKI%E7%BB%84%E5%90%88%E5%AD%90%E6%BC%94%E7%AE%97)
+7. [SKI组合子演算 - 维基百科,自由的百科全书](https://zh.wikipedia.org/wiki/SKI%E7%BB%84%E5%90%88%E5%AD%90%E6%BC%94%E7%AE%97)
diff --git a/zh-cn/make-cn.html.markdown b/zh-cn/make-cn.html.markdown
index 4cdf1e63..76dde941 100644
--- a/zh-cn/make-cn.html.markdown
+++ b/zh-cn/make-cn.html.markdown
@@ -1,5 +1,6 @@
---
-language: make
+category: tool
+tool: make
contributors:
- ["Robert Steed", "https://github.com/robochat"]
- ["Jichao Ouyang", "https://github.com/jcouyang"]
@@ -38,7 +39,7 @@ Makefile 用于定义如何创建目标文件, 比如如何从源码到可执行
# …
# prerequisites(依赖) 是可选的, recipe(做法) 也可以多个或者不给.
-# 下面这个任务没有给 prerequisites, 只会在目标文件 file0.txt 文件不存在是跑
+# 下面这个任务没有给 prerequisites, 只会在目标文件 file0.txt 文件不存在时执行
file0.txt:
echo "foo" > file0.txt
# 试试 `make file0.txt`
@@ -46,12 +47,12 @@ file0.txt:
# 注意: 即使是这些注释, 如果前面有 TAB, 也会发送给 shell, 注意看 `make file0.txt` 输出
# 如果提供 prerequisites, 则只有 prerequisites 比 target 新时会执行
-# 比如下面这个任务只有当 file1.txt 比 file0.txt 新时才会执行.
+# 比如下面这个任务只有当 file0.txt 比 file1.txt 新时才会执行.
file1.txt: file0.txt
cat file0.txt > file1.txt
- # 这里跟shell里的命令式一毛一样的.
+ # 这里跟shell里的命令式一模一样.
@cat file0.txt >> file1.txt
- # @ 不会把命令往 stdout 打印.
+ # @ 不会把命令打印到 stdout.
-@echo 'hello'
# - 意思是发生错误了也没关系.
# 试试 `make file1.txt` 吧.
@@ -234,7 +235,7 @@ ls: *
# include foo.mk
sport = tennis
-# 一些逻辑语句 if else 什么的, 顶个写
+# 流程控制语句 (如if else 等等) 顶格写
report:
ifeq ($(sport),tennis)
@echo 'game, set, match'
diff --git a/zh-cn/markdown-cn.html.markdown b/zh-cn/markdown-cn.html.markdown
index 2bd8d11a..9b3d96ab 100644
--- a/zh-cn/markdown-cn.html.markdown
+++ b/zh-cn/markdown-cn.html.markdown
@@ -5,6 +5,7 @@ contributors:
translators:
- ["Fangzhou Chen","https://github.com/FZSS"]
- ["Luffy Zhong", "https://github.com/mengzhongshi"]
+ - ["Yuchen Liu", "https://github.com/smallg0at"]
filename: learnmarkdown-cn.md
lang: zh-cn
---
@@ -46,6 +47,16 @@ Markdown 是 HTML 的父集,所以任何 HTML 文件都是有效的 Markdown
##### 这是一个 <h5>
###### 这是一个 <h6>
```
+
+实际效果(最终显示时会因设置而看起来不同):
+# 这是一个
+## 这也是一个
+### 这还是一个
+#### 这依旧是一个
+##### 这真的是一个
+###### 这...是一个
+
+
对于 `<h1>` 和 `<h2>` 元素,Markdown 额外提供了两种添加方式。
```md
@@ -58,7 +69,7 @@ Markdown 是 HTML 的父集,所以任何 HTML 文件都是有效的 Markdown
## 文本样式
-文本的斜体,粗体在 Markdown 中可以轻易实现。
+文本的*斜体*,**粗体**在 Markdown 中可以轻易实现。
```md
*此文本为斜体。*
@@ -72,7 +83,7 @@ __此文本也是__
*__这个也是!__*
```
-GitHub 也支持 Markdown,在 GitHub 的 Markdown 解析器中,我们可以使用删除线:
+GitHub 也支持 Markdown,在 GitHub 的 Markdown 解析器中,我们可以使用~~删除线~~:
```md
~~此文本为删除线效果。~~
@@ -80,6 +91,7 @@ GitHub 也支持 Markdown,在 GitHub 的 Markdown 解析器中,我们可以
## 段落
段落由一个句子或是多个中间没有空行的句子组成,每个段落由一个或是多个空行分隔开来。
+(注:部分解析器有无需空行就能换行的设置,这个主要看个人喜好)
```md
这是第一段落. 这句话在同一个段落里,好玩么?
@@ -92,7 +104,9 @@ GitHub 也支持 Markdown,在 GitHub 的 Markdown 解析器中,我们可以
```
如果你想插入一个 `<br />` 标签,你可以在段末加入两个以上的空格,然后另起一
-段。(译者注:试了一下,很多解析器,并不需要空两个空格,直接换行就会添加一个`<br />`)
+段。
+
+(译者注:试了一下,很多解析器,并不需要空两个空格,直接换行就会添加一个`<br />`)
```md
此段落结尾有两个空格(选中以显示)。
@@ -102,6 +116,8 @@ GitHub 也支持 Markdown,在 GitHub 的 Markdown 解析器中,我们可以
段落引用可由 `>` 字符轻松实现。
+> 对的很轻松
+
```md
> 这是一个段落引用。 你可以
> 手动断开你的句子,然后在每句句子前面添加 `>` 字符。或者让你的句子变得很长,以至于他们自动得换行。
@@ -113,7 +129,7 @@ GitHub 也支持 Markdown,在 GitHub 的 Markdown 解析器中,我们可以
```
## 列表
-无序列表可由星号,加号或者减号来创建
+- 无序列表可由星号,加号或者减号来创建
```md
* 项目
@@ -172,6 +188,7 @@ GitHub 也支持 Markdown,在 GitHub 的 Markdown 解析器中,我们可以
下面这个选择框将会是选中状态
- [x] 这个任务已经完成
```
+- [ ] 你看完了这个任务(注:此选择框是无法直接更改的,即禁用状态。)
## 代码块
@@ -217,7 +234,10 @@ end
---
- - -
****************
+
+下面这个就是示例
```
+---
## 链接
@@ -294,33 +314,45 @@ Markdown同样支持引用形式的链接
我希望 *将这段文字置于星号之间* 但是我不希望它被
斜体化, 这么做: \*这段置文字于星号之间\*。
```
+对比一下:*将这段文字置于星号之间* 和 \*将这段文字置于星号之间\*
### 键盘上的功能键
-在 GitHub 的 Markdown中,你可以使用 `<kbd>` 标签来表示功能键。
+在 GitHub 的 Markdown 中,你可以使用 `<kbd>` 标签来表示功能键。
```md
你的电脑死机了?试试
<kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>Del</kbd>
```
<kbd>Ctrl</kbd>+<kbd>Alt</kbd>+<kbd>Del</kbd>
+
+(译注:可能由于网站本身样式问题,效果不明显)
+
### 表格
-表格只被 GitHub 的 Markdown 支持,并且有一点笨重,但如果你真的要用的话: (译者注:其实现在大部分markdown都已经支持)
+下面示例的表格长这样:
+
+| 第一列 | 第二列 | 第三列 |
+| :----------- | :-------: | ----------: |
+| 我是左对齐 | 居个中 | 右对齐 |
+| 注意 | 冒 | 号 |
+
+工整一点的写法是这样的:
```md
| 第一列 | 第二列 | 第三列 |
-| :--------- | :------: | ----------: |
-| 左对齐 | 居个中 | 右对齐 |
-| 某某某 | 某某某 | 某某某 |
+| :----------- | :-------: | ----------: |
+| 我是左对齐 | 居个中 | 右对齐 |
+| 注意 | 冒 | 号 |
```
-
-或者, 同样的
+好吧,强行对齐字符是很难的。但是,至少比下面这种写法好一点——
```md
-第一列 | 第二列 | 第三列
+我是超级超级长的第一列 | 第二列 | 第三列
:-- | :-: | --:
-这太丑了 | 药不能 | 停
+这真的太丑了 | 药不能 | 停!!!!
```
+真的是*看着令人头晕*
+
更多信息, 请于[此处](http://daringfireball.net/projects/Markdown/syntax)参见 John Gruber 关于语法的官方帖子,及于[此处](https://github.com/adam-p/Markdown-here/wiki/Markdown-Cheatsheet) 参见 Adam Pritchard 的摘要笔记。
diff --git a/zh-cn/python-cn.html.markdown b/zh-cn/python-cn.html.markdown
index deb94cdc..65f125d1 100644
--- a/zh-cn/python-cn.html.markdown
+++ b/zh-cn/python-cn.html.markdown
@@ -439,7 +439,7 @@ Human.grunt() # => "*grunt*"
# 我们可以导入其他模块
import math
-print math.sqrt(16) # => 4
+print math.sqrt(16) # => 4.0
# 我们也可以从一个模块中导入特定的函数
from math import ceil, floor
diff --git a/zh-cn/ruby-cn.html.markdown b/zh-cn/ruby-cn.html.markdown
index 657a913d..9918c022 100644
--- a/zh-cn/ruby-cn.html.markdown
+++ b/zh-cn/ruby-cn.html.markdown
@@ -6,11 +6,25 @@ contributors:
- ["David Underwood", "http://theflyingdeveloper.com"]
- ["Joel Walden", "http://joelwalden.net"]
- ["Luke Holder", "http://twitter.com/lukeholder"]
+ - ["Tristan Hume", "http://thume.ca/"]
+ - ["Nick LaMuro", "https://github.com/NickLaMuro"]
+ - ["Marcos Brizeno", "http://www.about.me/marcosbrizeno"]
+ - ["Ariel Krakowski", "http://www.learneroo.com"]
+ - ["Dzianis Dashkevich", "https://github.com/dskecse"]
+ - ["Levi Bostian", "https://github.com/levibostian"]
+ - ["Rahil Momin", "https://github.com/iamrahil"]
+ - ["Gabriel Halley", "https://github.com/ghalley"]
+ - ["Persa Zula", "http://persazula.com"]
+ - ["Jake Faris", "https://github.com/farisj"]
+ - ["Corey Ward", "https://github.com/coreyward"]
+ - ["Jannik Siebert", "https://github.com/janniks"]
+ - ["Keith Miyake", "https://github.com/kaymmm"]
- ["lidashuang", "https://github.com/lidashuang"]
- ["ftwbzhao", "https://github.com/ftwbzhao"]
translators:
- ["Lin Xiangyu", "https://github.com/oa414"]
- ["Jiang Haiyun", "https://github.com/haiiiiiyun"]
+ - ["woclass", "https://github.com/inkydragon"]
---
```ruby
@@ -18,26 +32,27 @@ translators:
=begin
这是多行注释
-没人用这个
-你也不该用
=end
-# 首先,也是最重要的,所有东西都是对象
+# 在 Ruby 中,(几乎)所有东西都是对象
# 数字是对象
-
-3.class #=> Fixnum
-
+3.class #=> Integer
3.to_s #=> "3"
+# 字符串是对象
+"Hello".class #=> String
+
+# 甚至方法也是对象
+"Hello".method(:class).class #=> Method
-# 一些基本的算术符号
-1 + 1 #=> 2
-8 - 1 #=> 7
-10 * 2 #=> 20
-35 / 5 #=> 7
-2**5 #=> 32
-5 % 3 #=> 2
+# 一些基本的算术操作
+1 + 1 #=> 2
+8 - 1 #=> 7
+10 * 2 #=> 20
+35 / 5 #=> 7
+2 ** 5 #=> 32
+5 % 3 #=> 2
# 位运算符
3 & 5 #=> 1
@@ -48,6 +63,7 @@ translators:
# 实际上是调用对象的方法
1.+(3) #=> 4
10.* 5 #=> 50
+100.methods.include?(:/) #=> true
# 特殊的值也是对象
nil # 相当于其它语言中的 null
@@ -66,11 +82,11 @@ false.class #=> FalseClass
1 != 1 #=> false
2 != 1 #=> true
-# 除了false自己,nil是唯一的另一个值为false的对象
-
-!nil #=> true
-!false #=> true
-!0 #=> false
+# 除了 false 自己,nil 是唯一的另一个值为 false 的对象
+!!nil #=> false
+!!false #=> false
+!!0 #=> true
+!!"" #=> true
# 更多比较
1 < 10 #=> true
@@ -90,11 +106,11 @@ true || false #=> true
!true #=> false
# 也有优先级更低的逻辑运算符
-# 它们用于控制流结构中,用来串接语句,直到返回true或false。
+# 它们用于控制流结构中,用来串接语句,直到返回 true 或 false。
-# `do_something_else` 只当 `do_something` 返回true时才会被调用
+# `do_something_else` 只当 `do_something` 返回 true 时才会被调用
do_something() and do_something_else()
-# `log_error` 只当 `do_something` 返回false时才会被调用
+# `log_error` 只当 `do_something` 返回 false 时才会被调用
do_something() or log_error()
@@ -114,6 +130,7 @@ placeholder = "use string interpolation"
'hello ' + 'world' #=> "hello world"
'hello ' + 3 #=> TypeError: can't convert Fixnum into String
'hello ' + 3.to_s #=> "hello 3"
+"hello #{3}" #=> "hello 3"
# 合并字符串及其运算符
'hello ' * 3 #=> "hello hello hello "
@@ -141,7 +158,7 @@ x = y = 10 #=> 10
x #=> 10
y #=> 10
-# 按照惯例,使用类似snake_case风格的变量名
+# 按照惯例,使用类似 snake_case 风格的变量名
snake_case = true
# 使用有意义的变量名
@@ -174,6 +191,7 @@ array = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5]
# 数组可以被索引
# 从前面开始
array[0] #=> 1
+array.first #=> 1
array[12] #=> nil
# 像运算符一样,[var] 形式的访问
@@ -189,13 +207,13 @@ array.last #=> 5
# 同时指定开始的位置和长度
array[2, 3] #=> [3, 4, 5]
+# 或者指定一个区间
+array[1..3] #=> [2, 3, 4]
+
# 将数组逆序
a=[1,2,3]
a.reverse! #=> [3,2,1]
-# 或者指定一个区间
-array[1..3] #=> [2, 3, 4]
-
# 像这样往数组增加一个元素
array << 6 #=> [1, 2, 3, 4, 5, 6]
# 或者像这样
@@ -217,14 +235,18 @@ hash['number'] #=> 5
# 查询一个不存在的键将会返回nil
hash['nothing here'] #=> nil
-# 从Ruby 1.9开始,用符号作为键的时候有特别的记号表示:
+# 从 Ruby 1.9 开始,用符号作为键的时候有特别的记号表示:
new_hash = { defcon: 3, action: true }
new_hash.keys #=> [:defcon, :action]
+# 检查键值是否存在
+hash.key?(:defcon) #=> true
+hash.value?(3) #=> true
+
# 小贴士:数组和哈希表都是可枚举的
-# 它们共享一些有用的方法,比如each,map,count等等
+# 它们共享一些有用的方法,比如 each, map, count 等等
# 控制流
@@ -236,6 +258,8 @@ else
"else, also optional"
end
+# 循环
+
for counter in 1..5
puts "iteration #{counter}"
end
@@ -246,14 +270,14 @@ end
#=> iteration 5
-# 但是,没有人用for循环。
-# 你应该使用"each"方法,然后再传给它一个块。
-# 所谓块就是可以传给像"each"这样的方法的代码段。
-# 它类似于其它语言中的lambdas, 匿名函数或闭包。
+# 但是,没有人用 for 循环。
+# 你应该使用 "each" 方法,然后再传给它一个块。
+# 所谓块就是可以传给像 "each" 这样的方法的代码段。
+# 它类似于其它语言中的 lambdas, 匿名函数或闭包。
#
-# 区间上的"each"方法会对区间中的每个元素运行一次块代码。
-# 我们将counter作为一个参数传给了块。
-# 调用带有块的"each"方法看起来如下:
+# 区间上的 "each" 方法会对区间中的每个元素运行一次块代码。
+# 我们将 counter 作为一个参数传给了块。
+# 调用带有块的 "each" 方法看起来如下:
(1..5).each do |counter|
puts "iteration #{counter}"
@@ -275,7 +299,7 @@ hash.each do |key, value|
puts "#{key} is #{value}"
end
-# 如果你还需要索引值,可以使用"each_with_index",并且定义
+# 如果你还需要索引值,可以使用 "each_with_index",并且定义
# 一个索引变量
array.each_with_index do |element, index|
puts "#{element} is number #{index} in the array"
@@ -293,7 +317,7 @@ end
#=> iteration 5
# Ruby 中还有很多有用的循环遍历函数,
-# 如"map","reduce","inject"等等。
+# 如 "map", "reduce", "inject" 等等。
# 以map为例,它会遍历数组,并根据你在
# 块中定义的逻辑对它进行处理,然后返回
# 一个全新的数组。
@@ -388,19 +412,26 @@ surround { puts 'hello world' }
# {
# hello world
# }
+# => nil
# 可以向函数传递一个块
# "&"标记传递的块是一个引用
def guests(&block)
- block.call 'some_argument'
+ block.class #=> Proc
+ block.call(4)
end
+guests { |n| "You have #{n} guests." }
+# => "You have 4 guests."
+
# 可以传递多个参数,这些参数会转成一个数组,
# 这也是使用星号符 ("*") 的原因:
def guests(*array)
array.each { |guest| puts guest }
end
+# 结构
+
# 如果函数返回一个数组,在赋值时可以进行拆分:
def foods
['pancake', 'sandwich', 'quesadilla']
@@ -409,21 +440,42 @@ breakfast, lunch, dinner = foods
breakfast #=> 'pancake'
dinner #=> 'quesadilla'
-# 按照惯例,所有返回布尔值的方法都以?结尾
+# 有些情况下,你会想使用解构操作符 `*` 来解构数组
+ranked_competitors = ["John", "Sally", "Dingus", "Moe", "Marcy"]
+
+def best(first, second, third)
+ puts "Winners are #{first}, #{second}, and #{third}."
+end
+
+best *ranked_competitors.first(3) #=> Winners are John, Sally, and Dingus.
+
+# 结构操作符也可放在参数里面
+def best(first, second, third, *others)
+ puts "Winners are #{first}, #{second}, and #{third}."
+ puts "There were #{others.count} other participants."
+end
+
+best *ranked_competitors
+#=> Winners are John, Sally, and Dingus.
+#=> There were 2 other participants.
+
+# 按照惯例,所有返回布尔值的方法都以 ? 结尾
5.even? # false
5.odd? # true
-# 如果方法名末尾有!,表示会做一些破坏性的操作,比如修改调用者自身。
-# 很多方法都会有一个!的版本来进行修改,和一个非!的版本
-# 只用来返回更新了的结果
+# 如果方法名末尾有感叹号 !,表示会做一些破坏性的操作,比如修改调用者自身。
+# 很多方法都会有一个 ! 的版本来进行修改,
+# 和一个只返回更新结果的非 ! 版本
company_name = "Dunder Mifflin"
company_name.upcase #=> "DUNDER MIFFLIN"
company_name #=> "Dunder Mifflin"
-company_name.upcase! # we're mutating company_name this time!
+# 这次我们修改了 company_name
+company_name.upcase! #=> "DUNDER MIFFLIN"
company_name #=> "DUNDER MIFFLIN"
+# 类
-# 用class关键字定义一个类
+# 用 class 关键字定义一个类
class Human
# 一个类变量,它被这个类的所有实例变量共享
@@ -431,30 +483,30 @@ class Human
# 基本构造函数
def initialize(name, age = 0)
- # 将参数值赋给实例变量"name"
+ # 将参数值赋给实例变量 "name"
@name = name
- # 如果没有给出age,那么会采用参数列表中的默认值
+ # 如果没有给出 age,那么会采用参数列表中的默认值
@age = age
end
- # 基本的setter方法
+ # 基本的 setter 方法
def name=(name)
@name = name
end
- # 基本地getter方法
+ # 基本地 getter 方法
def name
@name
end
- # 以上的功能也可以用下面的attr_accessor来封装
+ # 以上的功能也可以用下面的 attr_accessor 来封装
attr_accessor :name
- # Getter/setter方法也可以像这样单独创建
+ # Getter/setter 方法也可以像这样单独创建
attr_reader :name
attr_writer :name
- # 类方法通过使用self与实例方法区别开来。
+ # 类方法通过使用 self 与实例方法区别开来。
# 它只能通过类来调用,不能通过实例调用。
def self.say(msg)
puts "#{msg}"
@@ -468,7 +520,6 @@ end
# 初始化一个类
jim = Human.new("Jim Halpert")
-
dwight = Human.new("Dwight K. Schrute")
# 让我们来调用一些方法
@@ -483,15 +534,15 @@ dwight.name #=> "Dwight K. Schrute"
Human.say('Hi') #=> "Hi"
# 变量的作用域由它们的名字格式定义
-# 以$开头的变量具有全局域
+# 以 $ 开头的变量具有全局域
$var = "I'm a global var"
defined? $var #=> "global-variable"
-# 以@开头的变量具有实例作用域
+# 以 @ 开头的变量具有实例作用域
@var = "I'm an instance var"
defined? @var #=> "instance-variable"
-# 以@@开头的变量具有类作用域
+# 以 @@ 开头的变量具有类作用域
@@var = "I'm a class var"
defined? @@var #=> "class variable"
@@ -568,7 +619,6 @@ Book.foo # => 'foo'
Book.new.foo # => NoMethodError: undefined method `foo'
# 当包含或扩展一个模块时,相应的回调代码会被执行。
-
module ConcernExample
def self.included(base)
base.extend(ClassMethods)
diff --git a/zh-cn/solidity-cn.html.markdown b/zh-cn/solidity-cn.html.markdown
new file mode 100644
index 00000000..ec684997
--- /dev/null
+++ b/zh-cn/solidity-cn.html.markdown
@@ -0,0 +1,825 @@
+---
+language: Solidity
+filename: learnSolidity-cn.sol
+lang: zh-cn
+contributors:
+ - ["Nemil Dalal", "https://www.nemil.com"]
+ - ["Joseph Chow", ""]
+ - ["Bhoomtawath Plinsut", "https://github.com/varshard"]
+ - ["Shooter", "https://github.com/liushooter"]
+translators:
+ - ["Bob Jiang", "https://github.com/bobjiang"]
+---
+
+Solidity 使你在[以太坊](https://www.ethereum.org/)上编程,一个基于区块链的虚拟机,
+允许创建和执行智能合约,无需中心化的或可信的一方。
+
+Solidity 是一种与 Javascript 和 C 的相似的、静态类型的合约编程语言。与OOP(面向对象)中
+的对象一样,每个合约都包含状态变量、函数和公共数据类型。合约特定功能包括修饰符(guard)子句,
+事件通知的侦听器及自定义的全局变量。
+
+以太坊合约的例子包括众筹、投票以及盲拍(私密拍卖)。
+
+Solidity 代码中存在高风险和高成本的错误,因此你必须非常小心地进行测试并慢慢地发布。**随着
+以太坊的快速变化,本文档不可能是最新的,所以你应该关注最新的的 solidity 聊天室和以太网博客。
+照搬这里的代码,会存在重大错误或弃用代码模式的风险。(说人话--别照抄例子中的代码)**
+
+与其他代码不同,可能还需要添加如暂停、弃用和限制使用的设计模式,来降低风险。本文档主要讨论语法,
+因此排除了许多流行的设计模式。
+
+由于 Solidity 和以太坊正在积极开发,通常会标记为实验或 beta 特性,并很可能会更改。因此欢迎
+提交更改请求。
+
+```javascript
+// 首先,一个简单的银行合约
+// 允许存款、取款、以及检查余额
+
+// simple_bank.sol (注意 .sol 后缀)
+/* **** 例子开始 **** */
+
+// 声明源文件的编译器版本
+pragma solidity ^0.4.19;
+
+// 开始 Natspec 注释(三个斜杠)
+// 用作文档 - 及UI元素、动作的描述性数据
+
+/// @title SimpleBank
+/// @author nemild
+
+/* 'contract' 和其他语言的 'class' 类似 (类变量、继承等) */
+contract SimpleBank { // 单词首字母大写
+ // 声明函数外的状态变量,合约生命周期内可用
+
+ // 地址映射到余额的字典,总是要小心数字的溢出攻击
+ mapping (address => uint) private balances;
+
+ // "private" 的意思是其他合约不能直接查询余额,但对于区块链上的其他方来说,数据仍然是可见的。
+
+ address public owner;
+ // 'public' 使用户或合约可以从外部读取(不可写)
+
+ // Events(事件) - 向外部监听器发布动作
+ event LogDepositMade(address accountAddress, uint amount);
+
+ // Constructor(构造函数)(译者注:solidity 从0.4.22开始使用 constructor() 作为构造函数)
+ function SimpleBank() public {
+ // msg 提供了发送给合约的消息详情
+ // msg.sender 是合约的调用者(这里是合约创建者的地址)
+ owner = msg.sender;
+ }
+
+ /// @notice 存款 ether (以太币)
+ /// @return 存款后用户的余额
+ function deposit() public payable returns (uint) {
+ // 使用 'require' 来检测用户的输入,'assert' 是内部常量
+ // 我们要确保不会发生溢出问题(上溢)
+ require((balances[msg.sender] + msg.value) >= balances[msg.sender]);
+
+ balances[msg.sender] += msg.value;
+ // 状态变量不需要 "this." 或 "self."
+ // 默认情况下,所有值都设置为数据类型的初始值
+
+ LogDepositMade(msg.sender, msg.value); // 触发事件
+
+ return balances[msg.sender];
+ }
+
+ /// @notice 从银行取款以太币 (ether)
+ /// @dev 不会返回任何多余的以太币(ether)
+ /// @param withdrawAmount 取款的数量
+ /// @return 用户还剩下的余额
+ function withdraw(uint withdrawAmount) public returns (uint remainingBal) {
+ require(withdrawAmount <= balances[msg.sender]);
+
+ // 注意在发送任何交易,即通过 .transfer .send 调用外部函数之前,马上减掉取款数量
+ // 这可以允许调用者使用递归请求大于其余额的金额。目标是在调用外部函数之前提交状态,
+ // 包括.transfer / .send
+ balances[msg.sender] -= withdrawAmount;
+
+ // 这会自动引发失败,也就是说还原了更新的余额
+ msg.sender.transfer(withdrawAmount);
+
+ return balances[msg.sender];
+ }
+
+ /// @notice 获取余额
+ /// @return 用户的余额
+ // 'view' 防止函数编辑状态变量;允许函数本地运行或链下运行
+ function balance() view public returns (uint) {
+ return balances[msg.sender];
+ }
+}
+// ** 例子结束 **
+
+
+// 下面, solidity 基础
+
+// 1. 数据类型与关联的方法
+// uint 类型用作现金数量(没有双浮点型或单浮点型)及日期(用 unix 时间)
+uint x;
+
+// 256字节的 int, 实例化后不能改变
+int constant a = 8;
+int256 constant a = 8; // 和上一行一样,这里256字节显性化了
+uint constant VERSION_ID = 0x123A1; // 16进制常量
+// 'constant' 关键字, 编译器在每个出现的地方替换为实际的值
+
+// 所有的状态变量(函数之外的那些),默认是 'internal' 的,只能在合约及所有继承的合约内
+// 可以访问。需要显性的设置为 'public' 才能允许外部合约访问。
+int256 public a = 8;
+
+// 对于 int 和 uint,可以显性的设置位数(从8位到256位,8位跳跃),如int8, int16, int24
+uint8 b;
+int64 c;
+uint248 e;
+
+// 当心不要溢出以及免收此类攻击,例如,对于加法最好这么做:
+uint256 c = a + b;
+assert(c >= a); // assert 测试内部不变的值;require 用来测试用户输入
+// 更多通用算法问题的例子,参考 Zeppelin's SafeMath library
+// https://github.com/OpenZeppelin/zeppelin-solidity/blob/master/contracts/math/SafeMath.sol
+
+
+// 没有内建的随机函数,使用其他合约获得随机数
+
+// 类型转换
+int x = int(b);
+
+bool b = true; // 或 'var b = true;' 隐含的类型
+
+// 地址 - 20个字节或160位以太坊地址(16进制数字),不允许进行运算
+address public owner;
+
+// 账户类型:
+// 合约账户:在创建时设置地址(创建者地址函数,交易发送)
+// 外部账户:(个人账户)从公钥创建的地址
+
+// 'public' 的含义是自动创建的 getter 方法,而不是 setter 方法可以公开的、外部访问。
+
+// 所有地址都可以进行转账
+owner.transfer(SOME_BALANCE); // 失败后还原
+
+// 还可以调用较低级别的 .send , 转账失败会返回 false
+if (owner.send) {}
+// 记住:用 'if' 包着 send 函数,因为合约地址执行这些函数转账时,可能会失败
+// 另外,确保转账前先减掉余额,因为存在递归调用的风险。
+
+// 检查余额
+owner.balance; // 所有者的余额(用户或合约)
+
+
+// 字符类型,从1到32位可用
+byte a; // byte 等同于 byte1
+bytes2 b;
+bytes32 c;
+
+// 动态大小的字符
+bytes m; // 特殊的数组,等同于 byte[],比 byte1 到 byte32 更贵
+// 尽可能不用 bytes
+
+// 等同于 bytes,但不允许长度或索引的访问
+string n = "hello"; // UTF8存储,注意双引号而不是单引号
+// 字符功能未来会增加,推荐使用 bytes32 或 bytes
+
+// 推断类型
+// var 会根据第一次赋值决定类型,不能用来作为函数的参数
+var a = true;
+// 小心使用,推断可能带来错误的类型,例如,int8,而计数器需要的是 int16
+
+// 函数可以用 var 类型赋值给变量
+function a(uint x) returns (uint) {
+ return x * 2;
+}
+var f = a;
+f(22); // 调用
+
+// 默认的,所有值实例化后都设为 0
+
+// 大多数类型上可以调用删除(不会销毁值,而是设置为0,初始值)
+uint x = 5;
+
+
+// 集合
+(x, y) = (2, 7); // 多值的赋值
+
+
+// 2. 数据结构
+// 数组
+bytes32[5] nicknames; // 静态数组
+bytes32[] names; // 动态数组
+uint newLength = names.push("John"); // 添加返回数组的新长度
+// 长度
+names.length; // 获得数组长度
+names.length = 1; // 可以设定长度(仅针对 storage 中的动态数组)
+
+// 多维数组
+uint x[][5]; // 5个动态数组元素的数组(和多数语言的顺序相反)
+
+// 字典类型 (任一类型到其他类型的映射)
+mapping (string => uint) public balances;
+balances["charles"] = 1;
+// balances["ada"]得到 0, 所有没有设定key值的,返回0
+// 'public' 允许跟着(调用)另一份合约
+contractName.balances("charles"); // returns 1
+// 'public' 创建 getter (而不是 setter )如下:
+function balances(string _account) returns (uint balance) {
+ return balances[_account];
+}
+
+// 内嵌的 mapping
+mapping (address => mapping (address => uint)) public custodians;
+
+// 删除
+delete balances["John"];
+delete balances; // 所有元素设为 0
+
+// 不像其他语言,不知道 keys 的话不能列出 mapping 中的所有元素 - 可以在这之上构建数据结构
+
+// 结构
+struct Bank {
+ address owner;
+ uint balance;
+}
+Bank b = Bank({
+ owner: msg.sender,
+ balance: 5
+});
+// 或
+Bank c = Bank(msg.sender, 5);
+
+c.balance = 5; // 设为新值
+delete b;
+// 设为初始值,结构内所有变量设为0,除了 mapping
+
+// 枚举
+enum State { Created, Locked, Inactive }; // 常常作为状态机
+State public state; // 声明枚举变量
+state = State.Created;
+// 枚举类型可以显性化的转换为 ints
+uint createdState = uint(State.Created); // 0
+
+// 数据位置:内存(Memory) vs. 存储(storage) vs. 调用数据(calldata)
+// 所有复杂类型(数据、结构)都有一个数据位置,内存数据不持久,而存储的数据是持久的。
+// 本地变量和状态变量默认是存储,函数参数默认是内存。堆栈存放较小的本地变量
+
+// 多数类型,可以显性化的设定使用的数据位置
+
+
+// 3. 简单操作符
+// solidity 提供了比较、位运算及数学运算的功能
+// 指数运算: **
+// 异或运算: ^
+// 按位取反: ~
+
+
+// 4. 值得注意的全局变量
+// ** this **
+this; // 合约的地址
+// 常常用在合约生命周期结束前,转走剩下的余额
+this.balance;
+this.someFunction(); // 通过 call 的方式而不是内部跳转的方式,从外部调用函数
+
+// ** msg - 合约收到的当前消息 ** **
+msg.sender; // 发送者的地址
+msg.value; // 该合约内的以太币数量(单位 wei),该函数应该标记为 "payable"
+msg.data; // 字符,完整的调用数据
+msg.gas; // 剩余 gas
+
+// ** tx - 交易信息 **
+tx.origin; // 本次交易的发送者地址
+tx.gasprice; // 本次交易的 gas price
+
+// ** block - 当前区块信息 **
+now; // 当前时间(大概)block.timestamp的别名 (采用的 Unix 时间)
+// 注意这个可能被矿工操纵,因此请小心使用
+
+block.number; // 当前区块号
+block.difficulty; // 当前区块难度
+block.blockhash(1); // 返回 bytes32,只对最近 256 个区块有效
+block.gasLimit();
+
+// ** 存储 - 持久化存储哈希 **
+storage['abc'] = 'def'; // 256 位单词 到 256 位单词的映射
+
+
+// 4. 函数及更多
+// A. 函数
+// 简单函数
+function increment(uint x) returns (uint) {
+ x += 1;
+ return x;
+}
+
+// 函数可以通过指定返回的参数名,来返回多个参数
+function increment(uint x, uint y) returns (uint x, uint y) {
+ x += 1;
+ y += 1;
+}
+// 调用前一个函数
+uint (a,b) = increment(1,1);
+
+// 'view' ('constant'的别名)
+// 表明函数不会改变持久化的变量,View函数会本地执行,而不是链上运行。
+// 注意:constant 关键字很快会废弃。
+uint y = 1;
+
+function increment(uint x) view returns (uint x) {
+ x += 1;
+ y += 1; // 这一行会失败
+ // y 是一个状态变量,不能在 view 的函数里改变 y
+}
+
+// 'pure' 比 'view' 或 'constant' 更加严格,甚至不允许读取状态变量
+// 具体的规则很复杂,请参考
+// view/pure:
+// http://solidity.readthedocs.io/en/develop/contracts.html#view-functions
+
+// '函数可见性指示器'
+// 'view'可以有以下修饰符,包括:
+// public - 内部及外部可见(函数的默认值)
+// external - 仅外部可见(包括 this 发起的调用)
+// private - 仅当前合约可见
+// internal - 仅当前合约及继承的合约可见
+
+// 通常,显性的标记每个函数是个好主意
+
+// 函数的挂起 - 可以将函数赋值给变量
+function a() {
+ var z = b;
+ b();
+}
+
+function b() {
+
+}
+
+// 所有接收 ether 的函数必须标记为 'payable'
+function depositEther() public payable {
+ balances[msg.sender] += msg.value;
+}
+
+
+// 首选循环来递归(最大的调用堆栈深度是 1024),另外不要设置没有限制的循环,
+// 因为这可能会达到 gas limit
+
+// B. 事件
+// 事件通知外部各方; 易于搜索和访问来自外部区块链(使用轻客户端)的事件
+// 通常在合约参数之后声明
+
+// 通常,首字母大写并在前面加上 Log ,防止与函数混淆
+
+// 声明
+event LogSent(address indexed from, address indexed to, uint amount); // 注意 capital first letter
+
+// 调用
+LogSent(from, to, amount);
+
+/*
+ // 对于外部方(合约或外部实体),使用 Web3 Javascript 库来监听
+ // 以下是javascript代码,不是solidity代码
+ Coin.LogSent().watch({}, '', function(error, result) {
+ if (!error) {
+ console.log("Coin transfer: " + result.args.amount +
+ " coins were sent from " + result.args.from +
+ " to " + result.args.to + ".");
+ console.log("Balances now:\n" +
+ "Sender: " + Coin.balances.call(result.args.from) +
+ "Receiver: " + Coin.balances.call(result.args.to));
+ }
+ }
+
+*/
+
+// 一个合约依赖另一个合约的共同范例(例如,合约取决于另一个合约提供的当前汇率)
+
+// C. 修饰器
+// 修饰器验证函数的输入,例如最小余额或用户身份验证; 类似于其他语言的保护子句
+
+// '_' (下划线)经常用在代码的最后一行,表明被调用的函数放在那里
+modifier onlyAfter(uint _time) { require (now >= _time); _; }
+modifier onlyOwner { require(msg.sender == owner) _; }
+// 常用于状态机
+modifier onlyIfStateA (State currState) { require(currState == State.A) _; }
+
+// 修饰器紧跟在函数声明之后
+function changeOwner(newOwner)
+onlyAfter(someTime)
+onlyOwner()
+onlyIfState(State.A)
+{
+ owner = newOwner;
+}
+
+// 下划线可以包含在代码结束之前,但明显地返回将跳过后面的代码,因此谨慎使用
+modifier checkValue(uint amount) {
+ _;
+ if (msg.value > amount) {
+ uint amountToRefund = amount - msg.value;
+ msg.sender.transfer(amountToRefund);
+ }
+}
+
+
+// 6. 判断和循环
+
+// 所有基本的逻辑判断都有效 - 包括 if else, for, while, break, continue
+// return - 但不跳转
+
+// 语法同 javascript, 但没有从非布尔值到布尔值的类型转换
+// (必须使用比较操作符获得布尔变量值)
+
+// 请注意由用户行为决定的循环 - 因为合约对于代码块具有最大量的 gas 限制 -
+// 如果超过限制该代码则将失败
+// 例如:
+for(uint x = 0; x < refundAddressList.length; x++) {
+ refundAddressList[x].transfer(SOME_AMOUNT);
+}
+
+// 上述两个错误:
+// 1. 转账失败会阻塞循环完成,钱被占用
+// 2. 该循环可能会很长(根据需要赔偿的用户数量而定),并且也可能由于超过一个区块最大 gas 限制
+// 而总是失败。你应该让人们自己从他们的子账户取款并标记取款完成
+// 例如,首选拉动式的付款,而不是推动式的付款
+
+
+// 7. 对象与合约
+
+// A. 调用外部合约
+contract InfoFeed {
+ function info() returns (uint ret) { return 42; }
+}
+
+contract Consumer {
+ InfoFeed feed; // 指向区块链上的一个合约
+
+ // 设置 feed 为已存在的合约实例
+ function setFeed(address addr) {
+ // 当心类型自动转换;不会调用构造函数
+ feed = InfoFeed(addr);
+ }
+
+ // 设置 feed 为一个合约的新实例
+ function createNewFeed() {
+ feed = new InfoFeed(); // 创建新实例,调用构造函数
+ }
+
+ function callFeed() {
+ // 最后的括号调用合约,可选择的增加自定义的 ether 或 gas 价格
+ feed.info.value(10).gas(800)();
+ }
+}
+
+// B. 继承
+
+// 和顺序有关,最后继承的合约(如 'def')可以覆盖之前已继承合约的部分
+contract MyContract is abc, def("a custom argument to def") {
+
+// 覆盖函数
+ function z() {
+ if (msg.sender == owner) {
+ def.z(); // 调用覆盖的函数
+ super.z(); // 调用继承的上层合约的函数
+ }
+ }
+}
+
+// 抽象函数
+function someAbstractFunction(uint x);
+// 不可以编译,因此用在基础或抽象合约中,等待实现
+
+// C. 导入
+
+import "filename";
+import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol";
+
+
+// 8. 其他关键字
+
+// A. 自毁
+// 自毁当前的合约,转账资金到一个地址(常常是创建者的地址)
+selfdestruct(SOME_ADDRESS);
+
+// 从当前或以后的区块中移除存储或代码,会帮助客户端瘦身,但之前的数据会永久在区块链中
+
+// 常见模式,让所有者结束合约并收回剩余的资金
+function remove() {
+ if(msg.sender == creator) { // 只有合约的创建者可以这么做
+ selfdestruct(creator); // 自毁合约,返还资金
+ }
+}
+
+// 可能希望手动停用合约,而不是自毁
+// (发送到自毁合约的 ether 会丢失掉)
+
+
+// 9. 注意合约的设计
+
+// A. 困惑
+// 区块链上所有变量都是公开可见的,因此任何私有的需求变得很困惑。(好比哈希的秘密)
+
+// 步骤: 1. 承诺某事, 2. 揭示承诺
+keccak256("some_bid_amount", "some secret"); // commit
+
+// 以后调用合约的 reveal 函数,展示出用 SHA3 哈希的 bid 加 secret
+reveal(100, "mySecret");
+
+// B. 存储优化
+// 写入区块链可能很昂贵,因为数据是永久存储的;鼓励用巧妙的方法使用内存
+//(最终,编译会更好,但现在有利于规划数据结构 - 并将最小数量存储在区块链中)
+
+// 多维数组这样的变量可能会成本很高
+// (成本用于存储数据 - 而不是声明未填充的变量)
+
+// C. 区块链中的数据访问
+// 不能限制人或计算机读取交易或交易状态的内容
+
+// 然而 'private' 可以防止其他*合约*直接读取数据 - 任意其他方仍然可以从区块链读取数据
+
+// 从开始的所有数据都存在区块链上,因此任何人都可以查看之前的所有数据和变化
+
+// D. 定时任务
+// 必须手动调用合约来处理时间相关的调度;也可以创建外部代码来定期的ping,
+// 或为其他人提供激励(以太)
+
+// E. 观察者模式
+//观察者模式允许您注册为订阅者,然后注册一个由oracle调用的函数
+//(注意,oracle 需要付费来运行此操作)。与 Pub / sub 中的订阅有些相似之处
+
+// 这是一个抽象合约,包括客户端和服务器端的类的导入,客户端应该要实现
+contract SomeOracleCallback {
+ function oracleCallback(int _value, uint _time, bytes32 info) external;
+}
+
+contract SomeOracle {
+ SomeOracleCallback[] callbacks; // 所有订阅者的数组
+
+ // 注册订阅者
+ function addSubscriber(SomeOracleCallback a) {
+ callbacks.push(a);
+ }
+
+ function notify(value, time, info) private {
+ for(uint i = 0;i < callbacks.length; i++) {
+ // 所有调用的订阅者必须实现 oracleCallback
+ callbacks[i].oracleCallback(value, time, info);
+ }
+ }
+
+ function doSomething() public {
+ // 实现的代码
+
+ // 通知所有的订阅者
+ notify(_value, _time, _info);
+ }
+}
+
+// 现在你的客户端合约可以通过 importing SomeOracleCallback 和注册某些 Oracle 来
+// addSubscriber 添加订阅者
+
+// F. 状态机
+// 参见如下的例子,枚举类型的 State 和 修饰器 inState
+
+
+// *** 例子: 众筹的例子(与 Kickstarter 大致相似)***
+// ** 开始例子 **
+
+// CrowdFunder.sol
+pragma solidity ^0.4.19;
+
+/// @title CrowdFunder
+/// @author nemild
+/// @translator bobjiang
+contract CrowdFunder {
+ // 由创建者创建的变量
+ address public creator;
+ address public fundRecipient; // 创建者可能和收件人不同
+ uint public minimumToRaise; // 需要提示,否则每个人都会得到退款
+ string campaignUrl;
+ byte constant version = 1;
+
+ // 数据结构
+ enum State {
+ Fundraising,
+ ExpiredRefund,
+ Successful
+ }
+ struct Contribution {
+ uint amount;
+ address contributor;
+ }
+
+ // 状态变量State variables
+ State public state = State.Fundraising; // 创建时实例化
+ uint public totalRaised;
+ uint public raiseBy;
+ uint public completeAt;
+ Contribution[] contributions;
+
+ event LogFundingReceived(address addr, uint amount, uint currentTotal);
+ event LogWinnerPaid(address winnerAddress);
+
+ modifier inState(State _state) {
+ require(state == _state);
+ _;
+ }
+
+ modifier isCreator() {
+ require(msg.sender == creator);
+ _;
+ }
+
+ // 允许合约销毁之前,最终合约状态后要等待24周
+ modifier atEndOfLifecycle() {
+ require(((state == State.ExpiredRefund || state == State.Successful) &&
+ completeAt + 24 weeks < now));
+ _;
+ }
+
+ function CrowdFunder(
+ uint timeInHoursForFundraising,
+ string _campaignUrl,
+ address _fundRecipient,
+ uint _minimumToRaise)
+ public
+ {
+ creator = msg.sender;
+ fundRecipient = _fundRecipient;
+ campaignUrl = _campaignUrl;
+ minimumToRaise = _minimumToRaise;
+ raiseBy = now + (timeInHoursForFundraising * 1 hours);
+ }
+
+ function contribute()
+ public
+ payable
+ inState(State.Fundraising)
+ returns(uint256 id)
+ {
+ contributions.push(
+ Contribution({
+ amount: msg.value,
+ contributor: msg.sender
+ }) // 采用数组,因此可以遍历
+ );
+ totalRaised += msg.value;
+
+ LogFundingReceived(msg.sender, msg.value, totalRaised);
+
+ checkIfFundingCompleteOrExpired();
+ return contributions.length - 1; // 返回 id
+ }
+
+ function checkIfFundingCompleteOrExpired()
+ public
+ {
+ if (totalRaised > minimumToRaise) {
+ state = State.Successful;
+ payOut();
+
+ // 可以激励在这里发起状态改变的人
+ } else if ( now > raiseBy ) {
+ state = State.ExpiredRefund; // 支持者可以通过调用 getRefund(id) 收取退款
+ }
+ completeAt = now;
+ }
+
+ function payOut()
+ public
+ inState(State.Successful)
+ {
+ fundRecipient.transfer(this.balance);
+ LogWinnerPaid(fundRecipient);
+ }
+
+ function getRefund(uint256 id)
+ inState(State.ExpiredRefund)
+ public
+ returns(bool)
+ {
+ require(contributions.length > id && id >= 0 && contributions[id].amount != 0 );
+
+ uint256 amountToRefund = contributions[id].amount;
+ contributions[id].amount = 0;
+
+ contributions[id].contributor.transfer(amountToRefund);
+
+ return true;
+ }
+
+ function removeContract()
+ public
+ isCreator()
+ atEndOfLifecycle()
+ {
+ selfdestruct(msg.sender);
+ // 创建者获得所有未被声明的钱
+ }
+}
+// ** 结束例子 **
+
+// 10. 其他原生的函数
+
+// 货币单位
+// 货币使用 wei 来定义,以太币的最小单位 = 1 wei;
+uint minAmount = 1 wei;
+uint a = 1 finney; // 1 ether == 1000 finney
+// 其他单位,请参阅: http://ether.fund/tool/converter
+
+// 时间单位
+1 == 1 second
+1 minutes == 60 seconds
+
+// 可以乘以带时间单位的变量,因为单位不会存储在变量中
+uint x = 5;
+(x * 1 days); // 5 天
+
+// 小心闰秒闰年与平等声明的时间
+// (相反,首选大于或小于)
+
+// 加密算法
+// 传递的所有字符串在哈希操作之前需要连接在一起
+sha3("ab", "cd");
+ripemd160("abc");
+sha256("def");
+
+// 11. 安全
+
+// 以太坊的合约中,错误可能是灾难性的 - 即使在 solidity 中是流行的模式,也可能发现是反模式的
+
+// 参见文档底部的安全链接
+
+// 12. 较低层次的函数
+// call - 较低层次,不会经常使用,不提供类型安全性
+successBoolean = someContractAddress.call('function_name', 'arg1', 'arg2');
+
+// callcode - 在调用合约的*上下文*中执行的目标地址上的代码
+// 提供库功能
+someContractAddress.callcode('function_name');
+
+
+// 13. 注意风格
+// 基于 Python 的 PEP8 风格指南
+// 全部风格指南: http://solidity.readthedocs.io/en/develop/style-guide.html
+
+// 快速总结:
+// 4个空格缩进
+// 两行隔开合约声明(和其他高级别的声明)
+// 避免括号内留出多余的空格
+// 可以省略一行语句的花括号 (if, for, 等)
+// else 应该单独一行
+
+
+// 14. NATSPEC 注释
+// 用于文档、注释和外部UI
+
+// 合约的 natspec - 总是在合约定义的上面
+/// @title 合约标题
+/// @author 作者名字
+
+// 函数的 natspec
+/// @notice 函数做什么的相关信息;展示什么时候执行该函数、
+/// @dev 开发者使用的函数文档
+
+// 函数参数、返回值的 natspec
+/// @param 有关参数用途的描述
+/// @return 返回值的描述
+```
+
+## 更多资源
+- [Solidity Docs](https://solidity.readthedocs.org/en/latest/)
+- [Smart Contract Best Practices](https://github.com/ConsenSys/smart-contract-best-practices)
+- [EthFiddle - The JsFiddle for Solidity](https://ethfiddle.com/)
+- [Browser-based Solidity Editor](https://remix.ethereum.org/)
+- [Gitter Solidity Chat room](https://gitter.im/ethereum/solidity)
+- [Modular design strategies for Ethereum Contracts](https://docs.erisindustries.com/tutorials/solidity/)
+
+## 重要的库文件
+- [Zeppelin](https://github.com/OpenZeppelin/zeppelin-solidity/): Libraries that provide common contract patterns (crowdfuding, safemath, etc)
+
+## 示例合约
+- [Dapp Bin](https://github.com/ethereum/dapp-bin)
+- [Solidity Baby Step Contracts](https://github.com/fivedogit/solidity-baby-steps/tree/master/contracts)
+- [ConsenSys Contracts](https://github.com/ConsenSys/dapp-store-contracts)
+- [State of Dapps](http://dapps.ethercasts.com/)
+
+## 安全
+- [Thinking About Smart Contract Security](https://blog.ethereum.org/2016/06/19/thinking-smart-contract-security/)
+- [Smart Contract Security](https://blog.ethereum.org/2016/06/10/smart-contract-security/)
+- [Hacking Distributed Blog](http://hackingdistributed.com/)
+
+## 风格
+- [Solidity Style Guide](http://solidity.readthedocs.io/en/latest/style-guide.html): Ethereum's style guide is heavily derived from Python's [PEP 8](https://www.python.org/dev/peps/pep-0008/) style guide.
+
+## 编辑器
+- [Emacs Solidity Mode](https://github.com/ethereum/emacs-solidity)
+- [Vim Solidity](https://github.com/tomlion/vim-solidity)
+- Editor Snippets ([Ultisnips format](https://gist.github.com/nemild/98343ce6b16b747788bc))
+
+## Future to Dos
+- 新关键字: protected, inheritable
+- 常见设计模式列表 (throttling, RNG, version upgrade)
+- 常见的安全反模式
+
+请随意发送 pull request 或者发邮件给作者 nemild -/at-/ gmail
+
+或者发邮件给译者 jiangxb -/at-/ gmail.com
diff --git a/zh-cn/sql.html.markdown b/zh-cn/sql.html.markdown
new file mode 100644
index 00000000..9d430bd1
--- /dev/null
+++ b/zh-cn/sql.html.markdown
@@ -0,0 +1,105 @@
+---
+language: SQL
+filename: learnsql.sql
+contributors:
+ - ["Bob DuCharme", "http://bobdc.com/"]
+translators:
+ - ["Shuxin Shu", "https://github.com/NamelessAshone"]
+lang: zh-cn
+---
+
+结构化查询语言(SQL)是一个ISO标准语言,用于创建和管理数据库,
+这种数据库存储一系列表。不同的实现通常会添加特有的语言扩展;
+[不同SQL实现的比较(Comparison of different SQL implementat-
+ions)](http://troels.arvin.dk/db/rdbms/)是一份很好的产品差
+异参考文档。
+
+不同的实现通常会提供一个命令行用于交互式键入命令和显示输出,
+同时这些实现也会提供一种执行脚本文件的方法。(如何退出命令行
+就是就是SQL中尚未被标准化部分的一个典型例子,绝大多数SQL实
+现支持关键字QUIT、EXIT或者两者。)
+
+本文的实例命令假设你已经加载了[github](https://github.com/datacharmer/test_db)上的[MySQL示例员工数据库](https://dev.mysql.com/doc/employee/en/)。
+运行脚本的语法取决于你使用的SQL实现。通常是一个命令行工具。
+
+```sql
+
+-- 注释以两个连字符开始。命令以分号结束。
+
+-- SQL关键字大小写不敏感。在下文的示例命令中关键字大写,
+-- 因为大写更容易区分数据库、表和列名。
+
+-- 创建和删除一个数据库。数据库名和表名是大小写敏感的。
+CREATE DATABASE someDatabase;
+DROP DATABASE someDatabase;
+
+-- 列出可用的数据库。
+SHOW DATABASES;
+
+-- 使用某个已经存在的数据库
+USE employees;
+
+-- 从当前的departments表,选择所有的行和列
+-- 解释器的默认行为是将结果打印在屏幕上。
+SELECT * FROM departments;
+
+-- 检索departments表中所有的行,但只取dept_no和dept_name列。
+-- 一条命令可以跨越多行
+SELECT dept_no,
+ dept_name FROM departments;
+
+-- 检索departments表中所有的行,但是只输出5行。
+SELECT * FROM departments LIMIT 5;
+
+-- 检索departments表中dept_name列包含子串'en'的行。
+SELECT dept_name FROM departments WHERE dept_name LIKE '%en%';
+
+-- 检索departmnets表中所有dept_name列值为'S'开头并且'S'后接4个字符的行。
+SELECT * FROM departments WHERE dept_name LIKE 'S____';
+
+-- 检索title表中所有行,不显示重复的行。
+SELECT DISTINCT title FROM titles;
+
+-- 和上面的查询相同,但是以title的值排序(大小写敏感)。
+SELECT DISTINCT title FROM titles ORDER BY title;
+
+-- 计算departments表的总行数。
+SELECT COUNT(*) FROM departments;
+
+-- 计算departments表中dept_name列以'en'字段开头的行的数量。
+SELECT COUNT(*) FROM departments WHERE dept_name LIKE '%en%';
+
+-- 不同表中信息的JOIN: titles表显示谁有什么工作,员工编号,
+-- 入职离职时间。检索这些信息,但是使用员工编号作为employees表
+-- 的交叉引用,而不是直接使用员工编号,来获得每个员工的名和姓。
+-- (同时只取10行)
+
+SELECT employees.first_name, employees.last_name,
+ titles.title, titles.from_date, titles.to_date
+FROM titles INNER JOIN employees ON
+ employees.emp_no = titles.emp_no LIMIT 10;
+
+-- 列出所有数据库中所有的表。不同实现通常提供各自的快捷命令
+-- 来列出当前使用数据库的所有表。
+SELECT * FROM INFORMATION_SCHEMA.TABLES
+WHERE TABLE_TYPE='BASE TABLE';
+
+-- 在当前使用的数据库中,创建一个名为tablename1的表,包含下
+-- 述两列。许多其它选项可用于定制列,比如列的数据类型。
+CREATE TABLE tablename1 (fname VARCHAR(20), lname VARCHAR(20));
+
+-- 向tablename1表插入一行数据。假设该表已经定义并且接受这些值。
+INSERT INTO tablename1 VALUES('Richard','Mutt');
+
+-- 更新tablename1表中lname为'Mutt'的行fname的值改为'John'。
+UPDATE tablename1 SET fname='John' WHERE lname='Mutt';
+
+-- 删除tablename1表lname列以'M'开头的行。
+DELETE FROM tablename1 WHERE lname like 'M%';
+
+-- 删除tablename1表的所有行,留下空表。
+DELETE FROM tablename1;
+
+-- 删除整个tablename1表。
+DROP TABLE tablename1;
+```