summaryrefslogtreecommitdiffhomepage
path: root/zh-cn
diff options
context:
space:
mode:
Diffstat (limited to 'zh-cn')
-rw-r--r--zh-cn/bash-cn.html.markdown189
-rw-r--r--zh-cn/c++-cn.html.markdown572
-rw-r--r--zh-cn/c-cn.html.markdown4
-rw-r--r--zh-cn/common-lisp-cn.html.markdown2
-rw-r--r--zh-cn/csharp-cn.html.markdown3
-rw-r--r--zh-cn/go-cn.html.markdown6
-rw-r--r--zh-cn/groovy-cn.html.markdown420
-rw-r--r--zh-cn/haskell-cn.html.markdown269
-rw-r--r--zh-cn/java-cn.html.markdown19
-rw-r--r--zh-cn/javascript-cn.html.markdown517
-rw-r--r--zh-cn/julia-cn.html.markdown729
-rw-r--r--zh-cn/livescript-cn.html.markdown322
-rw-r--r--zh-cn/lua-cn.html.markdown9
-rw-r--r--zh-cn/markdown-cn.html.markdown240
-rw-r--r--zh-cn/matlab-cn.html.markdown491
-rw-r--r--zh-cn/php-cn.html.markdown2
-rw-r--r--zh-cn/python3-cn.html.markdown629
-rw-r--r--zh-cn/r-cn.html.markdown2
-rw-r--r--zh-cn/ruby-cn.html.markdown11
-rw-r--r--zh-cn/rust-cn.html.markdown296
-rw-r--r--zh-cn/scala-cn.html.markdown560
-rw-r--r--zh-cn/swift-cn.html.markdown607
-rw-r--r--zh-cn/tmux-cn.html.markdown253
23 files changed, 5451 insertions, 701 deletions
diff --git a/zh-cn/bash-cn.html.markdown b/zh-cn/bash-cn.html.markdown
index 6afa659a..d85e5b8f 100644
--- a/zh-cn/bash-cn.html.markdown
+++ b/zh-cn/bash-cn.html.markdown
@@ -5,7 +5,14 @@ contributors:
- ["Max Yankov", "https://github.com/golergka"]
- ["Darren Lin", "https://github.com/CogBear"]
- ["Alexandre Medeiros", "http://alemedeiros.sdf.org"]
+ - ["Denis Arh", "https://github.com/darh"]
+ - ["akirahirose", "https://twitter.com/akirahirose"]
+ - ["Anton Strömkvist", "http://lutic.org/"]
+ - ["Rahil Momin", "https://github.com/iamrahil"]
+ - ["Gregrory Kielian", "https://github.com/gskielian"]
+ - ["Etan Reisner", "https://github.com/deryni"]
translators:
+ - ["Jinchang Ye", "https://github.com/Alwayswithme"]
- ["Chunyang Xu", "https://github.com/XuChunyang"]
filename: LearnBash-cn.sh
lang: zh-cn
@@ -23,31 +30,45 @@ Bash 是一个为 GNU 计划编写的 Unix shell,是 Linux 和 Mac OS X 下的
# 如你所见,注释以 # 开头,shebang 也是注释。
# 显示 “Hello world!”
-echo Hello, world!
+echo Hello world!
# 每一句指令以换行或分号隔开:
echo 'This is the first line'; echo 'This is the second line'
# 声明一个变量:
-VARIABLE="Some string"
+Variable="Some string"
# 下面是错误的做法:
-VARIABLE = "Some string"
-# Bash 会把 VARIABLE 当做一个指令,由于找不到该指令,因此这里会报错。
+Variable = "Some string"
+# Bash 会把 Variable 当做一个指令,由于找不到该指令,因此这里会报错。
+# 也不可以这样:
+Variable= 'Some string'
+# Bash 会认为 'Some string' 是一条指令,由于找不到该指令,这里再次报错。
+# (这个例子中 'Variable=' 这部分会被当作仅对 'Some string' 起作用的赋值。)
# 使用变量:
-echo $VARIABLE
-echo "$VARIABLE"
-echo '$VARIABLE'
+echo $Variable
+echo "$Variable"
+echo '$Variable'
# 当你赋值 (assign) 、导出 (export),或者以其他方式使用变量时,变量名前不加 $。
# 如果要使用变量的值, 则要加 $。
# 注意: ' (单引号) 不会展开变量(即会屏蔽掉变量)。
# 在变量内部进行字符串代换
-echo ${VARIABLE/Some/A}
-# 会把 VARIABLE 中首次出现的 "some" 替换成 “A”。
+echo ${Variable/Some/A}
+# 会把 Variable 中首次出现的 "some" 替换成 “A”。
+
+# 变量的截取
+Length=7
+echo ${Variable:0:Length}
+# 这样会仅返回变量值的前7个字符
+
+# 变量的默认值
+echo ${Foo:-"DefaultValueIfFooIsMissingOrEmpty"}
+# 对 null (Foo=) 和空串 (Foo="") 起作用; 零(Foo=0)时返回0
+# 注意这仅返回默认值而不是改变变量的值
# 内置变量:
# 下面的内置变量很有用
@@ -55,26 +76,37 @@ echo "Last program return value: $?"
echo "Script's PID: $$"
echo "Number of arguments: $#"
echo "Scripts arguments: $@"
-echo "Scripts arguments separeted in different variables: $1 $2..."
+echo "Scripts arguments separated in different variables: $1 $2..."
# 读取输入:
echo "What's your name?"
-read NAME # 这里不需要声明新变量
-echo Hello, $NAME!
+read Name # 这里不需要声明新变量
+echo Hello, $Name!
# 通常的 if 结构看起来像这样:
# 'man test' 可查看更多的信息
-if [ $NAME -ne $USER ]
+if [ $Name -ne $USER ]
then
- echo "Your name is you username"
+ echo "Your name isn't your username"
else
- echo "Your name isn't you username"
+ echo "Your name is your username"
fi
# 根据上一个指令执行结果决定是否执行下一个指令
-echo "Always executed" || echo "Only executed if first command fail"
+echo "Always executed" || echo "Only executed if first command fails"
echo "Always executed" && echo "Only executed if first command does NOT fail"
+# 在 if 语句中使用 && 和 || 需要多对方括号
+if [ $Name == "Steve" ] && [ $Age -eq 15 ]
+then
+ echo "This will run if $Name is Steve AND $Age is 15."
+fi
+
+if [ $Name == "Daniya" ] || [ $Name == "Zach" ]
+then
+ echo "This will run if $Name is Daniya OR Zach."
+fi
+
# 表达式的格式如下:
echo $(( 10 + 5 ))
@@ -88,18 +120,54 @@ ls -l # 列出文件和目录的详细信息
# 用下面的指令列出当前目录下所有的 txt 文件:
ls -l | grep "\.txt"
+# 重定向输入和输出(标准输入,标准输出,标准错误)。
+# 以 ^EOF$ 作为结束标记从标准输入读取数据并覆盖 hello.py :
+cat > hello.py << EOF
+#!/usr/bin/env python
+from __future__ import print_function
+import sys
+print("#stdout", file=sys.stdout)
+print("#stderr", file=sys.stderr)
+for line in sys.stdin:
+ print(line, file=sys.stdout)
+EOF
+
# 重定向可以到输出,输入和错误输出。
-python2 hello.py < "input.in"
-python2 hello.py > "output.out"
-python2 hello.py 2> "error.err"
+python hello.py < "input.in"
+python hello.py > "output.out"
+python hello.py 2> "error.err"
+python hello.py > "output-and-error.log" 2>&1
+python hello.py > /dev/null 2>&1
# > 会覆盖已存在的文件, >> 会以累加的方式输出文件中。
+python hello.py >> "output.out" 2>> "error.err"
+
+# 覆盖 output.out , 追加 error.err 并统计行数
+info bash 'Basic Shell Features' 'Redirections' > output.out 2>> error.err
+wc -l output.out error.err
+
+# 运行指令并打印文件描述符 (比如 /dev/fd/123)
+# 具体可查看: man fd
+echo <(echo "#helloworld")
+
+# 以 "#helloworld" 覆盖 output.out:
+cat > output.out <(echo "#helloworld")
+echo "#helloworld" > output.out
+echo "#helloworld" | cat > output.out
+echo "#helloworld" | tee output.out >/dev/null
+
+# 清理临时文件并显示详情(增加 '-i' 选项启用交互模式)
+rm -v output.out error.err output-and-error.log
# 一个指令可用 $( ) 嵌套在另一个指令内部:
# 以下的指令会打印当前目录下的目录和文件总数
echo "There are $(ls | wc -l) items here."
+# 反引号 `` 起相同作用,但不允许嵌套
+# 优先使用 $( ).
+echo "There are `ls | wc -l` items here."
+
# Bash 的 case 语句与 Java 和 C++ 中的 switch 语句类似:
-case "$VARIABLE" in
+case "$Variable" in
# 列出需要匹配的字符串
0) echo "There is a zero.";;
1) echo "There is a one.";;
@@ -107,11 +175,37 @@ case "$VARIABLE" in
esac
# 循环遍历给定的参数序列:
-# 变量$VARIABLE 的值会被打印 3 次。
-# 注意 ` ` 和 $( ) 等价。seq 返回长度为 3 的数组。
-for VARIABLE in `seq 3`
+# 变量$Variable 的值会被打印 3 次。
+for Variable in {1..3}
+do
+ echo "$Variable"
+done
+
+# 或传统的 “for循环” :
+for ((a=1; a <= 3; a++))
do
- echo "$VARIABLE"
+ echo $a
+done
+
+# 也可以用于文件
+# 用 cat 输出 file1 和 file2 内容
+for Variable in file1 file2
+do
+ cat "$Variable"
+done
+
+# 或作用于其他命令的输出
+# 对 ls 输出的文件执行 cat 指令。
+for Output in $(ls)
+do
+ cat "$Output"
+done
+
+# while 循环:
+while [ true ]
+do
+ echo "loop body here..."
+ break
done
# 你也可以使用函数
@@ -132,17 +226,52 @@ bar ()
}
# 调用函数
-foo "My name is" $NAME
+foo "My name is" $Name
# 有很多有用的指令需要学习:
-tail -n 10 file.txt
# 打印 file.txt 的最后 10 行
-head -n 10 file.txt
+tail -n 10 file.txt
# 打印 file.txt 的前 10 行
-sort file.txt
+head -n 10 file.txt
# 将 file.txt 按行排序
-uniq -d file.txt
+sort file.txt
# 报告或忽略重复的行,用选项 -d 打印重复的行
-cut -d ',' -f 1 file.txt
+uniq -d file.txt
# 打印每行中 ',' 之前内容
+cut -d ',' -f 1 file.txt
+# 将 file.txt 文件所有 'okay' 替换为 'great', (兼容正则表达式)
+sed -i 's/okay/great/g' file.txt
+# 将 file.txt 中匹配正则的行打印到标准输出
+# 这里打印以 "foo" 开头, "bar" 结尾的行
+grep "^foo.*bar$" file.txt
+# 使用选项 "-c" 统计行数
+grep -c "^foo.*bar$" file.txt
+# 如果只是要按字面形式搜索字符串而不是按正则表达式,使用 fgrep (或 grep -F)
+fgrep "^foo.*bar$" file.txt
+
+
+# 以 bash 内建的 'help' 指令阅读 Bash 自带文档:
+help
+help help
+help for
+help return
+help source
+help .
+
+# 用 man 指令阅读相关的 Bash 手册
+apropos bash
+man 1 bash
+man bash
+
+# 用 info 指令查阅命令的 info 文档 (info 中按 ? 显示帮助信息)
+apropos info | grep '^info.*('
+man info
+info info
+info 5 info
+
+# 阅读 Bash 的 info 文档:
+info bash
+info bash 'Bash Features'
+info bash 6
+info --apropos bash
```
diff --git a/zh-cn/c++-cn.html.markdown b/zh-cn/c++-cn.html.markdown
new file mode 100644
index 00000000..e1551e2b
--- /dev/null
+++ b/zh-cn/c++-cn.html.markdown
@@ -0,0 +1,572 @@
+---
+language: c++
+filename: learncpp-cn.cpp
+contributors:
+ - ["Steven Basart", "http://github.com/xksteven"]
+ - ["Matt Kline", "https://github.com/mrkline"]
+translators:
+ - ["Arnie97", "https://github.com/Arnie97"]
+lang: zh-cn
+---
+
+C++是一种系统编程语言。用它的发明者,
+[Bjarne Stroustrup的话](http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2014/Keynote)来说,C++的设计目标是:
+
+- 成为“更好的C语言”
+- 支持数据的抽象与封装
+- 支持面向对象编程
+- 支持泛型编程
+
+C++提供了对硬件的紧密控制(正如C语言一样),
+能够编译为机器语言,由处理器直接执行。
+与此同时,它也提供了泛型、异常和类等高层功能。
+虽然C++的语法可能比某些出现较晚的语言更复杂,它仍然得到了人们的青睞——
+功能与速度的平衡使C++成为了目前应用最广泛的系统编程语言之一。
+
+```c++
+////////////////
+// 与C语言的比较
+////////////////
+
+// C++_几乎_是C语言的一个超集,它与C语言的基本语法有许多相同之处,
+// 例如变量和函数的声明,原生数据类型等等。
+
+// 和C语言一样,在C++中,你的程序会从main()开始执行,
+// 该函数的返回值应当为int型,这个返回值会作为程序的退出状态值。
+// 不过,大多数的编译器(gcc,clang等)也接受 void main() 的函数原型。
+// (参见 http://en.wikipedia.org/wiki/Exit_status 来获取更多信息)
+int main(int argc, char** argv)
+{
+ // 和C语言一样,命令行参数通过argc和argv传递。
+ // argc代表命令行参数的数量,
+ // 而argv是一个包含“C语言风格字符串”(char *)的数组,
+ // 其中每个字符串代表一个命令行参数的内容,
+ // 首个命令行参数是调用该程序时所使用的名称。
+ // 如果你不关心命令行参数的值,argc和argv可以被忽略。
+ // 此时,你可以用int main()作为函数原型。
+
+ // 退出状态值为0时,表示程序执行成功
+ return 0;
+}
+
+// 然而,C++和C语言也有一些区别:
+
+// 在C++中,字符字面量的大小是一个字节。
+sizeof('c') == 1
+
+// 在C语言中,字符字面量的大小与int相同。
+sizeof('c') == sizeof(10)
+
+
+// C++的函数原型与函数定义是严格匹配的
+void func(); // 这个函数不能接受任何参数
+
+// 而在C语言中
+void func(); // 这个函数能接受任意数量的参数
+
+// 在C++中,用nullptr代替C语言中的NULL
+int* ip = nullptr;
+
+// C++也可以使用C语言的标准头文件,
+// 但是需要加上前缀“c”并去掉末尾的“.h”。
+#include <cstdio>
+
+int main()
+{
+ printf("Hello, world!\n");
+ return 0;
+}
+
+///////////
+// 函数重载
+///////////
+
+// C++支持函数重载,你可以定义一组名称相同而参数不同的函数。
+
+void print(char const* myString)
+{
+ printf("String %s\n", myString);
+}
+
+void print(int myInt)
+{
+ printf("My int is %d", myInt);
+}
+
+int main()
+{
+ print("Hello"); // 解析为 void print(const char*)
+ print(15); // 解析为 void print(int)
+}
+
+///////////////////
+// 函数参数的默认值
+///////////////////
+
+// 你可以为函数的参数指定默认值,
+// 它们将会在调用者没有提供相应参数时被使用。
+
+void doSomethingWithInts(int a = 1, int b = 4)
+{
+ // 对两个参数进行一些操作
+}
+
+int main()
+{
+ doSomethingWithInts(); // a = 1, b = 4
+ doSomethingWithInts(20); // a = 20, b = 4
+ doSomethingWithInts(20, 5); // a = 20, b = 5
+}
+
+// 默认参数必须放在所有的常规参数之后。
+
+void invalidDeclaration(int a = 1, int b) // 这是错误的!
+{
+}
+
+
+///////////
+// 命名空间
+///////////
+
+// 命名空间为变量、函数和其他声明提供了分离的的作用域。
+// 命名空间可以嵌套使用。
+
+namespace First {
+ namespace Nested {
+ void foo()
+ {
+ printf("This is First::Nested::foo\n");
+ }
+ } // 结束嵌套的命名空间Nested
+} // 结束命名空间First
+
+namespace Second {
+ void foo()
+ {
+ printf("This is Second::foo\n")
+ }
+}
+
+void foo()
+{
+ printf("This is global foo\n");
+}
+
+int main()
+{
+ // 如果没有特别指定,就从“Second”中取得所需的内容。
+ using namespace Second;
+
+ foo(); // 显示“This is Second::foo”
+ First::Nested::foo(); // 显示“This is First::Nested::foo”
+ ::foo(); // 显示“This is global foo”
+}
+
+////////////
+// 输入/输出
+////////////
+
+// C++使用“流”来输入输出。<<是流的插入运算符,>>是流提取运算符。
+// cin、cout、和cerr分别代表
+// stdin(标准输入)、stdout(标准输出)和stderr(标准错误)。
+
+#include <iostream> // 引入包含输入/输出流的头文件
+
+using namespace std; // 输入输出流在std命名空间(也就是标准库)中。
+
+int main()
+{
+ int myInt;
+
+ // 在标准输出(终端/显示器)中显示
+ cout << "Enter your favorite number:\n";
+ // 从标准输入(键盘)获得一个值
+ cin >> myInt;
+
+ // cout也提供了格式化功能
+ cout << "Your favorite number is " << myInt << "\n";
+ // 显示“Your favorite number is <myInt>”
+
+ cerr << "Used for error messages";
+}
+
+/////////
+// 字符串
+/////////
+
+// C++中的字符串是对象,它们有很多成员函数
+#include <string>
+
+using namespace std; // 字符串也在std命名空间(标准库)中。
+
+string myString = "Hello";
+string myOtherString = " World";
+
+// + 可以用于连接字符串。
+cout << myString + myOtherString; // "Hello World"
+
+cout << myString + " You"; // "Hello You"
+
+// C++中的字符串是可变的,具有“值语义”。
+myString.append(" Dog");
+cout << myString; // "Hello Dog"
+
+
+/////////////
+// 引用
+/////////////
+
+// 除了支持C语言中的指针类型以外,C++还提供了_引用_。
+// 引用是一种特殊的指针类型,一旦被定义就不能重新赋值,并且不能被设置为空值。
+// 使用引用时的语法与原变量相同:
+// 也就是说,对引用类型进行解引用时,不需要使用*;
+// 赋值时也不需要用&来取地址。
+
+using namespace std;
+
+string foo = "I am foo";
+string bar = "I am bar";
+
+
+string& fooRef = foo; // 建立了一个对foo的引用。
+fooRef += ". Hi!"; // 通过引用来修改foo的值
+cout << fooRef; // "I am foo. Hi!"
+
+// 这句话的并不会改变fooRef的指向,其效果与“foo = bar”相同。
+// 也就是说,在执行这条语句之后,foo == "I am bar"。
+fooRef = bar;
+
+const string& barRef = bar; // 建立指向bar的常量引用。
+// 和C语言中一样,(指针和引用)声明为常量时,对应的值不能被修改。
+barRef += ". Hi!"; // 这是错误的,不能修改一个常量引用的值。
+
+///////////////////
+// 类与面向对象编程
+///////////////////
+
+// 有关类的第一个示例
+#include <iostream>
+
+// 声明一个类。
+// 类通常在头文件(.h或.hpp)中声明。
+class Dog {
+ // 成员变量和成员函数默认情况下是私有(private)的。
+ std::string name;
+ int weight;
+
+// 在这个标签之后,所有声明都是公有(public)的,
+// 直到重新指定“private:”(私有继承)或“protected:”(保护继承)为止
+public:
+
+ // 默认的构造器
+ Dog();
+
+ // 这里是成员函数声明的一个例子。
+ // 可以注意到,我们在此处使用了std::string,而不是using namespace std
+ // 语句using namespace绝不应当出现在头文件当中。
+ void setName(const std::string& dogsName);
+
+ void setWeight(int dogsWeight);
+
+ // 如果一个函数不对对象的状态进行修改,
+ // 应当在声明中加上const。
+ // 这样,你就可以对一个以常量方式引用的对象执行该操作。
+ // 同时可以注意到,当父类的成员函数需要被子类重写时,
+ // 父类中的函数必须被显式声明为_虚函数(virtual)_。
+ // 考虑到性能方面的因素,函数默认情况下不会被声明为虚函数。
+ virtual void print() const;
+
+ // 函数也可以在class body内部定义。
+ // 这样定义的函数会自动成为内联函数。
+ void bark() const { std::cout << name << " barks!\n" }
+
+ // 除了构造器以外,C++还提供了析构器。
+ // 当一个对象被删除或者脱离其定义域时,它的析构函数会被调用。
+ // 这使得RAII这样的强大范式(参见下文)成为可能。
+ // 为了衍生出子类来,基类的析构函数必须定义为虚函数。
+ virtual ~Dog();
+
+}; // 在类的定义之后,要加一个分号
+
+// 类的成员函数通常在.cpp文件中实现。
+void Dog::Dog()
+{
+ std::cout << "A dog has been constructed\n";
+}
+
+// 对象(例如字符串)应当以引用的形式传递,
+// 对于不需要修改的对象,最好使用常量引用。
+void Dog::setName(const std::string& dogsName)
+{
+ name = dogsName;
+}
+
+void Dog::setWeight(int dogsWeight)
+{
+ weight = dogsWeight;
+}
+
+// 虚函数的virtual关键字只需要在声明时使用,不需要在定义时重复
+void Dog::print() const
+{
+ std::cout << "Dog is " << name << " and weighs " << weight << "kg\n";
+}
+
+void Dog::~Dog()
+{
+ cout << "Goodbye " << name << "\n";
+}
+
+int main() {
+ Dog myDog; // 此时显示“A dog has been constructed”
+ myDog.setName("Barkley");
+ myDog.setWeight(10);
+ myDog.printDog(); // 显示“Dog is Barkley and weighs 10 kg”
+ return 0;
+} // 显示“Goodbye Barkley”
+
+// 继承:
+
+// 这个类继承了Dog类中的公有(public)和保护(protected)对象
+class OwnedDog : public Dog {
+
+ void setOwner(const std::string& dogsOwner)
+
+ // 重写OwnedDogs类的print方法。
+ // 如果你不熟悉子类多态的话,可以参考这个页面中的概述:
+ // http://zh.wikipedia.org/wiki/%E5%AD%90%E7%B1%BB%E5%9E%8B
+
+ // override关键字是可选的,它确保你所重写的是基类中的方法。
+ void print() const override;
+
+private:
+ std::string owner;
+};
+
+// 与此同时,在对应的.cpp文件里:
+
+void OwnedDog::setOwner(const std::string& dogsOwner)
+{
+ owner = dogsOwner;
+}
+
+void OwnedDog::print() const
+{
+ Dog::print(); // 调用基类Dog中的print方法
+ // "Dog is <name> and weights <weight>"
+
+ std::cout << "Dog is owned by " << owner << "\n";
+ // "Dog is owned by <owner>"
+}
+
+/////////////////////
+// 初始化与运算符重载
+/////////////////////
+
+// 在C++中,通过定义一些特殊名称的函数,
+// 你可以重载+、-、*、/等运算符的行为。
+// 当运算符被使用时,这些特殊函数会被调用,从而实现运算符重载。
+
+#include <iostream>
+using namespace std;
+
+class Point {
+public:
+ // 可以以这样的方式为成员变量设置默认值。
+ double x = 0;
+ double y = 0;
+
+ // 定义一个默认的构造器。
+ // 除了将Point初始化为(0, 0)以外,这个函数什么都不做。
+ Point() { };
+
+ // 下面使用的语法称为初始化列表,
+ // 这是初始化类中成员变量的正确方式。
+ Point (double a, double b) :
+ x(a),
+ y(b)
+ { /* 除了初始化成员变量外,什么都不做 */ }
+
+ // 重载 + 运算符
+ Point operator+(const Point& rhs) const;
+
+ // 重载 += 运算符
+ Point& operator+=(const Point& rhs);
+
+ // 增加 - 和 -= 运算符也是有意义的,但这里不再赘述。
+};
+
+Point Point::operator+(const Point& rhs) const
+{
+ // 创建一个新的点,
+ // 其横纵坐标分别为这个点与另一点在对应方向上的坐标之和。
+ return Point(x + rhs.x, y + rhs.y);
+}
+
+Point& Point::operator+=(const Point& rhs)
+{
+ x += rhs.x;
+ y += rhs.y;
+ return *this;
+}
+
+int main () {
+ Point up (0,1);
+ Point right (1,0);
+ // 这里使用了Point类型的运算符“+”
+ // 调用up(Point类型)的“+”方法,并以right作为函数的参数
+ Point result = up + right;
+ // 显示“Result is upright (1,1)”
+ cout << "Result is upright (" << result.x << ',' << result.y << ")\n";
+ return 0;
+}
+
+///////////
+// 异常处理
+///////////
+
+// 标准库中提供了一些基本的异常类型
+// (参见http://en.cppreference.com/w/cpp/error/exception)
+// 但是,其他任何类型也可以作为一个异常被拋出
+#include <exception>
+
+// 在_try_代码块中拋出的异常可以被随后的_catch_捕获。
+try {
+ // 不要用 _new_关键字在堆上为异常分配空间。
+ throw std::exception("A problem occurred");
+}
+// 如果拋出的异常是一个对象,可以用常量引用来捕获它
+catch (const std::exception& ex)
+{
+ std::cout << ex.what();
+// 捕获尚未被_catch_处理的所有错误
+} catch (...)
+{
+ std::cout << "Unknown exception caught";
+ throw; // 重新拋出异常
+}
+
+///////
+// RAII
+///////
+
+// RAII指的是“资源获取就是初始化”(Resource Allocation Is Initialization),
+// 它被视作C++中最强大的编程范式之一。
+// 简单说来,它指的是,用构造函数来获取一个对象的资源,
+// 相应的,借助析构函数来释放对象的资源。
+
+// 为了理解这一范式的用处,让我们考虑某个函数使用文件句柄时的情况:
+void doSomethingWithAFile(const char* filename)
+{
+ // 首先,让我们假设一切都会顺利进行。
+
+ FILE* fh = fopen(filename, "r"); // 以只读模式打开文件
+
+ doSomethingWithTheFile(fh);
+ doSomethingElseWithIt(fh);
+
+ fclose(fh); // 关闭文件句柄
+}
+
+// 不幸的是,随着错误处理机制的引入,事情会变得复杂。
+// 假设fopen函数有可能执行失败,
+// 而doSomethingWithTheFile和doSomethingElseWithIt会在失败时返回错误代码。
+// (虽然异常是C++中处理错误的推荐方式,
+// 但是某些程序员,尤其是有C语言背景的,并不认可异常捕获机制的作用)。
+// 现在,我们必须检查每个函数调用是否成功执行,并在问题发生的时候关闭文件句柄。
+bool doSomethingWithAFile(const char* filename)
+{
+ FILE* fh = fopen(filename, "r"); // 以只读模式打开文件
+ if (fh == nullptr) // 当执行失败是,返回的指针是nullptr
+ return false; // 向调用者汇报错误
+
+ // 假设每个函数会在执行失败时返回false
+ if (!doSomethingWithTheFile(fh)) {
+ fclose(fh); // 关闭文件句柄,避免造成内存泄漏。
+ return false; // 反馈错误
+ }
+ if (!doSomethingElseWithIt(fh)) {
+ fclose(fh); // 关闭文件句柄
+ return false; // 反馈错误
+ }
+
+ fclose(fh); // 关闭文件句柄
+ return true; // 指示函数已成功执行
+}
+
+// C语言的程序员通常会借助goto语句简化上面的代码:
+bool doSomethingWithAFile(const char* filename)
+{
+ FILE* fh = fopen(filename, "r");
+ if (fh == nullptr)
+ return false;
+
+ if (!doSomethingWithTheFile(fh))
+ goto failure;
+
+ if (!doSomethingElseWithIt(fh))
+ goto failure;
+
+ fclose(fh); // 关闭文件
+ return true; // 执行成功
+
+failure:
+ fclose(fh);
+ return false; // 反馈错误
+}
+
+// 如果用异常捕获机制来指示错误的话,
+// 代码会变得清晰一些,但是仍然有优化的余地。
+void doSomethingWithAFile(const char* filename)
+{
+ FILE* fh = fopen(filename, "r"); // 以只读模式打开文件
+ if (fh == nullptr)
+ throw std::exception("Could not open the file.");
+
+ try {
+ doSomethingWithTheFile(fh);
+ doSomethingElseWithIt(fh);
+ }
+ catch (...) {
+ fclose(fh); // 保证出错的时候文件被正确关闭
+ throw; // 之后,重新抛出这个异常
+ }
+
+ fclose(fh); // 关闭文件
+ // 所有工作顺利完成
+}
+
+// 相比之下,使用C++中的文件流类(fstream)时,
+// fstream会利用自己的析构器来关闭文件句柄。
+// 只要离开了某一对象的定义域,它的析构函数就会被自动调用。
+void doSomethingWithAFile(const std::string& filename)
+{
+ // ifstream是输入文件流(input file stream)的简称
+ std::ifstream fh(filename); // 打开一个文件
+
+ // 对文件进行一些操作
+ doSomethingWithTheFile(fh);
+ doSomethingElseWithIt(fh);
+
+} // 文件已经被析构器自动关闭
+
+// 与上面几种方式相比,这种方式有着_明显_的优势:
+// 1. 无论发生了什么情况,资源(此例当中是文件句柄)都会被正确关闭。
+// 只要你正确使用了析构器,就_不会_因为忘记关闭句柄,造成资源的泄漏。
+// 2. 可以注意到,通过这种方式写出来的代码十分简洁。
+// 析构器会在后台关闭文件句柄,不再需要你来操心这些琐事。
+// 3. 这种方式的代码具有异常安全性。
+// 无论在函数中的何处拋出异常,都不会阻碍对文件资源的释放。
+
+// 地道的C++代码应当把RAII的使用扩展到各种类型的资源上,包括:
+// - 用unique_ptr和shared_ptr管理的内存
+// - 各种数据容器,例如标准库中的链表、向量(容量自动扩展的数组)、散列表等;
+// 当它们脱离作用域时,析构器会自动释放其中储存的内容。
+// - 用lock_guard和unique_lock实现的互斥
+```
+扩展阅读:
+
+<http://cppreference.com/w/cpp> 提供了最新的语法参考。
+
+可以在 <http://cplusplus.com> 找到一些补充资料。
diff --git a/zh-cn/c-cn.html.markdown b/zh-cn/c-cn.html.markdown
index 223f6e35..1e10416e 100644
--- a/zh-cn/c-cn.html.markdown
+++ b/zh-cn/c-cn.html.markdown
@@ -566,7 +566,7 @@ typedef void (*my_fnp_type)(char *);
'\'' // 单引号
'\"' // 双引号
'\xhh' // 十六进制数字. 例子: '\xb' = vertical tab
-'\ooo' // 十进制数字. 例子: '\013' = vertical tab
+'\ooo' // 八进制数字. 例子: '\013' = vertical tab
// 打印格式:
"%d" // 整数
@@ -579,7 +579,7 @@ typedef void (*my_fnp_type)(char *);
"%c" // 字母
"%p" // 指针
"%x" // 十六进制
-"%o" // 十进制
+"%o" // 八进制
"%%" // 打印 %
///////////////////////////////////////
diff --git a/zh-cn/common-lisp-cn.html.markdown b/zh-cn/common-lisp-cn.html.markdown
index c4dc3274..b82829a9 100644
--- a/zh-cn/common-lisp-cn.html.markdown
+++ b/zh-cn/common-lisp-cn.html.markdown
@@ -17,7 +17,7 @@ ANSI Common Lisp 是一个广泛通用于各个工业领域的、支持多种范
另外还有一本热门的近期出版的
[Land of Lisp](http://landoflisp.com/).
-```scheme
+```common-lisp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; 0. 语法
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
diff --git a/zh-cn/csharp-cn.html.markdown b/zh-cn/csharp-cn.html.markdown
index a3cda5b3..971c1be9 100644
--- a/zh-cn/csharp-cn.html.markdown
+++ b/zh-cn/csharp-cn.html.markdown
@@ -232,7 +232,8 @@ on a new line! ""Wow!"", the masses cried";
// 三元表达式
// 简单的 if/else 语句可以写成:
// <条件> ? <真> : <假>
- string isTrue = (true) ? "True" : "False";
+ int toCompare = 17;
+ string isTrue = toCompare == 17 ? "True" : "False";
// While 循环
int fooWhile = 0;
diff --git a/zh-cn/go-cn.html.markdown b/zh-cn/go-cn.html.markdown
index 4a87dc21..49224085 100644
--- a/zh-cn/go-cn.html.markdown
+++ b/zh-cn/go-cn.html.markdown
@@ -68,7 +68,7 @@ func learnTypes() {
can include line breaks.` // 同样是String类型
// 非ascii字符。Go使用UTF-8编码。
- g := 'Σ' // rune类型,uint32的别名,使用UTF-8编码
+ g := 'Σ' // rune类型,int32的别名,使用UTF-8编码
f := 3.14195 // float64类型,IEEE-754 64位浮点数
c := 3 + 4i // complex128类型,内部使用两个float64表示
@@ -239,7 +239,7 @@ func learnConcurrency() {
go inc(0, c) // go is a statement that starts a new goroutine.
go inc(10, c)
go inc(-805, c)
- // 从channel中独处结果并打印。
+ // 从channel中读取结果并打印。
// 打印出什么东西是不可预知的。
fmt.Println(<-c, <-c, <-c) // channel在右边的时候,<-是读操作。
@@ -283,4 +283,4 @@ Go的根源在[Go官方网站](http://golang.org/)。
强烈推荐阅读语言定义部分,很简单而且很简洁!(as language definitions go these days.)
-学习Go还要阅读Go标准库的源代码,全部文档化了,可读性非常好,可以学到go,go style和go idioms。在文档中点击函数名,源代码就出来了!
+学习Go还要阅读Go[标准库的源代码](http://golang.org/src/),全部文档化了,可读性非常好,可以学到go,go style和go idioms。在[文档](http://golang.org/pkg/)中点击函数名,源代码就出来了!
diff --git a/zh-cn/groovy-cn.html.markdown b/zh-cn/groovy-cn.html.markdown
new file mode 100644
index 00000000..562a0284
--- /dev/null
+++ b/zh-cn/groovy-cn.html.markdown
@@ -0,0 +1,420 @@
+---
+language: Groovy
+filename: learngroovy-cn.groovy
+contributors:
+ - ["Roberto Pérez Alcolea", "http://github.com/rpalcolea"]
+translators:
+ - ["Todd Gao", "http://github.com/7c00"]
+lang: zh-cn
+---
+
+Groovy - Java平台的动态语言。[了解更多。](http://www.groovy-lang.org/)
+
+```groovy
+
+/*
+ 安装:
+
+ 1) 安装 GVM - http://gvmtool.net/
+ 2) 安装 Groovy: gvm install groovy
+ 3) 启动 groovy 控制台,键入: groovyConsole
+
+*/
+
+// 双斜线开始的是单行注释
+/*
+像这样的是多行注释
+*/
+
+// Hello World
+println "Hello world!"
+
+/*
+ 变量:
+
+ 可以给变量赋值,以便稍后使用
+*/
+
+def x = 1
+println x
+
+x = new java.util.Date()
+println x
+
+x = -3.1499392
+println x
+
+x = false
+println x
+
+x = "Groovy!"
+println x
+
+/*
+ 集合和映射
+*/
+
+//创建一个空的列表
+def technologies = []
+
+/*** 往列表中增加一个元素 ***/
+
+// 和Java一样
+technologies.add("Grails")
+
+// 左移添加,返回该列表
+technologies << "Groovy"
+
+// 增加多个元素
+technologies.addAll(["Gradle","Griffon"])
+
+/*** 从列表中删除元素 ***/
+
+// 和Java一样
+technologies.remove("Griffon")
+
+// 减号也行
+technologies = technologies - 'Grails'
+
+/*** 遍历列表 ***/
+
+// 遍历列表中的元素
+technologies.each { println "Technology: $it"}
+technologies.eachWithIndex { it, i -> println "$i: $it"}
+
+/*** 检查列表内容 ***/
+
+//判断列表是否包含某元素,返回boolean
+contained = technologies.contains( 'Groovy' )
+
+// 或
+contained = 'Groovy' in technologies
+
+// 检查多个元素
+technologies.containsAll(['Groovy','Grails'])
+
+/*** 列表排序 ***/
+
+// 排序列表(修改原列表)
+technologies.sort()
+
+// 要想不修改原列表,可以这样:
+sortedTechnologies = technologies.sort( false )
+
+/*** 列表操作 ***/
+
+//替换列表元素
+Collections.replaceAll(technologies, 'Gradle', 'gradle')
+
+//打乱列表
+Collections.shuffle(technologies, new Random())
+
+//清空列表
+technologies.clear()
+
+//创建空的映射
+def devMap = [:]
+
+//增加值
+devMap = ['name':'Roberto', 'framework':'Grails', 'language':'Groovy']
+devMap.put('lastName','Perez')
+
+//遍历映射元素
+devMap.each { println "$it.key: $it.value" }
+devMap.eachWithIndex { it, i -> println "$i: $it"}
+
+//判断映射是否包含某键
+assert devMap.containsKey('name')
+
+//判断映射是否包含某值
+assert devMap.containsValue('Roberto')
+
+//取得映射所有的键
+println devMap.keySet()
+
+//取得映射所有的值
+println devMap.values()
+
+/*
+ Groovy Beans
+
+ GroovyBeans 是 JavaBeans,但使用了更简单的语法
+
+ Groovy 被编译为字节码时,遵循下列规则。
+
+ * 如果一个名字声明时带有访问修饰符(public, private, 或者 protected),
+ 则会生成一个字段(field)。
+
+ * 名字声明时没有访问修饰符,则会生成一个带有public getter和setter的
+ private字段,即属性(property)。
+
+ * 如果一个属性声明为final,则会创建一个final的private字段,但不会生成setter。
+
+ * 可以声明一个属性的同时定义自己的getter和setter。
+
+ * 可以声明具有相同名字的属性和字段,该属性会使用该字段。
+
+ * 如果要定义private或protected属性,必须提供声明为private或protected的getter
+ 和setter。
+
+ * 如果使用显式或隐式的 this(例如 this.foo, 或者 foo)访问类的在编译时定义的属性,
+ Groovy会直接访问对应字段,而不是使用getter或者setter
+
+ * 如果使用显式或隐式的 foo 访问一个不存在的属性,Groovy会通过元类(meta class)
+ 访问它,这可能导致运行时错误。
+
+*/
+
+class Foo {
+ // 只读属性
+ final String name = "Roberto"
+
+ // 只读属性,有public getter和protected setter
+ String language
+ protected void setLanguage(String language) { this.language = language }
+
+ // 动态类型属性
+ def lastName
+}
+
+/*
+ 逻辑分支和循环
+*/
+
+//Groovy支持常见的if - else语法
+def x = 3
+
+if(x==1) {
+ println "One"
+} else if(x==2) {
+ println "Two"
+} else {
+ println "X greater than Two"
+}
+
+//Groovy也支持三元运算符
+def y = 10
+def x = (y > 1) ? "worked" : "failed"
+assert x == "worked"
+
+//for循环
+//使用区间(range)遍历
+def x = 0
+for (i in 0 .. 30) {
+ x += i
+}
+
+//遍历列表
+x = 0
+for( i in [5,3,2,1] ) {
+ x += i
+}
+
+//遍历数组
+array = (0..20).toArray()
+x = 0
+for (i in array) {
+ x += i
+}
+
+//遍历映射
+def map = ['name':'Roberto', 'framework':'Grails', 'language':'Groovy']
+x = 0
+for ( e in map ) {
+ x += e.value
+}
+
+/*
+ 运算符
+
+ 在Groovy中以下常用运算符支持重载:
+ http://www.groovy-lang.org/operators.html#Operator-Overloading
+
+ 实用的groovy运算符
+*/
+//展开(spread)运算符:对聚合对象的所有元素施加操作
+def technologies = ['Groovy','Grails','Gradle']
+technologies*.toUpperCase() // 相当于 technologies.collect { it?.toUpperCase() }
+
+//安全导航(safe navigation)运算符:用来避免NullPointerException
+def user = User.get(1)
+def username = user?.username
+
+
+/*
+ 闭包
+ Groovy闭包好比代码块或者方法指针,它是一段代码定义,可以以后执行。
+
+ 更多信息见:http://www.groovy-lang.org/closures.html
+*/
+//例子:
+def clos = { println "Hello World!" }
+
+println "Executing the Closure:"
+clos()
+
+//传参数给闭包
+def sum = { a, b -> println a+b }
+sum(2,4)
+
+//闭包可以引用参数列表以外的变量
+def x = 5
+def multiplyBy = { num -> num * x }
+println multiplyBy(10)
+
+// 只有一个参数的闭包可以省略参数的定义
+def clos = { print it }
+clos( "hi" )
+
+/*
+ Groovy可以记忆闭包结果 [1][2][3]
+*/
+def cl = {a, b ->
+ sleep(3000) // 模拟费时操作
+ a + b
+}
+
+mem = cl.memoize()
+
+def callClosure(a, b) {
+ def start = System.currentTimeMillis()
+ mem(a, b)
+ println "Inputs(a = $a, b = $b) - took ${System.currentTimeMillis() - start} msecs."
+}
+
+callClosure(1, 2)
+callClosure(1, 2)
+callClosure(2, 3)
+callClosure(2, 3)
+callClosure(3, 4)
+callClosure(3, 4)
+callClosure(1, 2)
+callClosure(2, 3)
+callClosure(3, 4)
+
+/*
+ Expando
+
+ Expando类是一种动态bean类,可以给它的实例添加属性和添加闭包作为方法
+
+ http://mrhaki.blogspot.mx/2009/10/groovy-goodness-expando-as-dynamic-bean.html
+*/
+ def user = new Expando(name:"Roberto")
+ assert 'Roberto' == user.name
+
+ user.lastName = 'Pérez'
+ assert 'Pérez' == user.lastName
+
+ user.showInfo = { out ->
+ out << "Name: $name"
+ out << ", Last name: $lastName"
+ }
+
+ def sw = new StringWriter()
+ println user.showInfo(sw)
+
+
+/*
+ 元编程(MOP)
+*/
+
+//使用ExpandoMetaClass增加行为
+String.metaClass.testAdd = {
+ println "we added this"
+}
+
+String x = "test"
+x?.testAdd()
+
+//拦截方法调用
+class Test implements GroovyInterceptable {
+ def sum(Integer x, Integer y) { x + y }
+
+ def invokeMethod(String name, args) {
+ System.out.println "Invoke method $name with args: $args"
+ }
+}
+
+def test = new Test()
+test?.sum(2,3)
+test?.multiply(2,3)
+
+//Groovy支持propertyMissing,来处理属性解析尝试
+class Foo {
+ def propertyMissing(String name) { name }
+}
+def f = new Foo()
+
+assertEquals "boo", f.boo
+
+/*
+ 类型检查和静态编译
+ Groovy天生是并将永远是一门动态语言,但也支持类型检查和静态编译
+
+ 更多: http://www.infoq.com/articles/new-groovy-20
+*/
+//类型检查
+import groovy.transform.TypeChecked
+
+void testMethod() {}
+
+@TypeChecked
+void test() {
+ testMeethod()
+
+ def name = "Roberto"
+
+ println naameee
+
+}
+
+//另一例子
+import groovy.transform.TypeChecked
+
+@TypeChecked
+Integer test() {
+ Integer num = "1"
+
+ Integer[] numbers = [1,2,3,4]
+
+ Date date = numbers[1]
+
+ return "Test"
+
+}
+
+//静态编译例子
+import groovy.transform.CompileStatic
+
+@CompileStatic
+int sum(int x, int y) {
+ x + y
+}
+
+assert sum(2,5) == 7
+
+
+```
+
+## 进阶资源
+
+[Groovy文档](http://www.groovy-lang.org/documentation.html)
+
+[Groovy web console](http://groovyconsole.appspot.com/)
+
+加入[Groovy用户组](http://www.groovy-lang.org/usergroups.html)
+
+## 图书
+
+* [Groovy Goodness] (https://leanpub.com/groovy-goodness-notebook)
+
+* [Groovy in Action] (http://manning.com/koenig2/)
+
+* [Programming Groovy 2: Dynamic Productivity for the Java Developer] (http://shop.oreilly.com/product/9781937785307.do)
+
+[1] http://roshandawrani.wordpress.com/2010/10/18/groovy-new-feature-closures-can-now-memorize-their-results/
+[2] http://www.solutionsiq.com/resources/agileiq-blog/bid/72880/Programming-with-Groovy-Trampoline-and-Memoize
+[3] http://mrhaki.blogspot.mx/2011/05/groovy-goodness-cache-closure-results.html
+
+
+
diff --git a/zh-cn/haskell-cn.html.markdown b/zh-cn/haskell-cn.html.markdown
index 8d51f144..b0b1183f 100644
--- a/zh-cn/haskell-cn.html.markdown
+++ b/zh-cn/haskell-cn.html.markdown
@@ -1,28 +1,29 @@
---
-language: haskell
+language: Haskell
filename: learn-haskell-zh.hs
contributors:
- ["Adit Bhargava", "http://adit.io"]
translators:
- ["Peiyong Lin", ""]
+ - ["chad luo", "http://yuki.rocks"]
lang: zh-cn
---
-Haskell 被设计成一种实用的纯函数式编程语言。它因为 monads 及其类型系统而出名,但是我回归到它本身因为。Haskell 使得编程对于我而言是一种真正的快乐。
+Haskell 是一门实用的函数式编程语言,因其 Monads 与类型系统而闻名。而我使用它则是因为它异常优雅。用 Haskell 编程令我感到非常快乐。
```haskell
--- 单行注释以两个破折号开头
+-- 单行注释以两个减号开头
{- 多行注释像这样
- 被一个闭合的块包围
+ 被一个闭合的块包围
-}
----------------------------------------------------
-- 1. 简单的数据类型和操作符
----------------------------------------------------
--- 你有数字
+-- 数字
3 -- 3
--- 数学计算就像你所期待的那样
+-- 数学计算
1 + 1 -- 2
8 - 1 -- 7
10 * 2 -- 20
@@ -34,7 +35,7 @@ Haskell 被设计成一种实用的纯函数式编程语言。它因为 monads
-- 整除
35 `div` 4 -- 8
--- 布尔值也简单
+-- 布尔值
True
False
@@ -45,21 +46,22 @@ not False -- True
1 /= 1 -- False
1 < 10 -- True
--- 在上述的例子中,`not` 是一个接受一个值的函数。
--- Haskell 不需要括号来调用函数。。。所有的参数
--- 都只是在函数名之后列出来。因此,通常的函数调用模式是:
--- func arg1 arg2 arg3...
--- 查看关于函数的章节以获得如何写你自己的函数的相关信息。
+-- 在上面的例子中,`not` 是一个接受一个参数的函数。
+-- Haskell 不需要括号来调用函数,所有的参数都只是在函数名之后列出来
+-- 因此,通常的函数调用模式是:
+-- func arg1 arg2 arg3...
+-- 你可以查看函数部分了解如何自行编写。
-- 字符串和字符
-"This is a string."
+"This is a string." -- 字符串
'a' -- 字符
'对于字符串你不能使用单引号。' -- 错误!
--- 连结字符串
+-- 连接字符串
"Hello " ++ "world!" -- "Hello world!"
-- 一个字符串是一系列字符
+['H', 'e', 'l', 'l', 'o'] -- "Hello"
"This is a string" !! 0 -- 'T'
@@ -67,162 +69,164 @@ not False -- True
-- 列表和元组
----------------------------------------------------
--- 一个列表中的每一个元素都必须是相同的类型
--- 下面两个列表一样
+-- 一个列表中的每一个元素都必须是相同的类型。
+-- 下面两个列表等价
[1, 2, 3, 4, 5]
[1..5]
--- 在 Haskell 你可以拥有含有无限元素的列表
-[1..] -- 一个含有所有自然数的列表
+-- 区间也可以这样
+['A'..'F'] -- "ABCDEF"
--- 因为 Haskell 有“懒惰计算”,所以无限元素的列表可以正常运作。这意味着
--- Haskell 可以只在它需要的时候计算。所以你可以请求
--- 列表中的第1000个元素,Haskell 会返回给你
+-- 你可以在区间中指定步进
+[0,2..10] -- [0, 2, 4, 6, 8, 10]
+[5..1] -- 这样不行,因为 Haskell 默认递增
+[5,4..1] -- [5, 4, 3, 2, 1]
-[1..] !! 999 -- 1000
+-- 列表下标
+[0..] !! 5 -- 5
--- Haskell 计算了列表中 1 - 1000 个元素。。。但是
--- 这个无限元素的列表中剩下的元素还不存在! Haskell 不会
--- 真正地计算它们知道它需要。
+-- 在 Haskell 你可以使用无限列表
+[1..] -- 一个含有所有自然数的列表
-<FS>- 连接两个列表
+-- 无限列表的原理是,Haskell 有“惰性求值”。
+-- 这意味着 Haskell 只在需要时才会计算。
+-- 所以当你获取列表的第 1000 项元素时,Haskell 会返回给你:
+[1..] !! 999 -- 1000
+-- Haskell 计算了列表中第 1 至 1000 项元素,但这个无限列表中剩下的元素还不存在。
+-- Haskell 只有在需要时才会计算它们。
+
+-- 连接两个列表
[1..5] ++ [6..10]
-- 往列表头增加元素
0:[1..5] -- [0, 1, 2, 3, 4, 5]
--- 列表中的下标
-[0..] !! 5 -- 5
-
--- 更多列表操作
+-- 其它列表操作
head [1..5] -- 1
tail [1..5] -- [2, 3, 4, 5]
init [1..5] -- [1, 2, 3, 4]
last [1..5] -- 5
--- 列表推导
+-- 列表推导 (list comprehension)
[x*2 | x <- [1..5]] -- [2, 4, 6, 8, 10]
-- 附带条件
[x*2 | x <-[1..5], x*2 > 4] -- [6, 8, 10]
--- 元组中的每一个元素可以是不同类型的,但是一个元组
--- 的长度是固定的
+-- 元组中的每一个元素可以是不同类型,但是一个元组的长度是固定的
-- 一个元组
("haskell", 1)
--- 获取元组中的元素
+-- 获取元组中的元素(例如,一个含有 2 个元素的元祖)
fst ("haskell", 1) -- "haskell"
snd ("haskell", 1) -- 1
----------------------------------------------------
-- 3. 函数
----------------------------------------------------
+
-- 一个接受两个变量的简单函数
add a b = a + b
--- 注意,如果你使用 ghci (Hakell 解释器)
--- 你将需要使用 `let`,也就是
+-- 注意,如果你使用 ghci (Hakell 解释器),你需要使用 `let`,也就是
-- let add a b = a + b
--- 使用函数
+-- 调用函数
add 1 2 -- 3
--- 你也可以把函数放置在两个参数之间
--- 附带倒引号:
+-- 你也可以使用反引号中置函数名:
1 `add` 2 -- 3
--- 你也可以定义不带字符的函数!这使得
--- 你定义自己的操作符!这里有一个操作符
--- 来做整除
+-- 你也可以定义不带字母的函数名,这样你可以定义自己的操作符。
+-- 这里有一个做整除的操作符
(//) a b = a `div` b
35 // 4 -- 8
--- 守卫:一个简单的方法在函数里做分支
+-- Guard:一个在函数中做条件判断的简单方法
fib x
| x < 2 = x
| otherwise = fib (x - 1) + fib (x - 2)
--- 模式匹配是类型的。这里有三种不同的 fib
--- 定义。Haskell 将自动调用第一个
--- 匹配值的模式的函数。
+-- 模式匹配与 Guard 类似。
+-- 这里给出了三个不同的 fib 定义。
+-- Haskell 会自动调用第一个符合参数模式的声明
fib 1 = 1
fib 2 = 2
fib x = fib (x - 1) + fib (x - 2)
--- 元组的模式匹配:
+-- 元组的模式匹配
foo (x, y) = (x + 1, y + 2)
--- 列表的模式匹配。这里 `x` 是列表中第一个元素,
--- 并且 `xs` 是列表剩余的部分。我们可以写
--- 自己的 map 函数:
+-- 列表的模式匹配
+-- 这里 `x` 是列表中第一个元素,`xs` 是列表剩余的部分。
+-- 我们可以实现自己的 map 函数:
myMap func [] = []
myMap func (x:xs) = func x:(myMap func xs)
--- 编写出来的匿名函数带有一个反斜杠,后面跟着
--- 所有的参数。
+-- 匿名函数带有一个反斜杠,后面跟着所有的参数
myMap (\x -> x + 2) [1..5] -- [3, 4, 5, 6, 7]
--- 使用 fold (在一些语言称为`inject`)随着一个匿名的
--- 函数。foldl1 意味着左折叠(fold left), 并且使用列表中第一个值
--- 作为累加器的初始化值。
+-- 在 fold(在一些语言称 为`inject`)中使用匿名函数
+-- foldl1 意味着左折叠 (fold left), 并且使用列表中第一个值作为累加器的初始值。
foldl1 (\acc x -> acc + x) [1..5] -- 15
----------------------------------------------------
--- 4. 更多的函数
+-- 4. 其它函数
----------------------------------------------------
--- 柯里化(currying):如果你不传递函数中所有的参数,
--- 它就变成“柯里化的”。这意味着,它返回一个接受剩余参数的函数。
-
+-- 部分调用
+-- 如果你调用函数时没有给出所有参数,它就被“部分调用”。
+-- 它将返回一个接受余下参数的函数。
add a b = a + b
foo = add 10 -- foo 现在是一个接受一个数并对其加 10 的函数
foo 5 -- 15
--- 另外一种方式去做同样的事
+-- 另一种等价写法
foo = (+10)
foo 5 -- 15
--- 函数组合
--- (.) 函数把其它函数链接到一起
--- 举个列子,这里 foo 是一个接受一个值的函数。它对接受的值加 10,
--- 并对结果乘以 5,之后返回最后的值。
+-- 函列表合
+-- (.) 函数把其它函数链接到一起。
+-- 例如,这里 foo 是一个接受一个值的函数。
+-- 它对接受的值加 10,并对结果乘以 5,之后返回最后的值。
foo = (*5) . (+10)
-- (5 + 10) * 5 = 75
foo 5 -- 75
--- 修复优先级
--- Haskell 有另外一个函数称为 `$`。它改变优先级
--- 使得其左侧的每一个操作先计算然后应用到
--- 右侧的每一个操作。你可以使用 `.` 和 `$` 来除去很多
--- 括号:
+-- 修正优先级
+-- Haskell 有另外一个函数 `$` 可以改变优先级。
+-- `$` 使得 Haskell 先计算其右边的部分,然后调用左边的部分。
+-- 你可以使用 `$` 来移除多余的括号。
--- before
-(even (fib 7)) -- true
+-- 修改前
+(even (fib 7)) -- False
--- after
-even . fib $ 7 -- true
+-- 修改后
+even . fib $ 7 -- False
+
+-- 等价地
+even $ fib 7 -- False
----------------------------------------------------
--- 5. 类型签名
+-- 5. 类型声明
----------------------------------------------------
--- Haskell 有一个非常强壮的类型系统,一切都有一个类型签名。
+-- Haskell 有一个非常强大的类型系统,一切都有一个类型声明。
-- 一些基本的类型:
5 :: Integer
"hello" :: String
True :: Bool
--- 函数也有类型。
--- `not` 接受一个布尔型返回一个布尔型:
+-- 函数也有类型
+-- `not` 接受一个布尔型返回一个布尔型
-- not :: Bool -> Bool
--- 这是接受两个参数的函数:
+-- 这是接受两个参数的函数
-- add :: Integer -> Integer -> Integer
--- 当你定义一个值,在其上写明它的类型是一个好实践:
+-- 当你定义一个值,声明其类型是一个好做法
double :: Integer -> Integer
double x = x * 2
@@ -230,159 +234,148 @@ double x = x * 2
-- 6. 控制流和 If 语句
----------------------------------------------------
--- if 语句
+-- if 语句:
haskell = if 1 == 1 then "awesome" else "awful" -- haskell = "awesome"
--- if 语句也可以有多行,缩进是很重要的
+-- if 语句也可以有多行,注意缩进:
haskell = if 1 == 1
then "awesome"
else "awful"
--- case 语句:这里是你可以怎样去解析命令行参数
+-- case 语句
+-- 解析命令行参数:
case args of
"help" -> printHelp
"start" -> startProgram
_ -> putStrLn "bad args"
--- Haskell 没有循环因为它使用递归取代之。
--- map 应用一个函数到一个数组中的每一个元素
-
+-- Haskell 没有循环,它使用递归
+-- map 对一个列表中的每一个元素调用一个函数
map (*2) [1..5] -- [2, 4, 6, 8, 10]
-- 你可以使用 map 来编写 for 函数
for array func = map func array
--- 然后使用它
+-- 调用
for [0..5] $ \i -> show i
--- 我们也可以像这样写:
+-- 我们也可以像这样写
for [0..5] show
-- 你可以使用 foldl 或者 foldr 来分解列表
-- foldl <fn> <initial value> <list>
foldl (\x y -> 2*x + y) 4 [1,2,3] -- 43
--- 这和下面是一样的
+-- 等价于
(2 * (2 * (2 * 4 + 1) + 2) + 3)
--- foldl 是左手边的,foldr 是右手边的-
+-- foldl 从左开始,foldr 从右
foldr (\x y -> 2*x + y) 4 [1,2,3] -- 16
--- 这和下面是一样的
+-- 现在它等价于
(2 * 3 + (2 * 2 + (2 * 1 + 4)))
----------------------------------------------------
-- 7. 数据类型
----------------------------------------------------
--- 这里展示在 Haskell 中你怎样编写自己的数据类型
-
+-- 在 Haskell 中声明你自己的数据类型:
data Color = Red | Blue | Green
-- 现在你可以在函数中使用它:
-
-
say :: Color -> String
say Red = "You are Red!"
say Blue = "You are Blue!"
say Green = "You are Green!"
-- 你的数据类型也可以有参数:
-
data Maybe a = Nothing | Just a
--- 类型 Maybe 的所有
-Just "hello" -- of type `Maybe String`
-Just 1 -- of type `Maybe Int`
-Nothing -- of type `Maybe a` for any `a`
+-- 这些都是 Maybe 类型:
+Just "hello" -- `Maybe String` 类型
+Just 1 -- `Maybe Int` 类型
+Nothing -- 对任意 `a` 为 `Maybe a` 类型
----------------------------------------------------
-- 8. Haskell IO
----------------------------------------------------
--- 虽然在没有解释 monads 的情况下 IO不能被完全地解释,
--- 着手解释到位并不难。
-
--- 当一个 Haskell 程序被执行,函数 `main` 就被调用。
--- 它必须返回一个类型 `IO ()` 的值。举个列子:
+-- 虽然不解释 Monads 就无法完全解释 IO,但大致了解并不难。
+-- 当执行一个 Haskell 程序时,函数 `main` 就被调用。
+-- 它必须返回一个类型 `IO ()` 的值。例如:
main :: IO ()
main = putStrLn $ "Hello, sky! " ++ (say Blue)
--- putStrLn has type String -> IO ()
+-- putStrLn 的类型是 String -> IO ()
--- 如果你能实现你的程序依照函数从 String 到 String,那样编写 IO 是最简单的。
+-- 如果你的程序输入 String 返回 String,那样编写 IO 是最简单的。
-- 函数
-- interact :: (String -> String) -> IO ()
--- 输入一些文本,在其上运行一个函数,并打印出输出
+-- 输入一些文本,对其调用一个函数,并打印输出。
countLines :: String -> String
countLines = show . length . lines
main' = interact countLines
--- 你可以考虑一个 `IO()` 类型的值,当做一系列计算机所完成的动作的代表,
--- 就像一个以命令式语言编写的计算机程序。我们可以使用 `do` 符号来把动作链接到一起。
--- 举个列子:
-
+-- 你可以认为一个 `IO ()` 类型的值是表示计算机做的一系列操作,类似命令式语言。
+-- 我们可以使用 `do` 声明来把动作连接到一起。
+-- 举个列子
sayHello :: IO ()
sayHello = do
putStrLn "What is your name?"
- name <- getLine -- this gets a line and gives it the name "input"
+ name <- getLine -- 这里接受一行输入并绑定至 "name"
putStrLn $ "Hello, " ++ name
-- 练习:编写只读取一行输入的 `interact`
-- 然而,`sayHello` 中的代码将不会被执行。唯一被执行的动作是 `main` 的值。
--- 为了运行 `sayHello`,注释上面 `main` 的定义,并代替它:
+-- 为了运行 `sayHello`,注释上面 `main` 的定义,替换为:
-- main = sayHello
--- 让我们来更好地理解刚才所使用的函数 `getLine` 是怎样工作的。它的类型是:
+-- 让我们来更进一步理解刚才所使用的函数 `getLine` 是怎样工作的。它的类型是:
-- getLine :: IO String
--- 你可以考虑一个 `IO a` 类型的值,代表一个当被执行的时候
--- 将产生一个 `a` 类型的值的计算机程序(除了它所做的任何事之外)。我们可以保存和重用这个值通过 `<-`。
--- 我们也可以写自己的 `IO String` 类型的动作:
-
+-- 你可以认为一个 `IO a` 类型的值代表了一个运行时会生成一个 `a` 类型值的程序。
+-- (可能伴随其它行为)
+-- 我们可以通过 `<-` 保存和重用这个值。
+-- 我们也可以实现自己的 `IO String` 类型函数:
action :: IO String
action = do
putStrLn "This is a line. Duh"
input1 <- getLine
input2 <- getLine
- -- The type of the `do` statement is that of its last line.
- -- `return` is not a keyword, but merely a function
+ -- `do` 语句的类型是它的最后一行
+ -- `return` 不是关键字,只是一个普通函数
return (input1 ++ "\n" ++ input2) -- return :: String -> IO String
--- 我们可以使用这个动作就像我们使用 `getLine`:
-
+-- 我们可以像调用 `getLine` 一样调用它
main'' = do
putStrLn "I will echo two lines!"
result <- action
putStrLn result
putStrLn "This was all, folks!"
--- `IO` 类型是一个 "monad" 的例子。Haskell 使用一个 monad 来做 IO的方式允许它是一门纯函数式语言。
--- 任何与外界交互的函数(也就是 IO) 都在它的类型签名处做一个 `IO` 标志
--- 着让我们推出 什么样的函数是“纯洁的”(不与外界交互,不修改状态) 和 什么样的函数不是 “纯洁的”
-
--- 这是一个强有力的特征,因为并发地运行纯函数是简单的;因此,Haskell 中并发是非常简单的。
-
+-- `IO` 类型是一个 "Monad" 的例子。
+-- Haskell 通过使用 Monad 使得其本身为纯函数式语言。
+-- 任何与外界交互的函数(即 IO)都在它的类型声明中标记为 `IO`。
+-- 这告诉我们什么样的函数是“纯洁的”(不与外界交互,不修改状态) ,
+-- 什么样的函数不是 “纯洁的”。
+-- 这个功能非常强大,因为纯函数并发非常容易,由此在 Haskell 中做并发非常容易。
----------------------------------------------------
--- 9. The Haskell REPL
+-- 9. Haskell REPL
----------------------------------------------------
--- 键入 `ghci` 开始 repl。
+-- 键入 `ghci` 开始 REPL。
-- 现在你可以键入 Haskell 代码。
--- 任何新值都需要通过 `let` 来创建:
-
+-- 任何新值都需要通过 `let` 来创建
let foo = 5
--- 你可以查看任何值的类型,通过命令 `:t`:
-
+-- 你可以通过命令 `:t` 查看任何值的类型
>:t foo
foo :: Integer
-- 你也可以运行任何 `IO ()`类型的动作
-
> sayHello
What is your name?
Friend!
@@ -390,7 +383,7 @@ Hello, Friend!
```
-还有很多关于 Haskell,包括类型类和 monads。这些是使得编码 Haskell 是如此有趣的主意。我用一个最后的 Haskell 例子来结束:一个 Haskell 的快排实现:
+Haskell 还有许多内容,包括类型类 (typeclasses) 与 Monads。这些都是令 Haskell 编程非常有趣的好东西。我们最后给出 Haskell 的一个例子,一个快速排序的实现:
```haskell
qsort [] = []
@@ -399,9 +392,9 @@ qsort (p:xs) = qsort lesser ++ [p] ++ qsort greater
greater = filter (>= p) xs
```
-安装 Haskell 是简单的。你可以从[这里](http://www.haskell.org/platform/)获得它。
+安装 Haskell 很简单。你可以[从这里获得](http://www.haskell.org/platform/)。
你可以从优秀的
[Learn you a Haskell](http://learnyouahaskell.com/) 或者
[Real World Haskell](http://book.realworldhaskell.org/)
-找到优雅不少的入门介绍。
+找到更平缓的入门介绍。
diff --git a/zh-cn/java-cn.html.markdown b/zh-cn/java-cn.html.markdown
index f7d319e6..a8fd2a4c 100644
--- a/zh-cn/java-cn.html.markdown
+++ b/zh-cn/java-cn.html.markdown
@@ -124,7 +124,7 @@ public class LearnJava {
// HashMaps
///////////////////////////////////////
- // 操作符
+ // 操作符
///////////////////////////////////////
System.out.println("\n->Operators");
@@ -149,7 +149,7 @@ public class LearnJava {
// 位运算操作符
/*
- ~ 补
+ ~ 取反,求反码
<< 带符号左移
>> 带符号右移
>>> 无符号右移
@@ -161,10 +161,13 @@ public class LearnJava {
// 自增
int i = 0;
System.out.println("\n->Inc/Dec-rementation");
- System.out.println(i++); //i = 1 后自增
- System.out.println(++i); //i = 2 前自增
- System.out.println(i--); //i = 1 后自减
- System.out.println(--i); //i = 0 前自减
+ // ++ 和 -- 操作符使变量加或减1。放在变量前面或者后面的区别是整个表达
+ // 式的返回值。操作符在前面时,先加减,后取值。操作符在后面时,先取值
+ // 后加减。
+ System.out.println(i++); // 后自增 i = 1, 输出0
+ System.out.println(++i); // 前自增 i = 2, 输出2
+ System.out.println(i--); // 后自减 i = 1, 输出2
+ System.out.println(--i); // 前自减 i = 0, 输出0
///////////////////////////////////////
// 控制结构
@@ -192,7 +195,7 @@ public class LearnJava {
}
System.out.println("fooWhile Value: " + fooWhile);
- // Do While循环
+ // Do While循环
int fooDoWhile = 0;
do
{
@@ -402,4 +405,4 @@ class PennyFarthing extends Bicycle {
* [泛型](http://docs.oracle.com/javase/tutorial/java/generics/index.html)
-* [Java代码规范](http://www.oracle.com/technetwork/java/codeconv-138413.html)
+* [Java代码规范](http://www.oracle.com/technetwork/java/codeconvtoc-136057.html)
diff --git a/zh-cn/javascript-cn.html.markdown b/zh-cn/javascript-cn.html.markdown
index 86ad1d07..bdef0099 100644
--- a/zh-cn/javascript-cn.html.markdown
+++ b/zh-cn/javascript-cn.html.markdown
@@ -5,17 +5,19 @@ name: javascript
filename: javascript-zh.js
contributors:
- ["Adam Brenecki", "http://adam.brenecki.id.au"]
+ - ["Ariel Krakowski", "http://www.learneroo.com"]
translators:
- ["Chenbo Li", "http://binarythink.net"]
+ - ["Guodong Qu", "https://github.com/jasonqu"]
lang: zh-cn
---
Javascript于1995年由网景公司的Brendan Eich发明。
最初发明的目的是作为一个简单的网站脚本语言,来作为
-复杂网站应用java的补充。但由于javascript和网站结合度很高
-所以javascript逐渐变得比java在前端更为流行了。
+复杂网站应用java的补充。但由于它与网页结合度很高并且由浏览器内置支持,
+所以javascript变得比java在前端更为流行了。
-JavaScript 不仅仅只可以用于浏览器, 也可用于 Node.js 等后台环境。
+不过 JavaScript 可不仅仅只用于浏览器: Node.js,一个基于Google Chrome V8引擎的独立运行时环境,也越来越流行。
很欢迎来自您的反馈,您可以通过下列方式联系到我:
[@adambrenecki](https://twitter.com/adambrenecki), 或者
@@ -29,145 +31,167 @@ JavaScript 不仅仅只可以用于浏览器, 也可用于 Node.js 等后台环
// 语句可以以分号结束
doStuff();
-// ... 但是分号也可以省略,每当遇到一个新行时,分号会自动插入
+// ... 但是分号也可以省略,每当遇到一个新行时,分号会自动插入(除了一些特殊情况)。
doStuff()
-// 我们在这里会去掉分号,但是否添加最后的分号取决于你个人的习惯
-// 及你所在团队的编程风格
+// 因为这些特殊情况会导致意外的结果,所以我们在这里保留分号。
///////////////////////////////////
// 1. 数字、字符串与操作符
-// Javascript 只有一种数字类型 (即 64位 IEEE 754 双精度浮点).
-3 // = 3
-1.5 // = 1.5
+// Javascript 只有一种数字类型(即 64位 IEEE 754 双精度浮点 double)。
+// double 有 52 位表示尾数,足以精确存储大到 9✕10¹⁵ 的整数。
+3; // = 3
+1.5; // = 1.5
-// 所有基本的算数运算
-1 + 1 // = 2
-8 - 1 // = 7
-10 * 2 // = 20
-35 / 5 // = 7
+// 所有基本的算数运算都如你预期。
+1 + 1; // = 2
+0.1 + 0.2; // = 0.30000000000000004
+8 - 1; // = 7
+10 * 2; // = 20
+35 / 5; // = 7
-// 包括无法整除的除法
-5 / 2 // = 2.5
+// 包括无法整除的除法。
+5 / 2; // = 2.5
-// 位运算也和其他语言一样。当你对浮点数进行位运算时,
-// 浮点数会转换为至多 32 位的无符号整数
-1 << 2 // = 4
+// 位运算也和其他语言一样;当你对浮点数进行位运算时,
+// 浮点数会转换为*至多* 32 位的无符号整数。
+1 << 2; // = 4
-// 括号可以决定优先级
-(1 + 3) * 2 // = 8
+// 括号可以决定优先级。
+(1 + 3) * 2; // = 8
// 有三种非数字的数字类型
-Infinity // 1/0 的结果
--Infinity // -1/0 的结果
-NaN // 0/0 的结果
+Infinity; // 1/0 的结果
+-Infinity; // -1/0 的结果
+NaN; // 0/0 的结果
-// 也有布尔值
-true
-false
+// 也有布尔值。
+true;
+false;
-// 可以通过单引号或双引号来构造字符串
-'abc'
-"Hello, world"
+// 可以通过单引号或双引号来构造字符串。
+'abc';
+"Hello, world";
// 用!来取非
-!true // = false
-!false // = true
+!true; // = false
+!false; // = true
-// 相等 ==
-1 == 1 // = true
-2 == 1 // = false
+// 相等 ===
+1 === 1; // = true
+2 === 1; // = false
// 不等 !=
-1 != 1 // = false
-2 != 1 // = true
+1 !== 1; // = false
+2 !== 1; // = true
// 更多的比较操作符
-1 < 10 // = true
-1 > 10 // = false
-2 <= 2 // = true
-2 >= 2 // = true
+1 < 10; // = true
+1 > 10; // = false
+2 <= 2; // = true
+2 >= 2; // = true
// 字符串用+连接
-"Hello " + "world!" // = "Hello world!"
+"Hello " + "world!"; // = "Hello world!"
// 字符串也可以用 < 、> 来比较
-"a" < "b" // = true
+"a" < "b"; // = true
-// 比较时会进行类型转换...
-"5" == 5 // = true
+// 使用“==”比较时会进行类型转换...
+"5" == 5; // = true
+null == undefined; // = true
// ...除非你是用 ===
-"5" === 5 // = false
+"5" === 5; // = false
+null === undefined; // = false
-// 你可以用charAt来得到字符串中的字符
-"This is a string".charAt(0)
+// ...但会导致奇怪的行为
+13 + !0; // 14
+"13" + !0; // '13true'
-// 还有两个特殊的值:null和undefined
-null // 用来表示刻意设置成的空值
-undefined // 用来表示还没有设置的值
+// 你可以用`charAt`来得到字符串中的字符
+"This is a string".charAt(0); // = 'T'
-// null, undefined, NaN, 0 和 "" 都是假的(false),其他的都视作逻辑真
-// 注意 0 是逻辑假而 "0"是逻辑真, 尽管 0 == "0".
+// ...或使用 `substring` 来获取更大的部分。
+"Hello world".substring(0, 5); // = "Hello"
+
+// `length` 是一个属性,所以不要使用 ().
+"Hello".length; // = 5
+
+// 还有两个特殊的值:`null`和`undefined`
+null; // 用来表示刻意设置的空值
+undefined; // 用来表示还没有设置的值(尽管`undefined`自身实际是一个值)
+
+// false, null, undefined, NaN, 0 和 "" 都是假的;其他的都视作逻辑真
+// 注意 0 是逻辑假而 "0"是逻辑真,尽管 0 == "0"。
///////////////////////////////////
// 2. 变量、数组和对象
-// 变量需要用 var 这个关键字声明. Javascript是动态类型语言
-// 所以你在声明时无需指定类型。 赋值需要用 =
-var someVar = 5
+// 变量需要用`var`关键字声明。Javascript是动态类型语言,
+// 所以你无需指定类型。 赋值需要用 `=`
+var someVar = 5;
-// 如果你在声明时没有加var关键字,你也不会得到错误
-someOtherVar = 10
+// 如果你在声明时没有加var关键字,你也不会得到错误...
+someOtherVar = 10;
-// ...但是此时这个变量就会拥有全局的作用域,而非当前作用域
+// ...但是此时这个变量就会在全局作用域被创建,而非你定义的当前作用域
-// 没有被赋值的变量都会返回undefined这个值
-var someThirdVar // = undefined
+// 没有被赋值的变量都会被设置为undefined
+var someThirdVar; // = undefined
-// 对变量进行数学运算有一些简写法
-someVar += 5 // 等价于 someVar = someVar + 5; someVar 现在是 10
-someVar *= 10 // 现在 someVar 是 100
+// 对变量进行数学运算有一些简写法:
+someVar += 5; // 等价于 someVar = someVar + 5; someVar 现在是 10
+someVar *= 10; // 现在 someVar 是 100
// 自增和自减也有简写
-someVar++ // someVar 是 101
-someVar-- // 回到 100
+someVar++; // someVar 是 101
+someVar--; // 回到 100
// 数组是任意类型组成的有序列表
-var myArray = ["Hello", 45, true]
+var myArray = ["Hello", 45, true];
+
+// 数组的元素可以用方括号下标来访问。
+// 数组的索引从0开始。
+myArray[1]; // = 45
-// 数组的元素可以用方括号下标来访问
-// 数组的索引从0开始
-myArray[1] // = 45
+// 数组是可变的,并拥有变量 length。
+myArray.push("World");
+myArray.length; // = 4
-// javascript中的对象相当于其他语言中的字典或映射:是键-值的集合
-{key1: "Hello", key2: "World"}
+// 在指定下标添加/修改
+myArray[3] = "Hello";
-// 键是字符串,但是引号也并非是必须的,如果键本身是合法的js标识符
-// 而值则可以是任意类型的值
-var myObj = {myKey: "myValue", "my other key": 4}
+// javascript中的对象相当于其他语言中的“字典”或“映射”:是键-值对的无序集合。
+var myObj = {key1: "Hello", key2: "World"};
-// 对象的访问可以通过下标
-myObj["my other key"] // = 4
+// 键是字符串,但如果键本身是合法的js标识符,则引号并非是必须的。
+// 值可以是任意类型。
+var myObj = {myKey: "myValue", "my other key": 4};
+
+// 对象属性的访问可以通过下标
+myObj["my other key"]; // = 4
// ... 或者也可以用 . ,如果属性是合法的标识符
-myObj.myKey // = "myValue"
+myObj.myKey; // = "myValue"
-// 对象是可变的,键和值也可以被更改或增加
-myObj.myThirdKey = true
+// 对象是可变的;值也可以被更改或增加新的键
+myObj.myThirdKey = true;
-// 如果你想要访问一个还没有被定义的属性,那么会返回undefined
-myObj.myFourthKey // = undefined
+// 如果你想要获取一个还没有被定义的值,那么会返回undefined
+myObj.myFourthKey; // = undefined
///////////////////////////////////
// 3. 逻辑与控制结构
-// if语句和其他语言中一样
-var count = 1
+// 本节介绍的语法与Java的语法几乎完全相同
+
+// `if`语句和其他语言中一样。
+var count = 1;
if (count == 3){
// count 是 3 时执行
-} else if (count == 4) {
+} else if (count == 4){
// count 是 4 时执行
} else {
// 其他情况下执行
@@ -179,219 +203,270 @@ while (true) {
}
// Do-while 和 While 循环很像 ,但前者会至少执行一次
-var input
+var input;
do {
- input = getInput()
+ input = getInput();
} while (!isValid(input))
-// for循环和C、Java中的一样
-// 初始化; 继续执行的条件; 遍历后执行.
+// `for`循环和C、Java中的一样:
+// 初始化; 继续执行的条件; 迭代。
for (var i = 0; i < 5; i++){
// 遍历5次
}
// && 是逻辑与, || 是逻辑或
if (house.size == "big" && house.colour == "blue"){
- house.contains = "bear"
+ house.contains = "bear";
}
if (colour == "red" || colour == "blue"){
// colour是red或者blue时执行
}
-// && 和 || 是“短路”语句,在初始化值时会变得有用
-var name = otherName || "default"
+// && 和 || 是“短路”语句,它在设定初始化值时特别有用
+var name = otherName || "default";
+
+// `switch`语句使用`===`检查相等性。
+// 在每一个case结束时使用 'break'
+// 否则其后的case语句也将被执行。
+grade = 'B';
+switch (grade) {
+ case 'A':
+ console.log("Great job");
+ break;
+ case 'B':
+ console.log("OK job");
+ break;
+ case 'C':
+ console.log("You can do better");
+ break;
+ default:
+ console.log("Oy vey");
+ break;
+}
///////////////////////////////////
// 4. 函数、作用域、闭包
-// JavaScript 函数由function关键字定义
+// JavaScript 函数由`function`关键字定义
function myFunction(thing){
- return thing.toUpperCase()
+ return thing.toUpperCase();
}
-myFunction("foo") // = "FOO"
-
-// 函数也可以是匿名的:
-function(thing){
- return thing.toLowerCase()
+myFunction("foo"); // = "FOO"
+
+// 注意被返回的值必须开始于`return`关键字的那一行,
+// 否则由于自动的分号补齐,你将返回`undefined`。
+// 在使用Allman风格的时候要注意.
+function myFunction()
+{
+ return // <- 分号自动插在这里
+ {
+ thisIsAn: 'object literal'
+ }
}
-// (我们无法调用此函数,因为我们不知道这个函数的名字)
+myFunction(); // = undefined
-// javascript中的函数也是对象,所以函数也能够赋给一个变量,并且被传递
-// 比如一个事件处理函数:
+// javascript中函数是一等对象,所以函数也能够赋给一个变量,
+// 并且被作为参数传递 —— 比如一个事件处理函数:
function myFunction(){
- // this code will be called in 5 seconds' time
+ // 这段代码将在5秒钟后被调用
}
-setTimeout(myFunction, 5000)
-
-// 你甚至可以直接把一个函数写到另一个函数的参数中
+setTimeout(myFunction, 5000);
+// 注意:setTimeout不是js语言的一部分,而是由浏览器和Node.js提供的。
-setTimeout(function myFunction(){
- // 5秒之后会执行这里的代码
-}, 5000)
+// 函数对象甚至不需要声明名称 —— 你可以直接把一个函数定义写到另一个函数的参数中
+setTimeout(function(){
+ // 这段代码将在5秒钟后被调用
+}, 5000);
-// JavaScript 仅有函数作用于,而其他的语句则没有作用域
+// JavaScript 有函数作用域;函数有其自己的作用域而其他的代码块则没有。
if (true){
- var i = 5
+ var i = 5;
}
-i // = 5 - 并非我们在其他语言中所得到的undefined
-
-// 这就导致了人们经常用一种叫做“即使执行匿名函数”的模式
-// 这样可以避免一些临时变量扩散到外边去
-function(){
- var temporary = 5
- // 我们可以访问一个全局对象来访问全局作用域
- // 在浏览器中是 'window' 这个对象。
- // 在Node.js中这个对象的名字可能会不同。
- window.permanent = 10
- // 或者,我们也可以把var去掉就行了
- permanent2 = 15
-}()
-temporary // 抛出引用异常
-permanent // = 10
-permanent2 // = 15
-
-// javascript最强大的功能之一就是闭包
-// 如果一个函数在另一个函数中定义,那么这个函数就拥有外部函数的所有访问权
+i; // = 5 - 并非我们在其他语言中所期望得到的undefined
+
+// 这就导致了人们经常使用的“立即执行匿名函数”的模式,
+// 这样可以避免一些临时变量扩散到全局作用域去。
+(function(){
+ var temporary = 5;
+ // 我们可以访问修改全局对象("global object")来访问全局作用域,
+ // 在web浏览器中是`window`这个对象。
+ // 在其他环境如Node.js中这个对象的名字可能会不同。
+ window.permanent = 10;
+})();
+temporary; // 抛出引用异常ReferenceError
+permanent; // = 10
+
+// javascript最强大的功能之一就是闭包。
+// 如果一个函数在另一个函数中定义,那么这个内部函数就拥有外部函数的所有变量的访问权,
+// 即使在外部函数结束之后。
function sayHelloInFiveSeconds(name){
- var prompt = "Hello, " + name + "!"
+ var prompt = "Hello, " + name + "!";
+ // 内部函数默认是放在局部作用域的,
+ // 就像是用`var`声明的。
function inner(){
- alert(prompt)
+ alert(prompt);
}
- setTimeout(inner, 5000)
- // setTimeout 是异步的,所以这个函数会马上终止不会等待。
- // 然而,在5秒结束后,inner函数仍然会弹出prompt信息。
+ setTimeout(inner, 5000);
+ // setTimeout是异步的,所以 sayHelloInFiveSeconds 函数会立即退出,
+ // 而 setTimeout 会在后面调用inner
+ // 然而,由于inner是由sayHelloInFiveSeconds“闭合包含”的,
+ // 所以inner在其最终被调用时仍然能够访问`prompt`变量。
}
-sayHelloInFiveSeconds("Adam") // 会在5秒后弹出 "Hello, Adam!"
+sayHelloInFiveSeconds("Adam"); // 会在5秒后弹出 "Hello, Adam!"
+
///////////////////////////////////
// 5. 对象、构造函数与原型
-// 对象包含方法
+// 对象可以包含方法。
var myObj = {
myFunc: function(){
- return "Hello world!"
+ return "Hello world!";
}
-}
-myObj.myFunc() // = "Hello world!"
+};
+myObj.myFunc(); // = "Hello world!"
-// 当对象中的函数被调用时,这个函数就可以通过this关键字访问这个对象
+// 当对象中的函数被调用时,这个函数可以通过`this`关键字访问其依附的这个对象。
myObj = {
myString: "Hello world!",
myFunc: function(){
- return this.myString
+ return this.myString;
}
-}
-myObj.myFunc() // = "Hello world!"
+};
+myObj.myFunc(); // = "Hello world!"
-// 但这个函数访问的其实是其运行时环境,而非定义时环境
-// 所以如果函数所在的环境不在当前对象的环境中运行时,就运行不成功了
-var myFunc = myObj.myFunc
-myFunc() // = undefined
+// 但这个函数访问的其实是其运行时环境,而非定义时环境,即取决于函数是如何调用的。
+// 所以如果函数被调用时不在这个对象的上下文中,就不会运行成功了。
+var myFunc = myObj.myFunc;
+myFunc(); // = undefined
-// 相应的,一个函数也可以被指定为一个对象的方法,并且用过this可以访问
-// 这个对象的成员,即使在定义时并没有绑定任何值
+// 相应的,一个函数也可以被指定为一个对象的方法,并且可以通过`this`访问
+// 这个对象的成员,即使在函数被定义时并没有依附在对象上。
var myOtherFunc = function(){
- return this.myString.toUpperCase()
+ return this.myString.toUpperCase();
+}
+myObj.myOtherFunc = myOtherFunc;
+myObj.myOtherFunc(); // = "HELLO WORLD!"
+
+// 当我们通过`call`或者`apply`调用函数的时候,也可以为其指定一个执行上下文。
+var anotherFunc = function(s){
+ return this.myString + s;
}
-myObj.myOtherFunc = myOtherFunc
-myObj.myOtherFunc() // = "HELLO WORLD!"
+anotherFunc.call(myObj, " And Hello Moon!"); // = "Hello World! And Hello Moon!"
+
+// `apply`函数几乎完全一样,只是要求一个array来传递参数列表。
+anotherFunc.apply(myObj, [" And Hello Sun!"]); // = "Hello World! And Hello Sun!"
-// 当你通过new关键字调用一个函数时,就会生成一个对象
-// 而对象的成员需要通过this来定义。
-// 这样的函数就叫做构造函数
+// 当一个函数接受一系列参数,而你想传入一个array时特别有用。
+Math.min(42, 6, 27); // = 6
+Math.min([42, 6, 27]); // = NaN (uh-oh!)
+Math.min.apply(Math, [42, 6, 27]); // = 6
+// 但是`call`和`apply`只是临时的。如果我们希望函数附着在对象上,可以使用`bind`。
+var boundFunc = anotherFunc.bind(myObj);
+boundFunc(" And Hello Saturn!"); // = "Hello World! And Hello Saturn!"
+
+// `bind` 也可以用来部分应用一个函数(柯里化)。
+var product = function(a, b){ return a * b; }
+var doubler = product.bind(this, 2);
+doubler(8); // = 16
+
+// 当你通过`new`关键字调用一个函数时,就会创建一个对象,
+// 而且可以通过this关键字访问该函数。
+// 设计为这样调用的函数就叫做构造函数。
var MyConstructor = function(){
- this.myNumber = 5
+ this.myNumber = 5;
}
-myNewObj = new MyConstructor() // = {myNumber: 5}
-myNewObj.myNumber // = 5
+myNewObj = new MyConstructor(); // = {myNumber: 5}
+myNewObj.myNumber; // = 5
-// 每一个js对象都有一个原型,当你要访问一个没有定义过的成员时,
-// 解释器就回去找这个对象的原型
+// 每一个js对象都有一个‘原型’。当你要访问一个实际对象中没有定义的一个属性时,
+// 解释器就回去找这个对象的原型。
-// 有一些JS实现会让你通过一个对象的__proto__方法访问这个原型。
-// 这虽然对理解这个对象很有用,但是这并不是标准的一部分
-// 我们之后会通过标准方式来访问原型。
+// 一些JS实现会让你通过`__proto__`属性访问一个对象的原型。
+// 这虽然对理解原型很有用,但是它并不是标准的一部分;
+// 我们后面会介绍使用原型的标准方式。
var myObj = {
- myString: "Hello world!",
-}
+ myString: "Hello world!"
+};
var myPrototype = {
meaningOfLife: 42,
myFunc: function(){
return this.myString.toLowerCase()
}
-}
-myObj.__proto__ = myPrototype
-myObj.meaningOfLife // = 42
+};
+
+myObj.__proto__ = myPrototype;
+myObj.meaningOfLife; // = 42
-// This works for functions, too.
+// 函数也可以工作。
myObj.myFunc() // = "hello world!"
-// 当然,如果你要访问的成员在原型当中也没有定义的话,解释器就会去找原型的原型。
+// 当然,如果你要访问的成员在原型当中也没有定义的话,解释器就会去找原型的原型,以此类推。
myPrototype.__proto__ = {
myBoolean: true
-}
-myObj.myBoolean // = true
-
-// 这其中并没有对象的拷贝。每个对象的原型实际上是持有原型对象的引用
-// 这说明当我们改变对象的原型时,会影响到其他以这个原型为原型的对象
-myPrototype.meaningOfLife = 43
-myObj.meaningOfLife // = 43
-
-// 我们知道 __proto__ 并非标准规定,实际上也没有办法更改已经指定好的原型。
-// 但是,我们有两种方式可以为新的对象指定原型。
-
-// 第一种方式是 Object.create,这个方法是在最近才被添加到Js中的
-// 也因此并不是所有的JS实现都有这个放啊
-var myObj = Object.create(myPrototype)
-myObj.meaningOfLife // = 43
-
-// 第二种方式可以在任意版本中使用,不过需要通过构造函数。
-// 构造函数有一个属性prototype。但是这 *不是* 构造函数本身的函数
-// 而是通过构造函数和new关键字生成新对象时自动生成的。
-myConstructor.prototype = {
+};
+myObj.myBoolean; // = true
+
+// 这其中并没有对象的拷贝;每个对象实际上是持有原型对象的引用。
+// 这意味着当我们改变对象的原型时,会影响到其他以这个原型为原型的对象。
+myPrototype.meaningOfLife = 43;
+myObj.meaningOfLife; // = 43
+
+// 我们知道 `__proto__` 并非标准规定,实际上也没有标准办法来修改一个已存在对象的原型。
+// 然而,我们有两种方式为指定原型创建一个新的对象。
+
+// 第一种方式是 Object.create,这个方法是在最近才被添加到Js中的,
+// 因此并不是所有的JS实现都有这个方法
+var myObj = Object.create(myPrototype);
+myObj.meaningOfLife; // = 43
+
+// 第二种方式可以在任意版本中使用,不过必须通过构造函数。
+// 构造函数有一个属性prototype。但是它 *不是* 构造函数本身的原型;相反,
+// 是通过构造函数和new关键字创建的新对象的原型。
+MyConstructor.prototype = {
+ myNumber: 5,
getMyNumber: function(){
- return this.myNumber
+ return this.myNumber;
}
-}
-var myNewObj2 = new myConstructor()
-myNewObj2.getMyNumber() // = 5
+};
+var myNewObj2 = new MyConstructor();
+myNewObj2.getMyNumber(); // = 5
+myNewObj2.myNumber = 6
+myNewObj2.getMyNumber(); // = 6
// 字符串和数字等内置类型也有通过构造函数来创建的包装类型
-var myNumber = 12
-var myNumberObj = new Number(12)
-myNumber == myNumberObj // = true
+var myNumber = 12;
+var myNumberObj = new Number(12);
+myNumber == myNumberObj; // = true
// 但是它们并非严格等价
-typeof(myNumber) // = 'number'
-typeof(myNumberObj) // = 'object'
-myNumber === myNumberObj // = false
+typeof myNumber; // = 'number'
+typeof myNumberObj; // = 'object'
+myNumber === myNumberObj; // = false
if (0){
// 这段代码不会执行,因为0代表假
}
-if (Number(0)){
- // 这段代码会执行,因为Number(0)代表真
-}
-// 但是,包装类型和内置类型共享一个原型
-// 这样你就可以给内置类型也增加一些功能
+// 不过,包装类型和内置类型共享一个原型,
+// 所以你实际可以给内置类型也增加一些功能,例如对string:
String.prototype.firstCharacter = function(){
- return this.charAt(0)
+ return this.charAt(0);
}
-"abc".firstCharacter() // = "a"
+"abc".firstCharacter(); // = "a"
-// 这个技巧可以用来用老版本的javascript子集来是实现新版本js的功能
+// 这个技巧经常用在“代码填充”中,来为老版本的javascript子集增加新版本js的特性,
// 这样就可以在老的浏览器中使用新功能了。
-// 比如,我们知道Object.create并没有在所有的版本中都实现
-// 但是我们仍然可以通过这个技巧来使用
+// 比如,我们知道Object.create并没有在所有的版本中都实现,
+// 但是我们仍然可以通过“代码填充”来实现兼容:
if (Object.create === undefined){ // 如果存在则不覆盖
Object.create = function(proto){
// 用正确的原型来创建一个临时构造函数
- var Constructor = function(){}
- Constructor.prototype = proto
+ var Constructor = function(){};
+ Constructor.prototype = proto;
// 之后用它来创建一个新的对象
- return new Constructor()
+ return new Constructor();
}
}
```
@@ -399,19 +474,23 @@ if (Object.create === undefined){ // 如果存在则不覆盖
## 更多阅读
[Mozilla 开发者
-网络](https://developer.mozilla.org/en-US/docs/Web/JavaScript) 提供了很好的
-Javascript文档,并且由于是wiki,所以你也可以自行编辑来分享你的知识。
+网络](https://developer.mozilla.org/en-US/docs/Web/JavaScript) 提供了优秀的介绍
+Javascript如何在浏览器中使用的文档。而且它是wiki,所以你也可以自行编辑来分享你的知识。
MDN的 [A re-introduction to
JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript)
-覆盖了这里提到的绝大多数话题,大多数只是Javascript这个语言本身。
+覆盖了这里提到的绝大多数话题的细节。该导引的大多数内容被限定在只是Javascript这个语言本身;
如果你想了解Javascript是如何在网页中被应用的,那么可以查看
[Document Object
Model](https://developer.mozilla.org/en-US/docs/Using_the_W3C_DOM_Level_1_Core)
+[Learn Javascript by Example and with Challenges](http://www.learneroo.com/modules/64/nodes/350) 是本参考的另一个版本,并包含了挑战习题。
+
[Javascript Garden](http://bonsaiden.github.io/JavaScript-Garden/) 是一个深入
-讲解所有Javascript反直觉部分的一本书
+讲解所有Javascript反直觉部分的导引。
+
+[JavaScript: The Definitive Guide](http://www.amazon.com/gp/product/0596805527/) 是一个经典的指导参考书。
除了这篇文章的直接贡献者之外,这篇文章也参考了这个网站上
Louie Dinh 的 Python 教程,以及 Mozilla开发者网络上的[JS
-Tutorial](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript)
+Tutorial](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript)。
diff --git a/zh-cn/julia-cn.html.markdown b/zh-cn/julia-cn.html.markdown
new file mode 100644
index 00000000..1f91d52c
--- /dev/null
+++ b/zh-cn/julia-cn.html.markdown
@@ -0,0 +1,729 @@
+---
+language: Julia
+filename: learn-julia-zh.jl
+contributors:
+ - ["Jichao Ouyang", "http://oyanglul.us"]
+translators:
+ - ["Jichao Ouyang", "http://oyanglul.us"]
+lang: zh-cn
+---
+
+```ruby
+# 单行注释只需要一个井号
+#= 多行注释
+ 只需要以 '#=' 开始 '=#' 结束
+ 还可以嵌套.
+=#
+
+####################################################
+## 1. 原始类型与操作符
+####################################################
+
+# Julia 中一切皆是表达式。
+
+# 这是一些基本数字类型.
+3 # => 3 (Int64)
+3.2 # => 3.2 (Float64)
+2 + 1im # => 2 + 1im (Complex{Int64})
+2//3 # => 2//3 (Rational{Int64})
+
+# 支持所有的普通中缀操作符。
+1 + 1 # => 2
+8 - 1 # => 7
+10 * 2 # => 20
+35 / 5 # => 7.0
+5 / 2 # => 2.5 # 用 Int 除 Int 永远返回 Float
+div(5, 2) # => 2 # 使用 div 截断小数点
+5 \ 35 # => 7.0
+2 ^ 2 # => 4 # 次方, 不是二进制 xor
+12 % 10 # => 2
+
+# 用括号提高优先级
+(1 + 3) * 2 # => 8
+
+# 二进制操作符
+~2 # => -3 # 非
+3 & 5 # => 1 # 与
+2 | 4 # => 6 # 或
+2 $ 4 # => 6 # 异或
+2 >>> 1 # => 1 # 逻辑右移
+2 >> 1 # => 1 # 算术右移
+2 << 1 # => 4 # 逻辑/算术 右移
+
+# 可以用函数 bits 查看二进制数。
+bits(12345)
+# => "0000000000000000000000000000000000000000000000000011000000111001"
+bits(12345.0)
+# => "0100000011001000000111001000000000000000000000000000000000000000"
+
+# 布尔值是原始类型
+true
+false
+
+# 布尔操作符
+!true # => false
+!false # => true
+1 == 1 # => true
+2 == 1 # => false
+1 != 1 # => false
+2 != 1 # => true
+1 < 10 # => true
+1 > 10 # => false
+2 <= 2 # => true
+2 >= 2 # => true
+# 比较可以串联
+1 < 2 < 3 # => true
+2 < 3 < 2 # => false
+
+# 字符串可以由 " 创建
+"This is a string."
+
+# 字符字面量可用 ' 创建
+'a'
+
+# 可以像取数组取值一样用 index 取出对应字符
+"This is a string"[1] # => 'T' # Julia 的 index 从 1 开始 :(
+# 但是对 UTF-8 无效,
+# 因此建议使用遍历器 (map, for loops, 等).
+
+# $ 可用于字符插值:
+"2 + 2 = $(2 + 2)" # => "2 + 2 = 4"
+# 可以将任何 Julia 表达式放入括号。
+
+# 另一种格式化字符串的方式是 printf 宏.
+@printf "%d is less than %f" 4.5 5.3 # 5 is less than 5.300000
+
+# 打印字符串很容易
+println("I'm Julia. Nice to meet you!")
+
+####################################################
+## 2. 变量与集合
+####################################################
+
+# 给变量赋值就是声明变量
+some_var = 5 # => 5
+some_var # => 5
+
+# 访问未声明变量会抛出异常
+try
+ some_other_var # => ERROR: some_other_var not defined
+catch e
+ println(e)
+end
+
+# 变量名需要以字母开头.
+# 之后任何字母,数字,下划线,叹号都是合法的。
+SomeOtherVar123! = 6 # => 6
+
+# 甚至可以用 unicode 字符
+☃ = 8 # => 8
+# 用数学符号非常方便
+2 * π # => 6.283185307179586
+
+# 注意 Julia 的命名规约:
+#
+# * 变量名为小写,单词之间以下划线连接('\_')。
+#
+# * 类型名以大写字母开头,单词以 CamelCase 方式连接。
+#
+# * 函数与宏的名字小写,无下划线。
+#
+# * 会改变输入的函数名末位为 !。
+# 这类函数有时被称为 mutating functions 或 in-place functions.
+
+# 数组存储一列值,index 从 1 开始。
+a = Int64[] # => 0-element Int64 Array
+
+# 一维数组可以以逗号分隔值的方式声明。
+b = [4, 5, 6] # => 包含 3 个 Int64 类型元素的数组: [4, 5, 6]
+b[1] # => 4
+b[end] # => 6
+
+# 二维数组以分号分隔维度。
+matrix = [1 2; 3 4] # => 2x2 Int64 数组: [1 2; 3 4]
+
+# 使用 push! 和 append! 往数组末尾添加元素
+push!(a,1) # => [1]
+push!(a,2) # => [1,2]
+push!(a,4) # => [1,2,4]
+push!(a,3) # => [1,2,4,3]
+append!(a,b) # => [1,2,4,3,4,5,6]
+
+# 用 pop 弹出末尾元素
+pop!(b) # => 6 and b is now [4,5]
+
+# 可以再放回去
+push!(b,6) # b 又变成了 [4,5,6].
+
+a[1] # => 1 # 永远记住 Julia 的 index 从 1 开始!
+
+# 用 end 可以直接取到最后索引. 可用作任何索引表达式
+a[end] # => 6
+
+# 还支持 shift 和 unshift
+shift!(a) # => 返回 1,而 a 现在时 [2,4,3,4,5,6]
+unshift!(a,7) # => [7,2,4,3,4,5,6]
+
+# 以叹号结尾的函数名表示它会改变参数的值
+arr = [5,4,6] # => 包含三个 Int64 元素的数组: [5,4,6]
+sort(arr) # => [4,5,6]; arr 还是 [5,4,6]
+sort!(arr) # => [4,5,6]; arr 现在是 [4,5,6]
+
+# 越界会抛出 BoundsError 异常
+try
+ a[0] # => ERROR: BoundsError() in getindex at array.jl:270
+ a[end+1] # => ERROR: BoundsError() in getindex at array.jl:270
+catch e
+ println(e)
+end
+
+# 错误会指出发生的行号,包括标准库
+# 如果你有 Julia 源代码,你可以找到这些地方
+
+# 可以用 range 初始化数组
+a = [1:5] # => 5-element Int64 Array: [1,2,3,4,5]
+
+# 可以切割数组
+a[1:3] # => [1, 2, 3]
+a[2:end] # => [2, 3, 4, 5]
+
+# 用 splice! 切割原数组
+arr = [3,4,5]
+splice!(arr,2) # => 4 ; arr 变成了 [3,5]
+
+# 用 append! 连接数组
+b = [1,2,3]
+append!(a,b) # a 变成了 [1, 2, 3, 4, 5, 1, 2, 3]
+
+# 检查元素是否在数组中
+in(1, a) # => true
+
+# 用 length 获得数组长度
+length(a) # => 8
+
+# Tuples 是 immutable 的
+tup = (1, 2, 3) # => (1,2,3) # an (Int64,Int64,Int64) tuple.
+tup[1] # => 1
+try:
+ tup[1] = 3 # => ERROR: no method setindex!((Int64,Int64,Int64),Int64,Int64)
+catch e
+ println(e)
+end
+
+# 大多数组的函数同样支持 tuples
+length(tup) # => 3
+tup[1:2] # => (1,2)
+in(2, tup) # => true
+
+# 可以将 tuples 元素分别赋给变量
+a, b, c = (1, 2, 3) # => (1,2,3) # a is now 1, b is now 2 and c is now 3
+
+# 不用括号也可以
+d, e, f = 4, 5, 6 # => (4,5,6)
+
+# 单元素 tuple 不等于其元素值
+(1,) == 1 # => false
+(1) == 1 # => true
+
+# 交换值
+e, d = d, e # => (5,4) # d is now 5 and e is now 4
+
+
+# 字典Dictionaries store mappings
+empty_dict = Dict() # => Dict{Any,Any}()
+
+# 也可以用字面量创建字典
+filled_dict = ["one"=> 1, "two"=> 2, "three"=> 3]
+# => Dict{ASCIIString,Int64}
+
+# 用 [] 获得键值
+filled_dict["one"] # => 1
+
+# 获得所有键
+keys(filled_dict)
+# => KeyIterator{Dict{ASCIIString,Int64}}(["three"=>3,"one"=>1,"two"=>2])
+# 注意,键的顺序不是插入时的顺序
+
+# 获得所有值
+values(filled_dict)
+# => ValueIterator{Dict{ASCIIString,Int64}}(["three"=>3,"one"=>1,"two"=>2])
+# 注意,值的顺序也一样
+
+# 用 in 检查键值是否已存在,用 haskey 检查键是否存在
+in(("one", 1), filled_dict) # => true
+in(("two", 3), filled_dict) # => false
+haskey(filled_dict, "one") # => true
+haskey(filled_dict, 1) # => false
+
+# 获取不存在的键的值会抛出异常
+try
+ filled_dict["four"] # => ERROR: key not found: four in getindex at dict.jl:489
+catch e
+ println(e)
+end
+
+# 使用 get 可以提供默认值来避免异常
+# get(dictionary,key,default_value)
+get(filled_dict,"one",4) # => 1
+get(filled_dict,"four",4) # => 4
+
+# 用 Sets 表示无序不可重复的值的集合
+empty_set = Set() # => Set{Any}()
+# 初始化一个 Set 并定义其值
+filled_set = Set(1,2,2,3,4) # => Set{Int64}(1,2,3,4)
+
+# 添加值
+push!(filled_set,5) # => Set{Int64}(5,4,2,3,1)
+
+# 检查是否存在某值
+in(2, filled_set) # => true
+in(10, filled_set) # => false
+
+# 交集,并集,差集
+other_set = Set(3, 4, 5, 6) # => Set{Int64}(6,4,5,3)
+intersect(filled_set, other_set) # => Set{Int64}(3,4,5)
+union(filled_set, other_set) # => Set{Int64}(1,2,3,4,5,6)
+setdiff(Set(1,2,3,4),Set(2,3,5)) # => Set{Int64}(1,4)
+
+
+####################################################
+## 3. 控制流
+####################################################
+
+# 声明一个变量
+some_var = 5
+
+# 这是一个 if 语句,缩进不是必要的
+if some_var > 10
+ println("some_var is totally bigger than 10.")
+elseif some_var < 10 # elseif 是可选的.
+ println("some_var is smaller than 10.")
+else # else 也是可选的.
+ println("some_var is indeed 10.")
+end
+# => prints "some var is smaller than 10"
+
+
+# For 循环遍历
+# Iterable 类型包括 Range, Array, Set, Dict, 以及 String.
+for animal=["dog", "cat", "mouse"]
+ println("$animal is a mammal")
+ # 可用 $ 将 variables 或 expression 转换为字符串into strings
+end
+# prints:
+# dog is a mammal
+# cat is a mammal
+# mouse is a mammal
+
+# You can use 'in' instead of '='.
+for animal in ["dog", "cat", "mouse"]
+ println("$animal is a mammal")
+end
+# prints:
+# dog is a mammal
+# cat is a mammal
+# mouse is a mammal
+
+for a in ["dog"=>"mammal","cat"=>"mammal","mouse"=>"mammal"]
+ println("$(a[1]) is a $(a[2])")
+end
+# prints:
+# dog is a mammal
+# cat is a mammal
+# mouse is a mammal
+
+for (k,v) in ["dog"=>"mammal","cat"=>"mammal","mouse"=>"mammal"]
+ println("$k is a $v")
+end
+# prints:
+# dog is a mammal
+# cat is a mammal
+# mouse is a mammal
+
+# While 循环
+x = 0
+while x < 4
+ println(x)
+ x += 1 # x = x + 1
+end
+# prints:
+# 0
+# 1
+# 2
+# 3
+
+# 用 try/catch 处理异常
+try
+ error("help")
+catch e
+ println("caught it $e")
+end
+# => caught it ErrorException("help")
+
+
+####################################################
+## 4. 函数
+####################################################
+
+# 用关键字 'function' 可创建一个新函数
+#function name(arglist)
+# body...
+#end
+function add(x, y)
+ println("x is $x and y is $y")
+
+ # 最后一行语句的值为返回
+ x + y
+end
+
+add(5, 6) # => 在 "x is 5 and y is 6" 后会打印 11
+
+# 还可以定义接收可变长参数的函数
+function varargs(args...)
+ return args
+ # 关键字 return 可在函数内部任何地方返回
+end
+# => varargs (generic function with 1 method)
+
+varargs(1,2,3) # => (1,2,3)
+
+# 省略号 ... 被称为 splat.
+# 刚刚用在了函数定义中
+# 还可以用在函数的调用
+# Array 或者 Tuple 的内容会变成参数列表
+Set([1,2,3]) # => Set{Array{Int64,1}}([1,2,3]) # 获得一个 Array 的 Set
+Set([1,2,3]...) # => Set{Int64}(1,2,3) # 相当于 Set(1,2,3)
+
+x = (1,2,3) # => (1,2,3)
+Set(x) # => Set{(Int64,Int64,Int64)}((1,2,3)) # 一个 Tuple 的 Set
+Set(x...) # => Set{Int64}(2,3,1)
+
+
+# 可定义可选参数的函数
+function defaults(a,b,x=5,y=6)
+ return "$a $b and $x $y"
+end
+
+defaults('h','g') # => "h g and 5 6"
+defaults('h','g','j') # => "h g and j 6"
+defaults('h','g','j','k') # => "h g and j k"
+try
+ defaults('h') # => ERROR: no method defaults(Char,)
+ defaults() # => ERROR: no methods defaults()
+catch e
+ println(e)
+end
+
+# 还可以定义键值对的参数
+function keyword_args(;k1=4,name2="hello") # note the ;
+ return ["k1"=>k1,"name2"=>name2]
+end
+
+keyword_args(name2="ness") # => ["name2"=>"ness","k1"=>4]
+keyword_args(k1="mine") # => ["k1"=>"mine","name2"=>"hello"]
+keyword_args() # => ["name2"=>"hello","k1"=>4]
+
+# 可以组合各种类型的参数在同一个函数的参数列表中
+function all_the_args(normal_arg, optional_positional_arg=2; keyword_arg="foo")
+ println("normal arg: $normal_arg")
+ println("optional arg: $optional_positional_arg")
+ println("keyword arg: $keyword_arg")
+end
+
+all_the_args(1, 3, keyword_arg=4)
+# prints:
+# normal arg: 1
+# optional arg: 3
+# keyword arg: 4
+
+# Julia 有一等函数
+function create_adder(x)
+ adder = function (y)
+ return x + y
+ end
+ return adder
+end
+
+# 这是用 "stabby lambda syntax" 创建的匿名函数
+(x -> x > 2)(3) # => true
+
+# 这个函数和上面的 create_adder 一模一样
+function create_adder(x)
+ y -> x + y
+end
+
+# 你也可以给内部函数起个名字
+function create_adder(x)
+ function adder(y)
+ x + y
+ end
+ adder
+end
+
+add_10 = create_adder(10)
+add_10(3) # => 13
+
+
+# 内置的高阶函数有
+map(add_10, [1,2,3]) # => [11, 12, 13]
+filter(x -> x > 5, [3, 4, 5, 6, 7]) # => [6, 7]
+
+# 还可以使用 list comprehensions 替代 map
+[add_10(i) for i=[1, 2, 3]] # => [11, 12, 13]
+[add_10(i) for i in [1, 2, 3]] # => [11, 12, 13]
+
+####################################################
+## 5. 类型
+####################################################
+
+# Julia 有类型系统
+# 所有的值都有类型;但变量本身没有类型
+# 你可以用 `typeof` 函数获得值的类型
+typeof(5) # => Int64
+
+# 类型是一等值
+typeof(Int64) # => DataType
+typeof(DataType) # => DataType
+# DataType 是代表类型的类型,也代表他自己的类型
+
+# 类型可用作文档化,优化,以及调度
+# 并不是静态检查类型
+
+# 用户还可以自定义类型
+# 跟其他语言的 records 或 structs 一样
+# 用 `type` 关键字定义新的类型
+
+# type Name
+# field::OptionalType
+# ...
+# end
+type Tiger
+ taillength::Float64
+ coatcolor # 不附带类型标注的相当于 `::Any`
+end
+
+# 构造函数参数是类型的属性
+tigger = Tiger(3.5,"orange") # => Tiger(3.5,"orange")
+
+# 用新类型作为构造函数还会创建一个类型
+sherekhan = typeof(tigger)(5.6,"fire") # => Tiger(5.6,"fire")
+
+# struct 类似的类型被称为具体类型
+# 他们可被实例化但不能有子类型
+# 另一种类型是抽象类型
+
+# abstract Name
+abstract Cat # just a name and point in the type hierarchy
+
+# 抽象类型不能被实例化,但是可以有子类型
+# 例如,Number 就是抽象类型
+subtypes(Number) # => 6-element Array{Any,1}:
+ # Complex{Float16}
+ # Complex{Float32}
+ # Complex{Float64}
+ # Complex{T<:Real}
+ # ImaginaryUnit
+ # Real
+subtypes(Cat) # => 0-element Array{Any,1}
+
+# 所有的类型都有父类型; 可以用函数 `super` 得到父类型.
+typeof(5) # => Int64
+super(Int64) # => Signed
+super(Signed) # => Real
+super(Real) # => Number
+super(Number) # => Any
+super(super(Signed)) # => Number
+super(Any) # => Any
+# 所有这些类型,除了 Int64, 都是抽象类型.
+
+# <: 是类型集成操作符
+type Lion <: Cat # Lion 是 Cat 的子类型
+ mane_color
+ roar::String
+end
+
+# 可以继续为你的类型定义构造函数
+# 只需要定义一个同名的函数
+# 并调用已有的构造函数设置一个固定参数
+Lion(roar::String) = Lion("green",roar)
+# 这是一个外部构造函数,因为他再类型定义之外
+
+type Panther <: Cat # Panther 也是 Cat 的子类型
+ eye_color
+ Panther() = new("green")
+ # Panthers 只有这个构造函数,没有默认构造函数
+end
+# 使用内置构造函数,如 Panther,可以让你控制
+# 如何构造类型的值
+# 应该尽可能使用外部构造函数而不是内部构造函数
+
+####################################################
+## 6. 多分派
+####################################################
+
+# 在Julia中, 所有的具名函数都是类属函数
+# 这意味着他们都是有很大小方法组成的
+# 每个 Lion 的构造函数都是类属函数 Lion 的方法
+
+# 我们来看一个非构造函数的例子
+
+# Lion, Panther, Tiger 的 meow 定义为
+function meow(animal::Lion)
+ animal.roar # 使用点符号访问属性
+end
+
+function meow(animal::Panther)
+ "grrr"
+end
+
+function meow(animal::Tiger)
+ "rawwwr"
+end
+
+# 试试 meow 函数
+meow(tigger) # => "rawwr"
+meow(Lion("brown","ROAAR")) # => "ROAAR"
+meow(Panther()) # => "grrr"
+
+# 再看看层次结构
+issubtype(Tiger,Cat) # => false
+issubtype(Lion,Cat) # => true
+issubtype(Panther,Cat) # => true
+
+# 定义一个接收 Cats 的函数
+function pet_cat(cat::Cat)
+ println("The cat says $(meow(cat))")
+end
+
+pet_cat(Lion("42")) # => prints "The cat says 42"
+try
+ pet_cat(tigger) # => ERROR: no method pet_cat(Tiger,)
+catch e
+ println(e)
+end
+
+# 在面向对象语言中,通常都是单分派
+# 这意味着分派方法是通过第一个参数的类型决定的
+# 在Julia中, 所有参数类型都会被考虑到
+
+# 让我们定义有多个参数的函数,好看看区别
+function fight(t::Tiger,c::Cat)
+ println("The $(t.coatcolor) tiger wins!")
+end
+# => fight (generic function with 1 method)
+
+fight(tigger,Panther()) # => prints The orange tiger wins!
+fight(tigger,Lion("ROAR")) # => prints The orange tiger wins!
+
+# 让我们修改一下传入具体为 Lion 类型时的行为
+fight(t::Tiger,l::Lion) = println("The $(l.mane_color)-maned lion wins!")
+# => fight (generic function with 2 methods)
+
+fight(tigger,Panther()) # => prints The orange tiger wins!
+fight(tigger,Lion("ROAR")) # => prints The green-maned lion wins!
+
+# 把 Tiger 去掉
+fight(l::Lion,c::Cat) = println("The victorious cat says $(meow(c))")
+# => fight (generic function with 3 methods)
+
+fight(Lion("balooga!"),Panther()) # => prints The victorious cat says grrr
+try
+ fight(Panther(),Lion("RAWR")) # => ERROR: no method fight(Panther,Lion)
+catch
+end
+
+# 在试试让 Cat 在前面
+fight(c::Cat,l::Lion) = println("The cat beats the Lion")
+# => Warning: New definition
+# fight(Cat,Lion) at none:1
+# is ambiguous with
+# fight(Lion,Cat) at none:2.
+# Make sure
+# fight(Lion,Lion)
+# is defined first.
+#fight (generic function with 4 methods)
+
+# 警告说明了无法判断使用哪个 fight 方法
+fight(Lion("RAR"),Lion("brown","rarrr")) # => prints The victorious cat says rarrr
+# 结果在老版本 Julia 中可能会不一样
+
+fight(l::Lion,l2::Lion) = println("The lions come to a tie")
+fight(Lion("RAR"),Lion("brown","rarrr")) # => prints The lions come to a tie
+
+
+# Under the hood
+# 你还可以看看 llvm 以及生成的汇编代码
+
+square_area(l) = l * l # square_area (generic function with 1 method)
+
+square_area(5) #25
+
+# 给 square_area 一个整形时发生什么
+code_native(square_area, (Int32,))
+ # .section __TEXT,__text,regular,pure_instructions
+ # Filename: none
+ # Source line: 1 # Prologue
+ # push RBP
+ # mov RBP, RSP
+ # Source line: 1
+ # movsxd RAX, EDI # Fetch l from memory?
+ # imul RAX, RAX # Square l and store the result in RAX
+ # pop RBP # Restore old base pointer
+ # ret # Result will still be in RAX
+
+code_native(square_area, (Float32,))
+ # .section __TEXT,__text,regular,pure_instructions
+ # Filename: none
+ # Source line: 1
+ # push RBP
+ # mov RBP, RSP
+ # Source line: 1
+ # vmulss XMM0, XMM0, XMM0 # Scalar single precision multiply (AVX)
+ # pop RBP
+ # ret
+
+code_native(square_area, (Float64,))
+ # .section __TEXT,__text,regular,pure_instructions
+ # Filename: none
+ # Source line: 1
+ # push RBP
+ # mov RBP, RSP
+ # Source line: 1
+ # vmulsd XMM0, XMM0, XMM0 # Scalar double precision multiply (AVX)
+ # pop RBP
+ # ret
+ #
+# 注意 只要参数中又浮点类型,Julia 就使用浮点指令
+# 让我们计算一下圆的面积
+circle_area(r) = pi * r * r # circle_area (generic function with 1 method)
+circle_area(5) # 78.53981633974483
+
+code_native(circle_area, (Int32,))
+ # .section __TEXT,__text,regular,pure_instructions
+ # Filename: none
+ # Source line: 1
+ # push RBP
+ # mov RBP, RSP
+ # Source line: 1
+ # vcvtsi2sd XMM0, XMM0, EDI # Load integer (r) from memory
+ # movabs RAX, 4593140240 # Load pi
+ # vmulsd XMM1, XMM0, QWORD PTR [RAX] # pi * r
+ # vmulsd XMM0, XMM0, XMM1 # (pi * r) * r
+ # pop RBP
+ # ret
+ #
+
+code_native(circle_area, (Float64,))
+ # .section __TEXT,__text,regular,pure_instructions
+ # Filename: none
+ # Source line: 1
+ # push RBP
+ # mov RBP, RSP
+ # movabs RAX, 4593140496
+ # Source line: 1
+ # vmulsd XMM1, XMM0, QWORD PTR [RAX]
+ # vmulsd XMM0, XMM1, XMM0
+ # pop RBP
+ # ret
+ #
+```
diff --git a/zh-cn/livescript-cn.html.markdown b/zh-cn/livescript-cn.html.markdown
new file mode 100644
index 00000000..fea00bc1
--- /dev/null
+++ b/zh-cn/livescript-cn.html.markdown
@@ -0,0 +1,322 @@
+---
+language: LiveScript
+filename: learnLivescript.ls
+contributors:
+ - ["Christina Whyte", "http://github.com/kurisuwhyte/"]
+translators:
+ - ["ShengDa Lyu", "http://github.com/SDLyu/"]
+lang: zh-cn
+---
+
+LiveScript 是一种具有函数式特性且编译成 JavaScript 的语言,能对应 JavaScript 的基本语法。
+还有些额外的特性如:柯里化,组合函数,模式匹配,还有借镜于 Haskell,F# 和 Scala 的许多特点。
+
+LiveScript 诞生于 [Coco][],而 Coco 诞生于 [CoffeeScript][]。
+LiveScript 目前已释出稳定版本,开发中的新版本将会加入更多特性。
+
+[Coco]: http://satyr.github.io/coco/
+[CoffeeScript]: http://coffeescript.org/
+
+非常期待您的反馈,你可以通过
+[@kurisuwhyte](https://twitter.com/kurisuwhyte) 与我连系 :)
+
+
+```coffeescript
+# 与 CoffeeScript 一样,LiveScript 使用 # 单行注解。
+
+/*
+ 多行注解与 C 相同。使用注解可以避免被当成 JavaScript 输出。
+*/
+```
+```coffeescript
+# 语法的部份,LiveScript 使用缩进取代 {} 来定义区块,
+# 使用空白取代 () 来执行函数。
+
+
+########################################################################
+## 1. 值类型
+########################################################################
+
+# `void` 取代 `undefined` 表示未定义的值
+void # 与 `undefined` 等价但更安全(不会被覆写)
+
+# 空值则表示成 Null。
+null
+
+
+# 最基本的值类型数据是罗辑类型:
+true
+false
+
+# 罗辑类型的一些别名,等价于前者:
+on; off
+yes; no
+
+
+# 数字与 JS 一样,使用倍精度浮点数表示。
+10
+0.4 # 开头的 0 是必要的
+
+
+# 可以使用底线及单位后缀提高可读性,编译器会自动略过底线及单位后缀。
+12_344km
+
+
+# 字串与 JS 一样,是一种不可变的字元序列:
+"Christina" # 单引号也可以!
+"""Multi-line
+ strings
+ are
+ okay
+ too."""
+
+# 在前面加上 \ 符号也可以表示字串:
+\keyword # => 'keyword'
+
+
+# 数组是值的有序集合。
+fruits =
+ * \apple
+ * \orange
+ * \pear
+
+# 可以用 [] 简洁地表示数组:
+fruits = [ \apple, \orange, \pear ]
+
+
+# 你可以更方便地建立字串数组,并使用空白区隔元素。
+fruits = <[ apple orange pear ]>
+
+# 以 0 为起始值的数组下标获取元素:
+fruits[0] # => "apple"
+
+
+# 对象是无序键值对集合(更多给节将在下面章节讨论)。
+person =
+ name: "Christina"
+ likes:
+ * "kittens"
+ * "and other cute stuff"
+
+# 你也可以用更简洁的方式表示对象:
+person = {name: "Christina", likes: ["kittens", "and other cute stuff"]}
+
+# 可以通过键值获取值:
+person.name # => "Christina"
+person["name"] # => "Christina"
+
+
+# 正则表达式的使用跟 JavaScript 一样:
+trailing-space = /\s$/ # dashed-words 变成 dashedWords
+
+# 你也可以用多行描述表达式!(注解和空白会被忽略)
+funRE = //
+ function\s+(.+) # name
+ \s* \((.*)\) \s* # arguments
+ { (.*) } # body
+ //
+
+
+########################################################################
+## 2. 基本运算
+########################################################################
+
+# 数值操作符与 JavaScript 一样:
+1 + 2 # => 3
+2 - 1 # => 1
+2 * 3 # => 6
+4 / 2 # => 2
+3 % 2 # => 1
+
+
+# 比较操作符大部份也一样,除了 `==` 等价于 JS 中的 `===`,
+# JS 中的 `==` 在 LiveScript 里等价于 `~=`,
+# `===` 能进行对象、数组和严格比较。
+2 == 2 # => true
+2 == "2" # => false
+2 ~= "2" # => true
+2 === "2" # => false
+
+[1,2,3] == [1,2,3] # => false
+[1,2,3] === [1,2,3] # => true
+
++0 == -0 # => true
++0 === -0 # => false
+
+# 其它关系操作符包括 <、<=、> 和 >=
+
+# 罗辑值可以通过 `or`、`and` 和 `not` 结合:
+true and false # => false
+false or true # => true
+not false # => true
+
+
+# 集合也有一些便利的操作符
+[1, 2] ++ [3, 4] # => [1, 2, 3, 4]
+'a' in <[ a b c ]> # => true
+'name' of { name: 'Chris' } # => true
+
+
+########################################################################
+## 3. 函数
+########################################################################
+
+# 因为 LiveScript 是函数式特性的语言,你可以期待函数在语言里被高规格的对待。
+add = (left, right) -> left + right
+add 1, 2 # => 3
+
+# 加上 ! 防止函数执行后的返回值
+two = -> 2
+two!
+
+# LiveScript 与 JavaScript 一样使用函式作用域,且一样拥有闭包的特性。
+# 与 JavaScript 不同的地方在于,`=` 变量赋值时,左边的对象永远不用变量宣告。
+
+# `:=` 操作符允许*重新賦值*父作用域里的变量。
+
+
+# 你可以解构函数的参数,从不定长度的参数结构里获取感兴趣的值。
+tail = ([head, ...rest]) -> rest
+tail [1, 2, 3] # => [2, 3]
+
+# 你也可以使用一元或二元操作符转换参数。当然也可以预设传入的参数值。
+foo = (a = 1, b = 2) -> a + b
+foo! # => 3
+
+# 你可以以拷贝的方式传入参数来避免副作用,例如:
+copy = (^^target, source) ->
+ for k,v of source => target[k] = v
+ target
+a = { a: 1 }
+copy a, { b: 2 } # => { a: 1, b: 2 }
+a # => { a: 1 }
+
+
+# 使用长箭号取代短箭号来柯里化一个函数:
+add = (left, right) --> left + right
+add1 = add 1
+add1 2 # => 3
+
+# 函式里有一个隐式的 `it` 变量,意谓着你不用宣告它。
+identity = -> it
+identity 1 # => 1
+
+# 操作符在 LiveScript 里不是一個函数,但你可以简单地将它们转换成函数!
+# Enter the operator sectioning:
+divide-by-2 = (/ 2)
+[2, 4, 8, 16].map(divide-by-2) .reduce (+)
+
+
+# LiveScript 里不只有应用函数,如同其它良好的函数式语言,你可以合并函数获得更多发挥:
+double-minus-one = (- 1) . (* 2)
+
+# 除了普通的数学公式合并 `f . g` 之外,还有 `>>` 和 `<<` 操作符定义函数的合并顺序。
+double-minus-one = (* 2) >> (- 1)
+double-minus-one = (- 1) << (* 2)
+
+
+# 说到合并函数的参数, LiveScript 使用 `|>` 和 `<|` 操作符将参数传入:
+map = (f, xs) --> xs.map f
+[1 2 3] |> map (* 2) # => [2 4 6]
+
+# 你也可以选择填入值的位置,只需要使用底线 _ 标记:
+reduce = (f, xs, initial) --> xs.reduce f, initial
+[1 2 3] |> reduce (+), _, 0 # => 6
+
+
+# 你也能使 _ 让任何函数变成偏函数应用:
+div = (left, right) -> left / right
+div-by-2 = div _, 2
+div-by-2 4 # => 2
+
+
+# 最后,也很重要的,LiveScript 拥有後呼叫特性, 可以是基於回调的代码
+# (你可以试试其它函数式特性的解法,比如 Promises):
+readFile = (name, f) -> f name
+a <- readFile 'foo'
+b <- readFile 'bar'
+console.log a + b
+
+# 等同於:
+readFile 'foo', (a) -> readFile 'bar', (b) -> console.log a + b
+
+
+########################################################################
+## 4. 模式、判断和流程控制
+########################################################################
+
+# 流程控制可以使用 `if...else` 表达式:
+x = if n > 0 then \positive else \negative
+
+# 除了 `then` 你也可以使用 `=>`
+x = if n > 0 => \positive
+ else \negative
+
+# 过於复杂的流程可以用 `switch` 表达式代替:
+y = {}
+x = switch
+ | (typeof y) is \number => \number
+ | (typeof y) is \string => \string
+ | 'length' of y => \array
+ | otherwise => \object # `otherwise` 和 `_` 是等价的。
+
+# 函数主体、宣告式和赋值式可以表式成 `switch`,这可以省去一些代码:
+take = (n, [x, ...xs]) -->
+ | n == 0 => []
+ | _ => [x] ++ take (n - 1), xs
+
+
+########################################################################
+## 5. 推导式
+########################################################################
+
+# 在 JavaScript 的标准函式库里有一些辅助函数能帮助处理列表及对象
+#(LiveScript 则带有一个 prelude.ls ,作为标准函式库的补充 ),
+# 推导式能让你使用优雅的语法且快速地处理这些事:
+oneToTwenty = [1 to 20]
+evens = [x for x in oneToTwenty when x % 2 == 0]
+
+# 在推导式里 `when` 和 `unless` 可以当成过滤器使用。
+
+# 对象推导式在使用上也是同样的方式,差别在于你使用的是对象而不是数组:
+copy = { [k, v] for k, v of source }
+
+
+########################################################################
+## 6. OOP
+########################################################################
+
+# 虽然 LiveScript 是一门函数式语言,但具有一些命令式及面向对象的特性。
+# 像是 class 语法和一些借镜於 CoffeeScript 的类别继承语法糖:
+class Animal
+ (@name, kind) ->
+ @kind = kind
+ action: (what) -> "*#{@name} (a #{@kind}) #{what}*"
+
+class Cat extends Animal
+ (@name) -> super @name, 'cat'
+ purr: -> @action 'purrs'
+
+kitten = new Cat 'Mei'
+kitten.purr! # => "*Mei (a cat) purrs*"
+
+# 除了类别的单一继承模式之外,还提供了像混入 (Mixins) 这种特性。
+# Mixins 在语言里被当成普通对象:
+Huggable =
+ hug: -> @action 'is hugged'
+
+class SnugglyCat extends Cat implements Huggable
+
+kitten = new SnugglyCat 'Purr'
+kitten.hug! # => "*Mei (a cat) is hugged*"
+```
+
+## 延伸阅读
+
+LiveScript 还有许多强大之处,但这些应该足够启发你写些小型函数式程式了。
+[LiveScript](http://livescript.net/)有更多关于 LiveScript 的资讯
+和线上编译器等着你来试!
+
+你也可以参考
+[prelude.ls](http://gkz.github.io/prelude-ls/),和一些 `#livescript`
+的网络聊天室频道。
diff --git a/zh-cn/lua-cn.html.markdown b/zh-cn/lua-cn.html.markdown
index 95a94c76..098d0ab5 100644
--- a/zh-cn/lua-cn.html.markdown
+++ b/zh-cn/lua-cn.html.markdown
@@ -1,5 +1,5 @@
---
-language: lua
+language: Lua
lang: zh-cn
contributors:
- ["Tyler Neylon", "http://tylerneylon.com/"]
@@ -9,6 +9,7 @@ contributors:
- ["Amr Tamimi", "https://amrtamimi.com"]
translators:
- ["Jakukyo Friel", "http://weakish.github.io"]
+filename: lua-cn.lua
---
```lua
@@ -62,8 +63,8 @@ foo = anUnknownVariable -- 现在 foo = nil.
aBoolValue = false
---只有nil和false为假; 0和 ''都均为真!
-if not aBoolValue then print('twas false') end
+--只有nil和false为假; 0和 ''均为真!
+if not aBoolValue then print('false') end
-- 'or'和 'and'短路
-- 类似于C/js里的 a?b:c 操作符:
@@ -148,7 +149,7 @@ print {} -- 一样可以工作。
-- Table = Lua唯一的组合数据结构;
-- 它们是关联数组。
-- 类似于PHP的数组或者js的对象,
--- 它们是哈希表或者字典,也可以当初列表使用。
+-- 它们是哈希表或者字典,也可以当列表使用。
-- 按字典/map的方式使用Table:
diff --git a/zh-cn/markdown-cn.html.markdown b/zh-cn/markdown-cn.html.markdown
new file mode 100644
index 00000000..b633714d
--- /dev/null
+++ b/zh-cn/markdown-cn.html.markdown
@@ -0,0 +1,240 @@
+---
+language: markdown
+contributors:
+ - ["Dan Turkel", "http://danturkel.com/"]
+translators:
+ - ["Fangzhou Chen","https://github.com/FZSS"]
+filename: learnmarkdown-cn.md
+lang: zh-cn
+---
+
+Markdown 由 John Gruber 于 2004年创立. 它旨在成为一门容易读写的语法结构,并可以便利地转换成 HTML(以及其他很多)格式。
+
+欢迎您多多反馈以及分支和请求合并。
+
+
+```markdown
+<!-- Markdown 是 HTML 的父集,所以任何 HTML 文件都是有效的 Markdown。
+这意味着我们可以在 Markdown 里使用任何 HTML 元素,比如注释元素,
+且不会被 Markdown 解析器所影响。不过如果你在 Markdown 文件内创建了 HTML 元素,
+你将无法在 HTML 元素的内容中使用 Markdown 语法。-->
+
+<!-- 在不同的解析器中,Markdown 的实现方法有所不同。
+此教程会指出当某功能是否通用及是否只对某一解析器有效。 -->
+
+<!-- 标头 -->
+<!-- 通过在文本前加上不同数量的hash(#), 你可以创建相对应的 <h1>
+到 <h6> HTML元素。-->
+
+# 这是一个 <h1>
+## 这是一个 <h2>
+### 这是一个 <h3>
+#### 这是一个 <h4>
+##### 这是一个 <h5>
+###### 这是一个 <h6>
+
+<!-- 对于 <h1> 和 <h2> 元素,Markdown 额外提供了两种添加方式。 -->
+这是一个 h1
+=============
+
+这是一个 h2
+-------------
+
+<!-- 简易文本样式 -->
+<!-- 文本的斜体,粗体,和删除线在 Markdown 中可以轻易地被实现。-->
+
+*此文本为斜体。*
+_此文本也是。_
+
+**此文本为粗体。**
+__此文本也是__
+
+***此文本是斜体加粗体。***
+**_或者这样。_**
+*__这个也是!__*
+
+<!-- 在 Github 采用的 Markdown 中 -->
+
+~~此文本为删除线效果。~~
+
+<!-- 单个段落由一句或多句邻近的句子组成,这些句子由一个或多个空格分隔。-->
+
+这是第一段落. 这句话在同一个段落里,好玩么?
+
+现在我是第二段落。
+这句话也在第二段落!
+
+这句话在第三段落!
+
+<!-- 如果你插入一个 HTML中的<br />标签,你可以在段末加入两个以上的空格,
+然后另起一段。-->
+
+此段落结尾有两个空格(选中以显示)。
+
+上文有一个 <br /> !
+
+<!-- 段落引用可由 > 字符轻松实现。-->
+
+> 这是一个段落引用. 你可以
+> 手动断开你的句子,然后在每句句子前面添加 “>” 字符。或者让你的句子变得很长,以至于他们自动得断开。
+> 只要你的文字以“>” 字符开头,两种方式无异。
+
+> 你也对文本进行
+>> 多层引用
+> 这多机智啊!
+
+<!-- 序列 -->
+<!-- 无序序列可由星号,加号或者减号来建立 -->
+
+* 项目
+* 项目
+* 另一个项目
+
+或者
+
++ 项目
++ 项目
++ 另一个项目
+
+或者
+
+- 项目
+- 项目
+- 最后一个项目
+
+<!-- 有序序列可由数字加点来实现 -->
+
+1. 项目一
+2. 项目二
+3. 项目三
+
+<!-- 即使你的标签数字有误,Markdown 依旧会呈现出正确的序号,
+不过这并不是一个好主意-->
+
+1. 项目一
+1. 项目二
+1. 项目三
+<!-- (此段与前例一模一样) -->
+
+<!-- 你也可以使用子序列 -->
+
+1. 项目一
+2. 项目二
+3. 项目三
+ * 子项目
+ * 子项目
+4. 项目四
+
+<!-- 代码段落 -->
+<!-- 代码段落(HTML中 <code>标签)可以由缩进四格(spaces)
+或者一个制表符(tab)实现-->
+
+ This is code
+ So is this
+
+<!-- 在你的代码中,你仍然使用tab可以进行缩进操作 -->
+
+ my_array.each do |item|
+ puts item
+ end
+
+<!-- 内联代码可由反引号 ` 实现 -->
+
+John 甚至不知道 `go_to()` 方程是干嘛的!
+
+<!-- 在Github的 Markdown中,对于代码你可以使用特殊的语法 -->
+
+\`\`\`ruby <!-- 插入时记得移除反斜线, 仅留```ruby ! -->
+def foobar
+ puts "Hello world!"
+end
+\`\`\` <!-- 这里也是,移除反斜线,仅留 ``` -->
+
+<!-- 以上代码不需要缩进,而且 Github 会根据```后表明的语言来进行语法高亮 -->
+
+<!-- 水平线 (<hr />) -->
+<!-- 水平线可由三个或以上的星号或者减号创建,可带可不带空格。 -->
+
+***
+---
+- - -
+****************
+
+<!-- 链接 -->
+<!-- Markdown 最棒的地方就是简易的链接制作。链接文字放在中括号[]内,
+在随后的括弧()内加入url。-->
+
+[点我点我!](http://test.com/)
+
+<!-- 你也可以为链接加入一个标题:在括弧内使用引号 -->
+
+[点我点我!](http://test.com/ "连接到Test.com")
+
+<!-- 相对路径也可以有 -->
+
+[去 music](/music/).
+
+<!-- Markdown同样支持引用样式的链接 -->
+
+[点此链接][link1]以获取更多信息!
+[看一看这个链接][foobar] 如果你愿意的话.
+
+[link1]: http://test.com/ "Cool!"
+[foobar]: http://foobar.biz/ "Alright!"
+
+<!-- 链接的标题可以处于单引号中,括弧中或是被忽略。引用名可以在文档的任意何处,
+并且可以随意命名,只要名称不重复。-->
+
+<!-- “隐含式命名” 的功能可以让链接文字作为引用名 -->
+
+[This][] is a link.
+
+[this]: http://thisisalink.com/
+
+<!-- 但这并不常用 -->
+
+<!-- 图像 -->
+<!-- 图像与链接相似,只需在前添加一个感叹号 -->
+
+![这是我图像的悬停文本(alt text)](http://imgur.com/myimage.jpg "可选命名")
+
+<!-- 引用样式也同样起作用 -->
+
+![这是我的悬停文本.][myimage]
+
+[myimage]: relative/urls/cool/image.jpg "在此输入标题"
+
+<!-- 杂项 -->
+<!-- 自动链接 -->
+
+<http://testwebsite.com/> 与
+[http://testwebsite.com/](http://testwebsite.com/) 等同
+
+<!-- 电子邮件的自动链接 -->
+
+<foo@bar.com>
+
+<!-- 转义字符 -->
+
+我希望 *将这段文字置于星号之间* 但是我不希望它被
+斜体化, 所以我就: \*这段置文字于星号之间\*。
+
+<!-- 表格 -->
+<!-- 表格只被 Github 的 Markdown 支持,并且有一点笨重,但如果你真的要用的话: -->
+
+| 第一列 | 第二列 | 第三列 |
+| :---------- | :------: | ----------: |
+| 左对齐 | 居个中 | 右对齐 |
+| 某某某 | 某某某 | 某某某 |
+
+<!-- 或者, 同样的 -->
+
+第一列 | 第二列 | 第三列
+:-- | :-: | --:
+这太丑了 | 药不能 | 停
+
+<!-- 结束! -->
+
+```
+
+更多信息, 请于[此处](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/matlab-cn.html.markdown b/zh-cn/matlab-cn.html.markdown
new file mode 100644
index 00000000..77ba765a
--- /dev/null
+++ b/zh-cn/matlab-cn.html.markdown
@@ -0,0 +1,491 @@
+---
+language: Matlab
+contributors:
+ - ["mendozao", "http://github.com/mendozao"]
+ - ["jamesscottbrown", "http://jamesscottbrown.com"]
+translators:
+ - ["sunxb10", "https://github.com/sunxb10"]
+lang: zh-cn
+---
+
+MATLAB 是 MATrix LABoratory (矩阵实验室)的缩写,它是一种功能强大的数值计算语言,在工程和数学领域中应用广泛。
+
+如果您有任何需要反馈或交流的内容,请联系本教程作者[@the_ozzinator](https://twitter.com/the_ozzinator)、[osvaldo.t.mendoza@gmail.com](mailto:osvaldo.t.mendoza@gmail.com)。
+
+```matlab
+% 以百分号作为注释符
+
+%{
+多行注释
+可以
+这样
+表示
+%}
+
+% 指令可以随意跨行,但需要在跨行处用 '...' 标明:
+ a = 1 + 2 + ...
+ + 4
+
+% 可以在MATLAB中直接向操作系统发出指令
+!ping google.com
+
+who % 显示内存中的所有变量
+whos % 显示内存中的所有变量以及它们的类型
+clear % 清除内存中的所有变量
+clear('A') % 清除指定的变量
+openvar('A') % 在变量编辑器中编辑指定变量
+
+clc % 清除命令窗口中显示的所有指令
+diary % 将命令窗口中的内容写入本地文件
+ctrl-c % 终止当前计算
+
+edit('myfunction.m') % 在编辑器中打开指定函数或脚本
+type('myfunction.m') % 在命令窗口中打印指定函数或脚本的源码
+
+profile on % 打开 profile 代码分析工具
+profile of % 关闭 profile 代码分析工具
+profile viewer % 查看 profile 代码分析工具的分析结果
+
+help command % 在命令窗口中显示指定命令的帮助文档
+doc command % 在帮助窗口中显示指定命令的帮助文档
+lookfor command % 在所有 MATLAB 内置函数的头部注释块的第一行中搜索指定命令
+lookfor command -all % 在所有 MATLAB 内置函数的整个头部注释块中搜索指定命令
+
+
+% 输出格式
+format short % 浮点数保留 4 位小数
+format long % 浮点数保留 15 位小数
+format bank % 金融格式,浮点数只保留 2 位小数
+fprintf('text') % 在命令窗口中显示 "text"
+disp('text') % 在命令窗口中显示 "text"
+
+
+% 变量与表达式
+myVariable = 4 % 命令窗口中将新创建的变量
+myVariable = 4; % 加上分号可使命令窗口中不显示当前语句执行结果
+4 + 6 % ans = 10
+8 * myVariable % ans = 32
+2 ^ 3 % ans = 8
+a = 2; b = 3;
+c = exp(a)*sin(pi/2) % c = 7.3891
+
+
+% 调用函数有两种方式:
+% 标准函数语法:
+load('myFile.mat', 'y') % 参数放在括号内,以英文逗号分隔
+% 指令语法:
+load myFile.mat y % 不加括号,以空格分隔参数
+% 注意在指令语法中参数不需要加引号:在这种语法下,所有输入参数都只能是文本文字,
+% 不能是变量的具体值,同样也不能是输出变量
+[V,D] = eig(A); % 这条函数调用无法转换成等价的指令语法
+[~,D] = eig(A); % 如果结果中只需要 D 而不需要 V 则可以这样写
+
+
+
+% 逻辑运算
+1 > 5 % 假,ans = 0
+10 >= 10 % 真,ans = 1
+3 ~= 4 % 不等于 -> ans = 1
+3 == 3 % 等于 -> ans = 1
+3 > 1 && 4 > 1 % 与 -> ans = 1
+3 > 1 || 4 > 1 % 或 -> ans = 1
+~1 % 非 -> ans = 0
+
+% 逻辑运算可直接应用于矩阵,运算结果也是矩阵
+A > 5
+% 对矩阵中每个元素做逻辑运算,若为真,则在运算结果的矩阵中对应位置的元素就是 1
+A( A > 5 )
+% 如此返回的向量,其元素就是 A 矩阵中所有逻辑运算为真的元素
+
+% 字符串
+a = 'MyString'
+length(a) % ans = 8
+a(2) % ans = y
+[a,a] % ans = MyStringMyString
+b = '字符串' % MATLAB目前已经可以支持包括中文在内的多种文字
+length(b) % ans = 3
+b(2) % ans = 符
+[b,b] % ans = 字符串字符串
+
+
+% 元组(cell 数组)
+a = {'one', 'two', 'three'}
+a(1) % ans = 'one' - 返回一个元组
+char(a(1)) % ans = one - 返回一个字符串
+
+
+% 结构体
+A.b = {'one','two'};
+A.c = [1 2];
+A.d.e = false;
+
+
+% 向量
+x = [4 32 53 7 1]
+x(2) % ans = 32,MATLAB中向量的下标索引从1开始,不是0
+x(2:3) % ans = 32 53
+x(2:end) % ans = 32 53 7 1
+
+x = [4; 32; 53; 7; 1] % 列向量
+
+x = [1:10] % x = 1 2 3 4 5 6 7 8 9 10
+
+
+% 矩阵
+A = [1 2 3; 4 5 6; 7 8 9]
+% 以分号分隔不同的行,以空格或逗号分隔同一行中的不同元素
+% A =
+
+% 1 2 3
+% 4 5 6
+% 7 8 9
+
+A(2,3) % ans = 6,A(row, column)
+A(6) % ans = 8
+% (隐式地将 A 的三列首尾相接组成一个列向量,然后取其下标为 6 的元素)
+
+
+A(2,3) = 42 % 将第 2 行第 3 列的元素设为 42
+% A =
+
+% 1 2 3
+% 4 5 42
+% 7 8 9
+
+A(2:3,2:3) % 取原矩阵中的一块作为新矩阵
+%ans =
+
+% 5 42
+% 8 9
+
+A(:,1) % 第 1 列的所有元素
+%ans =
+
+% 1
+% 4
+% 7
+
+A(1,:) % 第 1 行的所有元素
+%ans =
+
+% 1 2 3
+
+[A ; A] % 将两个矩阵上下相接构成新矩阵
+%ans =
+
+% 1 2 3
+% 4 5 42
+% 7 8 9
+% 1 2 3
+% 4 5 42
+% 7 8 9
+
+% 等价于
+vertcat(A, A);
+
+
+[A , A] % 将两个矩阵左右相接构成新矩阵
+
+%ans =
+
+% 1 2 3 1 2 3
+% 4 5 42 4 5 42
+% 7 8 9 7 8 9
+
+% 等价于
+horzcat(A, A);
+
+
+A(:, [3 1 2]) % 重新排布原矩阵的各列
+%ans =
+
+% 3 1 2
+% 42 4 5
+% 9 7 8
+
+size(A) % 返回矩阵的行数和列数,ans = 3 3
+
+A(1, :) =[] % 删除矩阵的第 1 行
+A(:, 1) =[] % 删除矩阵的第 1 列
+
+transpose(A) % 矩阵转置,等价于 A'
+ctranspose(A) % 矩阵的共轭转置(对矩阵中的每个元素取共轭复数)
+
+
+% 元素运算 vs. 矩阵运算
+% 单独运算符就是对矩阵整体进行矩阵运算
+% 在运算符加上英文句点就是对矩阵中的元素进行元素计算
+% 示例如下:
+A * B % 矩阵乘法,要求 A 的列数等于 B 的行数
+A .* B % 元素乘法,要求 A 和 B 形状一致(A 的行数等于 B 的行数, A 的列数等于 B 的列数)
+% 元素乘法的结果是与 A 和 B 形状一致的矩阵,其每个元素等于 A 对应位置的元素乘 B 对应位置的元素
+
+% 以下函数中,函数名以 m 结尾的执行矩阵运算,其余执行元素运算:
+exp(A) % 对矩阵中每个元素做指数运算
+expm(A) % 对矩阵整体做指数运算
+sqrt(A) % 对矩阵中每个元素做开方运算
+sqrtm(A) % 对矩阵整体做开放运算(即试图求出一个矩阵,该矩阵与自身的乘积等于 A 矩阵)
+
+
+% 绘图
+x = 0:.10:2*pi; % 生成一向量,其元素从 0 开始,以 0.1 的间隔一直递增到 2*pi(pi 就是圆周率)
+y = sin(x);
+plot(x,y)
+xlabel('x axis')
+ylabel('y axis')
+title('Plot of y = sin(x)')
+axis([0 2*pi -1 1]) % x 轴范围是从 0 到 2*pi,y 轴范围是从 -1 到 1
+
+plot(x,y1,'-',x,y2,'--',x,y3,':') % 在同一张图中绘制多条曲线
+legend('Line 1 label', 'Line 2 label') % 为图片加注图例
+% 图例数量应当小于或等于实际绘制的曲线数目,从 plot 绘制的第一条曲线开始对应
+
+% 在同一张图上绘制多条曲线的另一种方法:
+% 使用 hold on,令系统保留前次绘图结果并在其上直接叠加新的曲线,
+% 如果没有 hold on,则每个 plot 都会首先清除之前的绘图结果再进行绘制。
+% 在 hold on 和 hold off 中可以放置任意多的 plot 指令,
+% 它们和 hold on 前最后一个 plot 指令的结果都将显示在同一张图中。
+plot(x, y1)
+hold on
+plot(x, y2)
+plot(x, y3)
+plot(x, y4)
+hold off
+
+loglog(x, y) % 对数—对数绘图
+semilogx(x, y) % 半对数(x 轴对数)绘图
+semilogy(x, y) % 半对数(y 轴对数)绘图
+
+fplot (@(x) x^2, [2,5]) % 绘制函数 x^2 在 [2, 5] 区间的曲线
+
+grid on % 在绘制的图中显示网格,使用 grid off 可取消网格显示
+axis square % 将当前坐标系设定为正方形(保证在图形显示上各轴等长)
+axis equal % 将当前坐标系设定为相等(保证在实际数值上各轴等长)
+
+scatter(x, y); % 散点图
+hist(x); % 直方图
+
+z = sin(x);
+plot3(x,y,z); % 绘制三维曲线
+
+pcolor(A) % 伪彩色图(热图)
+contour(A) % 等高线图
+mesh(A) % 网格曲面图
+
+h = figure % 创建新的图片对象并返回其句柄 h
+figure(h) % 将句柄 h 对应的图片作为当前图片
+close(h) % 关闭句柄 h 对应的图片
+close all % 关闭 MATLAB 中所用打开的图片
+close % 关闭当前图片
+
+shg % 显示图形窗口
+clf clear % 清除图形窗口中的图像,并重置图像属性
+
+% 图像属性可以通过图像句柄进行设定
+% 在创建图像时可以保存图像句柄以便于设置
+% 也可以用 gcf 函数返回当前图像的句柄
+h = plot(x, y); % 在创建图像时显式地保存图像句柄
+set(h, 'Color', 'r')
+% 颜色代码:'y' 黄色,'m' 洋红色,'c' 青色,'r' 红色,'g' 绿色,'b' 蓝色,'w' 白色,'k' 黑色
+set(h, 'Color', [0.5, 0.5, 0.4])
+% 也可以使用 RGB 值指定颜色
+set(h, 'LineStyle', '--')
+% 线型代码:'--' 实线,'---' 虚线,':' 点线,'-.' 点划线,'none' 不划线
+get(h, 'LineStyle')
+% 获取当前句柄的线型
+
+
+% 用 gca 函数返回当前图像的坐标轴句柄
+set(gca, 'XDir', 'reverse'); % 令 x 轴反向
+
+% 用 subplot 指令创建平铺排列的多张子图
+subplot(2,3,1); % 选择 2 x 3 排列的子图中的第 1 张图
+plot(x1); title('First Plot') % 在选中的图中绘图
+subplot(2,3,2); % 选择 2 x 3 排列的子图中的第 2 张图
+plot(x2); title('Second Plot') % 在选中的图中绘图
+
+
+% 要调用函数或脚本,必须保证它们在你的当前工作目录中
+path % 显示当前工作目录
+addpath /path/to/dir % 将指定路径加入到当前工作目录中
+rmpath /path/to/dir % 将指定路径从当前工作目录中删除
+cd /path/to/move/into % 以制定路径作为当前工作目录
+
+
+% 变量可保存到 .mat 格式的本地文件
+save('myFileName.mat') % 保存当前工作空间中的所有变量
+load('myFileName.mat') % 将指定文件中的变量载入到当前工作空间
+
+
+% .m 脚本文件
+% 脚本文件是一个包含多条 MATLAB 指令的外部文件,以 .m 为后缀名
+% 使用脚本文件可以避免在命令窗口中重复输入冗长的指令
+
+
+% .m 函数文件
+% 与脚本文件类似,同样以 .m 作为后缀名
+% 但函数文件可以接受用户输入的参数并返回运算结果
+% 并且函数拥有自己的工作空间(变量域),不必担心变量名称冲突
+% 函数文件的名称应当与其所定义的函数的名称一致(比如下面例子中函数文件就应命名为 double_input.m)
+% 使用 'help double_input.m' 可返回函数定义中第一行注释信息
+function output = double_input(x)
+ % double_input(x) 返回 x 的 2 倍
+ output = 2*x;
+end
+double_input(6) % ans = 12
+
+
+% 同样还可以定义子函数和内嵌函数
+% 子函数与主函数放在同一个函数文件中,且只能被这个主函数调用
+% 内嵌函数放在另一个函数体内,可以直接访问被嵌套函数的各个变量
+
+
+% 使用匿名函数可以不必创建 .m 函数文件
+% 匿名函数适用于快速定义某函数以便传递给另一指令或函数(如绘图、积分、求根、求极值等)
+% 下面示例的匿名函数返回输入参数的平方根,可以使用句柄 sqr 进行调用:
+sqr = @(x) x.^2;
+sqr(10) % ans = 100
+doc function_handle % find out more
+
+
+% 接受用户输入
+a = input('Enter the value: ')
+
+
+% 从文件中读取数据
+fopen(filename)
+% 类似函数还有 xlsread(excel 文件)、importdata(CSV 文件)、imread(图像文件)
+
+
+% 输出
+disp(a) % 在命令窗口中打印变量 a 的值
+disp('Hello World') % 在命令窗口中打印字符串
+fprintf % 按照指定格式在命令窗口中打印内容
+
+% 条件语句(if 和 elseif 语句中的括号并非必需,但推荐加括号避免混淆)
+if (a > 15)
+ disp('Greater than 15')
+elseif (a == 23)
+ disp('a is 23')
+else
+ disp('neither condition met')
+end
+
+% 循环语句
+% 注意:对向量或矩阵使用循环语句进行元素遍历的效率很低!!
+% 注意:只要有可能,就尽量使用向量或矩阵的整体运算取代逐元素循环遍历!!
+% MATLAB 在开发时对向量和矩阵运算做了专门优化,做向量和矩阵整体运算的效率高于循环语句
+for k = 1:5
+ disp(k)
+end
+
+k = 0;
+while (k < 5)
+ k = k + 1;
+end
+
+
+% 程序运行计时:'tic' 是计时开始,'toc' 是计时结束并打印结果
+tic
+A = rand(1000);
+A*A*A*A*A*A*A;
+toc
+
+
+% 链接 MySQL 数据库
+dbname = 'database_name';
+username = 'root';
+password = 'root';
+driver = 'com.mysql.jdbc.Driver';
+dburl = ['jdbc:mysql://localhost:8889/' dbname];
+javaclasspath('mysql-connector-java-5.1.xx-bin.jar'); % 此处 xx 代表具体版本号
+% 这里的 mysql-connector-java-5.1.xx-bin.jar 可从 http://dev.mysql.com/downloads/connector/j/ 下载
+conn = database(dbname, username, password, driver, dburl);
+sql = ['SELECT * from table_name where id = 22'] % SQL 语句
+a = fetch(conn, sql) % a 即包含所需数据
+
+
+% 常用数学函数
+sin(x)
+cos(x)
+tan(x)
+asin(x)
+acos(x)
+atan(x)
+exp(x)
+sqrt(x)
+log(x)
+log10(x)
+abs(x)
+min(x)
+max(x)
+ceil(x)
+floor(x)
+round(x)
+rem(x)
+rand % 均匀分布的伪随机浮点数
+randi % 均匀分布的伪随机整数
+randn % 正态分布的伪随机浮点数
+
+% 常用常数
+pi
+NaN
+inf
+
+% 求解矩阵方程(如果方程无解,则返回最小二乘近似解)
+% \ 操作符等价于 mldivide 函数,/ 操作符等价于 mrdivide 函数
+x=A\b % 求解 Ax=b,比先求逆再左乘 inv(A)*b 更加高效、准确
+x=b/A % 求解 xA=b
+
+inv(A) % 逆矩阵
+pinv(A) % 伪逆矩阵
+
+
+% 常用矩阵函数
+zeros(m, n) % m x n 阶矩阵,元素全为 0
+ones(m, n) % m x n 阶矩阵,元素全为 1
+diag(A) % 返回矩阵 A 的对角线元素
+diag(x) % 构造一个对角阵,对角线元素就是向量 x 的各元素
+eye(m, n) % m x n 阶单位矩阵
+linspace(x1, x2, n) % 返回介于 x1 和 x2 之间的 n 个等距节点
+inv(A) % 矩阵 A 的逆矩阵
+det(A) % 矩阵 A 的行列式
+eig(A) % 矩阵 A 的特征值和特征向量
+trace(A) % 矩阵 A 的迹(即对角线元素之和),等价于 sum(diag(A))
+isempty(A) % 测试 A 是否为空
+all(A) % 测试 A 中所有元素是否都非 0 或都为真(逻辑值)
+any(A) % 测试 A 中是否有元素非 0 或为真(逻辑值)
+isequal(A, B) % 测试 A 和 B是否相等
+numel(A) % 矩阵 A 的元素个数
+triu(x) % 返回 x 的上三角这部分
+tril(x) % 返回 x 的下三角这部分
+cross(A, B) % 返回 A 和 B 的叉积(矢量积、外积)
+dot(A, B) % 返回 A 和 B 的点积(数量积、内积),要求 A 和 B 必须等长
+transpose(A) % A 的转置,等价于 A'
+fliplr(A) % 将一个矩阵左右翻转
+flipud(A) % 将一个矩阵上下翻转
+
+% 矩阵分解
+[L, U, P] = lu(A) % LU 分解:PA = LU,L 是下三角阵,U 是上三角阵,P 是置换阵
+[P, D] = eig(A) % 特征值分解:AP = PD,D 是由特征值构成的对角阵,P 的各列就是对应的特征向量
+[U, S, V] = svd(X) % 奇异值分解:XV = US,U 和 V 是酉矩阵,S 是由奇异值构成的半正定实数对角阵
+
+% 常用向量函数
+max % 最大值
+min % 最小值
+length % 元素个数
+sort % 按升序排列
+sum % 各元素之和
+prod % 各元素之积
+mode % 众数
+median % 中位数
+mean % 平均值
+std % 标准差
+perms(x) % x 元素的全排列
+
+```
+
+## 相关资料
+
+* 官方网页:[http://http://www.mathworks.com/products/matlab/](http://www.mathworks.com/products/matlab/)
+* 官方论坛:[http://www.mathworks.com/matlabcentral/answers/](http://www.mathworks.com/matlabcentral/answers/)
diff --git a/zh-cn/php-cn.html.markdown b/zh-cn/php-cn.html.markdown
index 24939681..2def7f1c 100644
--- a/zh-cn/php-cn.html.markdown
+++ b/zh-cn/php-cn.html.markdown
@@ -1,5 +1,5 @@
---
-language: php
+language: PHP
contributors:
- ["Malcolm Fell", "http://emarref.net/"]
- ["Trismegiste", "https://github.com/Trismegiste"]
diff --git a/zh-cn/python3-cn.html.markdown b/zh-cn/python3-cn.html.markdown
new file mode 100644
index 00000000..76455a46
--- /dev/null
+++ b/zh-cn/python3-cn.html.markdown
@@ -0,0 +1,629 @@
+---
+language: python3
+contributors:
+ - ["Louie Dinh", "http://pythonpracticeprojects.com"]
+ - ["Steven Basart", "http://github.com/xksteven"]
+ - ["Andre Polykanine", "https://github.com/Oire"]
+translators:
+ - ["Geoff Liu", "http://geoffliu.me"]
+filename: learnpython3-cn.py
+lang: zh-cn
+---
+
+Python是由吉多·范罗苏姆(Guido Van Rossum)在90年代早期设计。它是如今最常用的编程
+语言之一。它的语法简洁且优美,几乎就是可执行的伪代码。
+
+欢迎大家斧正。英文版原作Louie Dinh [@louiedinh](http://twitter.com/louiedinh)
+或着Email louiedinh [at] [谷歌的信箱服务]。中文翻译Geoff Liu。
+
+注意:这篇教程是特别为Python3写的。如果你想学旧版Python2,我们特别有另一篇教程。
+
+```python
+
+# 用井字符开头的是单行注释
+
+""" 多行字符串用三个引号
+ 包裹,也常被用来做多
+ 行注释
+"""
+
+####################################################
+## 1. 原始数据类型和运算符
+####################################################
+
+# 整数
+3 # => 3
+
+# 算术没有什么出乎意料的
+1 + 1 # => 2
+8 - 1 # => 7
+10 * 2 # => 20
+
+# 但是除法例外,会自动转换成浮点数
+35 / 5 # => 7.0
+5 / 3 # => 1.6666666666666667
+
+# 整数除法的结果都是向下取整
+5 // 3 # => 1
+5.0 // 3.0 # => 1.0 # 浮点数也可以
+-5 // 3 # => -2
+-5.0 // 3.0 # => -2.0
+
+# 浮点数的运算结果也是浮点数
+3 * 2.0 # => 6.0
+
+# 模除
+7 % 3 # => 1
+
+# x的y次方
+2**4 # => 16
+
+# 用括号决定优先级
+(1 + 3) * 2 # => 8
+
+# 布尔值
+True
+False
+
+# 用not取非
+not True # => False
+not False # => True
+
+# 逻辑运算符,注意and和or都是小写
+True and False #=> False
+False or True #=> True
+
+# 整数也可以当作布尔值
+0 and 2 #=> 0
+-5 or 0 #=> -5
+0 == False #=> True
+2 == True #=> False
+1 == True #=> True
+
+# 用==判断相等
+1 == 1 # => True
+2 == 1 # => False
+
+# 用!=判断不等
+1 != 1 # => False
+2 != 1 # => True
+
+# 比较大小
+1 < 10 # => True
+1 > 10 # => False
+2 <= 2 # => True
+2 >= 2 # => True
+
+# 大小比较可以连起来!
+1 < 2 < 3 # => True
+2 < 3 < 2 # => False
+
+# 字符串用单引双引都可以
+"这是个字符串"
+'这也是个字符串'
+
+# 用加号连接字符串
+"Hello " + "world!" # => "Hello world!"
+
+# 字符串可以被当作字符列表
+"This is a string"[0] # => 'T'
+
+# 用.format来格式化字符串
+"{} can be {}".format("strings", "interpolated")
+
+# 可以重复参数以节省时间
+"{0} be nimble, {0} be quick, {0} jump over the {1}".format("Jack", "candle stick")
+#=> "Jack be nimble, Jack be quick, Jack jump over the candle stick"
+
+# 如果不想数参数,可以用关键字
+"{name} wants to eat {food}".format(name="Bob", food="lasagna") #=> "Bob wants to eat lasagna"
+
+# 如果你的Python3程序也要在Python2.5以下环境运行,也可以用老式的格式化语法
+"%s can be %s the %s way" % ("strings", "interpolated", "old")
+
+# None是一个对象
+None # => None
+
+# 当与None进行比较时不要用 ==,要用is。is是用来比较两个变量是否指向同一个对象。
+"etc" is None # => False
+None is None # => True
+
+# None,0,空字符串,空列表,空字典都算是False
+# 所有其他值都是True
+bool(0) # => False
+bool("") # => False
+bool([]) #=> False
+bool({}) #=> False
+
+
+####################################################
+## 2. 变量和集合
+####################################################
+
+# print是内置的打印函数
+print("I'm Python. Nice to meet you!")
+
+# 在给变量赋值前不用提前声明
+# 传统的变量命名是小写,用下划线分隔单词
+some_var = 5
+some_var # => 5
+
+# 访问未赋值的变量会抛出异常
+# 参考流程控制一段来学习异常处理
+some_unknown_var # 抛出NameError
+
+# 用列表(list)储存序列
+li = []
+# 创建列表时也可以同时赋给元素
+other_li = [4, 5, 6]
+
+# 用append在列表最后追加元素
+li.append(1) # li现在是[1]
+li.append(2) # li现在是[1, 2]
+li.append(4) # li现在是[1, 2, 4]
+li.append(3) # li现在是[1, 2, 4, 3]
+# 用pop从列表尾部删除
+li.pop() # => 3 且li现在是[1, 2, 4]
+# 把3再放回去
+li.append(3) # li变回[1, 2, 4, 3]
+
+# 列表存取跟数组一样
+li[0] # => 1
+# 取出最后一个元素
+li[-1] # => 3
+
+# 越界存取会造成IndexError
+li[4] # 抛出IndexError
+
+# 列表有切割语法
+li[1:3] # => [2, 4]
+# 取尾
+li[2:] # => [4, 3]
+# 取头
+li[:3] # => [1, 2, 4]
+# 隔一个取一个
+li[::2] # =>[1, 4]
+# 倒排列表
+li[::-1] # => [3, 4, 2, 1]
+# 可以用三个参数的任何组合来构建切割
+# li[始:终:步伐]
+
+# 用del删除任何一个元素
+del li[2] # li is now [1, 2, 3]
+
+# 列表可以相加
+# 注意:li和other_li的值都不变
+li + other_li # => [1, 2, 3, 4, 5, 6]
+
+# 用extend拼接列表
+li.extend(other_li) # li现在是[1, 2, 3, 4, 5, 6]
+
+# 用in测试列表是否包含值
+1 in li # => True
+
+# 用len取列表长度
+len(li) # => 6
+
+
+# 元组是不可改变的序列
+tup = (1, 2, 3)
+tup[0] # => 1
+tup[0] = 3 # 抛出TypeError
+
+# 列表允许的操作元组大都可以
+len(tup) # => 3
+tup + (4, 5, 6) # => (1, 2, 3, 4, 5, 6)
+tup[:2] # => (1, 2)
+2 in tup # => True
+
+# 可以把元组合列表解包,赋值给变量
+a, b, c = (1, 2, 3) # 现在a是1,b是2,c是3
+# 元组周围的括号是可以省略的
+d, e, f = 4, 5, 6
+# 交换两个变量的值就这么简单
+e, d = d, e # 现在d是5,e是4
+
+
+# 用字典表达映射关系
+empty_dict = {}
+# 初始化的字典
+filled_dict = {"one": 1, "two": 2, "three": 3}
+
+# 用[]取值
+filled_dict["one"] # => 1
+
+
+# 用keys获得所有的键。因为keys返回一个可迭代对象,所以在这里把结果包在list里。我们下面会详细介绍可迭代。
+# 注意:字典键的顺序是不定的,你得到的结果可能和以下不同。
+list(filled_dict.keys()) # => ["three", "two", "one"]
+
+
+# 用values获得所有的值。跟keys一样,要用list包起来,顺序也可能不同。
+list(filled_dict.values()) # => [3, 2, 1]
+
+
+# 用in测试一个字典是否包含一个键
+"one" in filled_dict # => True
+1 in filled_dict # => False
+
+# 访问不存在的键会导致KeyError
+filled_dict["four"] # KeyError
+
+# 用get来避免KeyError
+filled_dict.get("one") # => 1
+filled_dict.get("four") # => None
+# 当键不存在的时候get方法可以返回默认值
+filled_dict.get("one", 4) # => 1
+filled_dict.get("four", 4) # => 4
+
+# setdefault方法只有当键不存在的时候插入新值
+filled_dict.setdefault("five", 5) # filled_dict["five"]设为5
+filled_dict.setdefault("five", 6) # filled_dict["five"]还是5
+
+# 字典赋值
+filled_dict.update({"four":4}) #=> {"one": 1, "two": 2, "three": 3, "four": 4}
+filled_dict["four"] = 4 # 另一种赋值方法
+
+# 用del删除
+del filled_dict["one"] # 从filled_dict中把one删除
+
+
+# 用set表达集合
+empty_set = set()
+# 初始化一个集合,语法跟字典相似。
+some_set = {1, 1, 2, 2, 3, 4} # some_set现在是{1, 2, 3, 4}
+
+# 可以把集合赋值于变量
+filled_set = some_set
+
+# 为集合添加元素
+filled_set.add(5) # filled_set现在是{1, 2, 3, 4, 5}
+
+# & 取交集
+other_set = {3, 4, 5, 6}
+filled_set & other_set # => {3, 4, 5}
+
+# | 取并集
+filled_set | other_set # => {1, 2, 3, 4, 5, 6}
+
+# - 取补集
+{1, 2, 3, 4} - {2, 3, 5} # => {1, 4}
+
+# in 测试集合是否包含元素
+2 in filled_set # => True
+10 in filled_set # => False
+
+
+####################################################
+## 3. 流程控制和迭代器
+####################################################
+
+# 先随便定义一个变量
+some_var = 5
+
+# 这是个if语句。注意缩进在Python里是有意义的
+# 印出"some_var比10小"
+if some_var > 10:
+ print("some_var比10大")
+elif some_var < 10: # elif句是可选的
+ print("some_var比10小")
+else: # else也是可选的
+ print("some_var就是10")
+
+
+"""
+用for循环语句遍历列表
+打印:
+ dog is a mammal
+ cat is a mammal
+ mouse is a mammal
+"""
+for animal in ["dog", "cat", "mouse"]:
+ print("{} is a mammal".format(animal))
+
+"""
+"range(number)"返回数字列表从0到给的数字
+打印:
+ 0
+ 1
+ 2
+ 3
+"""
+for i in range(4):
+ print(i)
+
+"""
+while循环直到条件不满足
+打印:
+ 0
+ 1
+ 2
+ 3
+"""
+x = 0
+while x < 4:
+ print(x)
+ x += 1 # x = x + 1 的简写
+
+# 用try/except块处理异常状况
+try:
+ # 用raise抛出异常
+ raise IndexError("This is an index error")
+except IndexError as e:
+ pass # pass是无操作,但是应该在这里处理错误
+except (TypeError, NameError):
+ pass # 可以同时处理不同类的错误
+else: # else语句是可选的,必须在所有的except之后
+ print("All good!") # 只有当try运行完没有错误的时候这句才会运行
+
+
+# Python提供一个叫做可迭代(iterable)的基本抽象。一个可迭代对象是可以被当作序列
+# 的对象。比如说上面range返回的对象就是可迭代的。
+
+filled_dict = {"one": 1, "two": 2, "three": 3}
+our_iterable = filled_dict.keys()
+print(our_iterable) # => range(1,10) 是一个实现可迭代接口的对象
+
+# 可迭代对象可以遍历
+for i in our_iterable:
+ print(i) # 打印 one, two, three
+
+# 但是不可以随机访问
+our_iterable[1] # 抛出TypeError
+
+# 可迭代对象知道怎么生成迭代器
+our_iterator = iter(our_iterable)
+
+# 迭代器是一个可以记住遍历的位置的对象
+# 用__next__可以取得下一个元素
+our_iterator.__next__() #=> "one"
+
+# 再一次调取__next__时会记得位置
+our_iterator.__next__() #=> "two"
+our_iterator.__next__() #=> "three"
+
+# 当迭代器所有元素都取出后,会抛出StopIteration
+our_iterator.__next__() # 抛出StopIteration
+
+# 可以用list一次取出迭代器所有的元素
+list(filled_dict.keys()) #=> Returns ["one", "two", "three"]
+
+
+
+####################################################
+## 4. 函数
+####################################################
+
+# 用def定义新函数
+def add(x, y):
+ print("x is {} and y is {}".format(x, y))
+ return x + y # 用return语句返回
+
+# 调用函数
+add(5, 6) # => 印出"x is 5 and y is 6"并且返回11
+
+# 也可以用关键字参数来调用函数
+add(y=6, x=5) # 关键字参数可以用任何顺序
+
+
+# 我们可以定义一个可变参数函数
+def varargs(*args):
+ return args
+
+varargs(1, 2, 3) # => (1, 2, 3)
+
+
+# 我们也可以定义一个关键字可变参数函数
+def keyword_args(**kwargs):
+ return kwargs
+
+# 我们来看看结果是什么:
+keyword_args(big="foot", loch="ness") # => {"big": "foot", "loch": "ness"}
+
+
+# 这两种可变参数可以混着用
+def all_the_args(*args, **kwargs):
+ print(args)
+ print(kwargs)
+"""
+all_the_args(1, 2, a=3, b=4) prints:
+ (1, 2)
+ {"a": 3, "b": 4}
+"""
+
+# 调用可变参数函数时可以做跟上面相反的,用*展开序列,用**展开字典。
+args = (1, 2, 3, 4)
+kwargs = {"a": 3, "b": 4}
+all_the_args(*args) # 相当于 foo(1, 2, 3, 4)
+all_the_args(**kwargs) # 相当于 foo(a=3, b=4)
+all_the_args(*args, **kwargs) # 相当于 foo(1, 2, 3, 4, a=3, b=4)
+
+
+# 函数作用域
+x = 5
+
+def setX(num):
+ # 局部作用域的x和全局域的x是不同的
+ x = num # => 43
+ print (x) # => 43
+
+def setGlobalX(num):
+ global x
+ print (x) # => 5
+ x = num # 现在全局域的x被赋值
+ print (x) # => 6
+
+setX(43)
+setGlobalX(6)
+
+
+# 函数在Python是一等公民
+def create_adder(x):
+ def adder(y):
+ return x + y
+ return adder
+
+add_10 = create_adder(10)
+add_10(3) # => 13
+
+# 也有匿名函数
+(lambda x: x > 2)(3) # => True
+
+# 内置的高阶函数
+map(add_10, [1, 2, 3]) # => [11, 12, 13]
+filter(lambda x: x > 5, [3, 4, 5, 6, 7]) # => [6, 7]
+
+# 用列表推导式可以简化映射和过滤。列表推导式的返回值是另一个列表。
+[add_10(i) for i in [1, 2, 3]] # => [11, 12, 13]
+[x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7]
+
+####################################################
+## 5. 类
+####################################################
+
+
+# 定义一个继承object的类
+class Human(object):
+
+ # 类属性,被所有此类的实例共用。
+ species = "H. sapiens"
+
+ # 构造方法,当实例被初始化时被调用。注意名字前后的双下划线,这是表明这个属
+ # 性或方法对Python有特殊意义,但是允许用户自行定义。你自己取名时不应该用这
+ # 种格式。
+ def __init__(self, name):
+ # Assign the argument to the instance's name attribute
+ self.name = name
+
+ # 实例方法,第一个参数总是self,就是这个实例对象
+ def say(self, msg):
+ return "{name}: {message}".format(name=self.name, message=msg)
+
+ # 类方法,被所有此类的实例共用。第一个参数是这个类对象。
+ @classmethod
+ def get_species(cls):
+ return cls.species
+
+ # 静态方法。调用时没有实例或类的绑定。
+ @staticmethod
+ def grunt():
+ return "*grunt*"
+
+
+# 构造一个实例
+i = Human(name="Ian")
+print(i.say("hi")) # 印出 "Ian: hi"
+
+j = Human("Joel")
+print(j.say("hello")) # 印出 "Joel: hello"
+
+# 调用一个类方法
+i.get_species() # => "H. sapiens"
+
+# 改一个共用的类属性
+Human.species = "H. neanderthalensis"
+i.get_species() # => "H. neanderthalensis"
+j.get_species() # => "H. neanderthalensis"
+
+# 调用静态方法
+Human.grunt() # => "*grunt*"
+
+
+####################################################
+## 6. 模块
+####################################################
+
+# 用import导入模块
+import math
+print(math.sqrt(16)) # => 4.0
+
+# 也可以从模块中导入个别值
+from math import ceil, floor
+print(ceil(3.7)) # => 4.0
+print(floor(3.7)) # => 3.0
+
+# 可以导入一个模块中所有值
+# 警告:不建议这么做
+from math import *
+
+# 如此缩写模块名字
+import math as m
+math.sqrt(16) == m.sqrt(16) # => True
+
+# Python模块其实就是普通的Python文件。你可以自己写,然后导入,
+# 模块的名字就是文件的名字。
+
+# 你可以这样列出一个模块里所有的值
+import math
+dir(math)
+
+
+####################################################
+## 7. 高级用法
+####################################################
+
+# 用生成器(generators)方便地写惰性运算
+def double_numbers(iterable):
+ for i in iterable:
+ yield i + i
+
+# 生成器只有在需要时才计算下一个值。它们每一次循环只生成一个值,而不是把所有的
+# 值全部算好。这意味着double_numbers不会生成大于15的数字。
+#
+# range的返回值也是一个生成器,不然一个1到900000000的列表会花很多时间和内存。
+#
+# 如果你想用一个Python的关键字当作变量名,可以加一个下划线来区分。
+range_ = range(1, 900000000)
+# 当找到一个 >=30 的结果就会停
+for i in double_numbers(range_):
+ print(i)
+ if i >= 30:
+ break
+
+
+# 装饰器(decorators)
+# 这个例子中,beg装饰say
+# beg会先调用say。如果返回的say_please为真,beg会改变返回的字符串。
+from functools import wraps
+
+
+def beg(target_function):
+ @wraps(target_function)
+ def wrapper(*args, **kwargs):
+ msg, say_please = target_function(*args, **kwargs)
+ if say_please:
+ return "{} {}".format(msg, "Please! I am poor :(")
+ return msg
+
+ return wrapper
+
+
+@beg
+def say(say_please=False):
+ msg = "Can you buy me a beer?"
+ return msg, say_please
+
+
+print(say()) # Can you buy me a beer?
+print(say(say_please=True)) # Can you buy me a beer? Please! I am poor :(
+```
+
+## 想继续学吗?
+
+### 线上免费材料(英文)
+
+* [Learn Python The Hard Way](http://learnpythonthehardway.org/book/)
+* [Dive Into Python](http://www.diveintopython.net/)
+* [Ideas for Python Projects](http://pythonpracticeprojects.com)
+
+* [The Official Docs](http://docs.python.org/3/)
+* [Hitchhiker's Guide to Python](http://docs.python-guide.org/en/latest/)
+* [Python Module of the Week](http://pymotw.com/3/)
+* [A Crash Course in Python for Scientists](http://nbviewer.ipython.org/5920182)
+
+### 书籍(也是英文)
+
+* [Programming Python](http://www.amazon.com/gp/product/0596158106/ref=as_li_qf_sp_asin_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596158106&linkCode=as2&tag=homebits04-20)
+* [Dive Into Python](http://www.amazon.com/gp/product/1441413022/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=1441413022&linkCode=as2&tag=homebits04-20)
+* [Python Essential Reference](http://www.amazon.com/gp/product/0672329786/ref=as_li_tf_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0672329786&linkCode=as2&tag=homebits04-20)
+
diff --git a/zh-cn/r-cn.html.markdown b/zh-cn/r-cn.html.markdown
index 19c5f25d..0c46bc22 100644
--- a/zh-cn/r-cn.html.markdown
+++ b/zh-cn/r-cn.html.markdown
@@ -13,7 +13,7 @@ lang: zh-cn
R 是一门统计语言。它有很多数据分析和挖掘程序包。可以用来统计、分析和制图。
你也可以在 LaTeX 文档中运行 `R` 命令。
-```python
+```r
# 评论以 # 开始
# R 语言原生不支持 多行注释
diff --git a/zh-cn/ruby-cn.html.markdown b/zh-cn/ruby-cn.html.markdown
index 3c47f3f9..14d38137 100644
--- a/zh-cn/ruby-cn.html.markdown
+++ b/zh-cn/ruby-cn.html.markdown
@@ -7,6 +7,7 @@ contributors:
- ["Joel Walden", "http://joelwalden.net"]
- ["Luke Holder", "http://twitter.com/lukeholder"]
- ["lidashuang", "https://github.com/lidashuang"]
+ - ["ftwbzhao", "https://github.com/ftwbzhao"]
translators:
- ["Lin Xiangyu", "https://github.com/oa414"]
---
@@ -40,7 +41,7 @@ translators:
1.+(3) #=> 4
10.* 5 #=> 50
-# 特殊的只也是对象
+# 特殊的值也是对象
nil # 空
true # 真
false # 假
@@ -120,11 +121,11 @@ status == :approved #=> false
# 数组
# 这是一个数组
-[1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5]
+array = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5]
# 数组可以包含不同类型的元素
-array = [1, "hello", false] #=> => [1, "hello", false]
+[1, "hello", false] #=> [1, "hello", false]
# 数组可以被索引
# 从前面开始
@@ -140,8 +141,8 @@ array.[] 12 #=> nil
# 从尾部开始
array[-1] #=> 5
-# 同时指定开始的位置和结束的位置
-array[2, 4] #=> [3, 4, 5]
+# 同时指定开始的位置和长度
+array[2, 3] #=> [3, 4, 5]
# 或者指定一个范围
array[1..3] #=> [2, 3, 4]
diff --git a/zh-cn/rust-cn.html.markdown b/zh-cn/rust-cn.html.markdown
new file mode 100644
index 00000000..17a897df
--- /dev/null
+++ b/zh-cn/rust-cn.html.markdown
@@ -0,0 +1,296 @@
+---
+language: rust
+contributors:
+ - ["P1start", "http://p1start.github.io/"]
+translators:
+ - ["Guangming Mao", "http://maogm.com"]
+filename: learnrust-cn.rs
+lang: zh-cn
+---
+
+Rust 是由 Mozilla 研究院开发的编程语言。Rust 将底层的性能控制与高级语言的便利性和安全保障结合在了一起。
+
+而 Rust 并不需要一个垃圾回收器或者运行时即可实现这个目的,这使得 Rust 库可以成为一种 C 语言的替代品。
+
+Rust 第一版(0.1 版)发布于 2012 年 1 月,3 年以来一直在紧锣密鼓地迭代。
+因为更新太频繁,一般建议使用每夜构建版而不是稳定版,直到最近 1.0 版本的发布。
+
+2015 年 3 月 15 日,Rust 1.0 发布,完美向后兼容,最新的每夜构建版提供了缩短编译时间等新特性。
+Rust 采用了持续迭代模型,每 6 周一个发布版。Rust 1.1 beta 版在 1.0 发布时同时发布。
+
+尽管 Rust 相对来说是一门底层语言,它提供了一些常见于高级语言的函数式编程的特性。这让 Rust 不仅高效,并且易用。
+
+```rust
+// 这是注释,单行注释...
+/* ...这是多行注释 */
+
+///////////////
+// 1. 基础 //
+///////////////
+
+// 函数 (Functions)
+// `i32` 是有符号 32 位整数类型(32-bit signed integers)
+fn add2(x: i32, y: i32) -> i32 {
+ // 隐式返回 (不要分号)
+ x + y
+}
+
+// 主函数(Main function)
+fn main() {
+ // 数字 (Numbers) //
+
+ // 不可变绑定
+ let x: i32 = 1;
+
+ // 整形/浮点型数 后缀
+ let y: i32 = 13i32;
+ let f: f64 = 1.3f64;
+
+ // 类型推导
+ // 大部分时间,Rust 编译器会推导变量类型,所以不必把类型显式写出来。
+ // 这个教程里面很多地方都显式写了类型,但是只是为了示范。
+ // 绝大部分时间可以交给类型推导。
+ let implicit_x = 1;
+ let implicit_f = 1.3;
+
+ // 算术运算
+ let sum = x + y + 13;
+
+ // 可变变量
+ let mut mutable = 1;
+ mutable = 4;
+ mutable += 2;
+
+ // 字符串 (Strings) //
+
+ // 字符串字面量
+ let x: &str = "hello world!";
+
+ // 输出
+ println!("{} {}", f, x); // 1.3 hello world
+
+ // 一个 `String` – 在堆上分配空间的字符串
+ let s: String = "hello world".to_string();
+
+ // 字符串分片(slice) - 另一个字符串的不可变视图
+ // 基本上就是指向一个字符串的不可变指针,它不包含字符串里任何内容,只是一个指向某个东西的指针
+ // 比如这里就是 `s`
+ let s_slice: &str = &s;
+
+ println!("{} {}", s, s_slice); // hello world hello world
+
+ // 数组 (Vectors/arrays) //
+
+ // 长度固定的数组 (array)
+ let four_ints: [i32; 4] = [1, 2, 3, 4];
+
+ // 变长数组 (vector)
+ let mut vector: Vec<i32> = vec![1, 2, 3, 4];
+ vector.push(5);
+
+ // 分片 - 某个数组(vector/array)的不可变视图
+ // 和字符串分片基本一样,只不过是针对数组的
+ let slice: &[i32] = &vector;
+
+ // 使用 `{:?}` 按调试样式输出
+ println!("{:?} {:?}", vector, slice); // [1, 2, 3, 4, 5] [1, 2, 3, 4, 5]
+
+ // 元组 (Tuples) //
+
+ // 元组是固定大小的一组值,可以是不同类型
+ let x: (i32, &str, f64) = (1, "hello", 3.4);
+
+ // 解构 `let`
+ let (a, b, c) = x;
+ println!("{} {} {}", a, b, c); // 1 hello 3.4
+
+ // 索引
+ println!("{}", x.1); // hello
+
+ //////////////
+ // 2. 类型 (Type) //
+ //////////////
+
+ // 结构体(Sturct)
+ struct Point {
+ x: i32,
+ y: i32,
+ }
+
+ let origin: Point = Point { x: 0, y: 0 };
+
+ // 匿名成员结构体,又叫“元组结构体”(‘tuple struct’)
+ struct Point2(i32, i32);
+
+ let origin2 = Point2(0, 0);
+
+ // 基础的 C 风格枚举类型(enum)
+ enum Direction {
+ Left,
+ Right,
+ Up,
+ Down,
+ }
+
+ let up = Direction::Up;
+
+ // 有成员的枚举类型
+ enum OptionalI32 {
+ AnI32(i32),
+ Nothing,
+ }
+
+ let two: OptionalI32 = OptionalI32::AnI32(2);
+ let nothing = OptionalI32::Nothing;
+
+ // 泛型 (Generics) //
+
+ struct Foo<T> { bar: T }
+
+ // 这个在标准库里面有实现,叫 `Option`
+ enum Optional<T> {
+ SomeVal(T),
+ NoVal,
+ }
+
+ // 方法 (Methods) //
+
+ impl<T> Foo<T> {
+ // 方法需要一个显式的 `self` 参数
+ fn get_bar(self) -> T {
+ self.bar
+ }
+ }
+
+ let a_foo = Foo { bar: 1 };
+ println!("{}", a_foo.get_bar()); // 1
+
+ // 接口(Traits) (其他语言里叫 interfaces 或 typeclasses) //
+
+ trait Frobnicate<T> {
+ fn frobnicate(self) -> Option<T>;
+ }
+
+ impl<T> Frobnicate<T> for Foo<T> {
+ fn frobnicate(self) -> Option<T> {
+ Some(self.bar)
+ }
+ }
+
+ let another_foo = Foo { bar: 1 };
+ println!("{:?}", another_foo.frobnicate()); // Some(1)
+
+ ///////////////////////////////////
+ // 3. 模式匹配 (Pattern matching) //
+ ///////////////////////////////////
+
+ let foo = OptionalI32::AnI32(1);
+ match foo {
+ OptionalI32::AnI32(n) => println!("it’s an i32: {}", n),
+ OptionalI32::Nothing => println!("it’s nothing!"),
+ }
+
+ // 高级模式匹配
+ struct FooBar { x: i32, y: OptionalI32 }
+ let bar = FooBar { x: 15, y: OptionalI32::AnI32(32) };
+
+ match bar {
+ FooBar { x: 0, y: OptionalI32::AnI32(0) } =>
+ println!("The numbers are zero!"),
+ FooBar { x: n, y: OptionalI32::AnI32(m) } if n == m =>
+ println!("The numbers are the same"),
+ FooBar { x: n, y: OptionalI32::AnI32(m) } =>
+ println!("Different numbers: {} {}", n, m),
+ FooBar { x: _, y: OptionalI32::Nothing } =>
+ println!("The second number is Nothing!"),
+ }
+
+ ///////////////////////////////
+ // 4. 流程控制 (Control flow) //
+ ///////////////////////////////
+
+ // `for` 循环
+ let array = [1, 2, 3];
+ for i in array.iter() {
+ println!("{}", i);
+ }
+
+ // 区间 (Ranges)
+ for i in 0u32..10 {
+ print!("{} ", i);
+ }
+ println!("");
+ // 输出 `0 1 2 3 4 5 6 7 8 9 `
+
+ // `if`
+ if 1 == 1 {
+ println!("Maths is working!");
+ } else {
+ println!("Oh no...");
+ }
+
+ // `if` 可以当表达式
+ let value = if true {
+ "good"
+ } else {
+ "bad"
+ };
+
+ // `while` 循环
+ while 1 == 1 {
+ println!("The universe is operating normally.");
+ }
+
+ // 无限循环
+ loop {
+ println!("Hello!");
+ }
+
+ ////////////////////////////////////////////////
+ // 5. 内存安全和指针 (Memory safety & pointers) //
+ ////////////////////////////////////////////////
+
+ // 独占指针 (Owned pointer) - 同一时刻只能有一个对象能“拥有”这个指针
+ // 意味着 `Box` 离开他的作用域后,会被安全地释放
+ let mut mine: Box<i32> = Box::new(3);
+ *mine = 5; // 解引用
+ // `now_its_mine` 获取了 `mine` 的所有权。换句话说,`mine` 移动 (move) 了
+ let mut now_its_mine = mine;
+ *now_its_mine += 2;
+
+ println!("{}", now_its_mine); // 7
+ // println!("{}", mine); // 编译报错,因为现在 `now_its_mine` 独占那个指针
+
+ // 引用 (Reference) – 引用其他数据的不可变指针
+ // 当引用指向某个值,我们称为“借用”这个值,因为是被不可变的借用,所以不能被修改,也不能移动
+ // 借用一直持续到生命周期结束,即离开作用域
+ let mut var = 4;
+ var = 3;
+ let ref_var: &i32 = &var;
+
+ println!("{}", var); //不像 `box`, `var` 还可以继续使用
+ println!("{}", *ref_var);
+ // var = 5; // 编译报错,因为 `var` 被借用了
+ // *ref_var = 6; // 编译报错,因为 `ref_var` 是不可变引用
+
+ // 可变引用 (Mutable reference)
+ // 当一个变量被可变地借用时,也不可使用
+ let mut var2 = 4;
+ let ref_var2: &mut i32 = &mut var2;
+ *ref_var2 += 2;
+
+ println!("{}", *ref_var2); // 6
+ // var2 = 2; // 编译报错,因为 `var2` 被借用了
+}
+```
+
+## 更深入的资料
+
+Rust 还有很多很多其他内容 - 这只是 Rust 最基本的功能,帮助你了解 Rust 里面最重要的东西。
+如果想深入学习 Rust,可以去读
+[The Rust Programming Language](http://doc.rust-lang.org/book/index.html)
+或者上 reddit [/r/rust](http://reddit.com/r/rust) 订阅。
+同时 irc.mozilla.org 的 #rust 频道上的小伙伴们也非常欢迎新来的朋友。
+
+你可以在这个在线编译器 [Rust playpen](http://play.rust-lang.org) 上尝试 Rust 的一些特性
+或者上[官方网站](http://rust-lang.org).
diff --git a/zh-cn/scala-cn.html.markdown b/zh-cn/scala-cn.html.markdown
index 28af8ddc..508dd58e 100644
--- a/zh-cn/scala-cn.html.markdown
+++ b/zh-cn/scala-cn.html.markdown
@@ -4,36 +4,47 @@ filename: learnscala-zh.scala
contributors:
- ["George Petrov", "http://github.com/petrovg"]
- ["Dominic Bou-Samra", "http://dbousamra.github.com"]
+ - ["Geoff Liu", "http://geoffliu.me"]
translators:
- ["Peiyong Lin", ""]
+ - ["Jinchang Ye", "http://github.com/alwayswithme"]
+ - ["Guodong Qu", "https://github.com/jasonqu"]
lang: zh-cn
---
-Scala - 一门可拓展性的语言
+Scala - 一门可拓展的语言
-```cpp
+```scala
/*
自行设置:
1) 下载 Scala - http://www.scala-lang.org/downloads
- 2) unzip/untar 到你喜欢的地方,放在路径中的 bin 目录下
- 3) 在终端输入 scala,开启 Scala 的 REPL,你会看到提示符:
+ 2) unzip/untar 到您喜欢的地方,并把 bin 子目录添加到 path 环境变量
+ 3) 在终端输入 scala,启动 Scala 的 REPL,您会看到提示符:
scala>
- 这就是所谓的 REPL,你现在可以在其中运行命令,让我们做到这一点:
+ 这就是所谓的 REPL (读取-求值-输出循环,英语: Read-Eval-Print Loop),
+ 您可以在其中输入合法的表达式,结果会被打印。
+ 在教程中我们会进一步解释 Scala 文件是怎样的,但现在先了解一点基础。
*/
-println(10) // 打印整数 10
-println("Boo!") // 打印字符串 "BOO!"
+/////////////////////////////////////////////////
+// 1. 基础
+/////////////////////////////////////////////////
+// 单行注释开始于两个斜杠
-// 一些基础
+/*
+ 多行注释,如您之前所见,看起来像这样
+*/
// 打印并强制换行
println("Hello world!")
+println(10)
+
// 没有强制换行的打印
print("Hello world")
@@ -41,13 +52,19 @@ print("Hello world")
// val 声明是不可变的,var 声明是可修改的。不可变性是好事。
val x = 10 // x 现在是 10
x = 20 // 错误: 对 val 声明的变量重新赋值
-var x = 10
-x = 20 // x 现在是 20
+var y = 10
+y = 20 // y 现在是 20
-// 单行注释开始于两个斜杠
-/*
-多行注释看起来像这样。
+/*
+ Scala 是静态语言,但注意上面的声明方式,我们没有指定类型。
+ 这是因为类型推导的语言特性。大多数情况, Scala 编译器可以推测变量的类型,
+ 所以您不需要每次都输入。可以像这样明确声明变量类型:
*/
+val z: Int = 10
+val a: Double = 1.0
+
+// 注意从 Int 到 Double 的自动转型,结果是 10.0, 不是 10
+val b: Double = 10
// 布尔值
true
@@ -64,9 +81,11 @@ true == false // false
2 - 1 // 1
5 * 3 // 15
6 / 2 // 3
+6 / 4 // 1
+6.0 / 4 // 1.5
-// 在 REPL 计算一个命令会返回给你结果的类型和值
+// 在 REPL 计算一个表达式会返回给您结果的类型和值
1 + 7
@@ -77,58 +96,190 @@ true == false // false
这意味着计算 1 + 7 的结果是一个 Int 类型的对象,其值为 8
- 1+7 的结果是一样的
+ 注意 "res29" 是一个连续生成的变量名,用以存储您输入的表达式结果,
+ 您看到的输出可能不一样。
*/
+"Scala strings are surrounded by double quotes"
+'a' // Scala 的字符
+// '不存在单引号字符串' <= 这会导致错误
-// 包括函数在内,每一个事物都是对象。在 REPL 中输入:
+// String 有常见的 Java 字符串方法
+"hello world".length
+"hello world".substring(2, 6)
+"hello world".replace("C", "3")
-7 // 结果 res30: Int = 7 (res30 是一个生成的结果的 var 命名)
+// 也有一些额外的 Scala 方法,另请参见:scala.collection.immutable.StringOps
+"hello world".take(5)
+"hello world".drop(5)
-// 下一行给你一个接收一个 Int 类型并返回该数的平方的函数
-(x:Int) => x * x
+// 字符串改写:留意前缀 "s"
+val n = 45
+s"We have $n apples" // => "We have 45 apples"
-// 你可以分配给函数一个标识符,像这样:
-val sq = (x:Int) => x * x
+// 在要改写的字符串中使用表达式也是可以的
+val a = Array(11, 9, 6)
+s"My second daughter is ${a(0) - a(2)} years old." // => "My second daughter is 5 years old."
+s"We have double the amount of ${n / 2.0} in apples." // => "We have double the amount of 22.5 in apples."
+s"Power of 2: ${math.pow(2, 2)}" // => "Power of 2: 4"
-/* 上面的例子说明
-
- sq: Int => Int = <function1>
+// 添加 "f" 前缀对要改写的字符串进行格式化
+f"Power of 5: ${math.pow(5, 2)}%1.0f" // "Power of 5: 25"
+f"Square root of 122: ${math.sqrt(122)}%1.4f" // "Square root of 122: 11.0454"
- 意味着这次我们给予了 sq 这样一个显式的名字给一个接受一个 Int 类型值并返回 一个 Int 类型值的函数
+// 未处理的字符串,忽略特殊字符。
+raw"New line feed: \n. Carriage return: \r." // => "New line feed: \n. Carriage return: \r."
- sq 可以像下面那样被执行:
-*/
+// 一些字符需要转义,比如字符串中的双引号
+"They stood outside the \"Rose and Crown\"" // => "They stood outside the "Rose and Crown""
-sq(10) // 返回给你:res33: Int = 100.
+// 三个双引号可以使字符串跨越多行,并包含引号
+val html = """<form id="daform">
+ <p>Press belo', Joe</p>
+ <input type="submit">
+ </form>"""
-// Scala 允许方法和函数返回或者接受其它的函数或者方法作为参数。
-val add10: Int => Int = _ + 10 // 一个接受一个 Int 类型参数并返回一个 Int 类型值的函数
-List(1, 2, 3) map add10 // List(11, 12, 13) - add10 被应用到每一个元素
+/////////////////////////////////////////////////
+// 2. 函数
+/////////////////////////////////////////////////
+
+// 函数可以这样定义:
+//
+// def functionName(args...): ReturnType = { body... }
+//
+// 如果您以前学习过传统的编程语言,注意 return 关键字的省略。
+// 在 Scala 中, 函数代码块最后一条表达式就是返回值。
+def sumOfSquares(x: Int, y: Int): Int = {
+ val x2 = x * x
+ val y2 = y * y
+ x2 + y2
+}
-// 匿名函数可以被使用来代替有命名的函数:
-List(1, 2, 3) map (x => x + 10)
+// 如果函数体是单行表达式,{ } 可以省略:
+def sumOfSquaresShort(x: Int, y: Int): Int = x * x + y * y
-// 下划线标志,如果匿名函数只有一个参数可以被使用来表示该参数变量
-List(1, 2, 3) map (_ + 10)
+// 函数调用的语法是熟知的:
+sumOfSquares(3, 4) // => 25
-// 如果你所应用的匿名块和匿名函数都接受一个参数,那么你甚至可以省略下划线
-List("Dom", "Bob", "Natalia") foreach println
+// 在多数情况下 (递归函数是需要注意的例外), 函数返回值可以省略,
+// 变量所用的类型推导一样会应用到函数返回值中:
+def sq(x: Int) = x * x // 编译器会推断得知返回值是 Int
+// 函数可以有默认参数
+def addWithDefault(x: Int, y: Int = 5) = x + y
+addWithDefault(1, 2) // => 3
+addWithDefault(1) // => 6
-// 数据结构
+// 匿名函数是这样的:
+(x:Int) => x * x
+
+// 和 def 不同,如果语义清晰,匿名函数的参数类型也可以省略。
+// 类型 "Int => Int" 意味着这个函数接收一个 Int 并返回一个 Int。
+val sq: Int => Int = x => x * x
+
+// 匿名函数的调用也是类似的:
+sq(10) // => 100
+
+// 如果您的匿名函数中每个参数仅使用一次,
+// Scala 提供一个更简洁的方式来定义他们。这样的匿名函数极为常见,
+// 在数据结构部分会明显可见。
+val addOne: Int => Int = _ + 1
+val weirdSum: (Int, Int) => Int = (_ * 2 + _ * 3)
+
+addOne(5) // => 6
+weirdSum(2, 4) // => 16
+
+
+// return 关键字是存在的,但它只从最里面包裹了 return 的 def 函数中返回。
+// 警告: 在 Scala 中使用 return 容易出错,应该避免使用。
+// 在匿名函数中没有效果,例如:
+def foo(x: Int): Int = {
+ val anonFunc: Int => Int = { z =>
+ if (z > 5)
+ return z // 这一行令 z 成为 foo 函数的返回值!
+ else
+ z + 2 // 这一行是 anonFunc 函数的返回值
+ }
+ anonFunc(x) // 这一行是 foo 函数的返回值
+}
+
+/*
+ * 译者注:此处是指匿名函数中的 return z 成为最后执行的语句,
+ * 在 anonFunc(x) 下面的表达式(假设存在)不再执行。如果 anonFunc
+ * 是用 def 定义的函数, return z 仅返回到 anonFunc(x) ,
+ * 在 anonFunc(x) 下面的表达式(假设存在)会继续执行。
+ */
+
+
+/////////////////////////////////////////////////
+// 3. 控制语句
+/////////////////////////////////////////////////
+
+1 to 5
+val r = 1 to 5
+r.foreach( println )
+
+r foreach println
+// 附注: Scala 对点和括号的要求想当宽松,注意其规则是不同的。
+// 这有助于写出读起来像英语的 DSL(领域特定语言) 和 API(应用编程接口)。
+
+(5 to 1 by -1) foreach ( println )
+
+// while 循环
+var i = 0
+while (i < 10) { println("i " + i); i+=1 }
+
+while (i < 10) { println("i " + i); i+=1 } // 没错,再执行一次,发生了什么?为什么?
+
+i // 显示 i 的值。注意 while 是经典的循环方式,它连续执行并改变循环中的变量。
+ // while 执行很快,比 Java 的循环快,但像上面所看到的那样用组合子和推导式
+ // 更易于理解和并行化。
+
+// do while 循环
+do {
+ println("x is still less than 10");
+ x += 1
+} while (x < 10)
+
+// Scala 中尾递归是一种符合语言习惯的递归方式。
+// 递归函数需要清晰的返回类型,编译器不能推断得知。
+// 这是一个 Unit。
+def showNumbersInRange(a:Int, b:Int):Unit = {
+ print(a)
+ if (a < b)
+ showNumbersInRange(a + 1, b)
+}
+showNumbersInRange(1,14)
+
+
+// 条件语句
+
+val x = 10
+
+if (x == 1) println("yeah")
+if (x == 10) println("yeah")
+if (x == 11) println("yeah")
+if (x == 11) println ("yeah") else println("nay")
+
+println(if (x == 10) "yeah" else "nope")
+val text = if (x == 10) "yeah" else "nope"
+
+
+/////////////////////////////////////////////////
+// 4. 数据结构
+/////////////////////////////////////////////////
val a = Array(1, 2, 3, 5, 8, 13)
a(0)
a(3)
-a(21) // 这会抛出一个异常
+a(21) // 抛出异常
val m = Map("fork" -> "tenedor", "spoon" -> "cuchara", "knife" -> "cuchillo")
m("fork")
m("spoon")
-m("bottle") // 这会抛出一个异常
+m("bottle") // 抛出异常
val safeM = m.withDefaultValue("no lo se")
safeM("bottle")
@@ -137,9 +288,9 @@ val s = Set(1, 3, 7)
s(0)
s(1)
-/* 查看 map 的文档
- * 点击[这里](http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.Map)
- * 确保你可以读它
+/* 这里查看 map 的文档 -
+ * http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.Map
+ * 并确保你会阅读
*/
@@ -154,13 +305,11 @@ s(1)
(a, 2, "three")
// 为什么有这个?
-
val divideInts = (x:Int, y:Int) => (x / y, x % y)
-divideInts(10,3) // 函数 divideInts 返回你结果和余数
+divideInts(10,3) // 函数 divideInts 同时返回结果和余数
// 要读取元组的元素,使用 _._n,n是从1开始的元素索引
-
val d = divideInts(10,3)
d._1
@@ -168,234 +317,289 @@ d._1
d._2
+/////////////////////////////////////////////////
+// 5. 面向对象编程
+/////////////////////////////////////////////////
-// 选择器
-
-s.map(sq)
-
-val sSquared = s. map(sq)
-
-sSquared.filter(_ < 10)
+/*
+ 旁白: 教程中到现在为止我们所做的一切只是简单的表达式(值,函数等)。
+ 这些表达式可以输入到命令行解释器中作为快速测试,但它们不能独立存在于 Scala
+ 文件。举个例子,您不能在 Scala 文件上简单的写上 "val x = 5"。相反 Scala 文件
+ 允许的顶级结构是:
-sSquared.reduce (_+_)
+ - objects
+ - classes
+ - case classes
+ - traits
-// filter 函数接受一个预测(一个函数,形式为 A -> Boolean) 并选择出所有的元素满足这个预测
+ 现在来解释这些是什么。
+*/
-List(1, 2, 3) filter (_ > 2) // List(3)
-List(
- Person(name = "Dom", age = 23),
- Person(name = "Bob", age = 30)
-).filter(_.age > 25) // List(Person("Bob", 30))
+// 类和其他语言的类相似,构造器参数在类名后声明,初始化在类结构体中完成。
+class Dog(br: String) {
+ // 构造器代码在此
+ var breed: String = br
+ // 定义名为 bark 的方法,返回字符串
+ def bark = "Woof, woof!"
-// Scala 的 foreach 方法定义在特定的接受一个类型的集合上
-// 返回 Unit(一个 void 方法)
-aListOfNumbers foreach (x => println(x))
-aListOfNumbers foreach println
+ // 值和方法作用域假定为 public。"protected" 和 "private" 关键字也是可用的。
+ private def sleep(hours: Int) =
+ println(s"I'm sleeping for $hours hours")
+ // 抽象方法是没有方法体的方法。如果取消下面那行注释,Dog 类必须被声明为 abstract
+ // abstract class Dog(...) { ... }
+ // def chaseAfter(what: String): String
+}
+val mydog = new Dog("greyhound")
+println(mydog.breed) // => "greyhound"
+println(mydog.bark) // => "Woof, woof!"
-// For 包含
+// "object" 关键字创造一种类型和该类型的单例。
+// Scala 的 class 常常也含有一个 “伴生对象”,class 中包含每个实例的行为,所有实例
+// 共用的行为则放入 object 中。两者的区别和其他语言中类方法和静态方法类似。
+// 请注意 object 和 class 可以同名。
+object Dog {
+ def allKnownBreeds = List("pitbull", "shepherd", "retriever")
+ def createDog(breed: String) = new Dog(breed)
+}
-for { n <- s } yield sq(n)
-val nSquared2 = for { n <- s } yield sq(n)
+// Case 类是有额外内建功能的类。Scala 初学者常遇到的问题之一便是何时用类
+// 和何时用 case 类。界线比较模糊,但通常类倾向于封装,多态和行为。类中的值
+// 的作用域一般为 private , 只有方向是暴露的。case 类的主要目的是放置不可变
+// 数据。它们通常只有几个方法,且方法几乎没有副作用。
+case class Person(name: String, phoneNumber: String)
-for { n <- nSquared2 if n < 10 } yield n
+// 创造新实例,注意 case 类不需要使用 "new" 关键字
+val george = Person("George", "1234")
+val kate = Person("Kate", "4567")
-for { n <- s; nSquared = n * n if nSquared < 10} yield nSquared
+// 使用 case 类,您可以轻松得到一些功能,像 getters:
+george.phoneNumber // => "1234"
-/* 注意:这些不是 for 循环. 一个 for 循环的语义是 '重复'('repeat'),
- 然而,一个 for-包含 定义了一个两个数据结合间的关系 */
+// 每个字段的相等性比较(无需覆盖 .equals)
+Person("George", "1234") == Person("Kate", "1236") // => false
+// 简单的拷贝方式
+// otherGeorge == Person("george", "9876")
+val otherGeorge = george.copy(phoneNumber = "9876")
+// 还有很多。case 类同时可以用于模式匹配,接下来会看到。
-// 循环和迭代
-1 to 5
-val r = 1 to 5
-r.foreach( println )
+// 敬请期待 Traits !
-r foreach println
-// 注意:Scala 是相当宽容的当它遇到点和括号 - 分别地学习这些规则。
-// 这帮助你编写读起来像英语的 DSLs 和 APIs
-(5 to 1 by -1) foreach ( println )
+/////////////////////////////////////////////////
+// 6. 模式匹配
+/////////////////////////////////////////////////
-// while 循环
-var i = 0
-while (i < 10) { println("i " + i); i+=1 }
-
-while (i < 10) { println("i " + i); i+=1 } // 发生了什么?为什么?
-
-i // 展示 i 的值。注意到 while 是一个传统意义上的循环
- // 它顺序地执行并且改变循环变量的值。while 非常快,比 Java // 循环快,
- // 但是在其上使用选择器和包含更容易理解和并行。
-
-// do while 循环
-do {
- println("x is still less then 10");
- x += 1
-} while (x < 10)
+// 模式匹配是一个强大和常用的 Scala 特性。这是用模式匹配一个 case 类的例子。
+// 附注:不像其他语言, Scala 的 case 不需要 break, 其他语言中 switch 语句的
+// fall-through 现象不会发生。
-// 在 Scala中,尾递归是一种惯用的执行循环的方式。
-// 递归函数需要显示的返回类型,编译器不能推断出类型。
-// 这里它是 Unit。
-def showNumbersInRange(a:Int, b:Int):Unit = {
- print(a)
- if (a < b)
- showNumbersInRange(a + 1, b)
+def matchPerson(person: Person): String = person match {
+ // Then you specify the patterns:
+ case Person("George", number) => "We found George! His number is " + number
+ case Person("Kate", number) => "We found Kate! Her number is " + number
+ case Person(name, number) => "We matched someone : " + name + ", phone : " + number
}
+val email = "(.*)@(.*)".r // 定义下一个例子会用到的正则
+// 模式匹配看起来和 C语言家族的 switch 语句相似,但更为强大。
+// Scala 中您可以匹配很多东西:
+def matchEverything(obj: Any): String = obj match {
+ // 匹配值:
+ case "Hello world" => "Got the string Hello world"
-// 条件语句
-
-val x = 10
-
-if (x == 1) println("yeah")
-if (x == 10) println("yeah")
-if (x == 11) println("yeah")
-if (x == 11) println ("yeah") else println("nay")
+ // 匹配类型:
+ case x: Double => "Got a Double: " + x
-println(if (x == 10) "yeah" else "nope")
-val text = if (x == 10) "yeah" else "nope"
+ // 匹配时指定条件
+ case x: Int if x > 10000 => "Got a pretty big number!"
-var i = 0
-while (i < 10) { println("i " + i); i+=1 }
+ // 像之前一样匹配 case 类:
+ case Person(name, number) => s"Got contact info for $name!"
+ // 匹配正则表达式:
+ case email(name, domain) => s"Got email address $name@$domain"
+ // 匹配元组:
+ case (a: Int, b: Double, c: String) => s"Got a tuple: $a, $b, $c"
-// 面向对象特性
+ // 匹配数据结构:
+ case List(1, b, c) => s"Got a list with three elements and starts with 1: 1, $b, $c"
-// 类名是 Dog
-class Dog {
- //bark 方法,返回字符串
- def bark: String = {
- // the body of the method
- "Woof, woof!"
- }
+ // 模式可以嵌套
+ case List(List((1, 2,"YAY"))) => "Got a list of list of tuple"
}
-// 类可以包含几乎其它的构造,包括其它的类,
-// 函数,方法,对象,case 类,特性等等。
-
-
+// 事实上,你可以对任何有 "unapply" 方法的对象进行模式匹配。
+// 这个特性如此强大以致于 Scala 允许定义一个函数作为模式匹配:
+val patternFunc: Person => String = {
+ case Person("George", number) => s"George's number: $number"
+ case Person(name, number) => s"Random person's number: $number"
+}
-// Case 类
-case class Person(name:String, phoneNumber:String)
+/////////////////////////////////////////////////
+// 7. 函数式编程
+/////////////////////////////////////////////////
-Person("George", "1234") == Person("Kate", "1236")
+// Scala 允许方法和函数作为其他方法和函数的参数和返回值。
+val add10: Int => Int = _ + 10 // 一个接受一个 Int 类型参数并返回一个 Int 类型值的函数
+List(1, 2, 3) map add10 // List(11, 12, 13) - add10 被应用到每一个元素
+// 匿名函数可以被使用来代替有命名的函数:
+List(1, 2, 3) map (x => x + 10)
+// 如果匿名函数只有一个参数可以用下划线作为变量
+List(1, 2, 3) map (_ + 10)
-// 模式匹配
+// 如果您所应用的匿名块和匿名函数都接受一个参数,那么你甚至可以省略下划线
+List("Dom", "Bob", "Natalia") foreach println
-val me = Person("George", "1234")
-me match { case Person(name, number) => {
- "We matched someone : " + name + ", phone : " + number }}
+// 组合子
-me match { case Person(name, number) => "Match : " + name; case _ => "Hm..." }
+// 译注: val sq: Int => Int = x => x * x
+s.map(sq)
-me match { case Person("George", number) => "Match"; case _ => "Hm..." }
+val sSquared = s. map(sq)
-me match { case Person("Kate", number) => "Match"; case _ => "Hm..." }
+sSquared.filter(_ < 10)
-me match { case Person("Kate", _) => "Girl"; case Person("George", _) => "Boy" }
+sSquared.reduce (_+_)
-val kate = Person("Kate", "1234")
+// filter 函数接受一个 predicate (函数根据条件 A 返回 Boolean)并选择
+// 所有满足 predicate 的元素
+List(1, 2, 3) filter (_ > 2) // List(3)
+case class Person(name:String, age:Int)
+List(
+ Person(name = "Dom", age = 23),
+ Person(name = "Bob", age = 30)
+).filter(_.age > 25) // List(Person("Bob", 30))
-kate match { case Person("Kate", _) => "Girl"; case Person("George", _) => "Boy" }
+// Scala 的 foreach 方法定义在某些集合中,接受一个函数并返回 Unit (void 方法)
+// 另请参见:
+// http://www.scala-lang.org/api/current/index.html#scala.collection.IterableLike@foreach(f:A=>Unit):Unit
+val aListOfNumbers = List(1, 2, 3, 4, 10, 20, 100)
+aListOfNumbers foreach (x => println(x))
+aListOfNumbers foreach println
+// For 推导式
-// 正则表达式
+for { n <- s } yield sq(n)
-val email = "(.*)@(.*)".r // 在字符串上调用 r 会使它变成一个正则表达式
+val nSquared2 = for { n <- s } yield sq(n)
-val email(user, domain) = "henry@zkpr.com"
+for { n <- nSquared2 if n < 10 } yield n
-"mrbean@pyahoo.com" match {
- case email(name, domain) => "I know your name, " + name
-}
+for { n <- s; nSquared = n * n if nSquared < 10} yield nSquared
+/* 注意,这些不是 for 循环,for 循环的语义是‘重复’,然而 for 推导式定义
+ 两个数据集合的关系。 */
-// 字符串
+/////////////////////////////////////////////////
+// 8. 隐式转换
+/////////////////////////////////////////////////
-"Scala 字符串被双引号包围" //
-'a' // Scala 字符
-'单引号的字符串不存在' // 错误
-"字符串拥有通常的 Java 方法定义在其上".length
-"字符串也有额外的 Scala 方法".reverse
+/* 警告 警告: 隐式转换是 Scala 中一套强大的特性,因此容易被滥用。
+ * Scala 初学者在理解它们的工作原理和最佳实践之前,应抵制使用它的诱惑。
+ * 我们加入这一章节仅因为它们在 Scala 的库中太过常见,导致没有用隐式转换的库
+ * 就不可能做有意义的事情。这章节主要让你理解和使用隐式转换,而不是自己声明。
+ */
-// 参见: scala.collection.immutable.StringOps
+// 可以通过 "implicit" 声明任何值(val, 函数,对象等)为隐式值,
+// 请注意这些例子中,我们用到第5部分的 Dog 类。
+implicit val myImplicitInt = 100
+implicit def myImplicitFunction(breed: String) = new Dog("Golden " + breed)
-println("ABCDEF".length)
-println("ABCDEF".substring(2, 6))
-println("ABCDEF".replace("C", "3"))
+// implicit 关键字本身不改变值的行为,所以上面的值可以照常使用。
+myImplicitInt + 2 // => 102
+myImplicitFunction("Pitbull").breed // => "Golden Pitbull"
-val n = 45
-println(s"We have $n apples")
+// 区别在于,当另一段代码“需要”隐式值时,这些值现在有资格作为隐式值。
+// 一种情况是隐式函数参数。
+def sendGreetings(toWhom: String)(implicit howMany: Int) =
+ s"Hello $toWhom, $howMany blessings to you and yours!"
-val a = Array(11, 9, 6)
-println(s"My second daughter is ${a(2-1)} years old")
+// 如果提供值给 “howMany”,函数正常运行
+sendGreetings("John")(1000) // => "Hello John, 1000 blessings to you and yours!"
-// 一些字符需要被转义,举例来说,字符串中的双引号:
-val a = "They stood outside the \"Rose and Crown\""
+// 如果省略隐式参数,会传一个和参数类型相同的隐式值,
+// 在这个例子中, 是 “myImplicitInt":
+sendGreetings("Jane") // => "Hello Jane, 100 blessings to you and yours!"
-// 三个双引号使得字符串可以跨行并且可以包含引号(无需转义)
+// 隐式的函数参数使我们可以模拟其他函数式语言的 type 类(type classes)。
+// 它经常被用到所以有特定的简写。这两行代码是一样的:
+def foo[T](implicit c: C[T]) = ...
+def foo[T : C] = ...
-val html = """<form id="daform">
- <p>Press belo', Joe</p>
- | <input type="submit">
- </form>"""
+// 编译器寻找隐式值另一种情况是你调用方法时
+// obj.method(...)
+// 但 "obj" 没有一个名为 "method" 的方法。这样的话,如果有一个参数类型为 A
+// 返回值类型为 B 的隐式转换,obj 的类型是 A,B 有一个方法叫 "method" ,这样
+// 转换就会被应用。所以作用域里有上面的 myImplicitFunction, 我们可以这样做:
+"Retriever".breed // => "Golden Retriever"
+"Sheperd".bark // => "Woof, woof!"
+// 这里字符串先被上面的函数转换为 Dog 对象,然后调用相应的方法。
+// 这是相当强大的特性,但再次提醒,请勿轻率使用。
+// 事实上,当你定义上面的隐式函数时,编译器会作出警告,除非你真的了解
+// 你正在做什么否则不要使用。
-// 应用结果和组织
+/////////////////////////////////////////////////
+// 9. 杂项
+/////////////////////////////////////////////////
-// import
+// 导入类
import scala.collection.immutable.List
-// Import 所有的子包
+// 导入所有子包
import scala.collection.immutable._
-// 在一条语句中 Import 多个类
+// 一条语句导入多个类
import scala.collection.immutable.{List, Map}
-// 使用 '=>' 来重命名一个 import
+// 使用 ‘=>’ 对导入进行重命名
import scala.collection.immutable.{ List => ImmutableList }
-// import 除了一些类的其它所有的类。下面的例子除去了 Map 类和 Set 类:
+// 导入所有类,排除其中一些。下面的语句排除了 Map 和 Set:
import scala.collection.immutable.{Map => _, Set => _, _}
-// 在 scala 源文件中,你的程序入口点使用一个拥有单一方法 main 的对象来定义:
-
+// 在 Scala 文件用 object 和单一的 main 方法定义程序入口:
object Application {
def main(args: Array[String]): Unit = {
// stuff goes here.
}
}
-// 文件可以包含多个类和对象。由 scalac 来编译
+// 文件可以包含多个 class 和 object,用 scalac 编译源文件
// 输入和输出
-// 一行一行读取文件
+// 按行读文件
import scala.io.Source
-for(line <- Source.fromPath("myfile.txt").getLines())
+for(line <- Source.fromFile("myfile.txt").getLines())
println(line)
-// 使用 Java 的 PrintWriter 来写文件
-
+// 用 Java 的 PrintWriter 写文件
+val writer = new PrintWriter("myfile.txt")
+writer.write("Writing line for line" + util.Properties.lineSeparator)
+writer.write("Another line here" + util.Properties.lineSeparator)
+writer.close()
```
diff --git a/zh-cn/swift-cn.html.markdown b/zh-cn/swift-cn.html.markdown
index c87f9d10..3efe4941 100644
--- a/zh-cn/swift-cn.html.markdown
+++ b/zh-cn/swift-cn.html.markdown
@@ -5,223 +5,610 @@ contributors:
- ["Grant Timmerman", "http://github.com/grant"]
translators:
- ["Xavier Yao", "http://github.com/xavieryao"]
+ - ["Joey Huang", "http://github.com/kamidox"]
+ - ["CY Lim", "http://github.com/cylim"]
lang: zh-cn
---
-Swift 是Apple 开发的用于iOS 和OS X 开发的编程语言。Swift 于2014年Apple WWDC (全球开发者大会)中被引入,用以与Objective-C 共存,同时对错误代码更具弹性。Swift 由Xcode 6 beta 中包含的LLVM编译器编译。
+Swift 是 Apple 开发的用于 iOS 和 OS X 开发的编程语言。Swift 于2014年 Apple WWDC (全球开发者大会)中被引入,用以与 Objective-C 共存,同时对错误代码更具弹性。Swift 由 Xcode 6 beta 中包含的 LLVM 编译器编译。
-参阅:Apple's [getting started guide](https://developer.apple.com/library/prerelease/ios/referencelibrary/GettingStarted/LandingPage/index.html) ——一个完整的Swift 教程
+Swift 的官方语言教程 [Swift Programming Language](https://itunes.apple.com/us/book/swift-programming-language/id881256329) 可以从 iBooks 免费下载.
+
+亦可参阅:Apple's [getting started guide](https://developer.apple.com/library/prerelease/ios/referencelibrary/GettingStarted/DevelopiOSAppsSwift/) ——一个完整的Swift 教程
+
+```swift
+// 导入外部模块
+import UIKit
-```js
//
-// 基础
+// MARK: 基础
//
-println("Hello, world")
+// XCODE 支持给注释代码作标记,这些标记会列在 XCODE 的跳转栏里,支持的标记为
+// MARK: 普通标记
+// TODO: TODO 标记
+// FIXME: FIXME 标记
+
+// Swift2.0 println() 及 print() 已经整合成 print()。
+print("Hello, world") // 这是原本的 println(),会自动进入下一行
+print("Hello, world", appendNewLine: false) // 如果不要自动进入下一行,需设定进入下一行为 false
+
+// 变量 (var) 的值设置后可以随意改变
+// 常量 (let) 的值设置后不能改变
var myVariable = 42
+let øπΩ = "value" // 可以支持 unicode 变量名
+let π = 3.1415926
let myConstant = 3.1415926
-let explicitDouble: Double = 70
-let label = "some text " + String(myVariable) // Casting
-let piText = "Pi = \(myConstant)" // String interpolation
-var optionalString: String? = "optional" // Can be nil
-optionalString = nil
+let explicitDouble: Double = 70 // 明确指定变量类型为 Double ,否则编译器将自动推断变量类型
+let weak = "keyword"; let override = "another keyword" // 语句之间可以用分号隔开,语句未尾不需要分号
+let intValue = 0007 // 7
+let largeIntValue = 77_000 // 77000
+let label = "some text " + String(myVariable) // 类型转换
+let piText = "Pi = \(π), Pi 2 = \(π * 2)" // 格式化字符串
+
+// 条件编译
+// 使用 -D 定义编译开关
+#if false
+ print("Not printed")
+ let buildValue = 3
+#else
+ let buildValue = 7
+#endif
+print("Build value: \(buildValue)") // Build value: 7
+
+/*
+ Optionals 是 Swift 的新特性,它允许你存储两种状态的值给 Optional 变量:有效值或 None 。
+ 可在值名称后加个问号 (?) 来表示这个值是 Optional。
+
+ Swift 要求所有的 Optinal 属性都必须有明确的值,如果为空,则必须明确设定为 nil
+
+ Optional<T> 是个枚举类型
+*/
+var someOptionalString: String? = "optional" // 可以是 nil
+// 下面的语句和上面完全等价,上面的写法更推荐,因为它更简洁,问号 (?) 是 Swift 提供的语法糖
+var someOptionalString2: Optional<String> = "optional"
+
+if someOptionalString != nil {
+ // 变量不为空
+ if someOptionalString!.hasPrefix("opt") {
+ print("has the prefix")
+ }
+
+ let empty = someOptionalString?.isEmpty
+}
+someOptionalString = nil
+
+/*
+ 使用 (!) 可以解决无法访问optional值的运行错误。若要使用 (!)来强制解析,一定要确保 Optional 里不是 nil参数。
+*/
+
+// 显式解包 optional 变量
+var unwrappedString: String! = "Value is expected."
+// 下面语句和上面完全等价,感叹号 (!) 是个后缀运算符,这也是个语法糖
+var unwrappedString2: ImplicitlyUnwrappedOptional<String> = "Value is expected."
+
+if let someOptionalStringConstant = someOptionalString {
+ // 由于变量 someOptinalString 有值,不为空,所以 if 条件为真
+ if !someOptionalStringConstant.hasPrefix("ok") {
+ // does not have the prefix
+ }
+}
+
+// Swift 支持可保存任何数据类型的变量
+// AnyObject == id
+// 和 Objective-C `id` 不一样, AnyObject 可以保存任何类型的值 (Class, Int, struct, 等)
+var anyObjectVar: AnyObject = 7
+anyObjectVar = "Changed value to a string, not good practice, but possible."
+
+/*
+ 这里是注释
+
+ /*
+ 支持嵌套的注释
+ */
+*/
//
-// 数组与字典(关联数组)
+// Mark: 数组与字典(关联数组)
//
-// 数组
+/*
+ Array 和 Dictionary 是结构体,不是类,他们作为函数参数时,是用值传递而不是指针传递。
+ 可以用 `var` 和 `let` 来定义变量和常量。
+*/
+
+// Array
var shoppingList = ["catfish", "water", "lemons"]
shoppingList[1] = "bottle of water"
-let emptyArray = String[]()
+let emptyArray = [String]() // 使用 let 定义常量,此时 emptyArray 数组不能添加或删除内容
+let emptyArray2 = Array<String>() // 与上一语句等价,上一语句更常用
+var emptyMutableArray = [String]() // 使用 var 定义变量,可以向 emptyMutableArray 添加数组元素
+var explicitEmptyMutableStringArray: [String] = [] // 与上一语句等价
// 字典
var occupations = [
- "Malcolm": "Captain",
- "kaylee": "Mechanic"
+ "Malcolm": "Captain",
+ "kaylee": "Mechanic"
]
-occupations["Jayne"] = "Public Relations"
-let emptyDictionary = Dictionary<String, Float>()
+occupations["Jayne"] = "Public Relations" // 修改字典,如果 key 不存在,自动添加一个字典元素
+let emptyDictionary = [String: Float]() // 使用 let 定义字典常量,字典常量不能修改里面的值
+let emptyDictionary2 = Dictionary<String, Float>() // 与上一语句类型等价,上一语句更常用
+var emptyMutableDictionary = [String: Float]() // 使用 var 定义字典变量
+var explicitEmptyMutableDictionary: [String: Float] = [:] // 与上一语句类型等价
//
-// 控制流
+// MARK: 控制流
//
-// 用于数组的for 循环
+// 数组的 for 循环
let myArray = [1, 1, 2, 3, 5]
for value in myArray {
- if value == 1 {
- println("One!")
- } else {
- println("Not one!")
- }
+ if value == 1 {
+ print("One!")
+ } else {
+ print("Not one!")
+ }
}
-// 用于字典的for 循环
+// 字典的 for 循环
+var dict = ["one": 1, "two": 2]
for (key, value) in dict {
- println("\(key): \(value)")
+ print("\(key): \(value)")
}
-// 用于区间的for 循环
-for i in -1...1 { // [-1, 0, 1]
- println(i)
+// 区间的 loop 循环:其中 `...` 表示闭环区间,即[-1, 3];`..<` 表示半开闭区间,即[-1,3)
+for i in -1...shoppingList.count {
+ print(i)
}
-// 使用 .. 表示的区间不包含最后一个元素 [-1,0,1)
+shoppingList[1...2] = ["steak", "peacons"]
+// 可以使用 `..<` 来去掉最后一个元素
// while 循环
var i = 1
while i < 1000 {
- i *= 2
+ i *= 2
}
// do-while 循环
do {
- println("hello")
+ print("hello")
} while 1 == 2
-// Switch
+// Switch 语句
+// Swift 里的 Switch 语句功能异常强大,结合枚举类型,可以实现非常简洁的代码,可以把 switch 语句想象成 `if` 的语法糖
+// 它支持字符串,类实例或原生数据类型 (Int, Double, etc)
let vegetable = "red pepper"
switch vegetable {
case "celery":
- let vegetableComment = "Add some raisins and make ants on a log."
+ let vegetableComment = "Add some raisins and make ants on a log."
case "cucumber", "watercress":
- let vegetableComment = "That would make a good tea sandwich."
-case let x where x.hasSuffix("pepper"):
- let vegetableComment = "Is it a spicy \(x)?"
-default: // 必须 (为了覆盖所有可能的输入)
- let vegetableComment = "Everything tastes good in soup."
+ let vegetableComment = "That would make a good tea sandwich."
+case let localScopeValue where localScopeValue.hasSuffix("pepper"):
+ let vegetableComment = "Is it a spicy \(localScopeValue)?"
+default: // 在 Swift 里,switch 语句的 case 必须处理所有可能的情况,如果 case 无法全部处理,则必须包含 default语句
+ let vegetableComment = "Everything tastes good in soup."
}
//
-// 函数
+// MARK: 函数
//
-// 函数是一等类型,这意味着可以在函数中构建函数
-// 并且可以被传递
+// 函数是一个 first-class 类型,他们可以嵌套,可以作为函数参数传递
-// 函数
+// 函数文档可使用 reStructedText 格式直接写在函数的头部
+/**
+ A greet operation
+
+ - A bullet in docs
+ - Another bullet in the docs
+
+ :param: name A name
+ :param: day A day
+ :returns: A string containing the name and day value.
+*/
func greet(name: String, day: String) -> String {
- return "Hello \(name), today is \(day)."
+ return "Hello \(name), today is \(day)."
}
greet("Bob", "Tuesday")
-// 使用多元数组返回多返回值的函数
-func getGasPrices() -> (Double, Double, Double) {
- return (3.59, 3.69, 3.79)
+// 函数参数前带 `#` 表示外部参数名和内部参数名使用同一个名称。
+// 第二个参数表示外部参数名使用 `externalParamName` ,内部参数名使用 `localParamName`
+func greet2(#requiredName: String, externalParamName localParamName: String) -> String {
+ return "Hello \(requiredName), the day is \(localParamName)"
}
+greet2(requiredName:"John", externalParamName: "Sunday") // 调用时,使用命名参数来指定参数的值
-// 不定参数
-func setup(numbers: Int...) {}
+// 函数可以通过元组 (tuple) 返回多个值
+func getGasPrices() -> (Double, Double, Double) {
+ return (3.59, 3.69, 3.79)
+}
+let pricesTuple = getGasPrices()
+let price = pricesTuple.2 // 3.79
+// 通过下划线 (_) 来忽略不关心的值
+let (_, price1, _) = pricesTuple // price1 == 3.69
+print(price1 == pricesTuple.1) // true
+print("Gas price: \(price)")
+
+// 可变参数
+func setup(numbers: Int...) {
+ // 可变参数是个数组
+ let number = numbers[0]
+ let argCount = numbers.count
+}
-// 传递、返回函数
+// 函数变量以及函数作为返回值返回
func makeIncrementer() -> (Int -> Int) {
- func addOne(number: Int) -> Int {
- return 1 + number
- }
- return addOne
+ func addOne(number: Int) -> Int {
+ return 1 + number
+ }
+ return addOne
}
var increment = makeIncrementer()
increment(7)
+// 强制进行指针传递 (引用传递),使用 `inout` 关键字修饰函数参数
+func swapTwoInts(inout a: Int, inout b: Int) {
+ let tempA = a
+ a = b
+ b = tempA
+}
+var someIntA = 7
+var someIntB = 3
+swapTwoInts(&someIntA, &someIntB)
+print(someIntB) // 7
+
//
-// 闭包
+// MARK: 闭包
//
+var numbers = [1, 2, 6]
-// 函数是特殊的闭包({})
+// 函数是闭包的一个特例 ({})
-// 闭包示例.
-// `->` 分隔参数和返回类型
-// `in` 分隔闭包头和闭包体
+// 闭包实例
+// `->` 分隔了闭包的参数和返回值
+// `in` 分隔了闭包头 (包括参数及返回值) 和闭包体
+// 下面例子中,`map` 的参数是一个函数类型,它的功能是把数组里的元素作为参数,逐个调用 `map` 参数传递进来的函数。
numbers.map({
- (number: Int) -> Int in
- let result = 3 * number
- return result
- })
+ (number: Int) -> Int in
+ let result = 3 * number
+ return result
+})
-// 当类型已知时,可以这样做:
-var numbers = [1, 2, 6]
+// 当闭包的参数类型和返回值都是己知的情况下,且只有一个语句作为其返回值时,我们可以简化闭包的写法
numbers = numbers.map({ number in 3 * number })
+// 我们也可以使用 $0, $1 来指代第 1 个,第 2 个参数,上面的语句最终可简写为如下形式
+// numbers = numbers.map({ $0 * 3 })
+
+print(numbers) // [3, 6, 18]
+
+// 简洁的闭包
+numbers = sorted(numbers) { $0 > $1 }
+// 函数的最后一个参数可以放在括号之外,上面的语句是这个语句的简写形式
+// numbers = sorted(numbers, { $0 > $1 })
+
+print(numbers) // [18, 6, 3]
+
+// 超级简洁的闭包,因为 `<` 是个操作符函数
+numbers = sorted(numbers, < )
+
print(numbers) // [3, 6, 18]
//
-// 类
+// MARK: 结构体
//
-// 类的全部方法和属性都是public 的
-// 如果你在一个数据结构中只需储存数据,
-// 应使用 `struct`
+// 结构体和类非常类似,可以有属性和方法
-// 集成自`Shape` 类的简单的类`Square
-class Rect: Shape {
- var sideLength: Int = 1
+struct NamesTable {
+ let names = [String]()
- // Custom getter and setter property
- var perimeter: Int {
- get {
- return 4 * sideLength
+ // 自定义下标运算符
+ subscript(index: Int) -> String {
+ return names[index]
}
- set {
- sideLength = newValue / 4
+}
+
+// 结构体有一个自动生成的隐含的命名构造函数
+let namesTable = NamesTable(names: ["Me", "Them"])
+let name = namesTable[1]
+print("Name is \(name)") // Name is Them
+
+//
+// MARK: 类
+//
+
+// 类和结构体的有三个访问控制级别,他们分别是 internal (默认), public, private
+// internal: 模块内部可以访问
+// public: 其他模块可以访问
+// private: 只有定义这个类或结构体的源文件才能访问
+
+public class Shape {
+ public func getArea() -> Int {
+ return 0;
+ }
+}
+
+// 类的所有方法和属性都是 public 的
+// 如果你只是需要把数据保存在一个结构化的实例里面,应该用结构体
+
+internal class Rect: Shape {
+ // 值属性 (Stored properties)
+ var sideLength: Int = 1
+
+ // 计算属性 (Computed properties)
+ private var perimeter: Int {
+ get {
+ return 4 * sideLength
+ }
+ set {
+ // `newValue` 是个隐含的变量,它表示将要设置进来的新值
+ sideLength = newValue / 4
+ }
+ }
+
+ // 延时加载的属性,只有这个属性第一次被引用时才进行初始化,而不是定义时就初始化
+ // subShape 值为 nil ,直到 subShape 第一次被引用时才初始化为一个 Rect 实例
+ lazy var subShape = Rect(sideLength: 4)
+
+ // 监控属性值的变化。
+ // 当我们需要在属性值改变时做一些事情,可以使用 `willSet` 和 `didSet` 来设置监控函数
+ // `willSet`: 值改变之前被调用
+ // `didSet`: 值改变之后被调用
+ var identifier: String = "defaultID" {
+ // `willSet` 的参数是即将设置的新值,参数名可以指定,如果没有指定,就是 `newValue`
+ willSet(someIdentifier) {
+ print(someIdentifier)
+ }
+ // `didSet` 的参数是已经被覆盖掉的旧的值,参数名也可以指定,如果没有指定,就是 `oldValue`
+ didSet {
+ print(oldValue)
+ }
+ }
+
+ // 命名构造函数 (designated inits),它必须初始化所有的成员变量,
+ // 然后调用父类的命名构造函数继续初始化父类的所有变量。
+ init(sideLength: Int) {
+ self.sideLength = sideLength
+ // 必须显式地在构造函数最后调用父类的构造函数 super.init
+ super.init()
}
- }
- init(sideLength: Int) {
- super.init()
- self.sideLength = sideLength
- }
+ func shrink() {
+ if sideLength > 0 {
+ --sideLength
+ }
+ }
- func shrink() {
- if sideLength > 0 {
- --sideLength
+ // 函数重载使用 override 关键字
+ override func getArea() -> Int {
+ return sideLength * sideLength
}
- }
+}
- override func getArea() -> Int {
- return sideLength * sideLength
- }
+// 类 `Square` 从 `Rect` 继承
+class Square: Rect {
+ // 便捷构造函数 (convenience inits) 是调用自己的命名构造函数 (designated inits) 的构造函数
+ // Square 自动继承了父类的命名构造函数
+ convenience init() {
+ self.init(sideLength: 5)
+ }
+ // 关于构造函数的继承,有以下几个规则:
+ // 1. 如果你没有实现任何命名构造函数,那么你就继承了父类的所有命名构造函数
+ // 2. 如果你重载了父类的所有命名构造函数,那么你就自动继承了所有的父类快捷构造函数
+ // 3. 如果你没有实现任何构造函数,那么你继承了父类的所有构造函数,包括命名构造函数和便捷构造函数
}
-var mySquare = new Square(sideLength: 5)
+
+var mySquare = Square()
print(mySquare.getArea()) // 25
mySquare.shrink()
print(mySquare.sideLength) // 4
-// 如果你不需要自定义getter 和setter,
-// 但仍希望在获取或设置一个属性之前或之后运行
-// 一些代码,你可以使用`willSet` 和 `didSet`
+// 类型转换
+let aShape = mySquare as Shape
+
+// 使用三个等号来比较是不是同一个实例
+if mySquare === aShape {
+ print("Yep, it's mySquare")
+}
+
+class Circle: Shape {
+ var radius: Int
+ override func getArea() -> Int {
+ return 3 * radius * radius
+ }
+
+ // optional 构造函数,可能会返回 nil
+ init?(radius: Int) {
+ self.radius = radius
+ super.init()
+
+ if radius <= 0 {
+ return nil
+ }
+ }
+}
+
+// 根据 Swift 类型推断,myCircle 是 Optional<Circle> 类型的变量
+var myCircle = Circle(radius: 1)
+print(myCircle?.getArea()) // Optional(3)
+print(myCircle!.getArea()) // 3
+var myEmptyCircle = Circle(radius: -1)
+print(myEmptyCircle?.getArea()) // "nil"
+if let circle = myEmptyCircle {
+ // 此语句不会输出,因为 myEmptyCircle 变量值为 nil
+ print("circle is not nil")
+}
//
-// 枚举类型
+// MARK: 枚举
//
-// 枚举类型可以是某种指定的类型,抑或自成一种类型
-// 像类一样,枚举类型可以包含方法
+// 枚举可以像类一样,拥有方法
enum Suit {
- case Spades, Hearts, Diamonds, Clubs
- func getIcon() -> String {
- switch self {
- case .Spades: return "♤"
- case .Hearts: return "♡"
- case .Diamonds: return "♢"
- case .Clubs: return "♧"
+ case Spades, Hearts, Diamonds, Clubs
+ func getIcon() -> String {
+ switch self {
+ case .Spades: return "♤"
+ case .Hearts: return "♡"
+ case .Diamonds: return "♢"
+ case .Clubs: return "♧"
+ }
+ }
+}
+
+// 当变量类型明确指定为某个枚举类型时,赋值时可以省略枚举类型
+var suitValue: Suit = .Hearts
+
+// 非整型的枚举类型需要在定义时赋值
+enum BookName: String {
+ case John = "John"
+ case Luke = "Luke"
+}
+print("Name: \(BookName.John.rawValue)")
+
+// 与特定数据类型关联的枚举
+enum Furniture {
+ // 和 Int 型数据关联的枚举记录
+ case Desk(height: Int)
+ // 和 String, Int 关联的枚举记录
+ case Chair(brand: String, height: Int)
+
+ func description() -> String {
+ switch self {
+ case .Desk(let height):
+ return "Desk with \(height) cm"
+ case .Chair(let brand, let height):
+ return "Chair of \(brand) with \(height) cm"
+ }
}
- }
}
+var desk: Furniture = .Desk(height: 80)
+print(desk.description()) // "Desk with 80 cm"
+var chair = Furniture.Chair(brand: "Foo", height: 40)
+print(chair.description()) // "Chair of Foo with 40 cm"
+
//
-// 其它
+// MARK: 协议
+// 与 Java 的 interface 类似
//
-// `协议(protocol)`: 与Java 的接口(Interface) 类似.
-// `扩展(extension)`: 为现有类型添加额外特性
-// 泛型: 与Java 相似。使用`where` 关键字指定
-// 泛型的要求.
+// 协议可以让遵循同一协议的类型实例拥有相同的属性,方法,类方法,操作符或下标运算符等
+// 下面代码定义一个协议,这个协议包含一个名为 enabled 的计算属性且包含 buildShape 方法
+protocol ShapeGenerator {
+ var enabled: Bool { get set }
+ func buildShape() -> Shape
+}
+
+// 协议声明时可以添加 @objc 前缀,添加 @objc 前缀后,
+// 可以使用 is, as, as? 等来检查协议兼容性
+// 需要注意,添加 @objc 前缀后,协议就只能被类来实现,
+// 结构体和枚举不能实现加了 @objc 的前缀
+// 只有添加了 @objc 前缀的协议才能声明 optional 方法
+// 一个类实现一个带 optional 方法的协议时,可以实现或不实现这个方法
+// optional 方法可以使用 optional 规则来调用
+@objc protocol TransformShape {
+ optional func reshaped()
+ optional func canReshape() -> Bool
+}
+
+class MyShape: Rect {
+ var delegate: TransformShape?
+
+ func grow() {
+ sideLength += 2
+
+ // 在 optional 属性,方法或下标运算符后面加一个问号,可以优雅地忽略 nil 值,返回 nil。
+ // 这样就不会引起运行时错误 (runtime error)
+ if let allow = self.delegate?.canReshape?() {
+ // 注意语句中的问号
+ self.delegate?.reshaped?()
+ }
+ }
+}
+
+
+//
+// MARK: 其它
+//
+
+// 扩展: 给一个已经存在的数据类型添加功能
+
+// 给 Square 类添加 `Printable` 协议的实现,现在其支持 `Printable` 协议
+extension Square: Printable {
+ var description: String {
+ return "Area: \(self.getArea()) - ID: \(self.identifier)"
+ }
+}
+
+print("Square: \(mySquare)") // Area: 16 - ID: defaultID
+
+// 也可以给系统内置类型添加功能支持
+extension Int {
+ var customProperty: String {
+ return "This is \(self)"
+ }
+
+ func multiplyBy(num: Int) -> Int {
+ return num * self
+ }
+}
+
+print(7.customProperty) // "This is 7"
+print(14.multiplyBy(3)) // 42
+
+// 泛型: 和 Java 及 C# 的泛型类似,使用 `where` 关键字来限制类型。
+// 如果只有一个类型限制,可以省略 `where` 关键字
+func findIndex<T: Equatable>(array: [T], valueToFind: T) -> Int? {
+ for (index, value) in enumerate(array) {
+ if value == valueToFind {
+ return index
+ }
+ }
+ return nil
+}
+let foundAtIndex = findIndex([1, 2, 3, 4], 3)
+print(foundAtIndex == 2) // true
+
+// 自定义运算符:
+// 自定义运算符可以以下面的字符打头:
+// / = - + * % < > ! & | ^ . ~
+// 甚至是 Unicode 的数学运算符等
+prefix operator !!! {}
+
+// 定义一个前缀运算符,使矩形的边长放大三倍
+prefix func !!! (inout shape: Square) -> Square {
+ shape.sideLength *= 3
+ return shape
+}
+
+// 当前值
+print(mySquare.sideLength) // 4
+
+// 使用自定义的 !!! 运算符来把矩形边长放大三倍
+!!!mySquare
+print(mySquare.sideLength) // 12
+
+// 运算符也可以是泛型
+infix operator <-> {}
+func <-><T: Equatable> (inout a: T, inout b: T) {
+ let c = a
+ a = b
+ b = c
+}
+
+var foo: Float = 10
+var bar: Float = 20
+
+foo <-> bar
+print("foo is \(foo), bar is \(bar)") // "foo is 20.0, bar is 10.0"
```
diff --git a/zh-cn/tmux-cn.html.markdown b/zh-cn/tmux-cn.html.markdown
new file mode 100644
index 00000000..cf865dce
--- /dev/null
+++ b/zh-cn/tmux-cn.html.markdown
@@ -0,0 +1,253 @@
+---
+category: tool
+tool: tmux
+filename: LearnTmux-cn.txt
+contributors:
+ - ["mdln", "https://github.com/mdln"]
+translators:
+ - ["Arnie97", "https://github.com/Arnie97"]
+lang: zh-cn
+---
+
+
+[tmux](http://tmux.github.io)是一款终端复用工具。
+在它的帮助下,你可以在同一个控制台上建立、访问并控制多个终端。
+你可以断开与一个 tmux 终端的连接,此时程序将在后台运行,
+当你需要时,可以随时重新连接到这个终端。
+
+```
+
+ tmux [command] # 运行一条命令
+ # 如果单独使用 'tmux' 而不指定某个命令,将会建立一个新的会话
+
+ new # 创建一个新的会话
+ -s "Session" # 创建一个会话,并命名为“Session”
+ -n "Window" # 创建一个窗口,并命名为“Window”
+ -c "/dir" # 在指定的工作目录中启动会话
+
+ attach # 连接到上一次的会话(如果可用)
+ -t "#" # 连接到指定的会话
+ -d # 断开其他客户端的会话
+
+ ls # 列出打开的会话
+ -a # 列出所有打开的会话
+
+ lsw # 列出窗口
+ -a # 列出所有窗口
+ -s # 列出会话中的所有窗口
+
+ lsp # 列出窗格
+ -a # 列出所有窗格
+ -s # 列出会话中的所有窗格
+ -t "#" # 列出指定窗口中的所有窗格
+
+ kill-window # 关闭当前窗口
+ -t "#" # 关闭指定的窗口
+ -a # 关闭所有窗口
+ -a -t "#" # 关闭除指定窗口以外的所有窗口
+
+ kill-session # 关闭当前会话
+ -t "#" # 关闭指定的会话
+ -a # 关闭所有会话
+ -a -t "#" # 关闭除指定会话以外的所有会话
+
+```
+
+
+### 快捷键
+
+通过“前缀”快捷键,可以控制一个已经连入的 tmux 会话。
+
+```
+----------------------------------------------------------------------
+ (C-b) = Ctrl + b # 在使用下列快捷键之前,需要按这个“前缀”快捷键
+
+ (M-1) = Meta + 1 或 Alt + 1
+----------------------------------------------------------------------
+
+ ? # 列出所有快捷键
+ : # 进入 tmux 的命令提示符
+ r # 强制重绘当前客户端
+ c # 创建一个新窗口
+
+ ! # 将当前窗格从窗口中移出,成为为一个新的窗口
+ % # 将当前窗格分为左右两半
+ " # 将当前窗格分为上下两半
+
+ n # 切换到下一个窗口
+ p # 切换到上一个窗口
+ { # 将当前窗格与上一个窗格交换
+ } # 将当前窗格与下一个窗格交换
+
+ s # 在交互式界面中,选择并连接至另一个会话
+ w # 在交互式界面中,选择并激活一个窗口
+ 0 至 9 # 选择 0 到 9 号窗口
+
+ d # 断开当前客户端
+ D # 选择并断开一个客户端
+
+ & # 关闭当前窗口
+ x # 关闭当前窗格
+
+ Up, Down # 将焦点移动至相邻的窗格
+ Left, Right
+
+ M-1 到 M-5 # 排列窗格:
+ # 1) 水平等分
+ # 2) 垂直等分
+ # 3) 将一个窗格作为主要窗格,其他窗格水平等分
+ # 4) 将一个窗格作为主要窗格,其他窗格垂直等分
+ # 5) 平铺
+
+ C-Up, C-Down # 改变当前窗格的大小,每按一次增减一个单位
+ C-Left, C-Right
+
+ M-Up, M-Down # 改变当前窗格的大小,每按一次增减五个单位
+ M-Left, M-Right
+
+```
+
+
+### 配置 ~/.tmux.conf
+
+tmux.conf 可以在 tmux 启动时自动设置选项,类似于 .vimrc 或 init.el 的用法。
+
+```
+# tmux.conf 示例
+# 2014.10
+
+
+### 通用设置
+###########################################################################
+
+# 启用 UTF-8 编码
+setw -g utf8 on
+set-option -g status-utf8 on
+
+# 命令回滚/历史数量限制
+set -g history-limit 2048
+
+# 从 1 开始编号,而不是从 0 开始
+set -g base-index 1
+
+# 启用鼠标
+set-option -g mouse-select-pane on
+
+# 重新加载配置文件
+unbind r
+bind r source-file ~/.tmux.conf
+
+
+### 快捷键设置
+###########################################################################
+
+# 取消默认的前缀键 C-b
+unbind C-b
+
+# 设置新的前缀键 `
+set-option -g prefix `
+
+# 多次按下前缀键时,切换到上一个窗口
+bind C-a last-window
+bind ` last-window
+
+# 按下F11/F12,可以选择不同的前缀键
+bind F11 set-option -g prefix C-a
+bind F12 set-option -g prefix `
+
+# Vim 风格的快捷键绑定
+setw -g mode-keys vi
+set-option -g status-keys vi
+
+# 使用 Vim 风格的按键在窗格间移动
+bind h select-pane -L
+bind j select-pane -D
+bind k select-pane -U
+bind l select-pane -R
+
+# 循环切换不同的窗口
+bind e previous-window
+bind f next-window
+bind E swap-window -t -1
+bind F swap-window -t +1
+
+# 较易于使用的窗格分割快捷键
+bind = split-window -h
+bind - split-window -v
+unbind '"'
+unbind %
+
+# 在嵌套使用 tmux 的情况下,激活最内层的会话,以便向其发送命令
+bind a send-prefix
+
+
+### 外观主题
+###########################################################################
+
+# 状态栏颜色
+set-option -g status-justify left
+set-option -g status-bg black
+set-option -g status-fg white
+set-option -g status-left-length 40
+set-option -g status-right-length 80
+
+# 窗格边框颜色
+set-option -g pane-active-border-fg green
+set-option -g pane-active-border-bg black
+set-option -g pane-border-fg white
+set-option -g pane-border-bg black
+
+# 消息框颜色
+set-option -g message-fg black
+set-option -g message-bg green
+
+# 窗口状态栏颜色
+setw -g window-status-bg black
+setw -g window-status-current-fg green
+setw -g window-status-bell-attr default
+setw -g window-status-bell-fg red
+setw -g window-status-content-attr default
+setw -g window-status-content-fg yellow
+setw -g window-status-activity-attr default
+setw -g window-status-activity-fg yellow
+
+
+### 用户界面
+###########################################################################
+
+# 通知方式
+setw -g monitor-activity on
+set -g visual-activity on
+set-option -g bell-action any
+set-option -g visual-bell off
+
+# 自动设置窗口标题
+set-option -g set-titles on
+set-option -g set-titles-string '#H:#S.#I.#P #W #T' # 窗口编号,程序名称,是否活动
+
+# 调整状态栏
+set -g status-left "#[fg=red] #H#[fg=green]:#[fg=white]#S#[fg=green] |#[default]"
+
+# 在状态栏中显示性能计数器
+# 需要用到 https://github.com/thewtex/tmux-mem-cpu-load
+set -g status-interval 4
+set -g status-right "#[fg=green] | #[fg=white]#(tmux-mem-cpu-load)#[fg=green] | #[fg=cyan]%H:%M #[default]"
+
+```
+
+
+### 参考资料
+
+[Tmux 主页](http://tmux.github.io)
+
+[Tmux 手册](http://www.openbsd.org/cgi-bin/man.cgi/OpenBSD-current/man1/tmux.1?query=tmux)
+
+[FreeBSDChina Wiki](https://wiki.freebsdchina.org/software/t/tmux)
+
+[Archlinux Wiki](https://wiki.archlinux.org/index.php/Tmux_(简体中文))
+
+[Tmux 快速教程](http://blog.jeswang.org/blog/2013/06/24/tmux-kuai-su-jiao-cheng)
+
+[如何在 tmux 状态栏中显示 CPU / 内存占用的百分比](https://stackoverflow.com/questions/11558907/is-there-a-better-way-to-display-cpu-usage-in-tmux)
+
+[管理复杂 tmux 会话的工具 - tmuxinator](https://github.com/tmuxinator/tmuxinator)