summaryrefslogtreecommitdiffhomepage
path: root/zh-cn
diff options
context:
space:
mode:
Diffstat (limited to 'zh-cn')
-rw-r--r--zh-cn/bash-cn.html.markdown2
-rw-r--r--zh-cn/c-cn.html.markdown394
-rw-r--r--zh-cn/clojure-cn.html.markdown2
-rw-r--r--zh-cn/clojure-macro-cn.html.markdown152
-rw-r--r--zh-cn/coffeescript-cn.html.markdown101
-rw-r--r--zh-cn/common-lisp-cn.html.markdown12
-rw-r--r--zh-cn/csharp-cn.html.markdown798
-rw-r--r--zh-cn/css-cn.html.markdown212
-rw-r--r--zh-cn/elisp-cn.html.markdown4
-rw-r--r--zh-cn/elixir-cn.html.markdown399
-rw-r--r--zh-cn/erlang-cn.html.markdown259
-rw-r--r--zh-cn/json-cn.html.markdown51
-rw-r--r--zh-cn/lua-cn.html.markdown413
-rw-r--r--zh-cn/php-cn.html.markdown6
-rw-r--r--zh-cn/r-cn.html.markdown2
-rw-r--r--zh-cn/racket-cn.html.markdown2
-rw-r--r--zh-cn/scala-cn.html.markdown1
-rw-r--r--zh-cn/visualbasic-cn.html.markdown274
-rw-r--r--zh-cn/xml-cn.html.markdown127
-rw-r--r--zh-cn/yaml-cn.html.markdown136
20 files changed, 3249 insertions, 98 deletions
diff --git a/zh-cn/bash-cn.html.markdown b/zh-cn/bash-cn.html.markdown
index 2e885833..6afa659a 100644
--- a/zh-cn/bash-cn.html.markdown
+++ b/zh-cn/bash-cn.html.markdown
@@ -17,7 +17,7 @@ Bash 是一个为 GNU 计划编写的 Unix shell,是 Linux 和 Mac OS X 下的
[更多信息](http://www.gnu.org/software/bash/manual/bashref.html)
```bash
-#!/bin/sh
+#!/bin/bash
# 脚本的第一行叫 shebang,用来告知系统如何执行该脚本:
# 参见: http://en.wikipedia.org/wiki/Shebang_(Unix)
# 如你所见,注释以 # 开头,shebang 也是注释。
diff --git a/zh-cn/c-cn.html.markdown b/zh-cn/c-cn.html.markdown
index b4bff8fc..223f6e35 100644
--- a/zh-cn/c-cn.html.markdown
+++ b/zh-cn/c-cn.html.markdown
@@ -5,37 +5,52 @@ contributors:
- ["Adam Bard", "http://adambard.com/"]
translators:
- ["Chenbo Li", "http://binarythink.net/"]
+ - ["Jakukyo Friel", "http://weakish.github.io"]
lang: zh-cn
---
C语言在今天仍然是高性能计算的主要选择。
-C大概是大多数程序员用到的最接近底层的语言了,但是C语言本身不仅可以用来提升程序运行的速度
-注意看看C语言的文档,你就会知道C语言在内存管理方面的强大也是其他语言无法比拟的。
+C大概是大多数程序员用到的最接近底层的语言了,C语言原生的速度就很高了,但是别忘了C的手动内存管理,它会让你将性能发挥到极致。
```c
-// 用“//”来实现单行注释
+// 单行注释以//开始。(仅适用于C99或更新的版本。)
/*
-多行注释是这个样子的
+多行注释是这个样子的。(C89也适用。)
*/
+// 常数: #define 关键词
+#define DAYS_IN_YEAR 365
+
+// 以枚举的方式定义常数
+enum days {SUN = 1, MON, TUE, WED, THU, FRI, SAT};
+// MON自动被定义为2,TUE被定义为3,以此类推。
+
// 用#include来导入头文件
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
-// 函数的标签(signature)应该放在.h文件中,并且引入到程序顶部
-// 也可以直接放到你的.c文件的最上面
-void function_1();
-void function_2();
+// <尖括号>间的文件名是C标准库的头文件。
+// 标准库以外的头文件,使用双引号代替尖括号。
+#include "my_header.h"
+
+// 函数的签名可以事先在.h文件中定义,
+// 也可以直接在.c文件的头部定义。
+void function_1(char c);
+void function_2(void);
-// c程序的入口是一个返回值为int型的函数,名字叫做main
+// 如果函数出现在main()之后,那么必须在main()之前
+// 先声明一个函数原型
+int add_two_ints(int x1, int x2); // 函数原型
+
+// 你的程序的入口是一个返回值为整型的main函数
int main() {
-// 用printf来实现标准输出,这种输出也可以用格式来控制
-// %d 代表一个整数, \n 代表一个新行
-printf("%d\n", 0); // => 输出 0
+// 用printf打印到标准输出,可以设定格式,
+// %d 代表整数, \n 代表换行
+printf("%d\n", 0); // => 打印 0
// 所有的语句都要以分号结束
///////////////////////////////////////
@@ -69,18 +84,29 @@ double x_double = 0.0;
// 整数类型也可以有无符号的类型表示。这样这些变量就无法表示负数
// 但是无符号整数所能表示的范围就可以比原来的整数大一些
-unsigned char ux_char;
unsigned short ux_short;
unsigned int ux_int;
unsigned long long ux_long_long;
+// 单引号内的字符是机器的字符集中的整数。
+'0' // => 在ASCII字符集中是48
+'A' // => 在ASCII字符集中是65
+
// char类型一定会占用1个字节,但是其他的类型却会因具体机器的不同而各异
// sizeof(T) 可以返回T类型在运行的机器上占用多少个字节
// 这样你的代码就可以在各处正确运行了
-// 比如
-printf("%lu\n", sizeof(int)); // => 4 (字长为4的机器上)
-
-// 数组必须要在开始被初始化为特定的长度
+// sizeof(obj)返回表达式(变量、字面量等)的尺寸
+printf("%zu\n", sizeof(int)); // => 4 (大多数的机器字长为4)
+
+// 如果`sizeof`的参数是一个表达式,那么这个参数不会被演算(VLA例外,见下)
+// 它产生的值是编译期的常数
+int a = 1;
+// size_t是一个无符号整型,表示对象的尺寸,至少2个字节
+size_t size = sizeof(a++); // a++ 不会被演算
+printf("sizeof(a++) = %zu where a = %d\n", size, a);
+// 打印 "sizeof(a++) = 4 where a = 1" (在32位架构上)
+
+// 数组必须要被初始化为具体的长度
char my_char_array[20]; // 这个数组占据 1 * 20 = 20 个字节
int my_int_array[20]; // 这个数组占据 4 * 20 = 80 个字节
// (这里我们假设字长为4)
@@ -89,48 +115,83 @@ int my_int_array[20]; // 这个数组占据 4 * 20 = 80 个字节
// 可以用下面的方法把数组初始化为0:
char my_array[20] = {0};
-// 对数组任意存取就像其他语言的方式 -- 其实是其他的语言像C
+// 索引数组和其他语言类似 -- 好吧,其实是其他的语言像C
my_array[0]; // => 0
// 数组是可变的,其实就是内存的映射!
my_array[1] = 2;
printf("%d\n", my_array[1]); // => 2
+// 在C99 (C11中是可选特性),变长数组(VLA)也可以声明长度。
+// 其长度不用是编译期常量。
+printf("Enter the array size: "); // 询问用户数组长度
+char buf[0x100];
+fgets(buf, sizeof buf, stdin);
+
+// stroul 将字符串解析为无符号整数
+size_t size = strtoul(buf, NULL, 10);
+int var_length_array[size]; // 声明VLA
+printf("sizeof array = %zu\n", sizeof var_length_array);
+
+// 上述程序可能的输出为:
+// > Enter the array size: 10
+// > sizeof array = 40
+
// 字符串就是以 NUL (0x00) 这个字符结尾的字符数组,
-// 这个字符可以用'\0'来表示.
-// (在字符串字面值中我们不必输入这个字符,编译器会自动添加的)
+// NUL可以用'\0'来表示.
+// (在字符串字面量中我们不必输入这个字符,编译器会自动添加的)
char a_string[20] = "This is a string";
printf("%s\n", a_string); // %s 可以对字符串进行格式化
-
/*
也许你会注意到 a_string 实际上只有16个字节长.
第17个字节是一个空字符(NUL)
-而第18, 19 和 20 个字符的值是不确定的。
+而第18, 19 和 20 个字符的值是未定义。
*/
printf("%d\n", a_string[16]); // => 0
+// byte #17值为0(18,19,20同样为0)
+
+// 单引号间的字符是字符字面量
+// 它的类型是`int`,而 *不是* `char`
+// (由于历史原因)
+int cha = 'a'; // 合法
+char chb = 'a'; // 同样合法 (隐式类型转换
+
+// 多维数组
+int multi_array[2][5] = {
+ {1, 2, 3, 4, 5},
+ {6, 7, 8, 9, 0}
+ }
+// 获取元素
+int array_int = multi_array[0][2]; // => 3
///////////////////////////////////////
// 操作符
///////////////////////////////////////
-int i1 = 1, i2 = 2; // 多个变量声明的简写
+// 多个变量声明的简写
+int i1 = 1, i2 = 2;
float f1 = 1.0, f2 = 2.0;
-// 算数运算
+int a, b, c;
+a = b = c = 0;
+
+// 算数运算直截了当
i1 + i2; // => 3
i2 - i1; // => 1
i2 * i1; // => 2
-i1 / i2; // => 0 (0.5 会被化整为 0)
+i1 / i2; // => 0 (0.5,但会被化整为 0)
f1 / f2; // => 0.5, 也许会有很小的误差
+// 浮点数和浮点数运算都是近似值
// 取余运算
11 % 3; // => 2
-// 比较操作符我们也很熟悉, 但是有一点,C中没有布尔类型
+// 你多半会觉得比较操作符很熟悉, 不过C中没有布尔类型
// 而是用整形替代
-// 0 就是 false, 其他的就是 true. (比较操作符的返回值则仅有0和1)
+// (C99中有_Bool或bool。)
+// 0为假, 其他均为真. (比较操作符的返回值总是返回0或1)
3 == 2; // => 0 (false)
3 != 2; // => 1 (true)
3 > 2; // => 1
@@ -138,7 +199,14 @@ f1 / f2; // => 0.5, 也许会有很小的误差
2 <= 2; // => 1
2 >= 2; // => 1
-// 逻辑运算符需要作用于整数
+// C不是Python —— 连续比较不合法
+int a = 1;
+// 错误
+int between_0_and_2 = 0 < a < 2;
+// 正确
+int between_0_and_2 = 0 < a && a < 2;
+
+// 逻辑运算符适用于整数
!3; // => 0 (非)
!0; // => 1
1 && 1; // => 1 (且)
@@ -146,6 +214,20 @@ f1 / f2; // => 0.5, 也许会有很小的误差
0 || 1; // => 1 (或)
0 || 0; // => 0
+// 条件表达式 ( ? : )
+int a = 5;
+int b = 10;
+int z;
+z = (a > b) ? a : b; // 10 “若a > b返回a,否则返回b。”
+
+// 增、减
+char *s = "iLoveC"
+int j = 0;
+s[j++]; // "i" 返回s的第j项,然后增加j的值。
+j = 0;
+s[++j]; // => "L" 增加j的值,然后返回s的第j项。
+// j-- 和 --j 同理
+
// 位运算
~0x0F; // => 0xF0 (取反)
0x0F & 0xF0; // => 0x00 (和)
@@ -154,6 +236,13 @@ f1 / f2; // => 0.5, 也许会有很小的误差
0x01 << 1; // => 0x02 (左移1位)
0x02 >> 1; // => 0x01 (右移1位)
+// 对有符号整数进行移位操作要小心 —— 以下未定义:
+// 有符号整数位移至符号位 int a = 1 << 32
+// 左移位一个负数 int a = -1 << 2
+// 移位超过或等于该类型数值的长度
+// int a = 1 << 32; // 假定int32位
+
+
///////////////////////////////////////
// 控制结构
///////////////////////////////////////
@@ -168,17 +257,17 @@ if (0) {
// While循环
int ii = 0;
-while (ii < 10) {
+while (ii < 10) { // 任何非0的值均为真
printf("%d, ", ii++); // ii++ 在取值过后自增
-} // => 输出 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
+} // => 打印 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
printf("\n");
int kk = 0;
do {
printf("%d, ", kk);
-} while (++kk < 10); // ++kk 先自增,在被取值
-// => 输出 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
+} while (++kk < 10); // ++kk 先自增,再被取值
+// => 打印 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
printf("\n");
@@ -186,29 +275,55 @@ printf("\n");
int jj;
for (jj=0; jj < 10; jj++) {
printf("%d, ", jj);
-} // => 输出 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
+} // => 打印 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
printf("\n");
+// *****注意*****:
+// 循环和函数必须有主体部分,如果不需要主体部分:
+int i;
+ for (i = 0; i <= 5; i++) {
+ ; // 使用分号表达主体(null语句)
+}
+
+// 多重分支:switch()
+switch (some_integral_expression) {
+case 0: // 标签必须是整数常量表达式
+ do_stuff();
+ break; // 如果不使用break,控制结构会继续执行下面的标签
+case 1:
+ do_something_else();
+ break;
+default:
+ // 假设 `some_integral_expression` 不匹配任何标签
+ fputs("error!\n", stderr);
+ exit(-1);
+ break;
+ }
+
///////////////////////////////////////
// 类型转换
///////////////////////////////////////
// 在C中每个变量都有类型,你可以将变量的类型进行转换
+// (有一定限制)
-int x_hex = 0x01; // 可以用16进制赋值
+int x_hex = 0x01; // 可以用16进制字面量赋值
// 在类型转换时,数字本身的值会被保留下来
-printf("%d\n", x_hex); // => 输出 1
-printf("%d\n", (short) x_hex); // => 输出 1
-printf("%d\n", (char) x_hex); // => 输出 1
+printf("%d\n", x_hex); // => 打印 1
+printf("%d\n", (short) x_hex); // => 打印 1
+printf("%d\n", (char) x_hex); // => 打印 1
// 类型转换时可能会造成溢出,而且不会抛出警告
-printf("%d\n", (char) 257); // => 1 (char的最大值为255)
+printf("%d\n", (char) 257); // => 1 (char的最大值为255,假定char为8位长)
+
+// 使用<limits.h>提供的CHAR_MAX、SCHAR_MAX和UCHAR_MAX宏可以确定`char`、`signed_char`和`unisigned char`的最大值。
+
// 整数型和浮点型可以互相转换
-printf("%f\n", (float)100); // %f 表示单精度浮点
-printf("%lf\n", (double)100); // %lf 表示双精度浮点
+printf("%f\n", (float)100); // %f 格式化单精度浮点
+printf("%lf\n", (double)100); // %lf 格式化双精度浮点
printf("%d\n", (char)100.0);
///////////////////////////////////////
@@ -216,67 +331,89 @@ printf("%d\n", (char)100.0);
///////////////////////////////////////
// 指针变量是用来储存内存地址的变量
-// 指针变量的定义也会告诉你指向的地址的变量的类型
-// 你也可以得到某个变量的地址,并对它们进行操作
+// 指针变量的声明也会告诉它所指向的数据的类型
+// 你可以使用得到你的变量的地址,并把它们搞乱,;-)
int x = 0;
printf("%p\n", &x); // 用 & 来获取变量的地址
-// (%p 表示一个指针)
-// => 输出某个内存地址
+// (%p 格式化一个类型为 void *的指针)
+// => 打印某个内存地址
-// 指针类型在定义是需要以*结束
-int* px; // px是一个指向int型的指针
+// 指针类型在声明中以*开头
+int* px, not_a_pointer; // px是一个指向int型的指针
px = &x; // 把x的地址保存到px中
-printf("%p\n", px); // => 输出内存中的某个地址
+printf("%p\n", (void *)px); // => 输出内存中的某个地址
+printf("%zu, %zu\n", sizeof(px), sizeof(not_a_pointer));
+// => 在64位系统上打印“8, 4”。
-// 要得到某个指针指向的内容的值,可以在指针前加一个*来取得(去引用)
+// 要得到某个指针指向的内容的值,可以在指针前加一个*来取得(取消引用)
+// 注意: 是的,这可能让人困惑,'*'在用来声明一个指针的同时取消引用它。
printf("%d\n", *px); // => 输出 0, 即x的值
// 你也可以改变指针所指向的值
-// 此时你需要在*运算符后添加一个括号,因为++比*的优先级更高
-(*px)++; // 把px所指向的值增加2
+// 此时你需要取消引用上添加括号,因为++比*的优先级更高
+(*px)++; // 把px所指向的值增加1
printf("%d\n", *px); // => 输出 1
printf("%d\n", x); // => 输出 1
-int x_array[20]; // 数组是分配一系列连续空间的常用方式
+// 数组是分配一系列连续空间的常用方式
+int x_array[20];
int xx;
for (xx=0; xx<20; xx++) {
x_array[xx] = 20 - xx;
} // 初始化 x_array 为 20, 19, 18,... 2, 1
-// 生命一个变量为指向整型的指针类型,并初始化为指向x_array
+// 声明一个整型的指针,并初始化为指向x_array
int* x_ptr = x_array;
// x_ptr现在指向了数组的第一个元素(即整数20).
-
-// 事实上数组本身就是指向它的第一个元素的指针
-printf("%d\n", *(x_ptr)); // => 输出 20
-printf("%d\n", x_array[0]); // => 输出 20
+// 这是因为数组通常衰减为指向它们的第一个元素的指针。
+// 例如,当一个数组被传递给一个函数或者绑定到一个指针时,
+//它衰减为(隐式转化为)一个指针。
+// 例外: 当数组是`&`操作符的参数:
+int arr[10];
+int (*ptr_to_arr)[10] = &arr; // &arr的类型不是`int *`!
+ // 它的类型是指向数组的指针(数组由10个int组成)
+// 或者当数组是字符串字面量(初始化字符数组)
+char arr[] = "foobarbazquirk";
+// 或者当它是`sizeof`或`alignof`操作符的参数时:
+int arr[10];
+int *ptr = arr; // 等价于 int *ptr = &arr[0];
+printf("%zu, %zu\n", sizeof arr, sizeof ptr); // 应该会输出"40, 4"或"40, 8"
// 指针的增减多少是依据它本身的类型而定的
-printf("%d\n", *(x_ptr + 1)); // => 输出 19
-printf("%d\n", x_array[1]); // => 输出 19
+// (这被称为指针算术)
+printf("%d\n", *(x_ptr + 1)); // => 打印 19
+printf("%d\n", x_array[1]); // => 打印 19
// 你也可以通过标准库函数malloc来实现动态分配
-// 这个函数接受一个代表容量的参数
-// 系统会从堆区分配指定容量字节大小的空间
-int* my_ptr = (int*) malloc(sizeof(int) * 20);
+// 这个函数接受一个代表容量的参数,参数类型为`size_t`
+// 系统一般会从堆区分配指定容量字节大小的空间
+// (在一些系统,例如嵌入式系统中这点不一定成立
+// C标准对此未置一词。)
+int *my_ptr = malloc(sizeof(*my_ptr) * 20);
for (xx=0; xx<20; xx++) {
- *(my_ptr + xx) = 20 - xx; // my_ptr[xx] = 20-xx 也可以
-} // 初始化内存为 20, 19, 18, 17... 2, 1 (as ints)
+ *(my_ptr + xx) = 20 - xx; // my_ptr[xx] = 20-xx
+} // 初始化内存为 20, 19, 18, 17... 2, 1 (类型为int)
-// 如果对一些未分配的内存取值则会得到未知的结果
+// 对未分配的内存进行取消引用会产生未定义的结果
printf("%d\n", *(my_ptr + 21)); // => 谁知道会输出什么
-// 当你通过malloc得到一块区域后,你需要释放它
+// malloc分配的区域需要手动释放
// 否则没人能够再次使用这块内存,直到程序结束为止
free(my_ptr);
// 字符串通常是字符数组,但是经常用字符指针表示
-// 指针:
-char* my_str = "This is my very own string";
-
+// (它是指向数组的第一个元素的指针)
+// 一个优良的实践是使用`const char *`来引用一个字符串字面量,
+// 因为字符串字面量不应当被修改(即"foo"[0] = 'a'犯了大忌)
+const char* my_str = "This is my very own string";
printf("%c\n", *my_str); // => 'T'
+// 如果字符串是数组,(多半是用字符串字面量初始化的)
+// 情况就不一样了,字符串位于可写的内存中
+char foo[] = "foo";
+foo[0] = 'a'; // 这是合法的,foo现在包含"aoo"
+
function_1();
} // main函数结束
@@ -292,16 +429,21 @@ int add_two_ints(int x1, int x2){
}
/*
-函数是按值传递的, 但是你可以通过传递参数来传递引用,这样函数就可以更改值
+函数是按值传递的。当调用一个函数的时候,传递给函数的参数
+是原有值的拷贝(数组除外)。你在函数内对参数所进行的操作
+不会改变该参数原有的值。
+
+但是你可以通过指针来传递引用,这样函数就可以更改值
例子:字符串本身翻转
*/
// 类型为void的函数没有返回值
-void str_reverse(char* str_in){
+void str_reverse(char *str_in){
char tmp;
- int ii=0, len = strlen(str_in); // Strlen 是C标准库函数
- for(ii=0; ii<len/2; ii++){
+ int ii = 0;
+ size_t len = strlen(str_in); // `strlen()`` 是C标准库函数
+ for(ii = 0; ii < len / 2; ii++){
tmp = str_in[ii];
str_in[ii] = str_in[len - ii - 1]; // 从倒数第ii个开始
str_in[len - ii - 1] = tmp;
@@ -314,6 +456,20 @@ str_reverse(c);
printf("%s\n", c); // => ".tset a si sihT"
*/
+// 如果引用函数之外的变量,必须使用extern关键字
+int i = 0;
+void testFunc() {
+ extern int i; // 使用外部变量 i
+}
+
+// 使用static确保external变量为源文件私有
+static int i = 0; // 其他使用 testFunc()的文件无法访问变量i
+void testFunc() {
+ extern int i;
+}
+//**你同样可以声明函数为static**
+
+
///////////////////////////////////////
// 用户自定义类型和结构
///////////////////////////////////////
@@ -322,12 +478,16 @@ printf("%s\n", c); // => ".tset a si sihT"
typedef int my_type;
my_type my_type_var = 0;
-// 结构是一系列数据的集合
+// struct是数据的集合,成员依序分配,按照
+// 编写的顺序
struct rectangle {
int width;
int height;
};
+// 一般而言,以下断言不成立:
+// sizeof(struct rectangle) == sizeof(int) + sizeof(int)
+//这是因为structure成员之间可能存在潜在的间隙(为了对齐)[1]
void function_1(){
@@ -338,12 +498,12 @@ void function_1(){
my_rec.height = 20;
// 你也可以声明指向结构体的指针
- struct rectangle* my_rec_ptr = &my_rec;
+ struct rectangle *my_rec_ptr = &my_rec;
- // 通过取值来改变结构体的成员...
+ // 通过取消引用来改变结构体的成员...
(*my_rec_ptr).width = 30;
- // ... 或者用 -> 操作符作为简写
+ // ... 或者用 -> 操作符作为简写提高可读性
my_rec_ptr->height = 10; // Same as (*my_rec_ptr).height = 10;
}
@@ -354,18 +514,25 @@ int area(rect r){
return r.width * r.height;
}
+// 如果struct较大,你可以通过指针传递,避免
+// 复制整个struct。
+int area(const rect *r)
+{
+ return r->width * r->height;
+}
+
///////////////////////////////////////
// 函数指针
///////////////////////////////////////
/*
在运行时,函数本身也被存放到某块内存区域当中
-函数指针就像其他指针一样, 但却可以被用来直接调用函数,
-并且可以被四处传递(就像回调函数那样)
-但是,定义的语法有可能在一开始会有些误解
+函数指针就像其他指针一样(不过是存储一个内存地址) 但却可以被用来直接调用函数,
+并且可以四处传递回调函数
+但是,定义的语法初看令人有些迷惑
例子:通过指针调用str_reverse
*/
-void str_reverse_through_pointer(char * str_in) {
+void str_reverse_through_pointer(char *str_in) {
// 定义一个函数指针 f.
void (*f)(char *); // 签名一定要与目标函数相同
f = &str_reverse; // 将函数的地址在运行时赋给指针
@@ -374,7 +541,7 @@ void str_reverse_through_pointer(char * str_in) {
}
/*
-只要函数签名是正确的,任何时候都能将正确的函数赋给某个函数指针
+只要函数签名是正确的,任何时候都能将任何函数赋给某个函数指针
为了可读性和简洁性,函数指针经常和typedef搭配使用:
*/
@@ -384,12 +551,73 @@ typedef void (*my_fnp_type)(char *);
// ...
// my_fnp_type f;
+// 特殊字符
+'\a' // bell
+'\n' // 换行
+'\t' // tab
+'\v' // vertical tab
+'\f' // formfeed
+'\r' // 回车
+'\b' // 退格
+'\0' // null,通常置于字符串的最后。
+ // hello\n\0. 按照惯例,\0用于标记字符串的末尾。
+'\\' // 反斜杠
+'\?' // 问号
+'\'' // 单引号
+'\"' // 双引号
+'\xhh' // 十六进制数字. 例子: '\xb' = vertical tab
+'\ooo' // 十进制数字. 例子: '\013' = vertical tab
+
+// 打印格式:
+"%d" // 整数
+"%3d" // 3位以上整数 (右对齐文本)
+"%s" // 字符串
+"%f" // float
+"%ld" // long
+"%3.2f" // 左3位以上、右2位以上十进制浮
+"%7.4s" // (字符串同样适用)
+"%c" // 字母
+"%p" // 指针
+"%x" // 十六进制
+"%o" // 十进制
+"%%" // 打印 %
+
+///////////////////////////////////////
+// 演算优先级
+///////////////////////////////////////
+//---------------------------------------------------//
+// 操作符 | 组合 //
+//---------------------------------------------------//
+// () [] -> . | 从左到右 //
+// ! ~ ++ -- + = *(type)sizeof | 从右到左 //
+// * / % | 从左到右 //
+// + - | 从左到右 //
+// << >> | 从左到右 //
+// < <= > >= | 从左到右 //
+// == != | 从左到右 //
+// & | 从左到右 //
+// ^ | 从左到右 //
+// | | 从左到右 //
+// && | 从左到右 //
+// || | 从左到右 //
+// ?: | 从右到左 //
+// = += -= *= /= %= &= ^= |= <<= >>= | 从右到左 //
+// , | 从左到右 //
+//---------------------------------------------------//
+
```
## 更多阅读
-最好找一本 [K&R, aka "The C Programming Language", “C程序设计语言”](https://en.wikipedia.org/wiki/The_C_Programming_Language)
+最好找一本 [K&R, aka "The C Programming Language", “C程序设计语言”](https://en.wikipedia.org/wiki/The_C_Programming_Language)。它是关于C最重要的一本书,由C的创作者撰写。不过需要留意的是它比较古老了,因此有些不准确的地方。
+
-其他一些比较好的资源 [Learn C the hard way](http://c.learncodethehardway.org/book/)
+另一个比较好的资源是 [Learn C the hard way](http://c.learncodethehardway.org/book/)
+如果你有问题,请阅读[compl.lang.c Frequently Asked Questions](http://c-faq.com/)。
+
+使用合适的空格、缩进,保持一致的代码风格非常重要。可读性强的代码比聪明的代码、高速的代码更重要。可以参考下[Linux内核编码风格](https://www.kernel.org/doc/Documentation/CodingStyle)
+。
除了这些,多多Google吧
+
+[1] http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member
diff --git a/zh-cn/clojure-cn.html.markdown b/zh-cn/clojure-cn.html.markdown
index d5d8232b..fa241384 100644
--- a/zh-cn/clojure-cn.html.markdown
+++ b/zh-cn/clojure-cn.html.markdown
@@ -2,6 +2,8 @@
language: clojure
filename: learnclojure-cn.clj
contributors:
+ - ["Adam Bard", "http://adambard.com/"]
+translators:
- ["Bill Zhang", "http://jingege.github.io/"]
lang: zh-cn
---
diff --git a/zh-cn/clojure-macro-cn.html.markdown b/zh-cn/clojure-macro-cn.html.markdown
new file mode 100644
index 00000000..9324841e
--- /dev/null
+++ b/zh-cn/clojure-macro-cn.html.markdown
@@ -0,0 +1,152 @@
+---
+language: "clojure macros"
+filename: learnclojuremacros-zh.clj
+contributors:
+ - ["Adam Bard", "http://adambard.com/"]
+translators:
+ - ["Jakukyo Friel", "http://weakish.github.io"]
+lang: zh-cn
+---
+
+和所有Lisp一样,Clojure内在的[同构性](https://en.wikipedia.org/wiki/Homoiconic)使得你可以穷尽语言的特性,编写生成代码的子过程——“宏”。宏是一种按需调制语言的强大方式。
+
+小心!可以用函数完成的事用宏去实现可不是什么好事。你应该仅在需要控制参数是否或者何时eval的时候使用宏。
+
+你应该熟悉Clojure.确保你了解[Y分钟学Clojure](http://learnxinyminutes.com/docs/zh-cn/clojure-cn/)中的所有内容。
+
+```clojure
+;; 使用defmacro定义宏。宏应该输出一个可以作为clojure代码演算的列表。
+;;
+;; 以下宏的效果和直接写(reverse "Hello World")一致。
+
+(defmacro my-first-macro []
+ (list reverse "Hello World"))
+
+;; 使用macroexpand或macroexpand-1查看宏的结果。
+;;
+;; 注意,调用需要引用。
+(macroexpand '(my-first-macro))
+;; -> (#<core$reverse clojure.core$reverse@xxxxxxxx> "Hello World")
+
+;; 你可以直接eval macroexpand的结果
+(eval (macroexpand '(my-first-macro)))
+; -> (\d \l \o \r \W \space \o \l \l \e \H)
+
+;; 不过一般使用以下形式,更简短,更像函数:
+(my-first-macro) ; -> (\d \l \o \r \W \space \o \l \l \e \H)
+
+;; 创建宏的时候可以使用更简短的引用形式来创建列表
+(defmacro my-first-quoted-macro []
+ '(reverse "Hello World"))
+
+(macroexpand '(my-first-quoted-macro))
+;; -> (reverse "Hello World")
+;; 注意reverse不再是一个函数对象,而是一个符号。
+
+;; 宏可以传入参数。
+(defmacro inc2 [arg]
+ (list + 2 arg))
+
+(inc2 2) ; -> 4
+
+;; 不过,如果你尝试配合使用引用列表,会导致错误,
+;; 因为参数也会被引用。
+;; 为了避免这个问题,clojure提供了引用宏的另一种方式:`
+;; 在`之内,你可以使用~获得外圈作用域的变量。
+(defmacro inc2-quoted [arg]
+ `(+ 2 ~arg))
+
+(inc2-quoted 2)
+
+;; 你可以使用通常的析构参数。用~@展开列表中的变量。
+(defmacro unless [arg & body]
+ `(if (not ~arg)
+ (do ~@body))) ; 别忘了 do!
+
+(macroexpand '(unless true (reverse "Hello World")))
+
+;; ->
+;; (if (clojure.core/not true) (do (reverse "Hello World")))
+
+;; 当第一个参数为假时,(unless)会演算、返回主体。
+;; 否则返回nil。
+
+(unless true "Hello") ; -> nil
+(unless false "Hello") ; -> "Hello"
+
+;; 需要小心,宏会搞乱你的变量
+(defmacro define-x []
+ '(do
+ (def x 2)
+ (list x)))
+
+(def x 4)
+(define-x) ; -> (2)
+(list x) ; -> (2)
+
+;; 使用gensym来获得独有的标识符
+(gensym 'x) ; -> x1281 (or some such thing)
+
+(defmacro define-x-safely []
+ (let [sym (gensym 'x)]
+ `(do
+ (def ~sym 2)
+ (list ~sym))))
+
+(def x 4)
+(define-x-safely) ; -> (2)
+(list x) ; -> (4)
+
+;; 你可以在 ` 中使用 # 为每个符号自动生成gensym
+(defmacro define-x-hygenically []
+ `(do
+ (def x# 2)
+ (list x#)))
+
+(def x 4)
+(define-x-hygenically) ; -> (2)
+(list x) ; -> (4)
+
+;; 通常会配合宏使用帮助函数。
+;; 让我们创建一些帮助函数来支持(无聊的)算术语法:
+
+(declare inline-2-helper)
+(defn clean-arg [arg]
+ (if (seq? arg)
+ (inline-2-helper arg)
+ arg))
+
+(defn apply-arg
+ "Given args [x (+ y)], return (+ x y)"
+ [val [op arg]]
+ (list op val (clean-arg arg)))
+
+(defn inline-2-helper
+ [[arg1 & ops-and-args]]
+ (let [ops (partition 2 ops-and-args)]
+ (reduce apply-arg (clean-arg arg1) ops)))
+
+;; 在创建宏前,我们可以先测试
+(inline-2-helper '(a + (b - 2) - (c * 5))) ; -> (- (+ a (- b 2)) (* c 5))
+
+; 然而,如果我们希望它在编译期执行,就需要创建宏
+(defmacro inline-2 [form]
+ (inline-2-helper form)))
+
+(macroexpand '(inline-2 (1 + (3 / 2) - (1 / 2) + 1)))
+; -> (+ (- (+ 1 (/ 3 2)) (/ 1 2)) 1)
+
+(inline-2 (1 + (3 / 2) - (1 / 2) + 1))
+; -> 3 (事实上,结果是3N, 因为数字被转化为带/的有理分数)
+```
+
+## 扩展阅读
+
+[Clojure for the Brave and True](http://www.braveclojure.com/)系列的编写宏
+http://www.braveclojure.com/writing-macros/
+
+官方文档
+http://clojure.org/macros
+
+何时使用宏?
+http://dunsmor.com/lisp/onlisp/onlisp_12.html
diff --git a/zh-cn/coffeescript-cn.html.markdown b/zh-cn/coffeescript-cn.html.markdown
new file mode 100644
index 00000000..44561541
--- /dev/null
+++ b/zh-cn/coffeescript-cn.html.markdown
@@ -0,0 +1,101 @@
+---
+language: coffeescript
+contributors:
+ - ["Tenor Biel", "http://github.com/L8D"]
+ - ["Xavier Yao", "http://github.com/xavieryao"]
+translators:
+ - ["Xavier Yao", "http://github.com/xavieryao"]
+filename: coffeescript-cn.coffee
+lang: zh-cn
+---
+
+CoffeeScript是逐句编译为JavaScript的一种小型语言,且没有运行时的解释器。
+作为JavaScript的替代品之一,CoffeeScript旨在编译人类可读、美观优雅且速度不输原生的代码,
+且编译后的代码可以在任何JavaScript运行时正确运行。
+
+参阅 [CoffeeScript官方网站](http://coffeescript.org/)以获取CoffeeScript的完整教程。
+
+``` coffeescript
+# CoffeeScript是一种很潮的编程语言,
+# 它紧随众多现代编程语言的趋势。
+# 因此正如Ruby和Python,CoffeeScript使用井号标记注释。
+
+###
+大段落注释以此为例,可以被直接编译为 '/ *' 和 '* /' 包裹的JavaScript代码。
+
+在继续之前你需要了解JavaScript的基本概念。
+
+示例中 => 后为编译后的JavaScript代码
+###
+
+# 赋值:
+number = 42 #=> var number = 42;
+opposite = true #=> var opposite = true;
+
+# 条件:
+number = -42 if opposite #=> if(opposite) { number = -42; }
+
+# 函数:
+square = (x) -> x * x #=> var square = function(x) { return x * x; }
+
+fill = (container, liquid = "coffee") ->
+ "Filling the #{container} with #{liquid}..."
+#=>var fill;
+#
+#fill = function(container, liquid) {
+# if (liquid == null) {
+# liquid = "coffee";
+# }
+# return "Filling the " + container + " with " + liquid + "...";
+#};
+
+# 区间:
+list = [1..5] #=> var list = [1, 2, 3, 4, 5];
+
+# 对象:
+math =
+ root: Math.sqrt
+ square: square
+ cube: (x) -> x * square x
+#=> var math = {
+# "root": Math.sqrt,
+# "square": square,
+# "cube": function(x) { return x * square(x); }
+#}
+
+# Splats:
+race = (winner, runners...) ->
+ print winner, runners
+#=>race = function() {
+# var runners, winner;
+# winner = arguments[0], runners = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
+# return print(winner, runners);
+#};
+
+# 存在判断:
+alert "I knew it!" if elvis?
+#=> if(typeof elvis !== "undefined" && elvis !== null) { alert("I knew it!"); }
+
+# 数组推导:
+cubes = (math.cube num for num in list)
+#=>cubes = (function() {
+# var _i, _len, _results;
+# _results = [];
+# for (_i = 0, _len = list.length; _i < _len; _i++) {
+# num = list[_i];
+# _results.push(math.cube(num));
+# }
+# return _results;
+# })();
+
+foods = ['broccoli', 'spinach', 'chocolate']
+eat food for food in foods when food isnt 'chocolate'
+#=>foods = ['broccoli', 'spinach', 'chocolate'];
+#
+#for (_k = 0, _len2 = foods.length; _k < _len2; _k++) {
+# food = foods[_k];
+# if (food !== 'chocolate') {
+# eat(food);
+# }
+#}
+```
diff --git a/zh-cn/common-lisp-cn.html.markdown b/zh-cn/common-lisp-cn.html.markdown
index f005dd58..c4dc3274 100644
--- a/zh-cn/common-lisp-cn.html.markdown
+++ b/zh-cn/common-lisp-cn.html.markdown
@@ -56,11 +56,11 @@ t ;还是一个原子,代表逻辑真值。
;; 有很多不同的Common Lisp的实现;并且大部分的实现是一致(可移植)的。
;; 对于入门学习来说,CLISP是个不错的选择。
-;; 可以通过QuickLisp.org's Quicklisp系统可以管理你的库。
+;; 可以通过QuickLisp.org的Quicklisp系统管理你的库。
-;; 通常,使用一个文本编辑器和一个的“REPL”来开发Common Lisp;
+;; 通常,使用文本编辑器和“REPL”来开发Common Lisp;
;; (译者注:“REPL”指读取-求值-打印循环)。
-;; “REPL”允许对程序进行交互式的运行、调试,就好像在系统中这是一场“现场直播”。
+;; “REPL”允许对程序进行交互式的运行、调试,就好像在系统“现场”操作。
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -329,7 +329,7 @@ nil ; 逻辑假,或者空列表
;; 或者使用`apply`
(apply (lambda () "Hello World") nil) ; => "Hello World"
-;; 显示地定义一个函数(译者注:即非匿名的)
+;; 显式地定义一个函数(译者注:即非匿名的)
(defun hello-world ()
"Hello World")
(hello-world) ; => "Hello World"
@@ -537,7 +537,7 @@ nil ; 逻辑假,或者空列表
;; 注意到这些有用的返回信息——Common Lisp一直是一个交互式的系统。
;; 若要定义一个方法;
-;; 先让我们注意到我们计算自行车轮子周长时使用了这样一个公式:C = d * pi
+;; 注意,我们计算自行车轮子周长时使用了这样一个公式:C = d * pi
(defmethod circumference ((object bicycle))
(* pi (wheel-size object)))
@@ -593,7 +593,7 @@ nil ; 逻辑假,或者空列表
;; 然而,在一个比较现代化的编译环境下,这样的WHILE是没有必要的;
;; LOOP形式的循环和这个WHILE同样的好,并且更易于阅读。
-;; 注意到反引号'`',逗号','以及'@'符号,这三个符号;
+;; 注意反引号'`',逗号','以及'@'这三个符号;
;; 反引号'`'是一种所谓“quasiquote”的引用类型的运算符,有了它,之后的逗号“,”才有意义。
;; 逗号“,”意味着解除引用(unquote,即开始求值);
;; “@”符号则表示将当前的参数插入到当前整个列表中。
diff --git a/zh-cn/csharp-cn.html.markdown b/zh-cn/csharp-cn.html.markdown
new file mode 100644
index 00000000..a3cda5b3
--- /dev/null
+++ b/zh-cn/csharp-cn.html.markdown
@@ -0,0 +1,798 @@
+---
+language: c#
+contributors:
+ - ["Irfan Charania", "https://github.com/irfancharania"]
+ - ["Max Yankov", "https://github.com/golergka"]
+ - ["Melvyn Laïly", "http://x2a.yt"]
+ - ["Shaun McCarthy", "http://www.shaunmccarthy.com"]
+translators:
+ - ["Jakukyo Friel", "http://weakish.github.io"]
+filename: LearnCSharp-cn.cs
+lang: zh-cn
+---
+
+
+C#是一个优雅的、类型安全的面向对象语言。使用C#,开发者可以在.NET框架下构建安全、健壮的应用程序。
+
+[更多关于C#的介绍](http://msdn.microsoft.com/en-us/library/vstudio/z1zx9t92.aspx)
+
+```c#
+// 单行注释以 // 开始
+/*
+多行注释是这样的
+*/
+/// <summary>
+/// XML文档注释
+/// </summary>
+
+// 声明应用用到的命名空间
+using System;
+using System.Collections.Generic;
+using System.Data.Entity;
+using System.Dynamic;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Net;
+using System.Threading.Tasks;
+using System.IO;
+
+// 定义作用域,将代码组织成包
+namespace Learning
+{
+ // 每个 .cs 文件至少需要包含一个和文件名相同的类
+ // 你可以不这么干,但是这样不好。
+ public class LearnCSharp
+ {
+ // 基本语法 - 如果你以前用过 Java 或 C++ 的话,可以直接跳到后文「有趣的特性」
+ public static void Syntax()
+ {
+ // 使用 Console.WriteLine 打印信息
+ Console.WriteLine("Hello World");
+ Console.WriteLine(
+ "Integer: " + 10 +
+ " Double: " + 3.14 +
+ " Boolean: " + true);
+
+ // 使用 Console.Write 打印,不带换行符号
+ Console.Write("Hello ");
+ Console.Write("World");
+
+ ///////////////////////////////////////////////////
+ // 类型和变量
+ //
+ // 使用 <type> <name> 定义变量
+ ///////////////////////////////////////////////////
+
+ // Sbyte - 有符号 8-bit 整数
+ // (-128 <= sbyte <= 127)
+ sbyte fooSbyte = 100;
+
+ // Byte - 无符号 8-bit 整数
+ // (0 <= byte <= 255)
+ byte fooByte = 100;
+
+ // Short - 16-bit 整数
+ // 有符号 - (-32,768 <= short <= 32,767)
+ // 无符号 - (0 <= ushort <= 65,535)
+ short fooShort = 10000;
+ ushort fooUshort = 10000;
+
+ // Integer - 32-bit 整数
+ int fooInt = 1; // (-2,147,483,648 <= int <= 2,147,483,647)
+ uint fooUint = 1; // (0 <= uint <= 4,294,967,295)
+
+ // Long - 64-bit 整数
+ long fooLong = 100000L; // (-9,223,372,036,854,775,808 <= long <= 9,223,372,036,854,775,807)
+ ulong fooUlong = 100000L; // (0 <= ulong <= 18,446,744,073,709,551,615)
+ // 数字默认为 int 或 uint (取决于尺寸)
+ // 使用 L 标明变量值类型为long 或 ulong
+
+ // Double - 双精度 64-bit IEEE 754 浮点数
+ double fooDouble = 123.4; // 精度: 15-16 位
+
+ // Float - 单精度 32-bit IEEE 754 浮点数
+ float fooFloat = 234.5f; // 精度: 7 位
+ // 使用 f 标明变量值类型为float
+
+ // Decimal - 128-bits 数据类型,比其他浮点类型精度更高
+ // 适合财务、金融
+ decimal fooDecimal = 150.3m;
+
+ // 布尔值 - true & false
+ bool fooBoolean = true; // 或 false
+
+ // Char - 单个 16-bit Unicode 字符
+ char fooChar = 'A';
+
+ // 字符串 -- 和前面的基本类型不同,字符串不是值,而是引用。
+ // 这意味着你可以将字符串设为null。
+ string fooString = "\"escape\" quotes and add \n (new lines) and \t (tabs)";
+ Console.WriteLine(fooString);
+
+ // 你可以通过索引访问字符串的每个字符:
+ char charFromString = fooString[1]; // => 'e'
+ // 字符串不可修改: fooString[1] = 'X' 是行不通的;
+
+ // 根据当前的locale设定比较字符串,大小写不敏感
+ string.Compare(fooString, "x", StringComparison.CurrentCultureIgnoreCase);
+
+ // 基于sprintf的字符串格式化
+ string fooFs = string.Format("Check Check, {0} {1}, {0} {1:0.0}", 1, 2);
+
+ // 日期和格式
+ DateTime fooDate = DateTime.Now;
+ Console.WriteLine(fooDate.ToString("hh:mm, dd MMM yyyy"));
+
+ // 使用 @ 符号可以创建跨行的字符串。使用 "" 来表示 "
+ string bazString = @"Here's some stuff
+on a new line! ""Wow!"", the masses cried";
+
+ // 使用const或read-only定义常量
+ // 常量在编译期演算
+ const int HOURS_I_WORK_PER_WEEK = 9001;
+
+ ///////////////////////////////////////////////////
+ // 数据结构
+ ///////////////////////////////////////////////////
+
+ // 数组 - 从0开始计数
+ // 声明数组时需要确定数组长度
+ // 声明数组的格式如下:
+ // <datatype>[] <var name> = new <datatype>[<array size>];
+ int[] intArray = new int[10];
+
+ // 声明并初始化数组的其他方式:
+ int[] y = { 9000, 1000, 1337 };
+
+ // 访问数组的元素
+ Console.WriteLine("intArray @ 0: " + intArray[0]);
+ // 数组可以修改
+ intArray[1] = 1;
+
+ // 列表
+ // 列表比数组更常用,因为列表更灵活。
+ // 声明列表的格式如下:
+ // List<datatype> <var name> = new List<datatype>();
+ List<int> intList = new List<int>();
+ List<string> stringList = new List<string>();
+ List<int> z = new List<int> { 9000, 1000, 1337 }; // i
+ // <>用于泛型 - 参考下文
+
+ // 列表无默认值
+ // 访问列表元素时必须首先添加元素
+ intList.Add(1);
+ Console.WriteLine("intList @ 0: " + intList[0]);
+
+ // 其他数据结构:
+ // 堆栈/队列
+ // 字典 (哈希表的实现)
+ // 哈希集合
+ // 只读集合
+ // 元组 (.Net 4+)
+
+ ///////////////////////////////////////
+ // 操作符
+ ///////////////////////////////////////
+ Console.WriteLine("\n->Operators");
+
+ int i1 = 1, i2 = 2; // 多重声明的简写形式
+
+ // 算术直截了当
+ Console.WriteLine(i1 + i2 - i1 * 3 / 7); // => 3
+
+ // 取余
+ Console.WriteLine("11%3 = " + (11 % 3)); // => 2
+
+ // 比较操作符
+ Console.WriteLine("3 == 2? " + (3 == 2)); // => false
+ Console.WriteLine("3 != 2? " + (3 != 2)); // => true
+ Console.WriteLine("3 > 2? " + (3 > 2)); // => true
+ Console.WriteLine("3 < 2? " + (3 < 2)); // => false
+ Console.WriteLine("2 <= 2? " + (2 <= 2)); // => true
+ Console.WriteLine("2 >= 2? " + (2 >= 2)); // => true
+
+ // 位操作符
+ /*
+ ~ 取反
+ << 左移(有符号)
+ >> 右移(有符号)
+ & 与
+ ^ 异或
+ | 或
+ */
+
+ // 自增、自减
+ int i = 0;
+ Console.WriteLine("\n->Inc/Dec-rementation");
+ Console.WriteLine(i++); //i = 1. 事后自增
+ Console.WriteLine(++i); //i = 2. 事先自增
+ Console.WriteLine(i--); //i = 1. 事后自减
+ Console.WriteLine(--i); //i = 0. 事先自减
+
+ ///////////////////////////////////////
+ // 控制结构
+ ///////////////////////////////////////
+ Console.WriteLine("\n->Control Structures");
+
+ // 类似C的if语句
+ int j = 10;
+ if (j == 10)
+ {
+ Console.WriteLine("I get printed");
+ }
+ else if (j > 10)
+ {
+ Console.WriteLine("I don't");
+ }
+ else
+ {
+ Console.WriteLine("I also don't");
+ }
+
+ // 三元表达式
+ // 简单的 if/else 语句可以写成:
+ // <条件> ? <真> : <假>
+ string isTrue = (true) ? "True" : "False";
+
+ // While 循环
+ int fooWhile = 0;
+ while (fooWhile < 100)
+ {
+ //迭代 100 次, fooWhile 0->99
+ fooWhile++;
+ }
+
+ // Do While 循环
+ int fooDoWhile = 0;
+ do
+ {
+ //迭代 100 次, fooDoWhile 0->99
+ fooDoWhile++;
+ } while (fooDoWhile < 100);
+
+ //for 循环结构 => for(<初始条件>; <条件>; <步>)
+ for (int fooFor = 0; fooFor < 10; fooFor++)
+ {
+ //迭代10次, fooFor 0->9
+ }
+
+ // foreach循环
+ // foreach 循环结构 => foreach(<迭代器类型> <迭代器> in <可枚举结构>)
+ // foreach 循环适用于任何实现了 IEnumerable 或 IEnumerable<T> 的对象。
+ // .Net 框架下的集合类型(数组, 列表, 字典...)
+ // 都实现了这些接口
+ // (下面的代码中,ToCharArray()可以删除,因为字符串同样实现了IEnumerable)
+ foreach (char character in "Hello World".ToCharArray())
+ {
+ //迭代字符串中的所有字符
+ }
+
+ // Switch 语句
+ // switch 适用于 byte、short、char和int 数据类型。
+ // 同样适用于可枚举的类型
+ // 包括字符串类, 以及一些封装了原始值的类:
+ // Character、Byte、Short和Integer。
+ int month = 3;
+ string monthString;
+ switch (month)
+ {
+ case 1:
+ monthString = "January";
+ break;
+ case 2:
+ monthString = "February";
+ break;
+ case 3:
+ monthString = "March";
+ break;
+ // 你可以一次匹配多个case语句
+ // 但是你在添加case语句后需要使用break
+ // (否则你需要显式地使用goto case x语句)
+ case 6:
+ case 7:
+ case 8:
+ monthString = "Summer time!!";
+ break;
+ default:
+ monthString = "Some other month";
+ break;
+ }
+
+ ///////////////////////////////////////
+ // 转换、指定数据类型
+ ///////////////////////////////////////
+
+ // 转换类型
+
+ // 转换字符串为整数
+ // 转换失败会抛出异常
+ int.Parse("123");//返回整数类型的"123"
+
+ // TryParse会尝试转换类型,失败时会返回缺省类型
+ // 例如 0
+ int tryInt;
+ if (int.TryParse("123", out tryInt)) // Funciton is boolean
+ Console.WriteLine(tryInt); // 123
+
+ // 转换整数为字符串
+ // Convert类提供了一系列便利转换的方法
+ Convert.ToString(123);
+ // or
+ tryInt.ToString();
+ }
+
+ ///////////////////////////////////////
+ // 类
+ ///////////////////////////////////////
+ public static void Classes()
+ {
+ // 参看文件尾部的对象声明
+
+ // 使用new初始化对象
+ Bicycle trek = new Bicycle();
+
+ // 调用对象的方法
+ trek.SpeedUp(3); // 你应该一直使用setter和getter方法
+ trek.Cadence = 100;
+
+ // 查看对象的信息.
+ Console.WriteLine("trek info: " + trek.Info());
+
+ // 实例化一个新的Penny Farthing
+ PennyFarthing funbike = new PennyFarthing(1, 10);
+ Console.WriteLine("funbike info: " + funbike.Info());
+
+ Console.Read();
+ } // 结束main方法
+
+ // 终端程序 终端程序必须有一个main方法作为入口
+ public static void Main(string[] args)
+ {
+ OtherInterestingFeatures();
+ }
+
+ //
+ // 有趣的特性
+ //
+
+ // 默认方法签名
+
+ public // 可见性
+ static // 允许直接调用类,无需先创建实例
+ int, //返回值
+ MethodSignatures(
+ int maxCount, // 第一个变量,类型为整型
+ int count = 0, // 如果没有传入值,则缺省值为0
+ int another = 3,
+ params string[] otherParams // 捕获其他参数
+ )
+ {
+ return -1;
+ }
+
+ // 方法可以重名,只要签名不一样
+ public static void MethodSignature(string maxCount)
+ {
+ }
+
+ //泛型
+ // TKey和TValue类由用用户调用函数时指定。
+ // 以下函数模拟了Python的SetDefault
+ public static TValue SetDefault<TKey, TValue>(
+ IDictionary<TKey, TValue> dictionary,
+ TKey key,
+ TValue defaultItem)
+ {
+ TValue result;
+ if (!dictionary.TryGetValue(key, out result))
+ return dictionary[key] = defaultItem;
+ return result;
+ }
+
+ // 你可以限定传入值的范围
+ public static void IterateAndPrint<T>(T toPrint) where T: IEnumerable<int>
+ {
+ // 我们可以进行迭代,因为T是可枚举的
+ foreach (var item in toPrint)
+ // ittm为整数
+ Console.WriteLine(item.ToString());
+ }
+
+ public static void OtherInterestingFeatures()
+ {
+ // 可选参数
+ MethodSignatures(3, 1, 3, "Some", "Extra", "Strings");
+ MethodSignatures(3, another: 3); // 显式指定参数,忽略可选参数
+
+ // 扩展方法
+ int i = 3;
+ i.Print(); // 参见下面的定义
+
+ // 可为null的类型 对数据库交互、返回值很有用
+ // 任何值类型 (i.e. 不为类) 添加后缀 ? 后会变为可为null的值
+ // <类型>? <变量名> = <值>
+ int? nullable = null; // Nullable<int> 的简写形式
+ Console.WriteLine("Nullable variable: " + nullable);
+ bool hasValue = nullable.HasValue; // 不为null时返回真
+ // ?? 是用于指定默认值的语法糖
+ // 以防变量为null的情况
+ int notNullable = nullable ?? 0; // 0
+
+ // 变量类型推断 - 你可以让编译器推断变量类型:
+ var magic = "编译器确定magic是一个字符串,所以仍然是类型安全的";
+ // magic = 9; // 不工作,因为magic是字符串,而不是整数。
+
+ // 泛型
+ //
+ var phonebook = new Dictionary<string, string>() {
+ {"Sarah", "212 555 5555"} // 在电话簿中加入新条目
+ };
+
+ // 调用上面定义为泛型的SETDEFAULT
+ Console.WriteLine(SetDefault<string,string>(phonebook, "Shaun", "No Phone")); // 没有电话
+ // 你不用指定TKey、TValue,因为它们会被隐式地推导出来
+ Console.WriteLine(SetDefault(phonebook, "Sarah", "No Phone")); // 212 555 5555
+
+ // lambda表达式 - 允许你用一行代码搞定函数
+ Func<int, int> square = (x) => x * x; // 最后一项为返回值
+ Console.WriteLine(square(3)); // 9
+
+ // 可抛弃的资源管理 - 让你很容易地处理未管理的资源
+ // 大多数访问未管理资源 (文件操作符、设备上下文, etc.)的对象
+ // 都实现了IDisposable接口。
+ // using语句会为你清理IDisposable对象。
+ using (StreamWriter writer = new StreamWriter("log.txt"))
+ {
+ writer.WriteLine("这里没有什么可疑的东西");
+ // 在作用域的结尾,资源会被回收
+ // (即使有异常抛出,也一样会回收)
+ }
+
+ // 并行框架
+ // http://blogs.msdn.com/b/csharpfaq/archive/2010/06/01/parallel-programming-in-net-framework-4-getting-started.aspx
+ var websites = new string[] {
+ "http://www.google.com", "http://www.reddit.com",
+ "http://www.shaunmccarthy.com"
+ };
+ var responses = new Dictionary<string, string>();
+
+ // 为每个请求新开一个线程
+ // 在运行下一步前合并结果
+ Parallel.ForEach(websites,
+ new ParallelOptions() {MaxDegreeOfParallelism = 3}, // max of 3 threads
+ website =>
+ {
+ // Do something that takes a long time on the file
+ using (var r = WebRequest.Create(new Uri(website)).GetResponse())
+ {
+ responses[website] = r.ContentType;
+ }
+ });
+
+ // 直到所有的请求完成后才会运行下面的代码
+ foreach (var key in responses.Keys)
+ Console.WriteLine("{0}:{1}", key, responses[key]);
+
+ // 动态对象(配合其他语言使用很方便)
+ dynamic student = new ExpandoObject();
+ student.FirstName = "First Name"; // 不需要先定义类!
+
+ // 你甚至可以添加方法(接受一个字符串,输出一个字符串)
+ student.Introduce = new Func<string, string>(
+ (introduceTo) => string.Format("Hey {0}, this is {1}", student.FirstName, introduceTo));
+ Console.WriteLine(student.Introduce("Beth"));
+
+ // IQUERYABLE<T> - 几乎所有的集合都实现了它,
+ // 带给你 Map / Filter / Reduce 风格的方法
+ var bikes = new List<Bicycle>();
+ bikes.Sort(); // Sorts the array
+ bikes.Sort((b1, b2) => b1.Wheels.CompareTo(b2.Wheels)); // 根据车轮数排序
+ var result = bikes
+ .Where(b => b.Wheels > 3) // 筛选 - 可以连锁使用 (返回IQueryable)
+ .Where(b => b.IsBroken && b.HasTassles)
+ .Select(b => b.ToString()); // Map - 这里我们使用了select,所以结果是IQueryable<string>
+
+ var sum = bikes.Sum(b => b.Wheels); // Reduce - 计算集合中的轮子总数
+
+ // 创建一个包含基于自行车的一些参数生成的隐式对象的列表
+ var bikeSummaries = bikes.Select(b=>new { Name = b.Name, IsAwesome = !b.IsBroken && b.HasTassles });
+ // 很难演示,但是编译器在代码编译完成前就能推导出以上对象的类型
+ foreach (var bikeSummary in bikeSummaries.Where(b => b.IsAwesome))
+ Console.WriteLine(bikeSummary.Name);
+
+ // ASPARALLEL
+ // 邪恶的特性 —— 组合了linq和并行操作
+ var threeWheelers = bikes.AsParallel().Where(b => b.Wheels == 3).Select(b => b.Name);
+ // 以上代码会并发地运行。会自动新开线程,分别计算结果。
+ // 适用于多核、大数据量的场景。
+
+ // LINQ - 将IQueryable<T>映射到存储,延缓执行
+ // 例如 LinqToSql 映射数据库, LinqToXml 映射XML文档
+ var db = new BikeRespository();
+
+ // 执行被延迟了,这对于查询数据库来说很好
+ var filter = db.Bikes.Where(b => b.HasTassles); // 不运行查询
+ if (42 > 6) // 你可以不断地增加筛选,包括有条件的筛选,例如用于“高级搜索”功能
+ filter = filter.Where(b => b.IsBroken); // 不运行查询
+
+ var query = filter
+ .OrderBy(b => b.Wheels)
+ .ThenBy(b => b.Name)
+ .Select(b => b.Name); // 仍然不运行查询
+
+ // 现在运行查询,运行查询的时候会打开一个读取器,所以你迭代的是一个副本
+ foreach (string bike in query)
+ Console.WriteLine(result);
+
+
+
+ }
+
+ } // 结束LearnCSharp类
+
+ // 你可以在同一个 .cs 文件中包含其他类
+
+ public static class Extensions
+ {
+ // 扩展函数
+ public static void Print(this object obj)
+ {
+ Console.WriteLine(obj.ToString());
+ }
+ }
+ // 声明类的语法:
+ // <public/private/protected/internal> class <类名>{
+ // //数据字段, 构造器, 内部函数.
+ / // 在Java中函数被称为方法。
+ // }
+
+ public class Bicycle
+ {
+ // 自行车的字段、变量
+ public int Cadence // Public: 任何地方都可以访问
+ {
+ get // get - 定义获取属性的方法
+ {
+ return _cadence;
+ }
+ set // set - 定义设置属性的方法
+ {
+ _cadence = value; // value是被传递给setter的值
+ }
+ }
+ private int _cadence;
+
+ protected virtual int Gear // 类和子类可以访问
+ {
+ get; // 创建一个自动属性,无需成员字段
+ set;
+ }
+
+ internal int Wheels // Internal:在同一程序集内可以访问
+ {
+ get;
+ private set; // 可以给get/set方法添加修饰符
+ }
+
+ int _speed; // 默认为private: 只可以在这个类内访问,你也可以使用`private`关键词
+ public string Name { get; set; }
+
+ // enum类型包含一组常量
+ // 它将名称映射到值(除非特别说明,是一个整型)
+ // enmu元素的类型可以是byte、sbyte、short、ushort、int、uint、long、ulong。
+ // enum不能包含相同的值。
+ public enum BikeBrand
+ {
+ AIST,
+ BMC,
+ Electra = 42, //你可以显式地赋值
+ Gitane // 43
+ }
+ // 我们在Bicycle类中定义的这个类型,所以它是一个内嵌类型。
+ // 这个类以外的代码应当使用`Bicycle.Brand`来引用。
+
+ public BikeBrand Brand; // 声明一个enum类型之后,我们可以声明这个类型的字段
+
+ // 静态方法的类型为自身,不属于特定的对象。
+ // 你无需引用对象就可以访问他们。
+ // Console.WriteLine("Bicycles created: " + Bicycle.bicyclesCreated);
+ static public int BicyclesCreated = 0;
+
+ // 只读值在运行时确定
+ // 它们只能在声明或构造器内被赋值
+ readonly bool _hasCardsInSpokes = false; // read-only private
+
+ // 构造器是创建类的一种方式
+ // 下面是一个默认的构造器
+ public Bicycle()
+ {
+ this.Gear = 1; // 你可以使用关键词this访问对象的成员
+ Cadence = 50; // 不过你并不总是需要它
+ _speed = 5;
+ Name = "Bontrager";
+ Brand = BikeBrand.AIST;
+ BicyclesCreated++;
+ }
+
+ // 另一个构造器的例子(包含参数)
+ public Bicycle(int startCadence, int startSpeed, int startGear,
+ string name, bool hasCardsInSpokes, BikeBrand brand)
+ : base() // 首先调用base
+ {
+ Gear = startGear;
+ Cadence = startCadence;
+ _speed = startSpeed;
+ Name = name;
+ _hasCardsInSpokes = hasCardsInSpokes;
+ Brand = brand;
+ }
+
+ // 构造器可以连锁使用
+ public Bicycle(int startCadence, int startSpeed, BikeBrand brand) :
+ this(startCadence, startSpeed, 0, "big wheels", true, brand)
+ {
+ }
+
+ // 函数语法
+ // <public/private/protected> <返回值> <函数名称>(<参数>)
+
+ // 类可以为字段实现 getters 和 setters 方法 for their fields
+ // 或者可以实现属性(C#推荐使用这个)
+ // 方法的参数可以有默认值
+ // 在有默认值的情况下,调用方法的时候可以省略相应的参数
+ public void SpeedUp(int increment = 1)
+ {
+ _speed += increment;
+ }
+
+ public void SlowDown(int decrement = 1)
+ {
+ _speed -= decrement;
+ }
+
+ // 属性可以访问和设置值
+ // 当只需要访问数据的时候,考虑使用属性。
+ // 属性可以定义get和set,或者是同时定义两者
+ private bool _hasTassles; // private variable
+ public bool HasTassles // public accessor
+ {
+ get { return _hasTassles; }
+ set { _hasTassles = value; }
+ }
+
+ // 你可以在一行之内定义自动属性
+ // 这个语法会自动创建后备字段
+ // 你可以给getter或setter设置访问修饰符
+ // 以便限制它们的访问
+ public bool IsBroken { get; private set; }
+
+ // 属性的实现可以是自动的
+ public int FrameSize
+ {
+ get;
+ // 你可以给get或set指定访问修饰符
+ // 以下代码意味着只有Bicycle类可以调用Framesize的set
+ private set;
+ }
+
+ //显示对象属性的方法
+ public virtual string Info()
+ {
+ return "Gear: " + Gear +
+ " Cadence: " + Cadence +
+ " Speed: " + _speed +
+ " Name: " + Name +
+ " Cards in Spokes: " + (_hasCardsInSpokes ? "yes" : "no") +
+ "\n------------------------------\n"
+ ;
+ }
+
+ // 方法可以是静态的。通常用于辅助方法。
+ public static bool DidWeCreateEnoughBycles()
+ {
+ // 在静态方法中,你只能引用类的静态成员
+ return BicyclesCreated > 9000;
+ } // 如果你的类只需要静态成员,考虑将整个类作为静态类。
+
+
+ } // Bicycle类结束
+
+ // PennyFarthing是Bicycle的一个子类
+ class PennyFarthing : Bicycle
+ {
+ // (Penny Farthings是一种前轮很大的自行车。没有齿轮。)
+
+ // 调用父构造器
+ public PennyFarthing(int startCadence, int startSpeed) :
+ base(startCadence, startSpeed, 0, "PennyFarthing", true, BikeBrand.Electra)
+ {
+ }
+
+ protected override int Gear
+ {
+ get
+ {
+ return 0;
+ }
+ set
+ {
+ throw new ArgumentException("你不可能在PennyFarthing上切换齿轮");
+ }
+ }
+
+ public override string Info()
+ {
+ string result = "PennyFarthing bicycle ";
+ result += base.ToString(); // 调用父方法
+ return result;
+ }
+ }
+
+ // 接口只包含成员的签名,而没有实现。
+ interface IJumpable
+ {
+ void Jump(int meters); // 所有接口成员是隐式地公开的
+ }
+
+ interface IBreakable
+ {
+ bool Broken { get; } // 接口可以包含属性、方法和事件
+ }
+
+ // 类只能继承一个类,但是可以实现任意数量的接口
+ {
+ int damage = 0;
+
+ public void Jump(int meters)
+ {
+ damage += meters;
+ }
+
+ public bool Broken
+ {
+ get
+ {
+ return damage > 100;
+ }
+ }
+ }
+
+ /// <summary>
+ /// 连接数据库,一个 LinqToSql的示例。
+ /// EntityFramework Code First 很棒 (类似 Ruby的 ActiveRecord, 不过是双向的)
+ /// http://msdn.microsoft.com/en-us/data/jj193542.aspx
+ /// </summary>
+ public class BikeRespository : DbSet
+ {
+ public BikeRespository()
+ : base()
+ {
+ }
+
+ public DbSet<Bicycle> Bikes { get; set; }
+ }
+} // 结束 Namespace
+```
+
+## 没有涉及到的主题
+
+ * Flags
+ * Attributes
+ * 静态属性
+ * Exceptions, Abstraction
+ * ASP.NET (Web Forms/MVC/WebMatrix)
+ * Winforms
+ * Windows Presentation Foundation (WPF)
+
+## 扩展阅读
+
+ * [DotNetPerls](http://www.dotnetperls.com)
+ * [C# in Depth](http://manning.com/skeet2)
+ * [Programming C#](http://shop.oreilly.com/product/0636920024064.do)
+ * [LINQ](http://shop.oreilly.com/product/9780596519254.do)
+ * [MSDN Library](http://msdn.microsoft.com/en-us/library/618ayhy6.aspx)
+ * [ASP.NET MVC Tutorials](http://www.asp.net/mvc/tutorials)
+ * [ASP.NET Web Matrix Tutorials](http://www.asp.net/web-pages/tutorials)
+ * [ASP.NET Web Forms Tutorials](http://www.asp.net/web-forms/tutorials)
+ * [Windows Forms Programming in C#](http://www.amazon.com/Windows-Forms-Programming-Chris-Sells/dp/0321116208)
+ * [C# Coding Conventions](http://msdn.microsoft.com/en-us/library/vstudio/ff926074.aspx)
diff --git a/zh-cn/css-cn.html.markdown b/zh-cn/css-cn.html.markdown
new file mode 100644
index 00000000..dc6dcc4f
--- /dev/null
+++ b/zh-cn/css-cn.html.markdown
@@ -0,0 +1,212 @@
+---
+language: css
+contributors:
+ - ["Mohammad Valipour", "https://github.com/mvalipour"]
+ - ["Marco Scannadinari", "https://github.com/marcoms"]
+translators:
+ - ["Jakukyo Friel", "https://weakish.github.io"]
+lang: zh-cn
+filename: learncss-cn.css
+---
+
+早期的web没有样式,只是单纯的文本。通过CSS,可以实现网页样式和内容的分离。
+
+简单来说,CSS可以指定HTML页面上的元素所使用的样式。
+
+和其他语言一样,CSS有很多版本。最新的版本是CSS 3. CSS 2.0兼容性最好。
+
+你可以使用[dabblet](http://dabblet.com/)来在线测试CSS的效果。
+
+```css
+/* 注释 */
+
+/* ####################
+ ## 选择器
+ ####################*/
+
+/* 一般而言,CSS的声明语句非常简单。 */
+选择器 { 属性: 值; /* 更多属性...*/ }
+
+/* 选择器用于指定页面上的元素。
+
+针对页面上的所有元素。 */
+* { color:red; }
+
+/*
+假定页面上有这样一个元素
+
+<div class='some-class class2' id='someId' attr='value' />
+*/
+
+/* 你可以通过类名来指定它 */
+.some-class { }
+
+/* 给出所有类名 */
+.some-class.class2 { }
+
+/* 标签名 */
+div { }
+
+/* id */
+#someId { }
+
+/* 由于元素包含attr属性,因此也可以通过这个来指定 */
+[attr] { font-size:smaller; }
+
+/* 以及有特定值的属性 */
+[attr='value'] { font-size:smaller; }
+
+/* 通过属性的值的开头指定 */
+[attr^='val'] { font-size:smaller; }
+
+/* 通过属性的值的结尾来指定 */
+[attr$='ue'] { font-size:smaller; }
+
+/* 通过属性的值的部分来指定 */
+[attr~='lu'] { font-size:smaller; }
+
+
+/* 你可以把这些全部结合起来,注意不同部分间不应该有空格,否则会改变语义 */
+div.some-class[attr$='ue'] { }
+
+/* 你也可以通过父元素来指定。*/
+
+/* 某个元素是另一个元素的直接子元素 */
+div.some-parent > .class-name {}
+
+/* 或者通过该元素的祖先元素 */
+div.some-parent .class-name {}
+
+/* 注意,去掉空格后语义就不同了。
+你能说出哪里不同么? */
+div.some-parent.class-name {}
+
+/* 你可以选择某元素前的相邻元素 */
+.i-am-before + .this-element { }
+
+/* 某元素之前的同级元素(相邻或不相邻) */
+.i-am-any-before ~ .this-element {}
+
+/* 伪类允许你基于页面的行为指定元素(而不是基于页面结构) */
+
+/* 例如,当鼠标悬停在某个元素上时 */
+:hover {}
+
+/* 已访问过的链接*/
+:visited {}
+
+/* 未访问过的链接*/
+:link {}
+
+/* 当前焦点的input元素 */
+:focus {}
+
+
+/* ####################
+ ## 属性
+ ####################*/
+
+选择器 {
+
+ /* 单位 */
+ width: 50%; /* 百分比 */
+ font-size: 2em; /* 当前字体大小的两倍 */
+ width: 200px; /* 像素 */
+ font-size: 20pt; /* 点 */
+ width: 5cm; /* 厘米 */
+ width: 50mm; /* 毫米 */
+ width: 5in; /* 英尺 */
+
+ /* 颜色 */
+ background-color: #F6E; /* 短16位 */
+ background-color: #F262E2; /* 长16位 */
+ background-color: tomato; /* 颜色名称 */
+ background-color: rgb(255, 255, 255); /* rgb */
+ background-color: rgb(10%, 20%, 50%); /* rgb 百分比 */
+ background-color: rgba(255, 0, 0, 0.3); /* rgb 加透明度 */
+
+ /* 图片 */
+ background-image: url(/path-to-image/image.jpg);
+
+ /* 字体 */
+ font-family: Arial;
+ font-family: "Courier New"; /* 使用双引号包裹含空格的字体名称 */
+ font-family: "Courier New", Trebuchet, Arial; /* 如果第一个
+ 字体没找到,浏览器会使用第二个字体,一次类推 */
+}
+
+```
+
+## 使用
+
+CSS文件使用 `.css` 后缀。
+
+```xml
+<!-- 你需要在文件的 <head> 引用CSS文件 -->
+<link rel='stylesheet' type='text/css' href='filepath/filename.css' />
+
+<!-- 你也可以在标记中内嵌CSS。不过强烈建议不要这么干。 -->
+<style>
+ 选择器 { 属性:值; }
+</style>
+
+<!-- 也可以直接使用元素的style属性。
+这是你最不该干的事情。 -->
+<div style='property:value;'>
+</div>
+
+```
+
+## 优先级
+
+同一个元素可能被多个不同的选择器指定,因此可能会有冲突。
+
+假定CSS是这样的:
+
+```css
+/*A*/
+p.class1[attr='value']
+
+/*B*/
+p.class1 {}
+
+/*C*/
+p.class2 {}
+
+/*D*/
+p {}
+
+/*E*/
+p { property: value !important; }
+
+```
+
+然后标记语言为:
+
+```xml
+<p style='/*F*/ property:value;' class='class1 class2' attr='value'>
+</p>
+```
+
+那么将会按照下面的顺序应用风格:
+
+
+* `E` 优先级最高,因为它使用了 `!important`,除非很有必要,尽量避免使用这个。
+* `F` 其次,因为它是嵌入的风格。
+* `A` 其次,因为它比其他指令更具体。
+* `C` 其次,虽然它的具体程度和`B`一样,但是它在`B`之后。
+* 接下来是 `B`。
+* 最后是 `D`。
+
+## 兼容性
+
+CSS2 的绝大部分特性兼容各种浏览器和设备。现在 CSS3 的兼容性也越来越好了。
+但是兼容性问题仍然是需要留意的一个问题。
+
+[QuirksMode CSS](http://www.quirksmode.org/css/)是关于这方面最好的资源。
+
+## 扩展阅读
+
+* [理解CSS的风格优先级: 特定性, 继承和层叠](http://www.vanseodesign.com/css/css-specificity-inheritance-cascaade/)
+* [QuirksMode CSS](http://www.quirksmode.org/css/)
+* [Z-Index - The stacking context](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context)
diff --git a/zh-cn/elisp-cn.html.markdown b/zh-cn/elisp-cn.html.markdown
index d303c2e8..06f38d77 100644
--- a/zh-cn/elisp-cn.html.markdown
+++ b/zh-cn/elisp-cn.html.markdown
@@ -132,7 +132,7 @@ lang: zh-cn
;; `C-xC-e' 这时屏幕上会显示两个窗口,而光标此时位于*test* buffer内
;; 用鼠标单击上面的buffer就会使光标移回。
-;; 或者你可以使用 `C-xo' 是的光标跳到另一个窗口中
+;; 或者你可以使用 `C-xo' 使得光标跳到另一个窗口中
;; 你可以用 `progn'命令将s式结合起来:
(progn
@@ -219,7 +219,7 @@ lang: zh-cn
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
-;; 我们将一些名字存到列表中;
+;; 我们将一些名字存到列表中:
(setq list-of-names '("Sarah" "Chloe" "Mathilde"))
;; 用 `car'来取得第一个名字:
diff --git a/zh-cn/elixir-cn.html.markdown b/zh-cn/elixir-cn.html.markdown
new file mode 100644
index 00000000..daee8d3c
--- /dev/null
+++ b/zh-cn/elixir-cn.html.markdown
@@ -0,0 +1,399 @@
+---
+language: elixir
+contributors:
+ - ["Joao Marques", "http://github.com/mrshankly"]
+translators:
+ - ["lidashuang", "http://github.com/lidashuang"]
+filename: learnelixir-cn.ex
+lang: zh-cn
+---
+
+Elixir 是一门构建在Erlang VM 之上的函数式编程语言。Elixir 完全兼容 Erlang,
+另外还提供了更标准的语法,特性。
+
+```elixir
+
+# 这是单行注释, 注释以井号开头
+
+# 没有多行注释
+# 但你可以堆叠多个注释。
+
+# elixir shell 使用命令 `iex` 进入。
+# 编译模块使用 `elixirc` 命令。
+
+# 如果安装正确,这些命令都会在环境变量里
+
+## ---------------------------
+## -- 基本类型
+## ---------------------------
+
+# 数字
+3 # 整型
+0x1F # 整型
+3.0 # 浮点类型
+
+# 原子(Atoms),以 `:`开头
+:hello # atom
+
+# 元组(Tuple) 在内存中的存储是连续的
+{1,2,3} # tuple
+
+# 使用`elem`函数访问元组(tuple)里的元素:
+elem({1, 2, 3}, 0) #=> 1
+
+# 列表(list)
+[1,2,3] # list
+
+# 可以用下面的方法访问列表的头尾元素:
+[head | tail] = [1,2,3]
+head #=> 1
+tail #=> [2,3]
+
+# 在elixir,就像在Erlang, `=` 表示模式匹配 (pattern matching)
+# 不是赋值。
+#
+# 这表示会用左边的模式(pattern)匹配右侧
+#
+# 上面的例子中访问列表的头部和尾部就是这样工作的。
+
+# 当左右两边不匹配时,会返回error, 在这个
+# 例子中,元组大小不一样。
+# {a, b, c} = {1, 2} #=> ** (MatchError) no match of right hand side value: {1,2}
+
+# 还有二进制类型 (binaries)
+<<1,2,3>> # binary
+
+# 字符串(Strings) 和 字符列表(char lists)
+"hello" # string
+'hello' # char list
+
+# 多行字符串
+"""
+I'm a multi-line
+string.
+"""
+#=> "I'm a multi-line\nstring.\n"
+
+# 所有的字符串(Strings)以UTF-8编码:
+"héllò" #=> "héllò"
+
+# 字符串(Strings)本质就是二进制类型(binaries), 字符列表(char lists)本质是列表(lists)
+<<?a, ?b, ?c>> #=> "abc"
+[?a, ?b, ?c] #=> 'abc'
+
+# 在 elixir中,`?a`返回 `a` 的 ASCII 整型值
+?a #=> 97
+
+# 合并列表使用 `++`, 对于二进制类型则使用 `<>`
+[1,2,3] ++ [4,5] #=> [1,2,3,4,5]
+'hello ' ++ 'world' #=> 'hello world'
+
+<<1,2,3>> <> <<4,5>> #=> <<1,2,3,4,5>>
+"hello " <> "world" #=> "hello world"
+
+## ---------------------------
+## -- 操作符(Operators)
+## ---------------------------
+
+# 一些数学运算
+1 + 1 #=> 2
+10 - 5 #=> 5
+5 * 2 #=> 10
+10 / 2 #=> 5.0
+
+# 在 elixir 中,操作符 `/` 返回值总是浮点数。
+
+# 做整数除法使用 `div`
+div(10, 2) #=> 5
+
+# 为了得到余数使用 `rem`
+rem(10, 3) #=> 1
+
+# 还有 boolean 操作符: `or`, `and` and `not`.
+# 第一个参数必须是boolean 类型
+true and true #=> true
+false or true #=> true
+# 1 and true #=> ** (ArgumentError) argument error
+
+# Elixir 也提供了 `||`, `&&` 和 `!` 可以接受任意的类型
+# 除了`false` 和 `nil` 其它都会被当作true.
+1 || true #=> 1
+false && 1 #=> false
+nil && 20 #=> nil
+
+!true #=> false
+
+# 比较有: `==`, `!=`, `===`, `!==`, `<=`, `>=`, `<` 和 `>`
+1 == 1 #=> true
+1 != 1 #=> false
+1 < 2 #=> true
+
+# `===` 和 `!==` 在比较整型和浮点类型时更为严格:
+1 == 1.0 #=> true
+1 === 1.0 #=> false
+
+# 我们也可以比较两种不同的类型:
+1 < :hello #=> true
+
+# 总的排序顺序定义如下:
+# number < atom < reference < functions < port < pid < tuple < list < bit string
+
+# 引用Joe Armstrong :“实际的顺序并不重要,
+# 但是,一个整体排序是否经明确界定是非常重要的。”
+
+## ---------------------------
+## -- 控制结构(Control Flow)
+## ---------------------------
+
+# `if` 表达式
+if false do
+ "This will never be seen"
+else
+ "This will"
+end
+
+# 还有 `unless`
+unless true do
+ "This will never be seen"
+else
+ "This will"
+end
+
+# 在Elixir中,很多控制结构都依赖于模式匹配
+
+# `case` 允许我们把一个值与多种模式进行比较:
+case {:one, :two} do
+ {:four, :five} ->
+ "This won't match"
+ {:one, x} ->
+ "This will match and assign `x` to `:two`"
+ _ ->
+ "This will match any value"
+end
+
+# 模式匹配时,如果不需要某个值,通用的做法是把值 匹配到 `_`
+# 例如,我们只需要要列表的头元素:
+[head | _] = [1,2,3]
+head #=> 1
+
+# 下面的方式效果一样,但可读性更好
+[head | _tail] = [:a, :b, :c]
+head #=> :a
+
+# `cond` 可以检测多种不同的分支
+# 使用 `cond` 代替多个`if` 表达式嵌套
+cond do
+ 1 + 1 == 3 ->
+ "I will never be seen"
+ 2 * 5 == 12 ->
+ "Me neither"
+ 1 + 2 == 3 ->
+ "But I will"
+end
+
+# 经常可以看到最后一个条件等于'true',这将总是匹配。
+cond do
+ 1 + 1 == 3 ->
+ "I will never be seen"
+ 2 * 5 == 12 ->
+ "Me neither"
+ true ->
+ "But I will (this is essentially an else)"
+end
+
+# `try/catch` 用于捕获被抛出的值, 它也支持 `after` 子句,
+# 无论是否值被捕获,after 子句都会被调用
+# `try/catch`
+try do
+ throw(:hello)
+catch
+ message -> "Got #{message}."
+after
+ IO.puts("I'm the after clause.")
+end
+#=> I'm the after clause
+# "Got :hello"
+
+## ---------------------------
+## -- 模块和函数(Modules and Functions)
+## ---------------------------
+
+# 匿名函数 (注意点)
+square = fn(x) -> x * x end
+square.(5) #=> 25
+
+
+# 也支持接收多个子句和卫士(guards).
+# Guards 可以进行模式匹配
+# Guards 使用 `when` 关键字指明:
+f = fn
+ x, y when x > 0 -> x + y
+ x, y -> x * y
+end
+
+f.(1, 3) #=> 4
+f.(-1, 3) #=> -3
+
+# Elixir 提供了很多内建函数
+# 在默认作用域都是可用的
+is_number(10) #=> true
+is_list("hello") #=> false
+elem({1,2,3}, 0) #=> 1
+
+# 你可以在一个模块里定义多个函数,定义函数使用 `def`
+defmodule Math do
+ def sum(a, b) do
+ a + b
+ end
+
+ def square(x) do
+ x * x
+ end
+end
+
+Math.sum(1, 2) #=> 3
+Math.square(3) #=> 9
+
+# 保存到 `math.ex`,使用 `elixirc` 编译你的 Math 模块
+# 在终端里: elixirc math.ex
+
+# 在模块中可以使用`def`定义函数,使用 `defp` 定义私有函数
+# 使用`def` 定义的函数可以被其它模块调用
+# 私有函数只能在本模块内调用
+defmodule PrivateMath do
+ def sum(a, b) do
+ do_sum(a, b)
+ end
+
+ defp do_sum(a, b) do
+ a + b
+ end
+end
+
+PrivateMath.sum(1, 2) #=> 3
+# PrivateMath.do_sum(1, 2) #=> ** (UndefinedFunctionError)
+
+
+# 函数定义同样支持 guards 和 多重子句:
+defmodule Geometry do
+ def area({:rectangle, w, h}) do
+ w * h
+ end
+
+ def area({:circle, r}) when is_number(r) do
+ 3.14 * r * r
+ end
+end
+
+Geometry.area({:rectangle, 2, 3}) #=> 6
+Geometry.area({:circle, 3}) #=> 28.25999999999999801048
+# Geometry.area({:circle, "not_a_number"})
+#=> ** (FunctionClauseError) no function clause matching in Geometry.area/1
+
+#由于不变性,递归是Elixir的重要组成部分
+defmodule Recursion do
+ def sum_list([head | tail], acc) do
+ sum_list(tail, acc + head)
+ end
+
+ def sum_list([], acc) do
+ acc
+ end
+end
+
+Recursion.sum_list([1,2,3], 0) #=> 6
+
+# Elixir 模块支持属性,模块内建了一些属性,你也可以自定义属性
+defmodule MyMod do
+ @moduledoc """
+ 内置的属性,模块文档
+ """
+
+ @my_data 100 # 自定义属性
+ IO.inspect(@my_data) #=> 100
+end
+
+## ---------------------------
+## -- 记录和异常(Records and Exceptions)
+## ---------------------------
+
+# 记录就是把特定值关联到某个名字的结构体
+defrecord Person, name: nil, age: 0, height: 0
+
+joe_info = Person.new(name: "Joe", age: 30, height: 180)
+#=> Person[name: "Joe", age: 30, height: 180]
+
+# 访问name的值
+joe_info.name #=> "Joe"
+
+# 更新age的值
+joe_info = joe_info.age(31) #=> Person[name: "Joe", age: 31, height: 180]
+
+# 使用 `try` `rescue` 进行异常处理
+try do
+ raise "some error"
+rescue
+ RuntimeError -> "rescued a runtime error"
+ _error -> "this will rescue any error"
+end
+
+# 所有的异常都有一个message
+try do
+ raise "some error"
+rescue
+ x in [RuntimeError] ->
+ x.message
+end
+
+## ---------------------------
+## -- 并发(Concurrency)
+## ---------------------------
+
+# Elixir 依赖于 actor并发模型。在Elixir编写并发程序的三要素:
+# 创建进程,发送消息,接收消息
+
+# 启动一个新的进程使用`spawn`函数,接收一个函数作为参数
+
+f = fn -> 2 * 2 end #=> #Function<erl_eval.20.80484245>
+spawn(f) #=> #PID<0.40.0>
+
+
+# `spawn` 函数返回一个pid(进程标识符),你可以使用pid向进程发送消息。
+# 使用 `<-` 操作符发送消息。
+# 我们需要在进程内接收消息,要用到 `receive` 机制。
+
+defmodule Geometry do
+ def area_loop do
+ receive do
+ {:rectangle, w, h} ->
+ IO.puts("Area = #{w * h}")
+ area_loop()
+ {:circle, r} ->
+ IO.puts("Area = #{3.14 * r * r}")
+ area_loop()
+ end
+ end
+end
+
+# 编译这个模块,在shell中创建一个进程,并执行 `area_looop` 函数。
+pid = spawn(fn -> Geometry.area_loop() end) #=> #PID<0.40.0>
+
+# 发送一个消息给 `pid`, 会在receive语句进行模式匹配
+pid <- {:rectangle, 2, 3}
+#=> Area = 6
+# {:rectangle,2,3}
+
+pid <- {:circle, 2}
+#=> Area = 12.56000000000000049738
+# {:circle,2}
+
+# shell也是一个进程(process), 你可以使用`self`获取当前 pid
+self() #=> #PID<0.27.0>
+```
+
+## 参考文献
+
+* [Getting started guide](http://elixir-lang.org/getting_started/1.html) from [elixir webpage](http://elixir-lang.org)
+* [Elixir Documentation](http://elixir-lang.org/docs/master/)
+* ["Learn You Some Erlang for Great Good!"](http://learnyousomeerlang.com/) by Fred Hebert
+* "Programming Erlang: Software for a Concurrent World" by Joe Armstrong
diff --git a/zh-cn/erlang-cn.html.markdown b/zh-cn/erlang-cn.html.markdown
new file mode 100644
index 00000000..32e84278
--- /dev/null
+++ b/zh-cn/erlang-cn.html.markdown
@@ -0,0 +1,259 @@
+---
+language: erlang
+lang: zh-cn
+contributors:
+ - ["Giovanni Cappellotto", "http://www.focustheweb.com/"]
+translators:
+ - ["Jakukyo Friel", "http://weakish.github.io"]
+filename: erlang-cn.erl
+---
+
+```erlang
+% 百分比符号标明注释的开始。
+
+%% 两个符号通常用于注释函数。
+
+%%% 三个符号通常用于注释模块。
+
+% Erlang 里使用三种标点符号:
+% 逗号 (`,`) 分隔函数调用中的参数、数据构建和模式。
+% 句号 (`.`) (后跟空格)分隔函数和 shell 中的表达式。
+% 分号 (`;`) 分隔语句。以下环境中使用语句:
+% 函数定义和`case`、`if`、`try..catch`、`receive`表达式。
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% 1. 变量和模式匹配
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Num = 42. % 变量必须以大写字母开头。
+
+% Erlang 的变量只能赋值一次。如果给变量赋不同的值,会导致错误:
+Num = 43. % ** exception error: no match of right hand side value 43
+
+% 大多数语言中`=`表示赋值语句,在Erlang中,则表示模式匹配。
+% `Lhs = Rhs`实际上意味着:
+% 演算右边(Rhs), 将结果与左边的模式匹配。
+Num = 7 * 6.
+
+% 浮点数
+Pi = 3.14159.
+
+% Atoms 用于表示非数字的常量。
+% Atom 以小写字母开始,包含字母、数字、`_`和`@`。
+Hello = hello.
+OtherNode = example@node.
+
+% Atom 中如果包含特殊字符,可以用单引号括起。
+AtomWithSpace = 'some atom with space'.
+
+% Erlang 的元组类似 C 的 struct.
+Point = {point, 10, 45}.
+
+% 使用模式匹配操作符`=`获取元组的值。
+{point, X, Y} = Point. % X = 10, Y = 45
+
+% 我们可以使用`_`存放我们不感兴趣的变量。
+% `_`被称为匿名变量。和其他变量不同,
+% 同一个模式中的多个`_`变量不必绑定到相同的值。
+Person = {person, {name, {first, joe}, {last, armstrong}}, {footsize, 42}}.
+{_, {_, {_, Who}, _}, _} = Person. % Who = joe
+
+% 列表使用方括号,元素间使用逗号分隔。
+% 列表的元素可以是任意类型。
+% 列表的第一个元素称为列表的 head,其余元素称为列表的 tail。
+ThingsToBuy = [{apples, 10}, {pears, 6}, {milk, 3}].
+
+% 若`T`是一个列表,那么`[H|T]`同样是一个列表,head为`H`,tail为`T`.
+% `|`分隔列表的 head 和 tail.
+% `[]`是空列表。
+% 我们可以使用模式匹配操作来抽取列表中的元素。
+% 如果我们有一个非空的列表`L`,那么`[X|Y] = L`则
+% 抽取 L 的 head 至 X,tail 至 Y (X、Y需为未定义的变量)。
+[FirstThing|OtherThingsToBuy] = ThingsToBuy.
+% FirstThing = {apples, 10}
+% OtherThingsToBuy = {pears, 6}, {milk, 3}
+
+% Erlang 中的字符串其实是由整数组成的数组。字符串使用双引号。
+Name = "Hello".
+[72, 101, 108, 108, 111] = "Hello".
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% 2. 循序编程
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Module 是 Erlang 代码的基本单位。我们编写的所有函数都储存在 module 中。
+% Module 存储在后缀为 `.erl` 的文件中。
+% Module 必须事先编译。编译好的 module 以 `.beam` 结尾。
+-module(geometry).
+-export([area/1]). % module 对外暴露的函数列表
+
+% `area`函数包含两个分句,分句间以分号相隔。
+% 最后一个分句以句号加换行结尾。
+% 每个分句由头、体两部门组成。
+% 头部包含函数名称和用括号括起的模式,
+% 体部包含一系列表达式,如果头部的模式和调用时的参数匹配,这些表达式会被演算。
+% 模式匹配依照定义时的顺序依次进行。
+area({rectangle, Width, Ht}) -> Width * Ht;
+area({circle, R}) -> 3.14159 * R * R.
+
+% 编译文件为 geometry.erl.
+c(geometry). % {ok,geometry}
+
+% 调用函数时必须使用 module 名和函数名。
+geometry:area({rectangle, 10, 5}). % 50
+geometry:area({circle, 1.4}). % 6.15752
+
+% 在 Erlang 中,同一模块中,参数数目不同,名字相同的函数是完全不同的函数。
+-module(lib_misc).
+-export([sum/1]). % 对外暴露的`sum`函数接受一个参数:由整数组成的列表。
+sum(L) -> sum(L, 0).
+sum([], N) -> N;
+sum([H|T], N) -> sum(T, H+N).
+
+% fun 是匿名函数。它们没有名字,不过可以赋值给变量。
+Double = fun(X) -> 2*X end. % `Double` 指向匿名函数 #Fun<erl_eval.6.17052888>
+Double(2). % 4
+
+% fun 可以作为函数的参数和返回值。
+Mult = fun(Times) -> ( fun(X) -> X * Times end ) end.
+Triple = Mult(3).
+Triple(5). % 15
+
+% 列表解析是创建列表的表达式(不使用fun、map 或 filter)。
+% `[F(X) || X <- L]` 表示 "由 `F(X)` 组成的列表,其中 `X` 取自列表 `L`。
+L = [1,2,3,4,5].
+[2*X || X <- L]. % [2,4,6,8,10]
+% 列表解析可以使用生成器,也可以使用过滤器,过滤器用于筛选列表的一部分。
+EvenNumbers = [N || N <- [1, 2, 3, 4], N rem 2 == 0]. % [2, 4]
+
+% Guard 是用于增强模式匹配的结构。
+% Guard 可用于简单的测试和比较。
+% Guard 可用于函数定义的头部,以`when`关键字开头,或者其他可以使用表达式的地方。
+max(X, Y) when X > Y -> X;
+max(X, Y) -> Y.
+
+% guard 可以由一系列 guard 表达式组成,这些表达式以逗号分隔。
+% `GuardExpr1, GuardExpr2, ..., GuardExprN` 为真,当且仅当每个 guard 表达式均为真。
+is_cat(A) when is_atom(A), A =:= cat -> true;
+is_cat(A) -> false.
+is_dog(A) when is_atom(A), A =:= dog -> true;
+is_dog(A) -> false.
+
+% guard 序列 `G1; G2; ...; Gn` 为真,当且仅当其中任意一个 guard 表达式为真。
+is_pet(A) when is_dog(A); is_cat(A) -> true;
+is_pet(A) -> false.
+
+% Record 可以将元组中的元素绑定到特定的名称。
+% Record 定义可以包含在 Erlang 源代码中,也可以放在后缀为`.hrl`的文件中(Erlang 源代码中 include 这些文件)。
+-record(todo, {
+ status = reminder, % Default value
+ who = joe,
+ text
+}).
+
+% 在定义某个 record 之前,我们需要在 shell 中导入 record 的定义。
+% 我们可以使用 shell 函数`rr` (read records 的简称)。
+rr("records.hrl"). % [todo]
+
+% 创建和更新 record。
+X = #todo{}.
+% #todo{status = reminder, who = joe, text = undefined}
+X1 = #todo{status = urgent, text = "Fix errata in book"}.
+% #todo{status = urgent, who = joe, text = "Fix errata in book"}
+X2 = X1#todo{status = done}.
+% #todo{status = done,who = joe,text = "Fix errata in book"}
+
+% `case` 表达式。
+% `filter` 返回由列表`L`中所有满足`P(x)`为真的元素`X`组成的列表。
+filter(P, [H|T]) ->
+ case P(H) of
+ true -> [H|filter(P, T)];
+ false -> filter(P, T)
+ end;
+filter(P, []) -> [].
+filter(fun(X) -> X rem 2 == 0 end, [1, 2, 3, 4]). % [2, 4]
+
+% `if` 表达式。
+max(X, Y) ->
+ if
+ X > Y -> X;
+ X < Y -> Y;
+ true -> nil;
+ end.
+
+% 警告: `if` 表达式里至少有一个 guard 为真,否则会触发异常。
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% 3. 异常
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% 当遇到内部错误或显式调用时,会触发异常。
+% 显式调用包括 `throw(Exception)`, `exit(Exception)` 和
+% `erlang:error(Exception)`.
+generate_exception(1) -> a;
+generate_exception(2) -> throw(a);
+generate_exception(3) -> exit(a);
+generate_exception(4) -> {'EXIT', a};
+generate_exception(5) -> erlang:error(a).
+
+% Erlang 有两种捕获异常的方法。其一是将调用包裹在`try...catch`表达式中。
+catcher(N) ->
+ try generate_exception(N) of
+ Val -> {N, normal, Val}
+ catch
+ throw:X -> {N, caught, thrown, X};
+ exit:X -> {N, caught, exited, X};
+ error:X -> {N, caught, error, X}
+ end.
+
+% 另一种方式是将调用包裹在`catch`表达式中。
+% 此时异常会被转化为一个描述错误的元组。
+catcher(N) -> catch generate_exception(N).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% 4. 并发
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% Erlang 依赖于 actor并发模型。在 Erlang 编写并发程序的三要素:
+% 创建进程,发送消息,接收消息
+
+% 启动一个新的进程使用`spawn`函数,接收一个函数作为参数
+
+F = fun() -> 2 + 2 end. % #Fun<erl_eval.20.67289768>
+spawn(F). % <0.44.0>
+
+% `spawn` 函数返回一个pid(进程标识符),你可以使用pid向进程发送消息。
+% 使用 `!` 操作符发送消息。
+% 我们需要在进程内接收消息,要用到 `receive` 机制。
+
+-module(caculateGeometry).
+-compile(export_all).
+caculateAera() ->
+ receive
+ {rectangle, W, H} ->
+ W * H;
+ {circle, R} ->
+ 3.14 * R * R;
+ _ ->
+ io:format("We can only caculate area of rectangles or circles.")
+ end.
+
+% 编译这个模块,在 shell 中创建一个进程,并执行 `caculateArea` 函数。
+c(caculateGeometry).
+CaculateAera = spawn(caculateGeometry, caculateAera, []).
+CaculateAera ! {circle, 2}. % 12.56000000000000049738
+
+% shell也是一个进程(process), 你可以使用`self`获取当前 pid
+
+self(). % <0.41.0>
+
+```
+
+## References
+
+* ["Learn You Some Erlang for great good!"](http://learnyousomeerlang.com/)
+* ["Programming Erlang: Software for a Concurrent World" by Joe Armstrong](http://pragprog.com/book/jaerlang/programming-erlang)
+* [Erlang/OTP Reference Documentation](http://www.erlang.org/doc/)
+* [Erlang - Programming Rules and Conventions](http://www.erlang.se/doc/programming_rules.shtml)
diff --git a/zh-cn/json-cn.html.markdown b/zh-cn/json-cn.html.markdown
new file mode 100644
index 00000000..75966595
--- /dev/null
+++ b/zh-cn/json-cn.html.markdown
@@ -0,0 +1,51 @@
+---
+language: json
+contributors:
+ - ["Anna Harren", "https://github.com/iirelu"]
+translators:
+ - ["Zach Zhang", "https://github.com/checkcheckzz"]
+filename: learnjson-cn.json
+lang: zh-cn
+---
+
+因为JSON是一个极其简单的数据交换形式,这个最有可能将会是曾经最简单
+的Learn X in Y Minutes。
+
+最纯正形式的JSON没有实际的注解,但是大多数解析器将会
+接受C-风格(//, /\* \*/)的注解。为了这个目的,但是,
+一切都将会是100%有效的JSON。幸亏,它是不言自明的。
+
+```json
+{
+ "numbers": 0,
+ "strings": "Hellø, wørld. All unicode is allowed, along with \"escaping\".",
+ "has bools?": true,
+ "nothingness": null,
+
+ "big number": 1.2e+100,
+
+ "objects": {
+ "comment": "Most of your structure will come from objects.",
+
+ "array": [0, 1, 2, 3, "Arrays can have anything in them.", 5],
+
+ "another object": {
+ "comment": "These things can be nested, very useful."
+ }
+ },
+
+ "silliness": [
+ {
+ "sources of potassium": ["bananas"]
+ },
+ [
+ [1, 0, 0, 0],
+ [0, 1, 0, 0],
+ [0, 0, 1, "neo"],
+ [0, 0, 0, 1]
+ ]
+ ],
+
+ "that was short": "And, you're done. You know know everything JSON has to offer."
+}
+```
diff --git a/zh-cn/lua-cn.html.markdown b/zh-cn/lua-cn.html.markdown
new file mode 100644
index 00000000..95a94c76
--- /dev/null
+++ b/zh-cn/lua-cn.html.markdown
@@ -0,0 +1,413 @@
+---
+language: lua
+lang: zh-cn
+contributors:
+ - ["Tyler Neylon", "http://tylerneylon.com/"]
+ - ["Rob Hoelz", "http://hoelz.ro"]
+ - ["Jakukyo Friel", "http://weakish.github.io"]
+ - ["Craig Roddin", "craig.roddin@gmail.com"]
+ - ["Amr Tamimi", "https://amrtamimi.com"]
+translators:
+ - ["Jakukyo Friel", "http://weakish.github.io"]
+---
+
+```lua
+-- 单行注释以两个连字符开头
+
+--[[
+ 多行注释
+--]]
+
+----------------------------------------------------
+-- 1. 变量和流程控制
+----------------------------------------------------
+
+num = 42 -- 所有的数字都是双精度浮点型。
+-- 别害怕,64位的双精度浮点型数字中有52位用于
+-- 保存精确的整型值; 对于52位以内的整型值,
+-- 不用担心精度问题。
+
+s = 'walternate' -- 和Python一样,字符串不可变。
+t = "也可以用双引号"
+u = [[ 多行的字符串
+ 以两个方括号
+ 开始和结尾。]]
+t = nil -- 撤销t的定义; Lua 支持垃圾回收。
+
+-- 块使用do/end之类的关键字标识:
+while num < 50 do
+ num = num + 1 -- 不支持 ++ 或 += 运算符。
+end
+
+-- If语句:
+if num > 40 then
+ print('over 40')
+elseif s ~= 'walternate' then -- ~= 表示不等于。
+ -- 像Python一样,用 == 检查是否相等 ;字符串同样适用。
+ io.write('not over 40\n') -- 默认标准输出。
+else
+ -- 默认全局变量。
+ thisIsGlobal = 5 -- 通常使用驼峰。
+
+ -- 如何定义局部变量:
+ local line = io.read() -- 读取标准输入的下一行。
+
+ -- ..操作符用于连接字符串:
+ print('Winter is coming, ' .. line)
+end
+
+-- 未定义的变量返回nil。
+-- 这不是错误:
+foo = anUnknownVariable -- 现在 foo = nil.
+
+aBoolValue = false
+
+--只有nil和false为假; 0和 ''都均为真!
+if not aBoolValue then print('twas false') end
+
+-- 'or'和 'and'短路
+-- 类似于C/js里的 a?b:c 操作符:
+ans = aBoolValue and 'yes' or 'no' --> 'no'
+
+karlSum = 0
+for i = 1, 100 do -- 范围包含两端
+ karlSum = karlSum + i
+end
+
+-- 使用 "100, 1, -1" 表示递减的范围:
+fredSum = 0
+for j = 100, 1, -1 do fredSum = fredSum + j end
+
+-- 通常,范围表达式为begin, end[, step].
+
+-- 循环的另一种结构:
+repeat
+ print('the way of the future')
+ num = num - 1
+until num == 0
+
+----------------------------------------------------
+-- 2. 函数。
+----------------------------------------------------
+
+function fib(n)
+ if n < 2 then return 1 end
+ return fib(n - 2) + fib(n - 1)
+end
+
+-- 支持闭包及匿名函数:
+function adder(x)
+ -- 调用adder时,会创建返回的函数,
+ -- 并且会记住x的值:
+ return function (y) return x + y end
+end
+a1 = adder(9)
+a2 = adder(36)
+print(a1(16)) --> 25
+print(a2(64)) --> 100
+
+-- 返回值、函数调用和赋值都可以
+-- 使用长度不匹配的list。
+-- 不匹配的接收方会被赋值nil;
+-- 不匹配的发送方会被丢弃。
+
+x, y, z = 1, 2, 3, 4
+-- x = 1、y = 2、z = 3, 而 4 会被丢弃。
+
+function bar(a, b, c)
+ print(a, b, c)
+ return 4, 8, 15, 16, 23, 42
+end
+
+x, y = bar('zaphod') --> 打印 "zaphod nil nil"
+-- 现在 x = 4, y = 8, 而值15..42被丢弃。
+
+-- 函数是一等公民,可以是局部的,也可以是全局的。
+-- 以下表达式等价:
+function f(x) return x * x end
+f = function (x) return x * x end
+
+-- 这些也是等价的:
+local function g(x) return math.sin(x) end
+local g; g = function (x) return math.sin(x) end
+-- 'local g'使得g可以自引用。
+
+-- 顺便提下,三角函数以弧度为单位。
+
+-- 用一个字符串参数调用函数,可以省略括号:
+print 'hello' --可以工作。
+
+-- 调用函数时,如果只有一个table参数,
+-- 同样可以省略括号(table详情见下):
+print {} -- 一样可以工作。
+
+----------------------------------------------------
+-- 3. Table。
+----------------------------------------------------
+
+-- Table = Lua唯一的组合数据结构;
+-- 它们是关联数组。
+-- 类似于PHP的数组或者js的对象,
+-- 它们是哈希表或者字典,也可以当初列表使用。
+
+-- 按字典/map的方式使用Table:
+
+-- Dict字面量默认使用字符串类型的key:
+t = {key1 = 'value1', key2 = false}
+
+-- 字符串key可以使用类似js的点标记:
+print(t.key1) -- 打印 'value1'.
+t.newKey = {} -- 添加新的键值对。
+t.key2 = nil -- 从table删除 key2。
+
+-- 使用任何非nil的值作为key:
+u = {['@!#'] = 'qbert', [{}] = 1729, [6.28] = 'tau'}
+print(u[6.28]) -- 打印 "tau"
+
+-- 数字和字符串的key按值匹配的
+-- table按id匹配。
+a = u['@!#'] -- 现在 a = 'qbert'.
+b = u[{}] -- 我们或许期待的是 1729, 但是得到的是nil:
+-- b = nil ,因为没有找到。
+-- 之所以没找到,是因为我们用的key与保存数据时用的不是同
+-- 一个对象。
+-- 所以字符串和数字是移植性更好的key。
+
+-- 只需要一个table参数的函数调用不需要括号:
+function h(x) print(x.key1) end
+h{key1 = 'Sonmi~451'} -- 打印'Sonmi~451'.
+
+for key, val in pairs(u) do -- 遍历Table
+ print(key, val)
+end
+
+-- _G 是一个特殊的table,用于保存所有的全局变量
+print(_G['_G'] == _G) -- 打印'true'.
+
+-- 按列表/数组的方式使用:
+
+-- 列表字面量隐式添加整数键:
+v = {'value1', 'value2', 1.21, 'gigawatts'}
+for i = 1, #v do -- #v 是列表的大小
+ print(v[i]) -- 索引从 1 开始!! 太疯狂了!
+end
+-- 'list'并非真正的类型,v 其实是一个table,
+-- 只不过它用连续的整数作为key,可以像list那样去使用。
+
+----------------------------------------------------
+-- 3.1 元表(metatable) 和元方法(metamethod)。
+----------------------------------------------------
+
+-- table的元表提供了一种机制,支持类似操作符重载的行为。
+-- 稍后我们会看到元表如何支持类似js prototype的行为。
+
+f1 = {a = 1, b = 2} -- 表示一个分数 a/b.
+f2 = {a = 2, b = 3}
+
+-- 这会失败:
+-- s = f1 + f2
+
+metafraction = {}
+function metafraction.__add(f1, f2)
+ sum = {}
+ sum.b = f1.b * f2.b
+ sum.a = f1.a * f2.b + f2.a * f1.b
+ return sum
+end
+
+setmetatable(f1, metafraction)
+setmetatable(f2, metafraction)
+
+s = f1 + f2 -- 调用在f1的元表上的__add(f1, f2) 方法
+
+-- f1, f2 没有关于元表的key,这点和js的prototype不一样。
+-- 因此你必须用getmetatable(f1)获取元表。
+-- 元表是一个普通的table,
+-- 元表的key是普通的Lua中的key,例如__add。
+
+-- 但是下面一行代码会失败,因为s没有元表:
+-- t = s + s
+-- 下面提供的与类相似的模式可以解决这个问题:
+
+-- 元表的__index 可以重载用于查找的点操作符:
+defaultFavs = {animal = 'gru', food = 'donuts'}
+myFavs = {food = 'pizza'}
+setmetatable(myFavs, {__index = defaultFavs})
+eatenBy = myFavs.animal -- 可以工作!感谢元表
+
+-- 如果在table中直接查找key失败,会使用
+-- 元表的__index 递归地重试。
+
+-- __index的值也可以是function(tbl, key)
+-- 这样可以支持自定义查找。
+
+-- __index、__add等的值,被称为元方法。
+-- 这里是一个table元方法的清单:
+
+-- __add(a, b) for a + b
+-- __sub(a, b) for a - b
+-- __mul(a, b) for a * b
+-- __div(a, b) for a / b
+-- __mod(a, b) for a % b
+-- __pow(a, b) for a ^ b
+-- __unm(a) for -a
+-- __concat(a, b) for a .. b
+-- __len(a) for #a
+-- __eq(a, b) for a == b
+-- __lt(a, b) for a < b
+-- __le(a, b) for a <= b
+-- __index(a, b) <fn or a table> for a.b
+-- __newindex(a, b, c) for a.b = c
+-- __call(a, ...) for a(...)
+
+----------------------------------------------------
+-- 3.2 与类相似的table和继承。
+----------------------------------------------------
+
+-- Lua没有内建的类;可以通过不同的方法,利用表和元表
+-- 来实现类。
+
+-- 下面是一个例子,解释在后面:
+
+Dog = {} -- 1.
+
+function Dog:new() -- 2.
+ newObj = {sound = 'woof'} -- 3.
+ self.__index = self -- 4.
+ return setmetatable(newObj, self) -- 5.
+end
+
+function Dog:makeSound() -- 6.
+ print('I say ' .. self.sound)
+end
+
+mrDog = Dog:new() -- 7.
+mrDog:makeSound() -- 'I say woof' -- 8.
+
+-- 1. Dog看上去像一个类;其实它是一个table。
+-- 2. 函数tablename:fn(...) 等价于
+-- 函数tablename.fn(self, ...)
+-- 冒号(:)只是添加了self作为第一个参数。
+-- 阅读7 & 8条 了解self变量是如何得到其值的。
+-- 3. newObj是类Dog的一个实例。
+-- 4. self = 被继承的类。通常self = Dog,不过继承可以改变它。
+-- 如果把newObj的元表和__index都设置为self,
+-- newObj就可以得到self的函数。
+-- 5. 备忘:setmetatable返回其第一个参数。
+-- 6. 冒号(:)的作用和第2条一样,不过这里
+-- self是一个实例,而不是类
+-- 7. 等价于Dog.new(Dog),所以在new()中,self = Dog。
+-- 8. 等价于mrDog.makeSound(mrDog); self = mrDog。
+
+----------------------------------------------------
+
+-- 继承的例子:
+
+LoudDog = Dog:new() -- 1.
+
+function LoudDog:makeSound()
+ s = self.sound .. ' ' -- 2.
+ print(s .. s .. s)
+end
+
+seymour = LoudDog:new() -- 3.
+seymour:makeSound() -- 'woof woof woof' -- 4.
+
+-- 1. LoudDog获得Dog的方法和变量列表。
+-- 2. 因为new()的缘故,self拥有了一个'sound' key,参见第3条。
+-- 3. 等价于LoudDog.new(LoudDog),转换一下就是
+-- Dog.new(LoudDog),这是因为LoudDog没有'new' key,
+-- 但是它的元表中有 __index = Dog。
+-- 结果: seymour的元表是LoudDog,并且
+-- LoudDog.__index = Dog。所以有seymour.key
+-- = seymour.key, LoudDog.key, Dog.key
+-- 从其中第一个有指定key的table获取。
+-- 4. 在LoudDog可以找到'makeSound'的key;
+-- 等价于LoudDog.makeSound(seymour)。
+
+-- 如果有必要,子类也可以有new(),与基类相似:
+function LoudDog:new()
+ newObj = {}
+ -- 初始化newObj
+ self.__index = self
+ return setmetatable(newObj, self)
+end
+
+----------------------------------------------------
+-- 4. 模块
+----------------------------------------------------
+
+
+--[[ 我把这部分给注释了,这样脚本剩下的部分可以运行
+
+-- 假设文件mod.lua的内容类似这样:
+local M = {}
+
+local function sayMyName()
+ print('Hrunkner')
+end
+
+function M.sayHello()
+ print('Why hello there')
+ sayMyName()
+end
+
+return M
+
+-- 另一个文件可以使用mod.lua的功能:
+local mod = require('mod') -- 运行文件mod.lua.
+
+-- require是包含模块的标准做法。
+-- require等价于: (针对没有被缓存的情况;参见后面的内容)
+local mod = (function ()
+ <contents of mod.lua>
+end)()
+-- mod.lua被包在一个函数体中,因此mod.lua的局部变量
+-- 对外不可见。
+
+-- 下面的代码可以工作,因为在这里mod = mod.lua 中的 M:
+mod.sayHello() -- Says hello to Hrunkner.
+
+-- 这是错误的;sayMyName只在mod.lua中存在:
+mod.sayMyName() -- 错误
+
+-- require返回的值会被缓存,所以一个文件只会被运行一次,
+-- 即使它被require了多次。
+
+-- 假设mod2.lua包含代码"print('Hi!')"。
+local a = require('mod2') -- 打印Hi!
+local b = require('mod2') -- 不再打印; a=b.
+
+-- dofile与require类似,但是不缓存:
+dofile('mod2') --> Hi!
+dofile('mod2') --> Hi! (再次运行,与require不同)
+
+-- loadfile加载一个lua文件,但是并不运行它。
+f = loadfile('mod2') -- Calling f() runs mod2.lua.
+
+-- loadstring是loadfile的字符串版本。
+g = loadstring('print(343)') --返回一个函数。
+g() -- 打印343; 在此之前什么也不打印。
+
+--]]
+```
+
+## 参考
+
+
+
+为什么?我非常兴奋地学习lua, 这样我就可以使用[Löve 2D游戏引擎](http://love2d.org/)来编游戏。
+
+怎么做?我从[BlackBulletIV的面向程序员的Lua指南](http://nova-fusion.com/2012/08/27/lua-for-programmers-part-1/)入门。接着我阅读了官方的[Lua编程](http://www.lua.org/pil/contents.html)一书。
+
+lua-users.org上的[Lua简明参考](http://lua-users.org/files/wiki_insecure/users/thomasl/luarefv51.pdf)应该值得一看。
+
+本文没有涉及标准库的内容:
+
+* <a href="http://lua-users.org/wiki/StringLibraryTutorial">string library</a>
+* <a href="http://lua-users.org/wiki/TableLibraryTutorial">table library</a>
+* <a href="http://lua-users.org/wiki/MathLibraryTutorial">math library</a>
+* <a href="http://lua-users.org/wiki/IoLibraryTutorial">io library</a>
+* <a href="http://lua-users.org/wiki/OsLibraryTutorial">os library</a>
+
+使用Lua,欢乐常在!
diff --git a/zh-cn/php-cn.html.markdown b/zh-cn/php-cn.html.markdown
index c6ebb515..24939681 100644
--- a/zh-cn/php-cn.html.markdown
+++ b/zh-cn/php-cn.html.markdown
@@ -180,7 +180,7 @@ assert($c >= $d);
// 下面的比较只有在类型相同、值相同的情况下才为真
assert($c === $d);
assert($a !== $d);
-assert(1 == '1');
+assert(1 === '1');
assert(1 !== '1');
// 变量可以根据其使用来进行类型转换
@@ -243,7 +243,7 @@ if ($x === '0') {
-// 下面的语法常用语模板中:
+// 下面的语法常用于模板中:
?>
<?php if ($x): ?>
@@ -333,7 +333,7 @@ function my_function () {
echo my_function(); // => "Hello"
// 函数名需要以字母或者下划线开头,
-// 后面可以跟着任意的字幕、下划线、数字.
+// 后面可以跟着任意的字母、下划线、数字.
function add ($x, $y = 1) { // $y 是可选参数,默认值为 1
$result = $x + $y;
diff --git a/zh-cn/r-cn.html.markdown b/zh-cn/r-cn.html.markdown
index ed8c43b6..19c5f25d 100644
--- a/zh-cn/r-cn.html.markdown
+++ b/zh-cn/r-cn.html.markdown
@@ -6,7 +6,7 @@ contributors:
translators:
- ["小柒", "http://weibo.com/u/2328126220"]
- ["alswl", "https://github.com/alswl"]
-filename: learnr.r
+filename: learnr-zh.r
lang: zh-cn
---
diff --git a/zh-cn/racket-cn.html.markdown b/zh-cn/racket-cn.html.markdown
index d43511ea..8ef3671f 100644
--- a/zh-cn/racket-cn.html.markdown
+++ b/zh-cn/racket-cn.html.markdown
@@ -2,7 +2,7 @@
language: racket
lang: zh-cn
-filename: learnracket.rkt
+filename: learnracket-zh.rkt
contributors:
- ["th3rac25", "https://github.com/voila"]
- ["Eli Barzilay", "https://github.com/elibarzilay"]
diff --git a/zh-cn/scala-cn.html.markdown b/zh-cn/scala-cn.html.markdown
index 1ce41ac6..24f73bb5 100644
--- a/zh-cn/scala-cn.html.markdown
+++ b/zh-cn/scala-cn.html.markdown
@@ -6,7 +6,6 @@ contributors:
- ["Dominic Bou-Samra", "http://dbousamra.github.com"]
translators:
- ["Peiyong Lin", ""]
-filename: learn.scala
lang: zh-cn
---
diff --git a/zh-cn/visualbasic-cn.html.markdown b/zh-cn/visualbasic-cn.html.markdown
new file mode 100644
index 00000000..95f01ed6
--- /dev/null
+++ b/zh-cn/visualbasic-cn.html.markdown
@@ -0,0 +1,274 @@
+---
+language: Visual Basic
+contributors:
+ - ["Brian Martin", "http://brianmartin.biz"]
+translators:
+ - ["Abner Chou", "http://github.com/NoahDragon"]
+lang: zh-cn
+filename: learnvisualbasic.vb-cn
+---
+
+```vb
+Module Module1
+
+ Sub Main()
+ ' 让我们先从简单的终端程序学起。
+ ' 单引号用来生成注释(注意是半角单引号,非全角单引号’)
+ ' 为了方便运行此示例代码,我写了个目录索引。
+ ' 可能你还不了解以下代码的意义,但随着教程的深入,
+ ' 你会渐渐理解其用法。
+ Console.Title = ("Learn X in Y Minutes")
+ Console.WriteLine("NAVIGATION") ' 显示目录
+ Console.WriteLine("")
+ Console.ForegroundColor = ConsoleColor.Green
+ Console.WriteLine("1. Hello World Output") ' Hello world 输出示例
+ Console.WriteLine("2. Hello World Input") ' Hello world 输入示例
+ Console.WriteLine("3. Calculating Whole Numbers") ' 求整数之和
+ Console.WriteLine("4. Calculating Decimal Numbers") ' 求小数之和
+ Console.WriteLine("5. Working Calculator") ' 计算器
+ Console.WriteLine("6. Using Do While Loops") ' 使用 Do While 循环
+ Console.WriteLine("7. Using For While Loops") ' 使用 For While 循环
+ Console.WriteLine("8. Conditional Statements") ' 条件语句
+ Console.WriteLine("9. Select A Drink") ' 选饮料
+ Console.WriteLine("50. About") ' 关于
+ Console.WriteLine("Please Choose A Number From The Above List")
+ Dim selection As String = Console.ReadLine
+ Select Case selection
+ Case "1" ' Hello world 输出示例
+ Console.Clear() ' 清空屏幕
+ HelloWorldOutput() ' 调用程序块
+ Case "2" ' Hello world 输入示例
+ Console.Clear()
+ HelloWorldInput()
+ Case "3" ' 求整数之和
+ Console.Clear()
+ CalculatingWholeNumbers()
+ Case "4" ' 求小数之和
+ Console.Clear()
+ CalculatingDecimalNumbers()
+ Case "5" ' 计算器
+ Console.Clear()
+ WorkingCalculator()
+ Case "6" ' 使用 do while 循环
+ Console.Clear()
+ UsingDoWhileLoops()
+ Case "7" ' 使用 for while 循环
+ Console.Clear()
+ UsingForLoops()
+ Case "8" ' 条件语句
+ Console.Clear()
+ ConditionalStatement()
+ Case "9" ' If/Else 条件语句
+ Console.Clear()
+ IfElseStatement() ' 选饮料
+ Case "50" ' 关于本程序和作者
+ Console.Clear()
+ Console.Title = ("Learn X in Y Minutes :: About")
+ MsgBox("This tutorial is by Brian Martin (@BrianMartinn")
+ Console.Clear()
+ Main()
+ Console.ReadLine()
+
+ End Select
+ End Sub
+
+ ' 一、对应程序目录1,下同
+
+ ' 使用 private subs 声明函数。
+ Private Sub HelloWorldOutput()
+ ' 程序名
+ Console.Title = "Hello World Ouput | Learn X in Y Minutes"
+ ' 使用 Console.Write("") 或者 Console.WriteLine("") 来输出文本到屏幕上
+ ' 对应的 Console.Read() 或 Console.Readline() 用来读取键盘输入
+ Console.WriteLine("Hello World")
+ Console.ReadLine()
+ ' Console.WriteLine()后加Console.ReadLine()是为了防止屏幕输出信息一闪而过
+ ' 类似平时常见的“单击任意键继续”的意思。
+ End Sub
+
+ ' 二
+ Private Sub HelloWorldInput()
+ Console.Title = "Hello World YourName | Learn X in Y Minutes"
+ ' 变量
+ ' 用来存储用户输入的数据
+ ' 变量声明以 Dim 开始,结尾为 As VariableType (变量类型).
+
+ ' 此教程中,我们希望知道你的姓名,并让程序记录并输出。
+ Dim username As String
+ ' 我们定义username使用字符串类型(String)来记录用户姓名。
+ Console.WriteLine("Hello, What is your name? ") ' 询问用户输入姓名
+ username = Console.ReadLine() ' 存储用户名到变量 username
+ Console.WriteLine("Hello " + username) ' 输出将是 Hello + username
+ Console.ReadLine() ' 暂停屏幕并显示以上输出
+ ' 以上程序将询问你的姓名,并和你打招呼。
+ ' 其它变量如整型(Integer)我们用整型来处理整数。
+ End Sub
+
+ ' 三
+ Private Sub CalculatingWholeNumbers()
+ Console.Title = "Calculating Whole Numbers | Learn X in Y Minutes"
+ Console.Write("First number: ") ' 输入一个整数:1,2,50,104,等等
+ Dim a As Integer = Console.ReadLine()
+ Console.Write("Second number: ") ' 输入第二个整数
+ Dim b As Integer = Console.ReadLine()
+ Dim c As Integer = a + b
+ Console.WriteLine(c)
+ Console.ReadLine()
+ ' 以上程序将两个整数相加
+ End Sub
+
+ ' 四
+ Private Sub CalculatingDecimalNumbers()
+ Console.Title = "Calculating with Double | Learn X in Y Minutes"
+ ' 当然,我们还需要能够处理小数。
+ ' 只需要要将整型(Integer)改为小数(Double)类型即可。
+
+ ' 输入一个小数: 1.2, 2.4, 50.1, 104.9,等等
+ Console.Write("First number: ")
+ Dim a As Double = Console.ReadLine
+ Console.Write("Second number: ") ' 输入第二个数
+ Dim b As Double = Console.ReadLine
+ Dim c As Double = a + b
+ Console.WriteLine(c)
+ Console.ReadLine()
+ ' 以上代码能实现两个小数相加
+ End Sub
+
+ ' 五
+ Private Sub WorkingCalculator()
+ Console.Title = "The Working Calculator| Learn X in Y Minutes"
+ ' 但是如果你希望有个能够处理加减乘除的计算器呢?
+ ' 只需将上面代码复制粘帖即可。
+ Console.Write("First number: ") ' 输入第一个数
+ Dim a As Double = Console.ReadLine
+ Console.Write("Second number: ") ' 输入第二个数
+ Dim b As Integer = Console.ReadLine
+ Dim c As Integer = a + b
+ Dim d As Integer = a * b
+ Dim e As Integer = a - b
+ Dim f As Integer = a / b
+
+ ' 通过以下代码我们可以将以上所算的加减乘除结果输出到屏幕上。
+ Console.Write(a.ToString() + " + " + b.ToString())
+ ' 我们希望答案开头能有3个空格,可以使用String.PadLeft(3)方法。
+ Console.WriteLine(" = " + c.ToString.PadLeft(3))
+ Console.Write(a.ToString() + " * " + b.ToString())
+ Console.WriteLine(" = " + d.ToString.PadLeft(3))
+ Console.Write(a.ToString() + " - " + b.ToString())
+ Console.WriteLine(" = " + e.ToString.PadLeft(3))
+ Console.Write(a.ToString() + " / " + b.ToString())
+ Console.WriteLine(" = " + e.ToString.PadLeft(3))
+ Console.ReadLine()
+
+ End Sub
+
+ ' 六
+ Private Sub UsingDoWhileLoops()
+ ' 如同以上的代码一样
+ ' 这次我们将询问用户是否继续 (Yes or No?)
+ ' 我们将使用Do While循环,因为我们不知到用户是否需要使用一次以上。
+ Console.Title = "UsingDoWhileLoops | Learn X in Y Minutes"
+ Dim answer As String ' 我们使用字符串变量来存储answer(答案)
+ Do ' 循环开始
+ Console.Write("First number: ")
+ Dim a As Double = Console.ReadLine
+ Console.Write("Second number: ")
+ Dim b As Integer = Console.ReadLine
+ Dim c As Integer = a + b
+ Dim d As Integer = a * b
+ Dim e As Integer = a - b
+ Dim f As Integer = a / b
+
+ Console.Write(a.ToString() + " + " + b.ToString())
+ Console.WriteLine(" = " + c.ToString.PadLeft(3))
+ Console.Write(a.ToString() + " * " + b.ToString())
+ Console.WriteLine(" = " + d.ToString.PadLeft(3))
+ Console.Write(a.ToString() + " - " + b.ToString())
+ Console.WriteLine(" = " + e.ToString.PadLeft(3))
+ Console.Write(a.ToString() + " / " + b.ToString())
+ Console.WriteLine(" = " + e.ToString.PadLeft(3))
+ Console.ReadLine()
+ ' 询问用户是否继续,注意大小写。
+ Console.Write("Would you like to continue? (yes / no)")
+ ' 程序读入用户输入
+ answer = Console.ReadLine() ' added a bracket here
+ ' 当用户输入"yes"时,程序将跳转到Do,并再次执行
+ Loop While answer = "yes"
+
+ End Sub
+
+ ' 七
+ Private Sub UsingForLoops()
+ ' 有一些程序只需要运行一次。
+ ' 这个程序我们将实现从10倒数计数.
+
+ Console.Title = "Using For Loops | Learn X in Y Minutes"
+ ' 声明变量和Step (步长,即递减的速度,如-1,-2,-3等)。
+ For i As Integer = 10 To 0 Step -1
+ Console.WriteLine(i.ToString) ' 将计数结果输出的屏幕
+ Next i ' 计算新的i值
+ Console.WriteLine("Start")
+ Console.ReadLine()
+ End Sub
+
+ ' 八
+ Private Sub ConditionalStatement()
+ Console.Title = "Conditional Statements | Learn X in Y Minutes"
+ Dim userName As String = Console.ReadLine
+ Console.WriteLine("Hello, What is your name? ") ' 询问用户姓名
+ userName = Console.ReadLine() ' 存储用户姓名
+ If userName = "Adam" Then
+ Console.WriteLine("Hello Adam")
+ Console.WriteLine("Thanks for creating this useful site")
+ Console.ReadLine()
+ Else
+ Console.WriteLine("Hello " + userName)
+ Console.WriteLine("Have you checked out www.learnxinyminutes.com")
+ Console.ReadLine() ' 程序停止,并输出以上文本
+ End If
+ End Sub
+
+ ' 九
+ Private Sub IfElseStatement()
+ Console.Title = "If / Else Statement | Learn X in Y Minutes"
+ ' 有时候我们需要考虑多于两种情况。
+ ' 这时我们就需要使用If/ElesIf条件语句。
+ ' If语句就好似个自动售货机,当用户输入A1,A2,A3,等去选择物品时,
+ ' 所有的选择可以合并到一个If语句中
+
+ Dim selection As String = Console.ReadLine() ' 读入用户选择
+ Console.WriteLine("A1. for 7Up") ' A1 七喜
+ Console.WriteLine("A2. for Fanta") ' A2 芬达
+ Console.WriteLine("A3. for Dr. Pepper") ' A3 胡椒医生
+ Console.WriteLine("A4. for Diet Coke") ' A4 无糖可乐
+ Console.ReadLine()
+ If selection = "A1" Then
+ Console.WriteLine("7up")
+ Console.ReadLine()
+ ElseIf selection = "A2" Then
+ Console.WriteLine("fanta")
+ Console.ReadLine()
+ ElseIf selection = "A3" Then
+ Console.WriteLine("dr. pepper")
+ Console.ReadLine()
+ ElseIf selection = "A4" Then
+ Console.WriteLine("diet coke")
+ Console.ReadLine()
+ Else
+ Console.WriteLine("Please select a product") ' 请选择你需要的产品
+ Console.ReadLine()
+ End If
+
+ End Sub
+
+End Module
+
+```
+
+## 参考
+
+我(译注:原作者)在命令行下学习的VB。命令行编程使我能够更好的了解程序编译运行机制,并使学习其它语言变得容易。
+
+如果希望进一步学习VB,这里还有更深层次的 <a href="http://www.vbbootcamp.co.uk/" Title="VB教学">VB教学(英文)</a>。
+
+所有代码均通过测试。只需复制粘帖到Visual Basic中,并按F5运行即可。
diff --git a/zh-cn/xml-cn.html.markdown b/zh-cn/xml-cn.html.markdown
new file mode 100644
index 00000000..bf0b074f
--- /dev/null
+++ b/zh-cn/xml-cn.html.markdown
@@ -0,0 +1,127 @@
+---
+language: xml
+contributors:
+ - ["João Farias", "https://github.com/JoaoGFarias"]
+translators:
+ - ["Zach Zhang", "https://github.com/checkcheckzz"]
+filename: learnxml-cn.xml
+lang: zh-cn
+---
+
+XML是一种标记语言,被设计用来存储数据和传输数据。
+
+不像HTML, XML不指定怎样显示或格式化数据,只是携带它。
+
+
+* XML 语法
+
+```xml
+<!-- XML中的注解像这样 -->
+
+<?xml version="1.0" encoding="UTF-8"?>
+<bookstore>
+ <book category="COOKING">
+ <title lang="en">Everyday Italian</title>
+ <author>Giada De Laurentiis</author>
+ <year>2005</year>
+ <price>30.00</price>
+ </book>
+ <book category="CHILDREN">
+ <title lang="en">Harry Potter</title>
+ <author>J K. Rowling</author>
+ <year>2005</year>
+ <price>29.99</price>
+ </book>
+ <book category="WEB">
+ <title lang="en">Learning XML</title>
+ <author>Erik T. Ray</author>
+ <year>2003</year>
+ <price>39.95</price>
+ </book>
+</bookstore>
+
+<!-- 上面是一个典型的XML文件。
+ 它以一个声明开始,通知一些元数据(自选的)
+
+ XML使用一个树的结构。上面的文件中,根节点是'bookstore',它有三个孩子节点,
+ 所有的'books'。那些节点有更多的孩子节点,等等。。。
+
+ 节点用开放/关闭标签创建, 并且孩子就是在开发和关闭标签之间的节点。-->
+
+
+
+<!-- XML 携带两类信息:
+ 1 - 属性 -> 那是关于一个元素的元数据。
+ 通常,XML解析器使用这些信息去正确地存储数据。
+ 它通过在开放标签里出现在插入语中来表示。
+ 2 - 元素 -> 那是纯数据。
+ 那就是解析器将从XML文件提取的东西。
+ 元素出现在开放和关闭标签之间,没插入语。-->
+
+
+<!-- 下面, 一个有两个属性的元素-->
+<file type="gif" id="4293">computer.gif</file>
+
+
+```
+
+* 良好格式的文件 x 验证
+
+一个XML文件是良好格式的如果它是语法正确的。
+但是, 使用文件定义,比如DTD和XML概要,在文件中插入更多的限制是可能的。
+
+一个遵守一个文件定义的XML文件被叫做有效的,对于那个文件来说。
+
+有了这个工具,你能够在应用逻辑之外检查XML数据。
+
+```xml
+
+<!-- 下面, 你能够看到一个简化版本的增加了DTD定义的bookstore文件。-->
+
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE note SYSTEM "Bookstore.dtd">
+<bookstore>
+ <book category="COOKING">
+ <title >Everyday Italian</title>
+ <price>30.00</price>
+ </book>
+</bookstore>
+
+<!-- 这个DTD可能是像这样的:-->
+
+<!DOCTYPE note
+[
+<!ELEMENT bookstore (book+)>
+<!ELEMENT book (title,price)>
+<!ATTLIST book category CDATA "Literature">
+<!ELEMENT title (#PCDATA)>
+<!ELEMENT price (#PCDATA)>
+]>
+
+
+<!-- 这个DTD以一个声明开始。
+ 接下来, 根节点被声明, 它需要一个或多个孩子节点'book'。
+ 每个 'book' 应该准确包含一个 'title' 和 'price' 和
+ 一个被叫做'category'的缺省值为"Literature"的属性。
+ 这个'title' 和 'price'节点包含一个解析过的字符数据。-->
+
+<!-- 这个DTD可以在XML文件中本身被声明。-->
+
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE note
+[
+<!ELEMENT bookstore (book+)>
+<!ELEMENT book (title,price)>
+<!ATTLIST book category CDATA "Literature">
+<!ELEMENT title (#PCDATA)>
+<!ELEMENT price (#PCDATA)>
+]>
+
+<bookstore>
+ <book category="COOKING">
+ <title >Everyday Italian</title>
+ <price>30.00</price>
+ </book>
+</bookstore>
+``` \ No newline at end of file
diff --git a/zh-cn/yaml-cn.html.markdown b/zh-cn/yaml-cn.html.markdown
new file mode 100644
index 00000000..bcc41067
--- /dev/null
+++ b/zh-cn/yaml-cn.html.markdown
@@ -0,0 +1,136 @@
+---
+language: yaml
+contributors:
+ - ["Adam Brenecki", "https://github.com/adambrenecki"]
+translators:
+ - ["Zach Zhang", "https://github.com/checkcheckzz"]
+filename: learnyaml-cn.yaml
+lang: zh-cn
+---
+
+YAML是一个数据序列化语言,被设计成人类直接可写可读的。
+
+它是JSON的严格超集,增加了语法显著换行符和缩进,就像Python。但和Python不一样,
+YAML根本不容许文字制表符。
+
+
+```yaml
+# YAML中的注解看起来像这样。
+
+################
+# 标量类型 #
+################
+
+# 我们的根对象 (它们在整个文件里延续) 将会是一个地图,
+# 它等价于在别的语言里的一个字典,哈西表或对象。
+key: value
+another_key: Another value goes here.
+a_number_value: 100
+scientific_notation: 1e+12
+boolean: true
+null_value: null
+key with spaces: value
+# 注意到字符串不需要被引用。但是,它们可以被引用。
+"Keys can be quoted too.": "Useful if you want to put a ':' in your key."
+
+# 多行字符串既可以写成像一个'文字块'(使用 |),
+# 或像一个'折叠块'(使用 '>')。
+literal_block: |
+ This entire block of text will be the value of the 'literal_block' key,
+ with line breaks being preserved.
+
+ The literal continues until de-dented, and the leading indentation is
+ stripped.
+
+ Any lines that are 'more-indented' keep the rest of their indentation -
+ these lines will be indented by 4 spaces.
+folded_style: >
+ This entire block of text will be the value of 'folded_style', but this
+ time, all newlines will be replaced with a single space.
+
+ Blank lines, like above, are converted to a newline character.
+
+ 'More-indented' lines keep their newlines, too -
+ this text will appear over two lines.
+
+####################
+# 集合类型 #
+####################
+
+# 嵌套是通过缩进完成的。
+a_nested_map:
+ key: value
+ another_key: Another Value
+ another_nested_map:
+ hello: hello
+
+# 地图不用有字符串键值。
+0.25: a float key
+
+# 键值也可以是多行对象,用?表明键值的开始。
+? |
+ This is a key
+ that has multiple lines
+: and this is its value
+
+# YAML也容许键值是集合类型,但是很多语言将会抱怨。
+
+# 序列 (等价于表或数组) 看起来像这样:
+a_sequence:
+ - Item 1
+ - Item 2
+ - 0.5 # sequences can contain disparate types
+ - Item 4
+ - key: value
+ another_key: another_value
+ -
+ - This is a sequence
+ - inside another sequence
+
+# 因为YAML是JSON的超集,你也可以写JSON风格的地图和序列:
+json_map: {"key": "value"}
+json_seq: [3, 2, 1, "takeoff"]
+
+#######################
+# 其余的YAML特点 #
+#######################
+
+# YAML还有一个方便的特点叫'锚',它让你简单地在整个文件里重复内容。
+# 两个键值将会有相同的值:
+anchored_content: &anchor_name This string will appear as the value of two keys.
+other_anchor: *anchor_name
+
+# YAML还有标签,你可以用它显示地声明类型。
+explicit_string: !!str 0.5
+# 一些解析器实现特定语言的标签,就像这个为了Python的复数类型。
+python_complex_number: !!python/complex 1+2j
+
+####################
+# 其余的YAML类型 #
+####################
+
+# 字符串和数字不是仅有的YAML可以理解的标量。
+# ISO 格式的日期和日期时间文字也是可以被解析的。
+datetime: 2001-12-15T02:59:43.1Z
+datetime_with_spaces: 2001-12-14 21:59:43.10 -5
+date: 2002-12-14
+
+# 这个!!binary标签表明一个字符串实际上是一个二进制blob的base64编码表示。
+gif_file: !!binary |
+ R0lGODlhDAAMAIQAAP//9/X17unp5WZmZgAAAOfn515eXvPz7Y6OjuDg4J+fn5
+ OTk6enp56enmlpaWNjY6Ojo4SEhP/++f/++f/++f/++f/++f/++f/++f/++f/+
+ +f/++f/++f/++f/++f/++SH+Dk1hZGUgd2l0aCBHSU1QACwAAAAADAAMAAAFLC
+ AgjoEwnuNAFOhpEMTRiggcz4BNJHrv/zCFcLiwMWYNG84BwwEeECcgggoBADs=
+
+# YAML还有一个集合类型,它看起来像这样:
+set:
+ ? item1
+ ? item2
+ ? item3
+
+# 像Python一样,集合仅是有null数值的地图;上面的集合等价于:
+set2:
+ item1: null
+ item2: null
+ item3: null
+```