├── README.md ├── learnbash-cn.sh ├── learnc-cn.c ├── learncsharp-cn.cs ├── learncss-cn.css ├── learngo-cn.go ├── learnlua-cn.lua ├── learnperl-cn.pl ├── learnphp-cn.php ├── learnpython-cn.py ├── learnpython3-cn.py ├── learnr-cn.r ├── learnruby-cn.rb └── learnswift-cn.swift /README.md: -------------------------------------------------------------------------------- 1 | # Learn X in Y minutes 2 | 在线编程语言速学网,C++、CSS、java、json、PHP、python、swift等各种语言的快速学习教程。 3 | - [C](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learnc-cn.c) 4 | - [C#](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learncsharp-cn.cs) 5 | - [Go](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learngo-cn.go) 6 | - [Lua](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learnlua-cn.lua) 7 | - [Perl](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learnperl-cn.pl) 8 | - [PHP](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learnphp-cn.php) 9 | - [Python](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learnpython-cn.py) 10 | - [Python3](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learnpython3-cn.py) 11 | - [R](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learnr-cn.r) 12 | - [Ruby](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learnruby-cn.rb) 13 | - [Swift](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learnswift-cn.swift) 14 | - [CSS](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learncss-cn.css) 15 | - [Bash](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learnbash-cn.sh) 16 | -------------------------------------------------------------------------------- /learnbash-cn.sh: -------------------------------------------------------------------------------- 1 | 2 | #!/bin/bash 3 | # 脚本的第一行叫 shebang,用来告知系统如何执行该脚本: 4 | # 参见: http://en.wikipedia.org/wiki/Shebang_(Unix) 5 | # 如你所见,注释以 # 开头,shebang 也是注释。 6 | 7 | # 显示 “Hello world!” 8 | echo Hello, world! 9 | 10 | # 每一句指令以换行或分号隔开: 11 | echo 'This is the first line'; echo 'This is the second line' 12 | 13 | # 声明一个变量: 14 | VARIABLE="Some string" 15 | 16 | # 下面是错误的做法: 17 | VARIABLE = "Some string" 18 | # Bash 会把 VARIABLE 当做一个指令,由于找不到该指令,因此这里会报错。 19 | 20 | 21 | # 使用变量: 22 | echo $VARIABLE 23 | echo "$VARIABLE" 24 | echo '$VARIABLE' 25 | # 当你赋值 (assign) 、导出 (export),或者以其他方式使用变量时,变量名前不加 $。 26 | # 如果要使用变量的值, 则要加 $。 27 | # 注意: ' (单引号) 不会展开变量(即会屏蔽掉变量)。 28 | 29 | 30 | # 在变量内部进行字符串代换 31 | echo ${VARIABLE/Some/A} 32 | # 会把 VARIABLE 中首次出现的 "some" 替换成 “A”。 33 | 34 | # 内置变量: 35 | # 下面的内置变量很有用 36 | echo "Last program return value: $?" 37 | echo "Script's PID: $$" 38 | echo "Number of arguments: $#" 39 | echo "Scripts arguments: $@" 40 | echo "Scripts arguments separeted in different variables: $1 $2..." 41 | 42 | # 读取输入: 43 | echo "What's your name?" 44 | read NAME # 这里不需要声明新变量 45 | echo Hello, $NAME! 46 | 47 | # 通常的 if 结构看起来像这样: 48 | # 'man test' 可查看更多的信息 49 | if [ $NAME -ne $USER ] 50 | then 51 | echo "Your name is you username" 52 | else 53 | echo "Your name isn't you username" 54 | fi 55 | 56 | # 根据上一个指令执行结果决定是否执行下一个指令 57 | echo "Always executed" || echo "Only executed if first command fail" 58 | echo "Always executed" && echo "Only executed if first command does NOT fail" 59 | 60 | # 表达式的格式如下: 61 | echo $(( 10 + 5 )) 62 | 63 | # 与其他编程语言不同的是,bash 运行时依赖上下文。比如,使用 ls 时,列出当前目录。 64 | ls 65 | 66 | # 指令可以带有选项: 67 | ls -l # 列出文件和目录的详细信息 68 | 69 | # 前一个指令的输出可以当作后一个指令的输入。grep 用来匹配字符串。 70 | # 用下面的指令列出当前目录下所有的 txt 文件: 71 | ls -l | grep "\.txt" 72 | 73 | # 重定向可以到输出,输入和错误输出。 74 | python2 hello.py < "input.in" 75 | python2 hello.py > "output.out" 76 | python2 hello.py 2> "error.err" 77 | # > 会覆盖已存在的文件, >> 会以累加的方式输出文件中。 78 | 79 | # 一个指令可用 $( ) 嵌套在另一个指令内部: 80 | # 以下的指令会打印当前目录下的目录和文件总数 81 | echo "There are $(ls | wc -l) items here." 82 | 83 | # Bash 的 case 语句与 Java 和 C++ 中的 switch 语句类似: 84 | case "$VARIABLE" in 85 | # 列出需要匹配的字符串 86 | 0) echo "There is a zero.";; 87 | 1) echo "There is a one.";; 88 | *) echo "It is not null.";; 89 | esac 90 | 91 | # 循环遍历给定的参数序列: 92 | # 变量$VARIABLE 的值会被打印 3 次。 93 | # 注意 ` ` 和 $( ) 等价。seq 返回长度为 3 的数组。 94 | for VARIABLE in `seq 3` 95 | do 96 | echo "$VARIABLE" 97 | done 98 | 99 | # 你也可以使用函数 100 | # 定义函数: 101 | function foo () 102 | { 103 | echo "Arguments work just like script arguments: $@" 104 | echo "And: $1 $2..." 105 | echo "This is a function" 106 | return 0 107 | } 108 | 109 | # 更简单的方法 110 | bar () 111 | { 112 | echo "Another way to declare functions!" 113 | return 0 114 | } 115 | 116 | # 调用函数 117 | foo "My name is" $NAME 118 | 119 | # 有很多有用的指令需要学习: 120 | tail -n 10 file.txt 121 | # 打印 file.txt 的最后 10 行 122 | head -n 10 file.txt 123 | # 打印 file.txt 的前 10 行 124 | sort file.txt 125 | # 将 file.txt 按行排序 126 | uniq -d file.txt 127 | # 报告或忽略重复的行,用选项 -d 打印重复的行 128 | cut -d ',' -f 1 file.txt 129 | # 打印每行中 ',' 之前内容 130 | -------------------------------------------------------------------------------- /learnc-cn.c: -------------------------------------------------------------------------------- 1 | 2 | // 单行注释以//开始。(仅适用于C99或更新的版本。) 3 | 4 | /* 5 | 多行注释是这个样子的。(C89也适用。) 6 | */ 7 | 8 | // 常数: #define 关键词 9 | #define DAYS_IN_YEAR 365 10 | 11 | // 以枚举的方式定义常数 12 | enum days {SUN = 1, MON, TUE, WED, THU, FRI, SAT}; 13 | // MON自动被定义为2,TUE被定义为3,以此类推。 14 | 15 | // 用#include来导入头文件 16 | #include 17 | #include 18 | #include 19 | 20 | // <尖括号>间的文件名是C标准库的头文件。 21 | // 标准库以外的头文件,使用双引号代替尖括号。 22 | #include "my_header.h" 23 | 24 | // 函数的签名可以事先在.h文件中定义, 25 | // 也可以直接在.c文件的头部定义。 26 | void function_1(char c); 27 | void function_2(void); 28 | 29 | // 如果函数出现在main()之后,那么必须在main()之前 30 | // 先声明一个函数原型 31 | int add_two_ints(int x1, int x2); // 函数原型 32 | 33 | // 你的程序的入口是一个返回值为整型的main函数 34 | int main() { 35 | 36 | // 用printf打印到标准输出,可以设定格式, 37 | // %d 代表整数, \n 代表换行 38 | printf("%d\n", 0); // => 打印 0 39 | // 所有的语句都要以分号结束 40 | 41 | /////////////////////////////////////// 42 | // 类型 43 | /////////////////////////////////////// 44 | 45 | // 在使用变量之前我们必须先声明它们。 46 | // 变量在声明时需要指明其类型,而类型能够告诉系统这个变量所占用的空间 47 | 48 | // int型(整型)变量一般占用4个字节 49 | int x_int = 0; 50 | 51 | // short型(短整型)变量一般占用2个字节 52 | short x_short = 0; 53 | 54 | // char型(字符型)变量会占用1个字节 55 | char x_char = 0; 56 | char y_char = 'y'; // 字符变量的字面值需要用单引号包住 57 | 58 | // long型(长整型)一般需要4个字节到8个字节; 而long long型则至少需要8个字节(64位) 59 | 60 | long x_long = 0; 61 | long long x_long_long = 0; 62 | 63 | // float一般是用32位表示的浮点数字 64 | float x_float = 0.0; 65 | 66 | // double一般是用64位表示的浮点数字 67 | double x_double = 0.0; 68 | 69 | // 整数类型也可以有无符号的类型表示。这样这些变量就无法表示负数 70 | // 但是无符号整数所能表示的范围就可以比原来的整数大一些 71 | 72 | unsigned short ux_short; 73 | unsigned int ux_int; 74 | unsigned long long ux_long_long; 75 | 76 | // 单引号内的字符是机器的字符集中的整数。 77 | '0' // => 在ASCII字符集中是48 78 | 'A' // => 在ASCII字符集中是65 79 | 80 | // char类型一定会占用1个字节,但是其他的类型却会因具体机器的不同而各异 81 | // sizeof(T) 可以返回T类型在运行的机器上占用多少个字节 82 | // 这样你的代码就可以在各处正确运行了 83 | // sizeof(obj)返回表达式(变量、字面量等)的尺寸 84 | printf("%zu\n", sizeof(int)); // => 4 (大多数的机器字长为4) 85 | 86 | // 如果`sizeof`的参数是一个表达式,那么这个参数不会被演算(VLA例外,见下) 87 | // 它产生的值是编译期的常数 88 | int a = 1; 89 | // size_t是一个无符号整型,表示对象的尺寸,至少2个字节 90 | size_t size = sizeof(a++); // a++ 不会被演算 91 | printf("sizeof(a++) = %zu where a = %d\n", size, a); 92 | // 打印 "sizeof(a++) = 4 where a = 1" (在32位架构上) 93 | 94 | // 数组必须要被初始化为具体的长度 95 | char my_char_array[20]; // 这个数组占据 1 * 20 = 20 个字节 96 | int my_int_array[20]; // 这个数组占据 4 * 20 = 80 个字节 97 | // (这里我们假设字长为4) 98 | 99 | 100 | // 可以用下面的方法把数组初始化为0: 101 | char my_array[20] = {0}; 102 | 103 | // 索引数组和其他语言类似 -- 好吧,其实是其他的语言像C 104 | my_array[0]; // => 0 105 | 106 | // 数组是可变的,其实就是内存的映射! 107 | my_array[1] = 2; 108 | printf("%d\n", my_array[1]); // => 2 109 | 110 | // 在C99 (C11中是可选特性),变长数组(VLA)也可以声明长度。 111 | // 其长度不用是编译期常量。 112 | printf("Enter the array size: "); // 询问用户数组长度 113 | char buf[0x100]; 114 | fgets(buf, sizeof buf, stdin); 115 | 116 | // stroul 将字符串解析为无符号整数 117 | size_t size = strtoul(buf, NULL, 10); 118 | int var_length_array[size]; // 声明VLA 119 | printf("sizeof array = %zu\n", sizeof var_length_array); 120 | 121 | // 上述程序可能的输出为: 122 | // > Enter the array size: 10 123 | // > sizeof array = 40 124 | 125 | // 字符串就是以 NUL (0x00) 这个字符结尾的字符数组, 126 | // NUL可以用'\0'来表示. 127 | // (在字符串字面量中我们不必输入这个字符,编译器会自动添加的) 128 | char a_string[20] = "This is a string"; 129 | printf("%s\n", a_string); // %s 可以对字符串进行格式化 130 | /* 131 | 也许你会注意到 a_string 实际上只有16个字节长. 132 | 第17个字节是一个空字符(NUL) 133 | 而第18, 19 和 20 个字符的值是未定义。 134 | */ 135 | 136 | printf("%d\n", a_string[16]); // => 0 137 | // byte #17值为0(18,19,20同样为0) 138 | 139 | // 单引号间的字符是字符字面量 140 | // 它的类型是`int`,而 *不是* `char` 141 | // (由于历史原因) 142 | int cha = 'a'; // 合法 143 | char chb = 'a'; // 同样合法 (隐式类型转换 144 | 145 | // 多维数组 146 | int multi_array[2][5] = { 147 | {1, 2, 3, 4, 5}, 148 | {6, 7, 8, 9, 0} 149 | } 150 | // 获取元素 151 | int array_int = multi_array[0][2]; // => 3 152 | 153 | /////////////////////////////////////// 154 | // 操作符 155 | /////////////////////////////////////// 156 | 157 | // 多个变量声明的简写 158 | int i1 = 1, i2 = 2; 159 | float f1 = 1.0, f2 = 2.0; 160 | 161 | int a, b, c; 162 | a = b = c = 0; 163 | 164 | // 算数运算直截了当 165 | i1 + i2; // => 3 166 | i2 - i1; // => 1 167 | i2 * i1; // => 2 168 | i1 / i2; // => 0 (0.5,但会被化整为 0) 169 | 170 | f1 / f2; // => 0.5, 也许会有很小的误差 171 | // 浮点数和浮点数运算都是近似值 172 | 173 | // 取余运算 174 | 11 % 3; // => 2 175 | 176 | // 你多半会觉得比较操作符很熟悉, 不过C中没有布尔类型 177 | // 而是用整形替代 178 | // (C99中有_Bool或bool。) 179 | // 0为假, 其他均为真. (比较操作符的返回值总是返回0或1) 180 | 3 == 2; // => 0 (false) 181 | 3 != 2; // => 1 (true) 182 | 3 > 2; // => 1 183 | 3 < 2; // => 0 184 | 2 <= 2; // => 1 185 | 2 >= 2; // => 1 186 | 187 | // C不是Python —— 连续比较不合法 188 | int a = 1; 189 | // 错误 190 | int between_0_and_2 = 0 < a < 2; 191 | // 正确 192 | int between_0_and_2 = 0 < a && a < 2; 193 | 194 | // 逻辑运算符适用于整数 195 | !3; // => 0 (非) 196 | !0; // => 1 197 | 1 && 1; // => 1 (且) 198 | 0 && 1; // => 0 199 | 0 || 1; // => 1 (或) 200 | 0 || 0; // => 0 201 | 202 | // 条件表达式 ( ? : ) 203 | int a = 5; 204 | int b = 10; 205 | int z; 206 | z = (a > b) ? a : b; // 10 “若a > b返回a,否则返回b。” 207 | 208 | // 增、减 209 | char *s = "iLoveC" 210 | int j = 0; 211 | s[j++]; // "i" 返回s的第j项,然后增加j的值。 212 | j = 0; 213 | s[++j]; // => "L" 增加j的值,然后返回s的第j项。 214 | // j-- 和 --j 同理 215 | 216 | // 位运算 217 | ~0x0F; // => 0xF0 (取反) 218 | 0x0F & 0xF0; // => 0x00 (和) 219 | 0x0F | 0xF0; // => 0xFF (或) 220 | 0x04 ^ 0x0F; // => 0x0B (异或) 221 | 0x01 << 1; // => 0x02 (左移1位) 222 | 0x02 >> 1; // => 0x01 (右移1位) 223 | 224 | // 对有符号整数进行移位操作要小心 —— 以下未定义: 225 | // 有符号整数位移至符号位 int a = 1 << 32 226 | // 左移位一个负数 int a = -1 << 2 227 | // 移位超过或等于该类型数值的长度 228 | // int a = 1 << 32; // 假定int32位 229 | 230 | 231 | /////////////////////////////////////// 232 | // 控制结构 233 | /////////////////////////////////////// 234 | 235 | if (0) { 236 | printf("I am never run\n"); 237 | } else if (0) { 238 | printf("I am also never run\n"); 239 | } else { 240 | printf("I print\n"); 241 | } 242 | 243 | // While循环 244 | int ii = 0; 245 | while (ii < 10) { // 任何非0的值均为真 246 | printf("%d, ", ii++); // ii++ 在取值过后自增 247 | } // => 打印 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " 248 | 249 | printf("\n"); 250 | 251 | int kk = 0; 252 | do { 253 | printf("%d, ", kk); 254 | } while (++kk < 10); // ++kk 先自增,再被取值 255 | // => 打印 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " 256 | 257 | printf("\n"); 258 | 259 | // For 循环 260 | int jj; 261 | for (jj=0; jj < 10; jj++) { 262 | printf("%d, ", jj); 263 | } // => 打印 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " 264 | 265 | printf("\n"); 266 | 267 | // *****注意*****: 268 | // 循环和函数必须有主体部分,如果不需要主体部分: 269 | int i; 270 | for (i = 0; i <= 5; i++) { 271 | ; // 使用分号表达主体(null语句) 272 | } 273 | 274 | // 多重分支:switch() 275 | switch (some_integral_expression) { 276 | case 0: // 标签必须是整数常量表达式 277 | do_stuff(); 278 | break; // 如果不使用break,控制结构会继续执行下面的标签 279 | case 1: 280 | do_something_else(); 281 | break; 282 | default: 283 | // 假设 `some_integral_expression` 不匹配任何标签 284 | fputs("error!\n", stderr); 285 | exit(-1); 286 | break; 287 | } 288 | 289 | /////////////////////////////////////// 290 | // 类型转换 291 | /////////////////////////////////////// 292 | 293 | // 在C中每个变量都有类型,你可以将变量的类型进行转换 294 | // (有一定限制) 295 | 296 | int x_hex = 0x01; // 可以用16进制字面量赋值 297 | 298 | // 在类型转换时,数字本身的值会被保留下来 299 | printf("%d\n", x_hex); // => 打印 1 300 | printf("%d\n", (short) x_hex); // => 打印 1 301 | printf("%d\n", (char) x_hex); // => 打印 1 302 | 303 | // 类型转换时可能会造成溢出,而且不会抛出警告 304 | printf("%d\n", (char) 257); // => 1 (char的最大值为255,假定char为8位长) 305 | 306 | // 使用提供的CHAR_MAX、SCHAR_MAX和UCHAR_MAX宏可以确定`char`、`signed_char`和`unisigned char`的最大值。 307 | 308 | 309 | // 整数型和浮点型可以互相转换 310 | printf("%f\n", (float)100); // %f 格式化单精度浮点 311 | printf("%lf\n", (double)100); // %lf 格式化双精度浮点 312 | printf("%d\n", (char)100.0); 313 | 314 | /////////////////////////////////////// 315 | // 指针 316 | /////////////////////////////////////// 317 | 318 | // 指针变量是用来储存内存地址的变量 319 | // 指针变量的声明也会告诉它所指向的数据的类型 320 | // 你可以使用得到你的变量的地址,并把它们搞乱,;-) 321 | 322 | int x = 0; 323 | printf("%p\n", &x); // 用 & 来获取变量的地址 324 | // (%p 格式化一个类型为 void *的指针) 325 | // => 打印某个内存地址 326 | 327 | // 指针类型在声明中以*开头 328 | int* px, not_a_pointer; // px是一个指向int型的指针 329 | px = &x; // 把x的地址保存到px中 330 | printf("%p\n", (void *)px); // => 输出内存中的某个地址 331 | printf("%zu, %zu\n", sizeof(px), sizeof(not_a_pointer)); 332 | // => 在64位系统上打印“8, 4”。 333 | 334 | // 要得到某个指针指向的内容的值,可以在指针前加一个*来取得(取消引用) 335 | // 注意: 是的,这可能让人困惑,'*'在用来声明一个指针的同时取消引用它。 336 | printf("%d\n", *px); // => 输出 0, 即x的值 337 | 338 | // 你也可以改变指针所指向的值 339 | // 此时你需要取消引用上添加括号,因为++比*的优先级更高 340 | (*px)++; // 把px所指向的值增加1 341 | printf("%d\n", *px); // => 输出 1 342 | printf("%d\n", x); // => 输出 1 343 | 344 | // 数组是分配一系列连续空间的常用方式 345 | int x_array[20]; 346 | int xx; 347 | for (xx=0; xx<20; xx++) { 348 | x_array[xx] = 20 - xx; 349 | } // 初始化 x_array 为 20, 19, 18,... 2, 1 350 | 351 | // 声明一个整型的指针,并初始化为指向x_array 352 | int* x_ptr = x_array; 353 | // x_ptr现在指向了数组的第一个元素(即整数20). 354 | // 这是因为数组通常衰减为指向它们的第一个元素的指针。 355 | // 例如,当一个数组被传递给一个函数或者绑定到一个指针时, 356 | //它衰减为(隐式转化为)一个指针。 357 | // 例外: 当数组是`&`操作符的参数: 358 | int arr[10]; 359 | int (*ptr_to_arr)[10] = &arr; // &arr的类型不是`int *`! 360 | // 它的类型是指向数组的指针(数组由10个int组成) 361 | // 或者当数组是字符串字面量(初始化字符数组) 362 | char arr[] = "foobarbazquirk"; 363 | // 或者当它是`sizeof`或`alignof`操作符的参数时: 364 | int arr[10]; 365 | int *ptr = arr; // 等价于 int *ptr = &arr[0]; 366 | printf("%zu, %zu\n", sizeof arr, sizeof ptr); // 应该会输出"40, 4"或"40, 8" 367 | 368 | // 指针的增减多少是依据它本身的类型而定的 369 | // (这被称为指针算术) 370 | printf("%d\n", *(x_ptr + 1)); // => 打印 19 371 | printf("%d\n", x_array[1]); // => 打印 19 372 | 373 | // 你也可以通过标准库函数malloc来实现动态分配 374 | // 这个函数接受一个代表容量的参数,参数类型为`size_t` 375 | // 系统一般会从堆区分配指定容量字节大小的空间 376 | // (在一些系统,例如嵌入式系统中这点不一定成立 377 | // C标准对此未置一词。) 378 | int *my_ptr = malloc(sizeof(*my_ptr) * 20); 379 | for (xx=0; xx<20; xx++) { 380 | *(my_ptr + xx) = 20 - xx; // my_ptr[xx] = 20-xx 381 | } // 初始化内存为 20, 19, 18, 17... 2, 1 (类型为int) 382 | 383 | // 对未分配的内存进行取消引用会产生未定义的结果 384 | printf("%d\n", *(my_ptr + 21)); // => 谁知道会输出什么 385 | 386 | // malloc分配的区域需要手动释放 387 | // 否则没人能够再次使用这块内存,直到程序结束为止 388 | free(my_ptr); 389 | 390 | // 字符串通常是字符数组,但是经常用字符指针表示 391 | // (它是指向数组的第一个元素的指针) 392 | // 一个优良的实践是使用`const char *`来引用一个字符串字面量, 393 | // 因为字符串字面量不应当被修改(即"foo"[0] = 'a'犯了大忌) 394 | const char* my_str = "This is my very own string"; 395 | printf("%c\n", *my_str); // => 'T' 396 | 397 | // 如果字符串是数组,(多半是用字符串字面量初始化的) 398 | // 情况就不一样了,字符串位于可写的内存中 399 | char foo[] = "foo"; 400 | foo[0] = 'a'; // 这是合法的,foo现在包含"aoo" 401 | 402 | function_1(); 403 | } // main函数结束 404 | 405 | /////////////////////////////////////// 406 | // 函数 407 | /////////////////////////////////////// 408 | 409 | // 函数声明语法: 410 | // <返回值类型> <函数名称>(<参数>) 411 | 412 | int add_two_ints(int x1, int x2){ 413 | return x1 + x2; // 用return来返回一个值 414 | } 415 | 416 | /* 417 | 函数是按值传递的。当调用一个函数的时候,传递给函数的参数 418 | 是原有值的拷贝(数组除外)。你在函数内对参数所进行的操作 419 | 不会改变该参数原有的值。 420 | 421 | 但是你可以通过指针来传递引用,这样函数就可以更改值 422 | 423 | 例子:字符串本身翻转 424 | */ 425 | 426 | // 类型为void的函数没有返回值 427 | void str_reverse(char *str_in){ 428 | char tmp; 429 | int ii = 0; 430 | size_t len = strlen(str_in); // `strlen()`` 是C标准库函数 431 | for(ii = 0; ii < len / 2; ii++){ 432 | tmp = str_in[ii]; 433 | str_in[ii] = str_in[len - ii - 1]; // 从倒数第ii个开始 434 | str_in[len - ii - 1] = tmp; 435 | } 436 | } 437 | 438 | /* 439 | char c[] = "This is a test."; 440 | str_reverse(c); 441 | printf("%s\n", c); // => ".tset a si sihT" 442 | */ 443 | 444 | // 如果引用函数之外的变量,必须使用extern关键字 445 | int i = 0; 446 | void testFunc() { 447 | extern int i; // 使用外部变量 i 448 | } 449 | 450 | // 使用static确保external变量为源文件私有 451 | static int i = 0; // 其他使用 testFunc()的文件无法访问变量i 452 | void testFunc() { 453 | extern int i; 454 | } 455 | //**你同样可以声明函数为static** 456 | 457 | 458 | /////////////////////////////////////// 459 | // 用户自定义类型和结构 460 | /////////////////////////////////////// 461 | 462 | // Typedefs可以创建类型别名 463 | typedef int my_type; 464 | my_type my_type_var = 0; 465 | 466 | // struct是数据的集合,成员依序分配,按照 467 | // 编写的顺序 468 | struct rectangle { 469 | int width; 470 | int height; 471 | }; 472 | 473 | // 一般而言,以下断言不成立: 474 | // sizeof(struct rectangle) == sizeof(int) + sizeof(int) 475 | //这是因为structure成员之间可能存在潜在的间隙(为了对齐)[1] 476 | 477 | void function_1(){ 478 | 479 | struct rectangle my_rec; 480 | 481 | // 通过 . 来访问结构中的数据 482 | my_rec.width = 10; 483 | my_rec.height = 20; 484 | 485 | // 你也可以声明指向结构体的指针 486 | struct rectangle *my_rec_ptr = &my_rec; 487 | 488 | // 通过取消引用来改变结构体的成员... 489 | (*my_rec_ptr).width = 30; 490 | 491 | // ... 或者用 -> 操作符作为简写提高可读性 492 | my_rec_ptr->height = 10; // Same as (*my_rec_ptr).height = 10; 493 | } 494 | 495 | // 你也可以用typedef来给一个结构体起一个别名 496 | typedef struct rectangle rect; 497 | 498 | int area(rect r){ 499 | return r.width * r.height; 500 | } 501 | 502 | // 如果struct较大,你可以通过指针传递,避免 503 | // 复制整个struct。 504 | int area(const rect *r) 505 | { 506 | return r->width * r->height; 507 | } 508 | 509 | /////////////////////////////////////// 510 | // 函数指针 511 | /////////////////////////////////////// 512 | /* 513 | 在运行时,函数本身也被存放到某块内存区域当中 514 | 函数指针就像其他指针一样(不过是存储一个内存地址) 但却可以被用来直接调用函数, 515 | 并且可以四处传递回调函数 516 | 但是,定义的语法初看令人有些迷惑 517 | 518 | 例子:通过指针调用str_reverse 519 | */ 520 | void str_reverse_through_pointer(char *str_in) { 521 | // 定义一个函数指针 f. 522 | void (*f)(char *); // 签名一定要与目标函数相同 523 | f = &str_reverse; // 将函数的地址在运行时赋给指针 524 | (*f)(str_in); // 通过指针调用函数 525 | // f(str_in); // 等价于这种调用方式 526 | } 527 | 528 | /* 529 | 只要函数签名是正确的,任何时候都能将任何函数赋给某个函数指针 530 | 为了可读性和简洁性,函数指针经常和typedef搭配使用: 531 | */ 532 | 533 | typedef void (*my_fnp_type)(char *); 534 | 535 | // 实际声明函数指针会这么用: 536 | // ... 537 | // my_fnp_type f; 538 | 539 | // 特殊字符 540 | '\a' // bell 541 | '\n' // 换行 542 | '\t' // tab 543 | '\v' // vertical tab 544 | '\f' // formfeed 545 | '\r' // 回车 546 | '\b' // 退格 547 | '\0' // null,通常置于字符串的最后。 548 | // hello\n\0. 按照惯例,\0用于标记字符串的末尾。 549 | '\\' // 反斜杠 550 | '\?' // 问号 551 | '\'' // 单引号 552 | '\"' // 双引号 553 | '\xhh' // 十六进制数字. 例子: '\xb' = vertical tab 554 | '\ooo' // 八进制数字. 例子: '\013' = vertical tab 555 | 556 | // 打印格式: 557 | "%d" // 整数 558 | "%3d" // 3位以上整数 (右对齐文本) 559 | "%s" // 字符串 560 | "%f" // float 561 | "%ld" // long 562 | "%3.2f" // 左3位以上、右2位以上十进制浮 563 | "%7.4s" // (字符串同样适用) 564 | "%c" // 字母 565 | "%p" // 指针 566 | "%x" // 十六进制 567 | "%o" // 八进制 568 | "%%" // 打印 % 569 | 570 | /////////////////////////////////////// 571 | // 演算优先级 572 | /////////////////////////////////////// 573 | //---------------------------------------------------// 574 | // 操作符 | 组合 // 575 | //---------------------------------------------------// 576 | // () [] -> . | 从左到右 // 577 | // ! ~ ++ -- + = *(type)sizeof | 从右到左 // 578 | // * / % | 从左到右 // 579 | // + - | 从左到右 // 580 | // << >> | 从左到右 // 581 | // < <= > >= | 从左到右 // 582 | // == != | 从左到右 // 583 | // & | 从左到右 // 584 | // ^ | 从左到右 // 585 | // | | 从左到右 // 586 | // && | 从左到右 // 587 | // || | 从左到右 // 588 | // ?: | 从右到左 // 589 | // = += -= *= /= %= &= ^= |= <<= >>= | 从右到左 // 590 | // , | 从左到右 // 591 | //---------------------------------------------------// 592 | -------------------------------------------------------------------------------- /learncsharp-cn.cs: -------------------------------------------------------------------------------- 1 | 2 | // 单行注释以 // 开始 3 | /* 4 | 多行注释是这样的 5 | */ 6 | /// 7 | /// XML文档注释 8 | /// 9 | 10 | // 声明应用用到的命名空间 11 | using System; 12 | using System.Collections.Generic; 13 | using System.Data.Entity; 14 | using System.Dynamic; 15 | using System.Linq; 16 | using System.Linq.Expressions; 17 | using System.Net; 18 | using System.Threading.Tasks; 19 | using System.IO; 20 | 21 | // 定义作用域,将代码组织成包 22 | namespace Learning 23 | { 24 | // 每个 .cs 文件至少需要包含一个和文件名相同的类 25 | // 你可以不这么干,但是这样不好。 26 | public class LearnCSharp 27 | { 28 | // 基本语法 - 如果你以前用过 Java 或 C++ 的话,可以直接跳到后文「有趣的特性」 29 | public static void Syntax() 30 | { 31 | // 使用 Console.WriteLine 打印信息 32 | Console.WriteLine("Hello World"); 33 | Console.WriteLine( 34 | "Integer: " + 10 + 35 | " Double: " + 3.14 + 36 | " Boolean: " + true); 37 | 38 | // 使用 Console.Write 打印,不带换行符号 39 | Console.Write("Hello "); 40 | Console.Write("World"); 41 | 42 | /////////////////////////////////////////////////// 43 | // 类型和变量 44 | // 45 | // 使用 定义变量 46 | /////////////////////////////////////////////////// 47 | 48 | // Sbyte - 有符号 8-bit 整数 49 | // (-128 <= sbyte <= 127) 50 | sbyte fooSbyte = 100; 51 | 52 | // Byte - 无符号 8-bit 整数 53 | // (0 <= byte <= 255) 54 | byte fooByte = 100; 55 | 56 | // Short - 16-bit 整数 57 | // 有符号 - (-32,768 <= short <= 32,767) 58 | // 无符号 - (0 <= ushort <= 65,535) 59 | short fooShort = 10000; 60 | ushort fooUshort = 10000; 61 | 62 | // Integer - 32-bit 整数 63 | int fooInt = 1; // (-2,147,483,648 <= int <= 2,147,483,647) 64 | uint fooUint = 1; // (0 <= uint <= 4,294,967,295) 65 | 66 | // Long - 64-bit 整数 67 | long fooLong = 100000L; // (-9,223,372,036,854,775,808 <= long <= 9,223,372,036,854,775,807) 68 | ulong fooUlong = 100000L; // (0 <= ulong <= 18,446,744,073,709,551,615) 69 | // 数字默认为 int 或 uint (取决于尺寸) 70 | // 使用 L 标明变量值类型为long 或 ulong 71 | 72 | // Double - 双精度 64-bit IEEE 754 浮点数 73 | double fooDouble = 123.4; // 精度: 15-16 位 74 | 75 | // Float - 单精度 32-bit IEEE 754 浮点数 76 | float fooFloat = 234.5f; // 精度: 7 位 77 | // 使用 f 标明变量值类型为float 78 | 79 | // Decimal - 128-bits 数据类型,比其他浮点类型精度更高 80 | // 适合财务、金融 81 | decimal fooDecimal = 150.3m; 82 | 83 | // 布尔值 - true & false 84 | bool fooBoolean = true; // 或 false 85 | 86 | // Char - 单个 16-bit Unicode 字符 87 | char fooChar = 'A'; 88 | 89 | // 字符串 -- 和前面的基本类型不同,字符串不是值,而是引用。 90 | // 这意味着你可以将字符串设为null。 91 | string fooString = "\"escape\" quotes and add \n (new lines) and \t (tabs)"; 92 | Console.WriteLine(fooString); 93 | 94 | // 你可以通过索引访问字符串的每个字符: 95 | char charFromString = fooString[1]; // => 'e' 96 | // 字符串不可修改: fooString[1] = 'X' 是行不通的; 97 | 98 | // 根据当前的locale设定比较字符串,大小写不敏感 99 | string.Compare(fooString, "x", StringComparison.CurrentCultureIgnoreCase); 100 | 101 | // 基于sprintf的字符串格式化 102 | string fooFs = string.Format("Check Check, {0} {1}, {0} {1:0.0}", 1, 2); 103 | 104 | // 日期和格式 105 | DateTime fooDate = DateTime.Now; 106 | Console.WriteLine(fooDate.ToString("hh:mm, dd MMM yyyy")); 107 | 108 | // 使用 @ 符号可以创建跨行的字符串。使用 "" 来表示 " 109 | string bazString = @"Here's some stuff 110 | on a new line! ""Wow!"", the masses cried"; 111 | 112 | // 使用const或read-only定义常量 113 | // 常量在编译期演算 114 | const int HOURS_I_WORK_PER_WEEK = 9001; 115 | 116 | /////////////////////////////////////////////////// 117 | // 数据结构 118 | /////////////////////////////////////////////////// 119 | 120 | // 数组 - 从0开始计数 121 | // 声明数组时需要确定数组长度 122 | // 声明数组的格式如下: 123 | // [] = new []; 124 | int[] intArray = new int[10]; 125 | 126 | // 声明并初始化数组的其他方式: 127 | int[] y = { 9000, 1000, 1337 }; 128 | 129 | // 访问数组的元素 130 | Console.WriteLine("intArray @ 0: " + intArray[0]); 131 | // 数组可以修改 132 | intArray[1] = 1; 133 | 134 | // 列表 135 | // 列表比数组更常用,因为列表更灵活。 136 | // 声明列表的格式如下: 137 | // List = new List(); 138 | List intList = new List(); 139 | List stringList = new List(); 140 | List z = new List { 9000, 1000, 1337 }; // i 141 | // <>用于泛型 - 参考下文 142 | 143 | // 列表无默认值 144 | // 访问列表元素时必须首先添加元素 145 | intList.Add(1); 146 | Console.WriteLine("intList @ 0: " + intList[0]); 147 | 148 | // 其他数据结构: 149 | // 堆栈/队列 150 | // 字典 (哈希表的实现) 151 | // 哈希集合 152 | // 只读集合 153 | // 元组 (.Net 4+) 154 | 155 | /////////////////////////////////////// 156 | // 操作符 157 | /////////////////////////////////////// 158 | Console.WriteLine("\n->Operators"); 159 | 160 | int i1 = 1, i2 = 2; // 多重声明的简写形式 161 | 162 | // 算术直截了当 163 | Console.WriteLine(i1 + i2 - i1 * 3 / 7); // => 3 164 | 165 | // 取余 166 | Console.WriteLine("11%3 = " + (11 % 3)); // => 2 167 | 168 | // 比较操作符 169 | Console.WriteLine("3 == 2? " + (3 == 2)); // => false 170 | Console.WriteLine("3 != 2? " + (3 != 2)); // => true 171 | Console.WriteLine("3 > 2? " + (3 > 2)); // => true 172 | Console.WriteLine("3 < 2? " + (3 < 2)); // => false 173 | Console.WriteLine("2 <= 2? " + (2 <= 2)); // => true 174 | Console.WriteLine("2 >= 2? " + (2 >= 2)); // => true 175 | 176 | // 位操作符 177 | /* 178 | ~ 取反 179 | << 左移(有符号) 180 | >> 右移(有符号) 181 | & 与 182 | ^ 异或 183 | | 或 184 | */ 185 | 186 | // 自增、自减 187 | int i = 0; 188 | Console.WriteLine("\n->Inc/Dec-rementation"); 189 | Console.WriteLine(i++); //i = 1. 事后自增 190 | Console.WriteLine(++i); //i = 2. 事先自增 191 | Console.WriteLine(i--); //i = 1. 事后自减 192 | Console.WriteLine(--i); //i = 0. 事先自减 193 | 194 | /////////////////////////////////////// 195 | // 控制结构 196 | /////////////////////////////////////// 197 | Console.WriteLine("\n->Control Structures"); 198 | 199 | // 类似C的if语句 200 | int j = 10; 201 | if (j == 10) 202 | { 203 | Console.WriteLine("I get printed"); 204 | } 205 | else if (j > 10) 206 | { 207 | Console.WriteLine("I don't"); 208 | } 209 | else 210 | { 211 | Console.WriteLine("I also don't"); 212 | } 213 | 214 | // 三元表达式 215 | // 简单的 if/else 语句可以写成: 216 | // <条件> ? <真> : <假> 217 | string isTrue = (true) ? "True" : "False"; 218 | 219 | // While 循环 220 | int fooWhile = 0; 221 | while (fooWhile < 100) 222 | { 223 | //迭代 100 次, fooWhile 0->99 224 | fooWhile++; 225 | } 226 | 227 | // Do While 循环 228 | int fooDoWhile = 0; 229 | do 230 | { 231 | //迭代 100 次, fooDoWhile 0->99 232 | fooDoWhile++; 233 | } while (fooDoWhile < 100); 234 | 235 | //for 循环结构 => for(<初始条件>; <条件>; <步>) 236 | for (int fooFor = 0; fooFor < 10; fooFor++) 237 | { 238 | //迭代10次, fooFor 0->9 239 | } 240 | 241 | // foreach循环 242 | // foreach 循环结构 => foreach(<迭代器类型> <迭代器> in <可枚举结构>) 243 | // foreach 循环适用于任何实现了 IEnumerable 或 IEnumerable 的对象。 244 | // .Net 框架下的集合类型(数组, 列表, 字典...) 245 | // 都实现了这些接口 246 | // (下面的代码中,ToCharArray()可以删除,因为字符串同样实现了IEnumerable) 247 | foreach (char character in "Hello World".ToCharArray()) 248 | { 249 | //迭代字符串中的所有字符 250 | } 251 | 252 | // Switch 语句 253 | // switch 适用于 byte、short、char和int 数据类型。 254 | // 同样适用于可枚举的类型 255 | // 包括字符串类, 以及一些封装了原始值的类: 256 | // Character、Byte、Short和Integer。 257 | int month = 3; 258 | string monthString; 259 | switch (month) 260 | { 261 | case 1: 262 | monthString = "January"; 263 | break; 264 | case 2: 265 | monthString = "February"; 266 | break; 267 | case 3: 268 | monthString = "March"; 269 | break; 270 | // 你可以一次匹配多个case语句 271 | // 但是你在添加case语句后需要使用break 272 | // (否则你需要显式地使用goto case x语句) 273 | case 6: 274 | case 7: 275 | case 8: 276 | monthString = "Summer time!!"; 277 | break; 278 | default: 279 | monthString = "Some other month"; 280 | break; 281 | } 282 | 283 | /////////////////////////////////////// 284 | // 转换、指定数据类型 285 | /////////////////////////////////////// 286 | 287 | // 转换类型 288 | 289 | // 转换字符串为整数 290 | // 转换失败会抛出异常 291 | int.Parse("123");//返回整数类型的"123" 292 | 293 | // TryParse会尝试转换类型,失败时会返回缺省类型 294 | // 例如 0 295 | int tryInt; 296 | if (int.TryParse("123", out tryInt)) // Funciton is boolean 297 | Console.WriteLine(tryInt); // 123 298 | 299 | // 转换整数为字符串 300 | // Convert类提供了一系列便利转换的方法 301 | Convert.ToString(123); 302 | // or 303 | tryInt.ToString(); 304 | } 305 | 306 | /////////////////////////////////////// 307 | // 类 308 | /////////////////////////////////////// 309 | public static void Classes() 310 | { 311 | // 参看文件尾部的对象声明 312 | 313 | // 使用new初始化对象 314 | Bicycle trek = new Bicycle(); 315 | 316 | // 调用对象的方法 317 | trek.SpeedUp(3); // 你应该一直使用setter和getter方法 318 | trek.Cadence = 100; 319 | 320 | // 查看对象的信息. 321 | Console.WriteLine("trek info: " + trek.Info()); 322 | 323 | // 实例化一个新的Penny Farthing 324 | PennyFarthing funbike = new PennyFarthing(1, 10); 325 | Console.WriteLine("funbike info: " + funbike.Info()); 326 | 327 | Console.Read(); 328 | } // 结束main方法 329 | 330 | // 终端程序 终端程序必须有一个main方法作为入口 331 | public static void Main(string[] args) 332 | { 333 | OtherInterestingFeatures(); 334 | } 335 | 336 | // 337 | // 有趣的特性 338 | // 339 | 340 | // 默认方法签名 341 | 342 | public // 可见性 343 | static // 允许直接调用类,无需先创建实例 344 | int, //返回值 345 | MethodSignatures( 346 | int maxCount, // 第一个变量,类型为整型 347 | int count = 0, // 如果没有传入值,则缺省值为0 348 | int another = 3, 349 | params string[] otherParams // 捕获其他参数 350 | ) 351 | { 352 | return -1; 353 | } 354 | 355 | // 方法可以重名,只要签名不一样 356 | public static void MethodSignature(string maxCount) 357 | { 358 | } 359 | 360 | //泛型 361 | // TKey和TValue类由用用户调用函数时指定。 362 | // 以下函数模拟了Python的SetDefault 363 | public static TValue SetDefault( 364 | IDictionary dictionary, 365 | TKey key, 366 | TValue defaultItem) 367 | { 368 | TValue result; 369 | if (!dictionary.TryGetValue(key, out result)) 370 | return dictionary[key] = defaultItem; 371 | return result; 372 | } 373 | 374 | // 你可以限定传入值的范围 375 | public static void IterateAndPrint(T toPrint) where T: IEnumerable 376 | { 377 | // 我们可以进行迭代,因为T是可枚举的 378 | foreach (var item in toPrint) 379 | // ittm为整数 380 | Console.WriteLine(item.ToString()); 381 | } 382 | 383 | public static void OtherInterestingFeatures() 384 | { 385 | // 可选参数 386 | MethodSignatures(3, 1, 3, "Some", "Extra", "Strings"); 387 | MethodSignatures(3, another: 3); // 显式指定参数,忽略可选参数 388 | 389 | // 扩展方法 390 | int i = 3; 391 | i.Print(); // 参见下面的定义 392 | 393 | // 可为null的类型 对数据库交互、返回值很有用 394 | // 任何值类型 (i.e. 不为类) 添加后缀 ? 后会变为可为null的值 395 | // <类型>? <变量名> = <值> 396 | int? nullable = null; // Nullable 的简写形式 397 | Console.WriteLine("Nullable variable: " + nullable); 398 | bool hasValue = nullable.HasValue; // 不为null时返回真 399 | // ?? 是用于指定默认值的语法糖 400 | // 以防变量为null的情况 401 | int notNullable = nullable ?? 0; // 0 402 | 403 | // 变量类型推断 - 你可以让编译器推断变量类型: 404 | var magic = "编译器确定magic是一个字符串,所以仍然是类型安全的"; 405 | // magic = 9; // 不工作,因为magic是字符串,而不是整数。 406 | 407 | // 泛型 408 | // 409 | var phonebook = new Dictionary() { 410 | {"Sarah", "212 555 5555"} // 在电话簿中加入新条目 411 | }; 412 | 413 | // 调用上面定义为泛型的SETDEFAULT 414 | Console.WriteLine(SetDefault(phonebook, "Shaun", "No Phone")); // 没有电话 415 | // 你不用指定TKey、TValue,因为它们会被隐式地推导出来 416 | Console.WriteLine(SetDefault(phonebook, "Sarah", "No Phone")); // 212 555 5555 417 | 418 | // lambda表达式 - 允许你用一行代码搞定函数 419 | Func square = (x) => x * x; // 最后一项为返回值 420 | Console.WriteLine(square(3)); // 9 421 | 422 | // 可抛弃的资源管理 - 让你很容易地处理未管理的资源 423 | // 大多数访问未管理资源 (文件操作符、设备上下文, etc.)的对象 424 | // 都实现了IDisposable接口。 425 | // using语句会为你清理IDisposable对象。 426 | using (StreamWriter writer = new StreamWriter("log.txt")) 427 | { 428 | writer.WriteLine("这里没有什么可疑的东西"); 429 | // 在作用域的结尾,资源会被回收 430 | // (即使有异常抛出,也一样会回收) 431 | } 432 | 433 | // 并行框架 434 | // http://blogs.msdn.com/b/csharpfaq/archive/2010/06/01/parallel-programming-in-net-framework-4-getting-started.aspx 435 | var websites = new string[] { 436 | "http://www.google.com", "http://www.reddit.com", 437 | "http://www.shaunmccarthy.com" 438 | }; 439 | var responses = new Dictionary(); 440 | 441 | // 为每个请求新开一个线程 442 | // 在运行下一步前合并结果 443 | Parallel.ForEach(websites, 444 | new ParallelOptions() {MaxDegreeOfParallelism = 3}, // max of 3 threads 445 | website => 446 | { 447 | // Do something that takes a long time on the file 448 | using (var r = WebRequest.Create(new Uri(website)).GetResponse()) 449 | { 450 | responses[website] = r.ContentType; 451 | } 452 | }); 453 | 454 | // 直到所有的请求完成后才会运行下面的代码 455 | foreach (var key in responses.Keys) 456 | Console.WriteLine("{0}:{1}", key, responses[key]); 457 | 458 | // 动态对象(配合其他语言使用很方便) 459 | dynamic student = new ExpandoObject(); 460 | student.FirstName = "First Name"; // 不需要先定义类! 461 | 462 | // 你甚至可以添加方法(接受一个字符串,输出一个字符串) 463 | student.Introduce = new Func( 464 | (introduceTo) => string.Format("Hey {0}, this is {1}", student.FirstName, introduceTo)); 465 | Console.WriteLine(student.Introduce("Beth")); 466 | 467 | // IQUERYABLE - 几乎所有的集合都实现了它, 468 | // 带给你 Map / Filter / Reduce 风格的方法 469 | var bikes = new List(); 470 | bikes.Sort(); // Sorts the array 471 | bikes.Sort((b1, b2) => b1.Wheels.CompareTo(b2.Wheels)); // 根据车轮数排序 472 | var result = bikes 473 | .Where(b => b.Wheels > 3) // 筛选 - 可以连锁使用 (返回IQueryable) 474 | .Where(b => b.IsBroken && b.HasTassles) 475 | .Select(b => b.ToString()); // Map - 这里我们使用了select,所以结果是IQueryable 476 | 477 | var sum = bikes.Sum(b => b.Wheels); // Reduce - 计算集合中的轮子总数 478 | 479 | // 创建一个包含基于自行车的一些参数生成的隐式对象的列表 480 | var bikeSummaries = bikes.Select(b=>new { Name = b.Name, IsAwesome = !b.IsBroken && b.HasTassles }); 481 | // 很难演示,但是编译器在代码编译完成前就能推导出以上对象的类型 482 | foreach (var bikeSummary in bikeSummaries.Where(b => b.IsAwesome)) 483 | Console.WriteLine(bikeSummary.Name); 484 | 485 | // ASPARALLEL 486 | // 邪恶的特性 —— 组合了linq和并行操作 487 | var threeWheelers = bikes.AsParallel().Where(b => b.Wheels == 3).Select(b => b.Name); 488 | // 以上代码会并发地运行。会自动新开线程,分别计算结果。 489 | // 适用于多核、大数据量的场景。 490 | 491 | // LINQ - 将IQueryable映射到存储,延缓执行 492 | // 例如 LinqToSql 映射数据库, LinqToXml 映射XML文档 493 | var db = new BikeRespository(); 494 | 495 | // 执行被延迟了,这对于查询数据库来说很好 496 | var filter = db.Bikes.Where(b => b.HasTassles); // 不运行查询 497 | if (42 > 6) // 你可以不断地增加筛选,包括有条件的筛选,例如用于“高级搜索”功能 498 | filter = filter.Where(b => b.IsBroken); // 不运行查询 499 | 500 | var query = filter 501 | .OrderBy(b => b.Wheels) 502 | .ThenBy(b => b.Name) 503 | .Select(b => b.Name); // 仍然不运行查询 504 | 505 | // 现在运行查询,运行查询的时候会打开一个读取器,所以你迭代的是一个副本 506 | foreach (string bike in query) 507 | Console.WriteLine(result); 508 | 509 | 510 | 511 | } 512 | 513 | } // 结束LearnCSharp类 514 | 515 | // 你可以在同一个 .cs 文件中包含其他类 516 | 517 | public static class Extensions 518 | { 519 | // 扩展函数 520 | public static void Print(this object obj) 521 | { 522 | Console.WriteLine(obj.ToString()); 523 | } 524 | } 525 | // 声明类的语法: 526 | // class <类名>{ 527 | // //数据字段, 构造器, 内部函数. 528 | / // 在Java中函数被称为方法。 529 | // } 530 | 531 | public class Bicycle 532 | { 533 | // 自行车的字段、变量 534 | public int Cadence // Public: 任何地方都可以访问 535 | { 536 | get // get - 定义获取属性的方法 537 | { 538 | return _cadence; 539 | } 540 | set // set - 定义设置属性的方法 541 | { 542 | _cadence = value; // value是被传递给setter的值 543 | } 544 | } 545 | private int _cadence; 546 | 547 | protected virtual int Gear // 类和子类可以访问 548 | { 549 | get; // 创建一个自动属性,无需成员字段 550 | set; 551 | } 552 | 553 | internal int Wheels // Internal:在同一程序集内可以访问 554 | { 555 | get; 556 | private set; // 可以给get/set方法添加修饰符 557 | } 558 | 559 | int _speed; // 默认为private: 只可以在这个类内访问,你也可以使用`private`关键词 560 | public string Name { get; set; } 561 | 562 | // enum类型包含一组常量 563 | // 它将名称映射到值(除非特别说明,是一个整型) 564 | // enmu元素的类型可以是byte、sbyte、short、ushort、int、uint、long、ulong。 565 | // enum不能包含相同的值。 566 | public enum BikeBrand 567 | { 568 | AIST, 569 | BMC, 570 | Electra = 42, //你可以显式地赋值 571 | Gitane // 43 572 | } 573 | // 我们在Bicycle类中定义的这个类型,所以它是一个内嵌类型。 574 | // 这个类以外的代码应当使用`Bicycle.Brand`来引用。 575 | 576 | public BikeBrand Brand; // 声明一个enum类型之后,我们可以声明这个类型的字段 577 | 578 | // 静态方法的类型为自身,不属于特定的对象。 579 | // 你无需引用对象就可以访问他们。 580 | // Console.WriteLine("Bicycles created: " + Bicycle.bicyclesCreated); 581 | static public int BicyclesCreated = 0; 582 | 583 | // 只读值在运行时确定 584 | // 它们只能在声明或构造器内被赋值 585 | readonly bool _hasCardsInSpokes = false; // read-only private 586 | 587 | // 构造器是创建类的一种方式 588 | // 下面是一个默认的构造器 589 | public Bicycle() 590 | { 591 | this.Gear = 1; // 你可以使用关键词this访问对象的成员 592 | Cadence = 50; // 不过你并不总是需要它 593 | _speed = 5; 594 | Name = "Bontrager"; 595 | Brand = BikeBrand.AIST; 596 | BicyclesCreated++; 597 | } 598 | 599 | // 另一个构造器的例子(包含参数) 600 | public Bicycle(int startCadence, int startSpeed, int startGear, 601 | string name, bool hasCardsInSpokes, BikeBrand brand) 602 | : base() // 首先调用base 603 | { 604 | Gear = startGear; 605 | Cadence = startCadence; 606 | _speed = startSpeed; 607 | Name = name; 608 | _hasCardsInSpokes = hasCardsInSpokes; 609 | Brand = brand; 610 | } 611 | 612 | // 构造器可以连锁使用 613 | public Bicycle(int startCadence, int startSpeed, BikeBrand brand) : 614 | this(startCadence, startSpeed, 0, "big wheels", true, brand) 615 | { 616 | } 617 | 618 | // 函数语法 619 | // <返回值> <函数名称>(<参数>) 620 | 621 | // 类可以为字段实现 getters 和 setters 方法 for their fields 622 | // 或者可以实现属性(C#推荐使用这个) 623 | // 方法的参数可以有默认值 624 | // 在有默认值的情况下,调用方法的时候可以省略相应的参数 625 | public void SpeedUp(int increment = 1) 626 | { 627 | _speed += increment; 628 | } 629 | 630 | public void SlowDown(int decrement = 1) 631 | { 632 | _speed -= decrement; 633 | } 634 | 635 | // 属性可以访问和设置值 636 | // 当只需要访问数据的时候,考虑使用属性。 637 | // 属性可以定义get和set,或者是同时定义两者 638 | private bool _hasTassles; // private variable 639 | public bool HasTassles // public accessor 640 | { 641 | get { return _hasTassles; } 642 | set { _hasTassles = value; } 643 | } 644 | 645 | // 你可以在一行之内定义自动属性 646 | // 这个语法会自动创建后备字段 647 | // 你可以给getter或setter设置访问修饰符 648 | // 以便限制它们的访问 649 | public bool IsBroken { get; private set; } 650 | 651 | // 属性的实现可以是自动的 652 | public int FrameSize 653 | { 654 | get; 655 | // 你可以给get或set指定访问修饰符 656 | // 以下代码意味着只有Bicycle类可以调用Framesize的set 657 | private set; 658 | } 659 | 660 | //显示对象属性的方法 661 | public virtual string Info() 662 | { 663 | return "Gear: " + Gear + 664 | " Cadence: " + Cadence + 665 | " Speed: " + _speed + 666 | " Name: " + Name + 667 | " Cards in Spokes: " + (_hasCardsInSpokes ? "yes" : "no") + 668 | "\n------------------------------\n" 669 | ; 670 | } 671 | 672 | // 方法可以是静态的。通常用于辅助方法。 673 | public static bool DidWeCreateEnoughBycles() 674 | { 675 | // 在静态方法中,你只能引用类的静态成员 676 | return BicyclesCreated > 9000; 677 | } // 如果你的类只需要静态成员,考虑将整个类作为静态类。 678 | 679 | 680 | } // Bicycle类结束 681 | 682 | // PennyFarthing是Bicycle的一个子类 683 | class PennyFarthing : Bicycle 684 | { 685 | // (Penny Farthings是一种前轮很大的自行车。没有齿轮。) 686 | 687 | // 调用父构造器 688 | public PennyFarthing(int startCadence, int startSpeed) : 689 | base(startCadence, startSpeed, 0, "PennyFarthing", true, BikeBrand.Electra) 690 | { 691 | } 692 | 693 | protected override int Gear 694 | { 695 | get 696 | { 697 | return 0; 698 | } 699 | set 700 | { 701 | throw new ArgumentException("你不可能在PennyFarthing上切换齿轮"); 702 | } 703 | } 704 | 705 | public override string Info() 706 | { 707 | string result = "PennyFarthing bicycle "; 708 | result += base.ToString(); // 调用父方法 709 | return result; 710 | } 711 | } 712 | 713 | // 接口只包含成员的签名,而没有实现。 714 | interface IJumpable 715 | { 716 | void Jump(int meters); // 所有接口成员是隐式地公开的 717 | } 718 | 719 | interface IBreakable 720 | { 721 | bool Broken { get; } // 接口可以包含属性、方法和事件 722 | } 723 | 724 | // 类只能继承一个类,但是可以实现任意数量的接口 725 | { 726 | int damage = 0; 727 | 728 | public void Jump(int meters) 729 | { 730 | damage += meters; 731 | } 732 | 733 | public bool Broken 734 | { 735 | get 736 | { 737 | return damage > 100; 738 | } 739 | } 740 | } 741 | 742 | /// 743 | /// 连接数据库,一个 LinqToSql的示例。 744 | /// EntityFramework Code First 很棒 (类似 Ruby的 ActiveRecord, 不过是双向的) 745 | /// http://msdn.microsoft.com/en-us/data/jj193542.aspx 746 | /// 747 | public class BikeRespository : DbSet 748 | { 749 | public BikeRespository() 750 | : base() 751 | { 752 | } 753 | 754 | public DbSet Bikes { get; set; } 755 | } 756 | } // 结束 Namespace 757 | -------------------------------------------------------------------------------- /learncss-cn.css: -------------------------------------------------------------------------------- 1 | 2 | /* 注释 */ 3 | 4 | /* #################### 5 | ## 选择器 6 | ####################*/ 7 | 8 | /* 一般而言,CSS的声明语句非常简单。 */ 9 | 选择器 { 属性: 值; /* 更多属性...*/ } 10 | 11 | /* 选择器用于指定页面上的元素。 12 | 13 | 针对页面上的所有元素。 */ 14 | * { color:red; } 15 | 16 | /* 17 | 假定页面上有这样一个元素 18 | 19 |
20 | */ 21 | 22 | /* 你可以通过类名来指定它 */ 23 | .some-class { } 24 | 25 | /* 给出所有类名 */ 26 | .some-class.class2 { } 27 | 28 | /* 标签名 */ 29 | div { } 30 | 31 | /* id */ 32 | #someId { } 33 | 34 | /* 由于元素包含attr属性,因此也可以通过这个来指定 */ 35 | [attr] { font-size:smaller; } 36 | 37 | /* 以及有特定值的属性 */ 38 | [attr='value'] { font-size:smaller; } 39 | 40 | /* 通过属性的值的开头指定 */ 41 | [attr^='val'] { font-size:smaller; } 42 | 43 | /* 通过属性的值的结尾来指定 */ 44 | [attr$='ue'] { font-size:smaller; } 45 | 46 | /* 通过属性的值的部分来指定 */ 47 | [attr~='lu'] { font-size:smaller; } 48 | 49 | 50 | /* 你可以把这些全部结合起来,注意不同部分间不应该有空格,否则会改变语义 */ 51 | div.some-class[attr$='ue'] { } 52 | 53 | /* 你也可以通过父元素来指定。*/ 54 | 55 | /* 某个元素是另一个元素的直接子元素 */ 56 | div.some-parent > .class-name {} 57 | 58 | /* 或者通过该元素的祖先元素 */ 59 | div.some-parent .class-name {} 60 | 61 | /* 注意,去掉空格后语义就不同了。 62 | 你能说出哪里不同么? */ 63 | div.some-parent.class-name {} 64 | 65 | /* 你可以选择某元素前的相邻元素 */ 66 | .i-am-before + .this-element { } 67 | 68 | /* 某元素之前的同级元素(相邻或不相邻) */ 69 | .i-am-any-before ~ .this-element {} 70 | 71 | /* 伪类允许你基于页面的行为指定元素(而不是基于页面结构) */ 72 | 73 | /* 例如,当鼠标悬停在某个元素上时 */ 74 | :hover {} 75 | 76 | /* 已访问过的链接*/ 77 | :visited {} 78 | 79 | /* 未访问过的链接*/ 80 | :link {} 81 | 82 | /* 当前焦点的input元素 */ 83 | :focus {} 84 | 85 | 86 | /* #################### 87 | ## 属性 88 | ####################*/ 89 | 90 | 选择器 { 91 | 92 | /* 单位 */ 93 | width: 50%; /* 百分比 */ 94 | font-size: 2em; /* 当前字体大小的两倍 */ 95 | width: 200px; /* 像素 */ 96 | font-size: 20pt; /* 点 */ 97 | width: 5cm; /* 厘米 */ 98 | width: 50mm; /* 毫米 */ 99 | width: 5in; /* 英尺 */ 100 | 101 | /* 颜色 */ 102 | background-color: #F6E; /* 短16位 */ 103 | background-color: #F262E2; /* 长16位 */ 104 | background-color: tomato; /* 颜色名称 */ 105 | background-color: rgb(255, 255, 255); /* rgb */ 106 | background-color: rgb(10%, 20%, 50%); /* rgb 百分比 */ 107 | background-color: rgba(255, 0, 0, 0.3); /* rgb 加透明度 */ 108 | 109 | /* 图片 */ 110 | background-image: url(/path-to-image/image.jpg); 111 | 112 | /* 字体 */ 113 | font-family: Arial; 114 | font-family: "Courier New"; /* 使用双引号包裹含空格的字体名称 */ 115 | font-family: "Courier New", Trebuchet, Arial; /* 如果第一个 116 | 字体没找到,浏览器会使用第二个字体,一次类推 */ 117 | } 118 | 119 | 120 | 121 | 122 | 123 | 124 | 127 | 128 | 130 |
131 |
132 | 133 | 134 | /*A*/ 135 | p.class1[attr='value'] 136 | 137 | /*B*/ 138 | p.class1 {} 139 | 140 | /*C*/ 141 | p.class2 {} 142 | 143 | /*D*/ 144 | p {} 145 | 146 | /*E*/ 147 | p { property: value !important; } 148 | 149 | 150 |

151 |

152 | -------------------------------------------------------------------------------- /learngo-cn.go: -------------------------------------------------------------------------------- 1 | 2 | // 单行注释 3 | /* 多行 4 | 注释 */ 5 | 6 | // 导入包的子句在每个源文件的开头。 7 | // Main比较特殊,它用来声明可执行文件,而不是一个库。 8 | package main 9 | 10 | // Import语句声明了当前文件引用的包。 11 | import ( 12 | "fmt" // Go语言标准库中的包 13 | "net/http" // 一个web服务器包 14 | "strconv" // 字符串转换 15 | ) 16 | 17 | // 函数声明:Main是程序执行的入口。 18 | // 不管你喜欢还是不喜欢,反正Go就用了花括号来包住函数体。 19 | func main() { 20 | // 往标准输出打印一行。 21 | // 用包名fmt限制打印函数。 22 | fmt.Println("Hello world!") 23 | 24 | // 调用当前包的另一个函数。 25 | beyondHello() 26 | } 27 | 28 | // 函数可以在括号里加参数。 29 | // 如果没有参数的话,也需要一个空括号。 30 | func beyondHello() { 31 | var x int // 变量声明,变量必须在使用之前声明。 32 | x = 3 // 变量赋值。 33 | // 可以用:=来偷懒,它自动把变量类型、声明和赋值都搞定了。 34 | y := 4 35 | sum, prod := learnMultiple(x, y) // 返回多个变量的函数 36 | fmt.Println("sum:", sum, "prod:", prod) // 简单输出 37 | learnTypes() // 少于y分钟,学的更多! 38 | } 39 | 40 | // 多变量和多返回值的函数 41 | func learnMultiple(x, y int) (sum, prod int) { 42 | return x + y, x * y // 返回两个值 43 | } 44 | 45 | // 内置变量类型和关键词 46 | func learnTypes() { 47 | // 短声明给你所想。 48 | s := "Learn Go!" // String类型 49 | 50 | s2 := `A "raw" string literal 51 | can include line breaks.` // 同样是String类型 52 | 53 | // 非ascii字符。Go使用UTF-8编码。 54 | g := 'Σ' // rune类型,int32的别名,使用UTF-8编码 55 | 56 | f := 3.14195 // float64类型,IEEE-754 64位浮点数 57 | c := 3 + 4i // complex128类型,内部使用两个float64表示 58 | 59 | // Var变量可以直接初始化。 60 | var u uint = 7 // unsigned 无符号变量,但是实现依赖int型变量的长度 61 | var pi float32 = 22. / 7 62 | 63 | // 字符转换 64 | n := byte('\n') // byte是uint8的别名 65 | 66 | // 数组类型编译的时候大小固定。 67 | var a4 [4] int // 有4个int变量的数组,初始为0 68 | a3 := [...]int{3, 1, 5} // 有3个int变量的数组,同时进行了初始化 69 | 70 | // Slice 可以动态的增删。Array和Slice各有千秋,但是使用slice的地方更多些。 71 | s3 := []int{4, 5, 9} // 和a3相比,这里没有省略号 72 | s4 := make([]int, 4) // 分配一个有4个int型变量的slice,全部被初始化为0 73 | 74 | var d2 [][]float64 // 声明而已,什么都没有分配 75 | bs := []byte("a slice") // 类型转换的语法 76 | 77 | p, q := learnMemory() // 声明p,q为int型变量的指针 78 | fmt.Println(*p, *q) // * 取值 79 | 80 | // Map是动态可增长关联数组,和其他语言中的hash或者字典相似。 81 | m := map[string]int{"three": 3, "four": 4} 82 | m["one"] = 1 83 | 84 | // 在Go语言中未使用的变量在编译的时候会报错,而不是warning。 85 | // 下划线 _ 可以使你“使用”一个变量,但是丢弃它的值。 86 | _,_,_,_,_,_,_,_,_ = s2, g, f, u, pi, n, a3, s4, bs 87 | // 输出变量 88 | fmt.Println(s, c, a4, s3, d2, m) 89 | 90 | learnFlowControl() // 回到流程控制 91 | } 92 | 93 | // Go全面支持垃圾回收。Go有指针,但是不支持指针运算。 94 | // 你会因为空指针而犯错,但是不会因为增加指针而犯错。 95 | func learnMemory() (p, q *int) { 96 | // 返回int型变量指针p和q 97 | p = new(int) // 内置函数new分配内存 98 | // 自动将分配的int赋值0,p不再是空的了。 99 | s := make([]int, 20) // 给20个int变量分配一块内存 100 | s[3] = 7 // 赋值 101 | r := -2 // 声明另一个局部变量 102 | return &s[3], &r // & 取地址 103 | } 104 | 105 | func expensiveComputation() int { 106 | return 1e6 107 | } 108 | 109 | func learnFlowControl() { 110 | // If需要花括号,括号就免了 111 | if true { 112 | fmt.Println("told ya") 113 | } 114 | // 用go fmt 命令可以帮你格式化代码,所以不用怕被人吐槽代码风格了, 115 | // 也不用容忍被人的代码风格。 116 | if false { 117 | // pout 118 | } else { 119 | // gloat 120 | } 121 | // 如果太多嵌套的if语句,推荐使用switch 122 | x := 1 123 | switch x { 124 | case 0: 125 | case 1: 126 | // 隐式调用break语句,匹配上一个即停止 127 | case 2: 128 | // 不会运行 129 | } 130 | // 和if一样,for也不用括号 131 | for x := 0; x < 3; x++ { // ++ 自增 132 | fmt.Println("iteration", x) 133 | } 134 | // x在这里还是1。为什么? 135 | 136 | // for 是go里唯一的循环关键字,不过它有很多变种 137 | for { // 死循环 138 | break // 骗你的 139 | continue // 不会运行的 140 | } 141 | // 和for一样,if中的:=先给y赋值,然后再和x作比较。 142 | if y := expensiveComputation(); y > x { 143 | x = y 144 | } 145 | // 闭包函数 146 | xBig := func() bool { 147 | return x > 100 // x是上面声明的变量引用 148 | } 149 | fmt.Println("xBig:", xBig()) // true (上面把y赋给x了) 150 | x /= 1e5 // x变成10 151 | fmt.Println("xBig:", xBig()) // 现在是false 152 | 153 | // 当你需要goto的时候,你会爱死它的! 154 | goto love 155 | love: 156 | 157 | learnInterfaces() // 好东西来了! 158 | } 159 | 160 | // 定义Stringer为一个接口类型,有一个方法String 161 | type Stringer interface { 162 | String() string 163 | } 164 | 165 | // 定义pair为一个结构体,有x和y两个int型变量。 166 | type pair struct { 167 | x, y int 168 | } 169 | 170 | // 定义pair类型的方法,实现Stringer接口。 171 | func (p pair) String() string { // p被叫做“接收器” 172 | // Sprintf是fmt包中的另一个公有函数。 173 | // 用 . 调用p中的元素。 174 | return fmt.Sprintf("(%d, %d)", p.x, p.y) 175 | } 176 | 177 | func learnInterfaces() { 178 | // 花括号用来定义结构体变量,:=在这里将一个结构体变量赋值给p。 179 | p := pair{3, 4} 180 | fmt.Println(p.String()) // 调用pair类型p的String方法 181 | var i Stringer // 声明i为Stringer接口类型 182 | i = p // 有效!因为p实现了Stringer接口(类似java中的塑型) 183 | // 调用i的String方法,输出和上面一样 184 | fmt.Println(i.String()) 185 | 186 | // fmt包中的Println函数向对象要它们的string输出,实现了String方法就可以这样使用了。 187 | // (类似java中的序列化) 188 | fmt.Println(p) // 输出和上面一样,自动调用String函数。 189 | fmt.Println(i) // 输出和上面一样。 190 | 191 | learnErrorHandling() 192 | } 193 | 194 | func learnErrorHandling() { 195 | // ", ok"用来判断有没有正常工作 196 | m := map[int]string{3: "three", 4: "four"} 197 | if x, ok := m[1]; !ok { // ok 为false,因为m中没有1 198 | fmt.Println("no one there") 199 | } else { 200 | fmt.Print(x) // 如果x在map中的话,x就是那个值喽。 201 | } 202 | // 错误可不只是ok,它还可以给出关于问题的更多细节。 203 | if _, err := strconv.Atoi("non-int"); err != nil { // _ discards value 204 | // 输出"strconv.ParseInt: parsing "non-int": invalid syntax" 205 | fmt.Println(err) 206 | } 207 | // 待会再说接口吧。同时, 208 | learnConcurrency() 209 | } 210 | 211 | // c是channel类型,一个并发安全的通信对象。 212 | func inc(i int, c chan int) { 213 | c <- i + 1 // <-把右边的发送到左边的channel。 214 | } 215 | 216 | // 我们将用inc函数来并发地增加一些数字。 217 | func learnConcurrency() { 218 | // 用make来声明一个slice,make会分配和初始化slice,map和channel。 219 | c := make(chan int) 220 | // 用go关键字开始三个并发的goroutine,如果机器支持的话,还可能是并行执行。 221 | // 三个都被发送到同一个channel。 222 | go inc(0, c) // go is a statement that starts a new goroutine. 223 | go inc(10, c) 224 | go inc(-805, c) 225 | // 从channel中独处结果并打印。 226 | // 打印出什么东西是不可预知的。 227 | fmt.Println(<-c, <-c, <-c) // channel在右边的时候,<-是读操作。 228 | 229 | cs := make(chan string) // 操作string的channel 230 | cc := make(chan chan string) // 操作channel的channel 231 | go func() { c <- 84 }() // 开始一个goroutine来发送一个新的数字 232 | go func() { cs <- "wordy" }() // 发送给cs 233 | // Select类似于switch,但是每个case包括一个channel操作。 234 | // 它随机选择一个准备好通讯的case。 235 | select { 236 | case i := <-c: // 从channel接收的值可以赋给其他变量 237 | fmt.Println("it's a", i) 238 | case <-cs: // 或者直接丢弃 239 | fmt.Println("it's a string") 240 | case <-cc: // 空的,还没作好通讯的准备 241 | fmt.Println("didn't happen.") 242 | } 243 | // 上面c或者cs的值被取到,其中一个goroutine结束,另外一个一直阻塞。 244 | 245 | learnWebProgramming() // Go很适合web编程,我知道你也想学! 246 | } 247 | 248 | // http包中的一个简单的函数就可以开启web服务器。 249 | func learnWebProgramming() { 250 | // ListenAndServe第一个参数指定了监听端口,第二个参数是一个接口,特定是http.Handler。 251 | err := http.ListenAndServe(":8080", pair{}) 252 | fmt.Println(err) // 不要无视错误。 253 | } 254 | 255 | // 使pair实现http.Handler接口的ServeHTTP方法。 256 | func (p pair) ServeHTTP(w http.ResponseWriter, r *http.Request) { 257 | // 使用http.ResponseWriter返回数据 258 | w.Write([]byte("You learned Go in Y minutes!")) 259 | } 260 | -------------------------------------------------------------------------------- /learnlua-cn.lua: -------------------------------------------------------------------------------- 1 | 2 | -- 单行注释以两个连字符开头 3 | 4 | --[[ 5 | 多行注释 6 | --]] 7 | 8 | ---------------------------------------------------- 9 | -- 1. 变量和流程控制 10 | ---------------------------------------------------- 11 | 12 | num = 42 -- 所有的数字都是双精度浮点型。 13 | -- 别害怕,64位的双精度浮点型数字中有52位用于 14 | -- 保存精确的整型值; 对于52位以内的整型值, 15 | -- 不用担心精度问题。 16 | 17 | s = 'walternate' -- 和Python一样,字符串不可变。 18 | t = "也可以用双引号" 19 | u = [[ 多行的字符串 20 | 以两个方括号 21 | 开始和结尾。]] 22 | t = nil -- 撤销t的定义; Lua 支持垃圾回收。 23 | 24 | -- 块使用do/end之类的关键字标识: 25 | while num < 50 do 26 | num = num + 1 -- 不支持 ++ 或 += 运算符。 27 | end 28 | 29 | -- If语句: 30 | if num > 40 then 31 | print('over 40') 32 | elseif s ~= 'walternate' then -- ~= 表示不等于。 33 | -- 像Python一样,用 == 检查是否相等 ;字符串同样适用。 34 | io.write('not over 40\n') -- 默认标准输出。 35 | else 36 | -- 默认全局变量。 37 | thisIsGlobal = 5 -- 通常使用驼峰。 38 | 39 | -- 如何定义局部变量: 40 | local line = io.read() -- 读取标准输入的下一行。 41 | 42 | -- ..操作符用于连接字符串: 43 | print('Winter is coming, ' .. line) 44 | end 45 | 46 | -- 未定义的变量返回nil。 47 | -- 这不是错误: 48 | foo = anUnknownVariable -- 现在 foo = nil. 49 | 50 | aBoolValue = false 51 | 52 | --只有nil和false为假; 0和 ''均为真! 53 | if not aBoolValue then print('false') end 54 | 55 | -- 'or'和 'and'短路 56 | -- 类似于C/js里的 a?b:c 操作符: 57 | ans = aBoolValue and 'yes' or 'no' --> 'no' 58 | 59 | karlSum = 0 60 | for i = 1, 100 do -- 范围包含两端 61 | karlSum = karlSum + i 62 | end 63 | 64 | -- 使用 "100, 1, -1" 表示递减的范围: 65 | fredSum = 0 66 | for j = 100, 1, -1 do fredSum = fredSum + j end 67 | 68 | -- 通常,范围表达式为begin, end[, step]. 69 | 70 | -- 循环的另一种结构: 71 | repeat 72 | print('the way of the future') 73 | num = num - 1 74 | until num == 0 75 | 76 | ---------------------------------------------------- 77 | -- 2. 函数。 78 | ---------------------------------------------------- 79 | 80 | function fib(n) 81 | if n < 2 then return 1 end 82 | return fib(n - 2) + fib(n - 1) 83 | end 84 | 85 | -- 支持闭包及匿名函数: 86 | function adder(x) 87 | -- 调用adder时,会创建返回的函数, 88 | -- 并且会记住x的值: 89 | return function (y) return x + y end 90 | end 91 | a1 = adder(9) 92 | a2 = adder(36) 93 | print(a1(16)) --> 25 94 | print(a2(64)) --> 100 95 | 96 | -- 返回值、函数调用和赋值都可以 97 | -- 使用长度不匹配的list。 98 | -- 不匹配的接收方会被赋值nil; 99 | -- 不匹配的发送方会被丢弃。 100 | 101 | x, y, z = 1, 2, 3, 4 102 | -- x = 1、y = 2、z = 3, 而 4 会被丢弃。 103 | 104 | function bar(a, b, c) 105 | print(a, b, c) 106 | return 4, 8, 15, 16, 23, 42 107 | end 108 | 109 | x, y = bar('zaphod') --> 打印 "zaphod nil nil" 110 | -- 现在 x = 4, y = 8, 而值15..42被丢弃。 111 | 112 | -- 函数是一等公民,可以是局部的,也可以是全局的。 113 | -- 以下表达式等价: 114 | function f(x) return x * x end 115 | f = function (x) return x * x end 116 | 117 | -- 这些也是等价的: 118 | local function g(x) return math.sin(x) end 119 | local g; g = function (x) return math.sin(x) end 120 | -- 'local g'使得g可以自引用。 121 | 122 | -- 顺便提下,三角函数以弧度为单位。 123 | 124 | -- 用一个字符串参数调用函数,可以省略括号: 125 | print 'hello' --可以工作。 126 | 127 | -- 调用函数时,如果只有一个table参数, 128 | -- 同样可以省略括号(table详情见下): 129 | print {} -- 一样可以工作。 130 | 131 | ---------------------------------------------------- 132 | -- 3. Table。 133 | ---------------------------------------------------- 134 | 135 | -- Table = Lua唯一的组合数据结构; 136 | -- 它们是关联数组。 137 | -- 类似于PHP的数组或者js的对象, 138 | -- 它们是哈希表或者字典,也可以当列表使用。 139 | 140 | -- 按字典/map的方式使用Table: 141 | 142 | -- Dict字面量默认使用字符串类型的key: 143 | t = {key1 = 'value1', key2 = false} 144 | 145 | -- 字符串key可以使用类似js的点标记: 146 | print(t.key1) -- 打印 'value1'. 147 | t.newKey = {} -- 添加新的键值对。 148 | t.key2 = nil -- 从table删除 key2。 149 | 150 | -- 使用任何非nil的值作为key: 151 | u = {['@!#'] = 'qbert', [{}] = 1729, [6.28] = 'tau'} 152 | print(u[6.28]) -- 打印 "tau" 153 | 154 | -- 数字和字符串的key按值匹配的 155 | -- table按id匹配。 156 | a = u['@!#'] -- 现在 a = 'qbert'. 157 | b = u[{}] -- 我们或许期待的是 1729, 但是得到的是nil: 158 | -- b = nil ,因为没有找到。 159 | -- 之所以没找到,是因为我们用的key与保存数据时用的不是同 160 | -- 一个对象。 161 | -- 所以字符串和数字是移植性更好的key。 162 | 163 | -- 只需要一个table参数的函数调用不需要括号: 164 | function h(x) print(x.key1) end 165 | h{key1 = 'Sonmi~451'} -- 打印'Sonmi~451'. 166 | 167 | for key, val in pairs(u) do -- 遍历Table 168 | print(key, val) 169 | end 170 | 171 | -- _G 是一个特殊的table,用于保存所有的全局变量 172 | print(_G['_G'] == _G) -- 打印'true'. 173 | 174 | -- 按列表/数组的方式使用: 175 | 176 | -- 列表字面量隐式添加整数键: 177 | v = {'value1', 'value2', 1.21, 'gigawatts'} 178 | for i = 1, #v do -- #v 是列表的大小 179 | print(v[i]) -- 索引从 1 开始!! 太疯狂了! 180 | end 181 | -- 'list'并非真正的类型,v 其实是一个table, 182 | -- 只不过它用连续的整数作为key,可以像list那样去使用。 183 | 184 | ---------------------------------------------------- 185 | -- 3.1 元表(metatable) 和元方法(metamethod)。 186 | ---------------------------------------------------- 187 | 188 | -- table的元表提供了一种机制,支持类似操作符重载的行为。 189 | -- 稍后我们会看到元表如何支持类似js prototype的行为。 190 | 191 | f1 = {a = 1, b = 2} -- 表示一个分数 a/b. 192 | f2 = {a = 2, b = 3} 193 | 194 | -- 这会失败: 195 | -- s = f1 + f2 196 | 197 | metafraction = {} 198 | function metafraction.__add(f1, f2) 199 | sum = {} 200 | sum.b = f1.b * f2.b 201 | sum.a = f1.a * f2.b + f2.a * f1.b 202 | return sum 203 | end 204 | 205 | setmetatable(f1, metafraction) 206 | setmetatable(f2, metafraction) 207 | 208 | s = f1 + f2 -- 调用在f1的元表上的__add(f1, f2) 方法 209 | 210 | -- f1, f2 没有关于元表的key,这点和js的prototype不一样。 211 | -- 因此你必须用getmetatable(f1)获取元表。 212 | -- 元表是一个普通的table, 213 | -- 元表的key是普通的Lua中的key,例如__add。 214 | 215 | -- 但是下面一行代码会失败,因为s没有元表: 216 | -- t = s + s 217 | -- 下面提供的与类相似的模式可以解决这个问题: 218 | 219 | -- 元表的__index 可以重载用于查找的点操作符: 220 | defaultFavs = {animal = 'gru', food = 'donuts'} 221 | myFavs = {food = 'pizza'} 222 | setmetatable(myFavs, {__index = defaultFavs}) 223 | eatenBy = myFavs.animal -- 可以工作!感谢元表 224 | 225 | -- 如果在table中直接查找key失败,会使用 226 | -- 元表的__index 递归地重试。 227 | 228 | -- __index的值也可以是function(tbl, key) 229 | -- 这样可以支持自定义查找。 230 | 231 | -- __index、__add等的值,被称为元方法。 232 | -- 这里是一个table元方法的清单: 233 | 234 | -- __add(a, b) for a + b 235 | -- __sub(a, b) for a - b 236 | -- __mul(a, b) for a * b 237 | -- __div(a, b) for a / b 238 | -- __mod(a, b) for a % b 239 | -- __pow(a, b) for a ^ b 240 | -- __unm(a) for -a 241 | -- __concat(a, b) for a .. b 242 | -- __len(a) for #a 243 | -- __eq(a, b) for a == b 244 | -- __lt(a, b) for a < b 245 | -- __le(a, b) for a <= b 246 | -- __index(a, b) for a.b 247 | -- __newindex(a, b, c) for a.b = c 248 | -- __call(a, ...) for a(...) 249 | 250 | ---------------------------------------------------- 251 | -- 3.2 与类相似的table和继承。 252 | ---------------------------------------------------- 253 | 254 | -- Lua没有内建的类;可以通过不同的方法,利用表和元表 255 | -- 来实现类。 256 | 257 | -- 下面是一个例子,解释在后面: 258 | 259 | Dog = {} -- 1. 260 | 261 | function Dog:new() -- 2. 262 | newObj = {sound = 'woof'} -- 3. 263 | self.__index = self -- 4. 264 | return setmetatable(newObj, self) -- 5. 265 | end 266 | 267 | function Dog:makeSound() -- 6. 268 | print('I say ' .. self.sound) 269 | end 270 | 271 | mrDog = Dog:new() -- 7. 272 | mrDog:makeSound() -- 'I say woof' -- 8. 273 | 274 | -- 1. Dog看上去像一个类;其实它是一个table。 275 | -- 2. 函数tablename:fn(...) 等价于 276 | -- 函数tablename.fn(self, ...) 277 | -- 冒号(:)只是添加了self作为第一个参数。 278 | -- 阅读7 & 8条 了解self变量是如何得到其值的。 279 | -- 3. newObj是类Dog的一个实例。 280 | -- 4. self = 被继承的类。通常self = Dog,不过继承可以改变它。 281 | -- 如果把newObj的元表和__index都设置为self, 282 | -- newObj就可以得到self的函数。 283 | -- 5. 备忘:setmetatable返回其第一个参数。 284 | -- 6. 冒号(:)的作用和第2条一样,不过这里 285 | -- self是一个实例,而不是类 286 | -- 7. 等价于Dog.new(Dog),所以在new()中,self = Dog。 287 | -- 8. 等价于mrDog.makeSound(mrDog); self = mrDog。 288 | 289 | ---------------------------------------------------- 290 | 291 | -- 继承的例子: 292 | 293 | LoudDog = Dog:new() -- 1. 294 | 295 | function LoudDog:makeSound() 296 | s = self.sound .. ' ' -- 2. 297 | print(s .. s .. s) 298 | end 299 | 300 | seymour = LoudDog:new() -- 3. 301 | seymour:makeSound() -- 'woof woof woof' -- 4. 302 | 303 | -- 1. LoudDog获得Dog的方法和变量列表。 304 | -- 2. 因为new()的缘故,self拥有了一个'sound' key,参见第3条。 305 | -- 3. 等价于LoudDog.new(LoudDog),转换一下就是 306 | -- Dog.new(LoudDog),这是因为LoudDog没有'new' key, 307 | -- 但是它的元表中有 __index = Dog。 308 | -- 结果: seymour的元表是LoudDog,并且 309 | -- LoudDog.__index = Dog。所以有seymour.key 310 | -- = seymour.key, LoudDog.key, Dog.key 311 | -- 从其中第一个有指定key的table获取。 312 | -- 4. 在LoudDog可以找到'makeSound'的key; 313 | -- 等价于LoudDog.makeSound(seymour)。 314 | 315 | -- 如果有必要,子类也可以有new(),与基类相似: 316 | function LoudDog:new() 317 | newObj = {} 318 | -- 初始化newObj 319 | self.__index = self 320 | return setmetatable(newObj, self) 321 | end 322 | 323 | ---------------------------------------------------- 324 | -- 4. 模块 325 | ---------------------------------------------------- 326 | 327 | 328 | --[[ 我把这部分给注释了,这样脚本剩下的部分可以运行 329 | 330 | -- 假设文件mod.lua的内容类似这样: 331 | local M = {} 332 | 333 | local function sayMyName() 334 | print('Hrunkner') 335 | end 336 | 337 | function M.sayHello() 338 | print('Why hello there') 339 | sayMyName() 340 | end 341 | 342 | return M 343 | 344 | -- 另一个文件可以使用mod.lua的功能: 345 | local mod = require('mod') -- 运行文件mod.lua. 346 | 347 | -- require是包含模块的标准做法。 348 | -- require等价于: (针对没有被缓存的情况;参见后面的内容) 349 | local mod = (function () 350 | 351 | end)() 352 | -- mod.lua被包在一个函数体中,因此mod.lua的局部变量 353 | -- 对外不可见。 354 | 355 | -- 下面的代码可以工作,因为在这里mod = mod.lua 中的 M: 356 | mod.sayHello() -- Says hello to Hrunkner. 357 | 358 | -- 这是错误的;sayMyName只在mod.lua中存在: 359 | mod.sayMyName() -- 错误 360 | 361 | -- require返回的值会被缓存,所以一个文件只会被运行一次, 362 | -- 即使它被require了多次。 363 | 364 | -- 假设mod2.lua包含代码"print('Hi!')"。 365 | local a = require('mod2') -- 打印Hi! 366 | local b = require('mod2') -- 不再打印; a=b. 367 | 368 | -- dofile与require类似,但是不缓存: 369 | dofile('mod2') --> Hi! 370 | dofile('mod2') --> Hi! (再次运行,与require不同) 371 | 372 | -- loadfile加载一个lua文件,但是并不运行它。 373 | f = loadfile('mod2') -- Calling f() runs mod2.lua. 374 | 375 | -- loadstring是loadfile的字符串版本。 376 | g = loadstring('print(343)') --返回一个函数。 377 | g() -- 打印343; 在此之前什么也不打印。 378 | 379 | --]] 380 | -------------------------------------------------------------------------------- /learnperl-cn.pl: -------------------------------------------------------------------------------- 1 | # 单行注释以#号开头 2 | 3 | 4 | #### Perl的变量类型 5 | 6 | # 变量以$号开头。 7 | # 合法变量名以英文字母或者下划线起始, 8 | # 后接任意数目的字母、数字或下划线。 9 | 10 | ### Perl有三种主要的变量类型:标量、数组和哈希。 11 | 12 | ## 标量 13 | # 标量类型代表单个值: 14 | my $animal = "camel"; 15 | my $answer = 42; 16 | 17 | # 标量类型值可以是字符串、整型或浮点类型,Perl会根据需要自动进行类型转换。 18 | 19 | ## 数组 20 | # 数组类型代表一列值: 21 | my @animals = ("camel", "llama", "owl"); 22 | my @numbers = (23, 42, 69); 23 | my @mixed = ("camel", 42, 1.23); 24 | 25 | 26 | 27 | ## 哈希 28 | # 哈希类型代表一个键/值对的集合: 29 | 30 | my %fruit_color = ("apple", "red", "banana", "yellow"); 31 | 32 | # 可以使用空格和“=>”操作符更清晰的定义哈希: 33 | 34 | my %fruit_color = ( 35 | apple => "red", 36 | banana => "yellow", 37 | ); 38 | # perldata中有标量、数组和哈希更详细的介绍。 (perldoc perldata). 39 | 40 | # 可以用引用构建更复杂的数据类型,比如嵌套的列表和哈希。 41 | 42 | #### 逻辑和循环结构 43 | 44 | # Perl有大多数常见的逻辑和循环控制结构 45 | 46 | if ( $var ) { 47 | ... 48 | } elsif ( $var eq 'bar' ) { 49 | ... 50 | } else { 51 | ... 52 | } 53 | 54 | unless ( condition ) { 55 | ... 56 | } 57 | # 上面这个比"if (!condition)"更可读。 58 | 59 | # 有Perl特色的后置逻辑结构 60 | print "Yow!" if $zippy; 61 | print "We have no bananas" unless $bananas; 62 | 63 | # while 64 | while ( condition ) { 65 | ... 66 | } 67 | 68 | 69 | # for和foreach 70 | for ($i = 0; $i <= $max; $i++) { 71 | ... 72 | } 73 | 74 | foreach (@array) { 75 | print "This element is $_\n"; 76 | } 77 | 78 | 79 | #### 正则表达式 80 | 81 | # Perl对正则表达式有深入广泛的支持,perlrequick和perlretut等文档有详细介绍。简单来说: 82 | 83 | # 简单匹配 84 | if (/foo/) { ... } # 如果 $_ 包含"foo"逻辑为真 85 | if ($a =~ /foo/) { ... } # 如果 $a 包含"foo"逻辑为真 86 | 87 | # 简单替换 88 | 89 | $a =~ s/foo/bar/; # 将$a中的foo替换为bar 90 | $a =~ s/foo/bar/g; # 将$a中所有的foo替换为bar 91 | 92 | 93 | #### 文件和输入输出 94 | 95 | # 可以使用“open()”函数打开文件用于输入输出。 96 | 97 | open(my $in, "<", "input.txt") or die "Can't open input.txt: $!"; 98 | open(my $out, ">", "output.txt") or die "Can't open output.txt: $!"; 99 | open(my $log, ">>", "my.log") or die "Can't open my.log: $!"; 100 | 101 | # 可以用"<>"操作符读取一个打开的文件句柄。 在标量语境下会读取一行, 102 | # 在列表环境下会将整个文件读入并将每一行赋给列表的一个元素: 103 | 104 | my $line = <$in>; 105 | my @lines = <$in>; 106 | 107 | #### 子程序 108 | 109 | # 写子程序很简单: 110 | 111 | sub logger { 112 | my $logmessage = shift; 113 | open my $logfile, ">>", "my.log" or die "Could not open my.log: $!"; 114 | print $logfile $logmessage; 115 | } 116 | 117 | # 现在可以像内置函数一样调用子程序: 118 | 119 | logger("We have a logger subroutine!"); 120 | -------------------------------------------------------------------------------- /learnphp-cn.php: -------------------------------------------------------------------------------- 1 | 2 | 之中 3 | 4 | // 如果你的文件中只有php代码,那么最好省略结束括号标记 5 | 6 | // 这是单行注释的标志 7 | 8 | # 井号也可以,但是//更常见 9 | 10 | /* 11 | 这是多行注释 12 | */ 13 | 14 | // 使用 "echo" 或者 "print" 来输出信息到标准输出 15 | print('Hello '); // 输出 "Hello " 并且没有换行符 16 | 17 | // () 对于echo和print是可选的 18 | echo "World\n"; // 输出 "World" 并且换行 19 | // (每个语句必须以分号结尾) 20 | 21 | // 在 Hello World Again! 23 | 12 39 | $int2 = -12; // => -12 40 | $int3 = 012; // => 10 (0开头代表八进制数) 41 | $int4 = 0x0F; // => 15 (0x开头代表十六进制数) 42 | 43 | // 浮点型 (即双精度浮点型) 44 | $float = 1.234; 45 | $float = 1.2e3; 46 | $float = 7E-10; 47 | 48 | // 算数运算 49 | $sum = 1 + 1; // 2 50 | $difference = 2 - 1; // 1 51 | $product = 2 * 2; // 4 52 | $quotient = 2 / 1; // 2 53 | 54 | // 算数运算的简写 55 | $number = 0; 56 | $number += 1; // $number 自增1 57 | echo $number++; // 输出1 (运算后自增) 58 | echo ++$number; // 输出3 (自增后运算) 59 | $number /= $float; // 先除后赋值给 $number 60 | 61 | // 字符串需要被包含在单引号之中 62 | $sgl_quotes = '$String'; // => '$String' 63 | 64 | // 如果需要在字符串中引用变量,就需要使用双引号 65 | $dbl_quotes = "This is a $sgl_quotes."; // => 'This is a $String.' 66 | 67 | // 特殊字符只有在双引号中有用 68 | $escaped = "This contains a \t tab character."; 69 | $unescaped = 'This just contains a slash and a t: \t'; 70 | 71 | // 可以把变量包含在一对大括号中 72 | $money = "I have $${number} in the bank."; 73 | 74 | // 自 PHP 5.3 开始, nowdocs 可以被用作多行非计算型字符串 75 | $nowdoc = <<<'END' 76 | Multi line 77 | string 78 | END; 79 | 80 | // 而Heredocs则可以用作多行计算型字符串 81 | $heredoc = << 1, 'Two' => 2, 'Three' => 3); 98 | 99 | // PHP 5.4 中引入了新的语法 100 | $associative = ['One' => 1, 'Two' => 2, 'Three' => 3]; 101 | 102 | echo $associative['One']; // 输出 1 103 | 104 | // 声明为列表实际上是给每个值都分配了一个整数键(key) 105 | $array = ['One', 'Two', 'Three']; 106 | echo $array[0]; // => "One" 107 | 108 | 109 | /******************************** 110 | * 输出 111 | */ 112 | 113 | echo('Hello World!'); 114 | // 输出到标准输出 115 | // 此时标准输出就是浏览器中的网页 116 | 117 | print('Hello World!'); // 和echo相同 118 | 119 | // echo和print实际上也属于这个语言本身,所以我们省略括号 120 | echo 'Hello World!'; 121 | print 'Hello World!'; 122 | 123 | $paragraph = 'paragraph'; 124 | 125 | echo 100; // 直接输出标量 126 | echo $paragraph; // 或者输出变量 127 | 128 | // 如果你配置了短标签,或者使用5.4.0及以上的版本 129 | // 你就可以使用简写的echo语法 130 | ?> 131 |

132 | 2 142 | echo $z; // => 2 143 | $y = 0; 144 | echo $x; // => 2 145 | echo $z; // => 0 146 | 147 | 148 | /******************************** 149 | * 逻辑 150 | */ 151 | $a = 0; 152 | $b = '0'; 153 | $c = '1'; 154 | $d = '1'; 155 | 156 | // 如果assert的参数为假,就会抛出警告 157 | 158 | // 下面的比较都为真,不管它们的类型是否匹配 159 | assert($a == $b); // 相等 160 | assert($c != $a); // 不等 161 | assert($c <> $a); // 另一种不等的表示 162 | assert($a < $c); 163 | assert($c > $b); 164 | assert($a <= $b); 165 | assert($c >= $d); 166 | 167 | // 下面的比较只有在类型相同、值相同的情况下才为真 168 | assert($c === $d); 169 | assert($a !== $d); 170 | assert(1 === '1'); 171 | assert(1 !== '1'); 172 | 173 | // 变量可以根据其使用来进行类型转换 174 | 175 | $integer = 1; 176 | echo $integer + $integer; // => 2 177 | 178 | $string = '1'; 179 | echo $string + $string; // => 2 (字符串在此时被转化为整数) 180 | 181 | $string = 'one'; 182 | echo $string + $string; // => 0 183 | // 输出0,因为'one'这个字符串无法被转换为整数 184 | 185 | // 类型转换可以将一个类型视作另一种类型 186 | 187 | $boolean = (boolean) 1; // => true 188 | 189 | $zero = 0; 190 | $boolean = (boolean) $zero; // => false 191 | 192 | // 还有一些专用的函数来进行类型转换 193 | $integer = 5; 194 | $string = strval($integer); 195 | 196 | $var = null; // 空值 197 | 198 | 199 | /******************************** 200 | * 控制结构 201 | */ 202 | 203 | if (true) { 204 | print 'I get printed'; 205 | } 206 | 207 | if (false) { 208 | print 'I don\'t'; 209 | } else { 210 | print 'I get printed'; 211 | } 212 | 213 | if (false) { 214 | print 'Does not get printed'; 215 | } elseif(true) { 216 | print 'Does'; 217 | } 218 | 219 | // 三目运算符 220 | print (false ? 'Does not get printed' : 'Does'); 221 | 222 | $x = 0; 223 | if ($x === '0') { 224 | print 'Does not print'; 225 | } elseif($x == '1') { 226 | print 'Does not print'; 227 | } else { 228 | print 'Does print'; 229 | } 230 | 231 | 232 | 233 | // 下面的语法常用于模板中: 234 | ?> 235 | 236 | 237 | This is displayed if the test is truthy. 238 | 239 | This is displayed otherwise. 240 | 241 | 242 | 2, 'car' => 4]; 280 | 281 | // Foreach 循环可以遍历数组 282 | foreach ($wheels as $wheel_count) { 283 | echo $wheel_count; 284 | } // 输出 "24" 285 | 286 | echo "\n"; 287 | 288 | // 也可以同时遍历键和值 289 | foreach ($wheels as $vehicle => $wheel_count) { 290 | echo "A $vehicle has $wheel_count wheels"; 291 | } 292 | 293 | echo "\n"; 294 | 295 | $i = 0; 296 | while ($i < 5) { 297 | if ($i === 3) { 298 | break; // 退出循环 299 | } 300 | echo $i++; 301 | } // 输出 "012" 302 | 303 | for ($i = 0; $i < 5; $i++) { 304 | if ($i === 3) { 305 | continue; // 跳过此次遍历 306 | } 307 | echo $i; 308 | } // 输出 "0124" 309 | 310 | 311 | /******************************** 312 | * 函数 313 | */ 314 | 315 | // 通过"function"定义函数: 316 | function my_function () { 317 | return 'Hello'; 318 | } 319 | 320 | echo my_function(); // => "Hello" 321 | 322 | // 函数名需要以字母或者下划线开头, 323 | // 后面可以跟着任意的字母、下划线、数字. 324 | 325 | function add ($x, $y = 1) { // $y 是可选参数,默认值为 1 326 | $result = $x + $y; 327 | return $result; 328 | } 329 | 330 | echo add(4); // => 5 331 | echo add(4, 2); // => 6 332 | 333 | // $result 在函数外部不可访问 334 | // print $result; // 抛出警告 335 | 336 | // 从 PHP 5.3 起我们可以定义匿名函数 337 | $inc = function ($x) { 338 | return $x + 1; 339 | }; 340 | 341 | echo $inc(2); // => 3 342 | 343 | function foo ($x, $y, $z) { 344 | echo "$x - $y - $z"; 345 | } 346 | 347 | // 函数也可以返回一个函数 348 | function bar ($x, $y) { 349 | // 用 'use' 将外部的参数引入到里面 350 | return function ($z) use ($x, $y) { 351 | foo($x, $y, $z); 352 | }; 353 | } 354 | 355 | $bar = bar('A', 'B'); 356 | $bar('C'); // 输出 "A - B - C" 357 | 358 | // 你也可以通过字符串调用函数 359 | $function_name = 'add'; 360 | echo $function_name(1, 2); // => 3 361 | // 在通过程序来决定调用哪个函数时很有用 362 | // 或者,使用 call_user_func(callable $callback [, $parameter [, ... ]]); 363 | 364 | /******************************** 365 | * 导入 366 | */ 367 | 368 | instanceProp = $instanceProp; 418 | } 419 | 420 | // 方法就是类中定义的函数 421 | public function myMethod() 422 | { 423 | print 'MyClass'; 424 | } 425 | 426 | final function youCannotOverrideMe() 427 | { 428 | } 429 | 430 | public static function myStaticMethod() 431 | { 432 | print 'I am static'; 433 | } 434 | } 435 | 436 | echo MyClass::MY_CONST; // 输出 'value'; 437 | echo MyClass::$staticVar; // 输出 'static'; 438 | MyClass::myStaticMethod(); // 输出 'I am static'; 439 | 440 | // 通过new来新建实例 441 | $my_class = new MyClass('An instance property'); 442 | // 如果不传递参数,那么括号可以省略 443 | 444 | // 用 -> 来访问成员 445 | echo $my_class->property; // => "public" 446 | echo $my_class->instanceProp; // => "An instance property" 447 | $my_class->myMethod(); // => "MyClass" 448 | 449 | 450 | // 使用extends来生成子类 451 | class MyOtherClass extends MyClass 452 | { 453 | function printProtectedProperty() 454 | { 455 | echo $this->prot; 456 | } 457 | 458 | // 方法覆盖 459 | function myMethod() 460 | { 461 | parent::myMethod(); 462 | print ' > MyOtherClass'; 463 | } 464 | } 465 | 466 | $my_other_class = new MyOtherClass('Instance prop'); 467 | $my_other_class->printProtectedProperty(); // => 输出 "protected" 468 | $my_other_class->myMethod(); // 输出 "MyClass > MyOtherClass" 469 | 470 | final class YouCannotExtendMe 471 | { 472 | } 473 | 474 | // 你可以使用“魔法方法”来生成getter和setter方法 475 | class MyMapClass 476 | { 477 | private $property; 478 | 479 | public function __get($key) 480 | { 481 | return $this->$key; 482 | } 483 | 484 | public function __set($key, $value) 485 | { 486 | $this->$key = $value; 487 | } 488 | } 489 | 490 | $x = new MyMapClass(); 491 | echo $x->property; // 会使用 __get() 方法 492 | $x->property = 'Something'; // 会使用 __set() 方法 493 | 494 | // 类可以是被定义成抽象类 (使用 abstract 关键字) 或者 495 | // 去实现接口 (使用 implements 关键字). 496 | // 接口需要通过interface关键字来定义 497 | 498 | interface InterfaceOne 499 | { 500 | public function doSomething(); 501 | } 502 | 503 | interface InterfaceTwo 504 | { 505 | public function doSomethingElse(); 506 | } 507 | 508 | // 接口可以被扩展 509 | interface InterfaceThree extends InterfaceTwo 510 | { 511 | public function doAnotherContract(); 512 | } 513 | 514 | abstract class MyAbstractClass implements InterfaceOne 515 | { 516 | public $x = 'doSomething'; 517 | } 518 | 519 | class MyConcreteClass extends MyAbstractClass implements InterfaceTwo 520 | { 521 | public function doSomething() 522 | { 523 | echo $x; 524 | } 525 | 526 | public function doSomethingElse() 527 | { 528 | echo 'doSomethingElse'; 529 | } 530 | } 531 | 532 | 533 | // 一个类可以实现多个接口 534 | class SomeOtherClass implements InterfaceOne, InterfaceTwo 535 | { 536 | public function doSomething() 537 | { 538 | echo 'doSomething'; 539 | } 540 | 541 | public function doSomethingElse() 542 | { 543 | echo 'doSomethingElse'; 544 | } 545 | } 546 | 547 | 548 | /******************************** 549 | * 特征 550 | */ 551 | 552 | // 特征 从 PHP 5.4.0 开始包括,需要用 "trait" 这个关键字声明 553 | 554 | trait MyTrait 555 | { 556 | public function myTraitMethod() 557 | { 558 | print 'I have MyTrait'; 559 | } 560 | } 561 | 562 | class MyTraitfulClass 563 | { 564 | use MyTrait; 565 | } 566 | 567 | $cls = new MyTraitfulClass(); 568 | $cls->myTraitMethod(); // 输出 "I have MyTrait" 569 | 570 | 571 | /******************************** 572 | * 命名空间 573 | */ 574 | 575 | // 这部分是独立于这个文件的 576 | // 因为命名空间必须在一个文件的开始处。 577 | 578 | 3 15 | 16 | # 简单的算数 17 | 1 + 1 # => 2 18 | 8 - 1 # => 7 19 | 10 * 2 # => 20 20 | 35 / 5 # => 7 21 | 22 | # 整数的除法会自动取整 23 | 5 / 2 # => 2 24 | 25 | # 要做精确的除法,我们需要引入浮点数 26 | 2.0 # 浮点数 27 | 11.0 / 4.0 # => 2.75 精确多了 28 | 29 | # 括号具有最高优先级 30 | (1 + 3) * 2 # => 8 31 | 32 | # 布尔值也是基本的数据类型 33 | True 34 | False 35 | 36 | # 用 not 来取非 37 | not True # => False 38 | not False # => True 39 | 40 | # 相等 41 | 1 == 1 # => True 42 | 2 == 1 # => False 43 | 44 | # 不等 45 | 1 != 1 # => False 46 | 2 != 1 # => True 47 | 48 | # 更多的比较操作符 49 | 1 < 10 # => True 50 | 1 > 10 # => False 51 | 2 <= 2 # => True 52 | 2 >= 2 # => True 53 | 54 | # 比较运算可以连起来写! 55 | 1 < 2 < 3 # => True 56 | 2 < 3 < 2 # => False 57 | 58 | # 字符串通过 " 或 ' 括起来 59 | "This is a string." 60 | 'This is also a string.' 61 | 62 | # 字符串通过加号拼接 63 | "Hello " + "world!" # => "Hello world!" 64 | 65 | # 字符串可以被视为字符的列表 66 | "This is a string"[0] # => 'T' 67 | 68 | # % 可以用来格式化字符串 69 | "%s can be %s" % ("strings", "interpolated") 70 | 71 | # 也可以用 format 方法来格式化字符串 72 | # 推荐使用这个方法 73 | "{0} can be {1}".format("strings", "formatted") 74 | # 也可以用变量名代替数字 75 | "{name} wants to eat {food}".format(name="Bob", food="lasagna") 76 | 77 | # None 是对象 78 | None # => None 79 | 80 | # 不要用相等 `==` 符号来和None进行比较 81 | # 要用 `is` 82 | "etc" is None # => False 83 | None is None # => True 84 | 85 | # 'is' 可以用来比较对象的相等性 86 | # 这个操作符在比较原始数据时没多少用,但是比较对象时必不可少 87 | 88 | # None, 0, 和空字符串都被算作 False 89 | # 其他的均为 True 90 | 0 == False # => True 91 | "" == False # => True 92 | 93 | 94 | #################################################### 95 | ## 2. 变量和集合 96 | #################################################### 97 | 98 | # 很方便的输出 99 | print "I'm Python. Nice to meet you!" 100 | 101 | 102 | # 给变量赋值前不需要事先声明 103 | some_var = 5 # 一般建议使用小写字母和下划线组合来做为变量名 104 | some_var # => 5 105 | 106 | # 访问未赋值的变量会抛出异常 107 | # 可以查看控制流程一节来了解如何异常处理 108 | some_other_var # 抛出 NameError 109 | 110 | # if 语句可以作为表达式来使用 111 | "yahoo!" if 3 > 2 else 2 # => "yahoo!" 112 | 113 | # 列表用来保存序列 114 | li = [] 115 | # 可以直接初始化列表 116 | other_li = [4, 5, 6] 117 | 118 | # 在列表末尾添加元素 119 | li.append(1) # li 现在是 [1] 120 | li.append(2) # li 现在是 [1, 2] 121 | li.append(4) # li 现在是 [1, 2, 4] 122 | li.append(3) # li 现在是 [1, 2, 4, 3] 123 | # 移除列表末尾元素 124 | li.pop() # => 3 li 现在是 [1, 2, 4] 125 | # 重新加进去 126 | li.append(3) # li is now [1, 2, 4, 3] again. 127 | 128 | # 像其他语言访问数组一样访问列表 129 | li[0] # => 1 130 | # 访问最后一个元素 131 | li[-1] # => 3 132 | 133 | # 越界会抛出异常 134 | li[4] # 抛出越界异常 135 | 136 | # 切片语法需要用到列表的索引访问 137 | # 可以看做数学之中左闭右开区间 138 | li[1:3] # => [2, 4] 139 | # 省略开头的元素 140 | li[2:] # => [4, 3] 141 | # 省略末尾的元素 142 | li[:3] # => [1, 2, 4] 143 | 144 | # 删除特定元素 145 | del li[2] # li 现在是 [1, 2, 3] 146 | 147 | # 合并列表 148 | li + other_li # => [1, 2, 3, 4, 5, 6] - 并不会不改变这两个列表 149 | 150 | # 通过拼接来合并列表 151 | li.extend(other_li) # li 是 [1, 2, 3, 4, 5, 6] 152 | 153 | # 用 in 来返回元素是否在列表中 154 | 1 in li # => True 155 | 156 | # 返回列表长度 157 | len(li) # => 6 158 | 159 | 160 | # 元组类似于列表,但它是不可改变的 161 | tup = (1, 2, 3) 162 | tup[0] # => 1 163 | tup[0] = 3 # 类型错误 164 | 165 | # 对于大多数的列表操作,也适用于元组 166 | len(tup) # => 3 167 | tup + (4, 5, 6) # => (1, 2, 3, 4, 5, 6) 168 | tup[:2] # => (1, 2) 169 | 2 in tup # => True 170 | 171 | # 你可以将元组解包赋给多个变量 172 | a, b, c = (1, 2, 3) # a 是 1,b 是 2,c 是 3 173 | # 如果不加括号,将会被自动视为元组 174 | d, e, f = 4, 5, 6 175 | # 现在我们可以看看交换两个数字是多么容易的事 176 | e, d = d, e # d 是 5,e 是 4 177 | 178 | 179 | # 字典用来储存映射关系 180 | empty_dict = {} 181 | # 字典初始化 182 | filled_dict = {"one": 1, "two": 2, "three": 3} 183 | 184 | # 字典也用中括号访问元素 185 | filled_dict["one"] # => 1 186 | 187 | # 把所有的键保存在列表中 188 | filled_dict.keys() # => ["three", "two", "one"] 189 | # 键的顺序并不是唯一的,得到的不一定是这个顺序 190 | 191 | # 把所有的值保存在列表中 192 | filled_dict.values() # => [3, 2, 1] 193 | # 和键的顺序相同 194 | 195 | # 判断一个键是否存在 196 | "one" in filled_dict # => True 197 | 1 in filled_dict # => False 198 | 199 | # 查询一个不存在的键会抛出 KeyError 200 | filled_dict["four"] # KeyError 201 | 202 | # 用 get 方法来避免 KeyError 203 | filled_dict.get("one") # => 1 204 | filled_dict.get("four") # => None 205 | # get 方法支持在不存在的时候返回一个默认值 206 | filled_dict.get("one", 4) # => 1 207 | filled_dict.get("four", 4) # => 4 208 | 209 | # setdefault 是一个更安全的添加字典元素的方法 210 | filled_dict.setdefault("five", 5) # filled_dict["five"] 的值为 5 211 | filled_dict.setdefault("five", 6) # filled_dict["five"] 的值仍然是 5 212 | 213 | 214 | # 集合储存无顺序的元素 215 | empty_set = set() 216 | # 初始化一个集合 217 | some_set = set([1, 2, 2, 3, 4]) # some_set 现在是 set([1, 2, 3, 4]) 218 | 219 | # Python 2.7 之后,大括号可以用来表示集合 220 | filled_set = {1, 2, 2, 3, 4} # => {1 2 3 4} 221 | 222 | # 向集合添加元素 223 | filled_set.add(5) # filled_set 现在是 {1, 2, 3, 4, 5} 224 | 225 | # 用 & 来计算集合的交 226 | other_set = {3, 4, 5, 6} 227 | filled_set & other_set # => {3, 4, 5} 228 | 229 | # 用 | 来计算集合的并 230 | filled_set | other_set # => {1, 2, 3, 4, 5, 6} 231 | 232 | # 用 - 来计算集合的差 233 | {1, 2, 3, 4} - {2, 3, 5} # => {1, 4} 234 | 235 | # 用 in 来判断元素是否存在于集合中 236 | 2 in filled_set # => True 237 | 10 in filled_set # => False 238 | 239 | 240 | #################################################### 241 | ## 3. 控制流程 242 | #################################################### 243 | 244 | # 新建一个变量 245 | some_var = 5 246 | 247 | # 这是个 if 语句,在 python 中缩进是很重要的。 248 | # 下面的代码片段将会输出 "some var is smaller than 10" 249 | if some_var > 10: 250 | print "some_var is totally bigger than 10." 251 | elif some_var < 10: # 这个 elif 语句是不必须的 252 | print "some_var is smaller than 10." 253 | else: # 这个 else 也不是必须的 254 | print "some_var is indeed 10." 255 | 256 | 257 | """ 258 | 用for循环遍历列表 259 | 输出: 260 | dog is a mammal 261 | cat is a mammal 262 | mouse is a mammal 263 | """ 264 | for animal in ["dog", "cat", "mouse"]: 265 | # 你可以用 % 来格式化字符串 266 | print "%s is a mammal" % animal 267 | 268 | """ 269 | `range(number)` 返回从0到给定数字的列表 270 | 输出: 271 | 0 272 | 1 273 | 2 274 | 3 275 | """ 276 | for i in range(4): 277 | print i 278 | 279 | """ 280 | while 循环 281 | 输出: 282 | 0 283 | 1 284 | 2 285 | 3 286 | """ 287 | x = 0 288 | while x < 4: 289 | print x 290 | x += 1 # x = x + 1 的简写 291 | 292 | # 用 try/except 块来处理异常 293 | 294 | # Python 2.6 及以上适用: 295 | try: 296 | # 用 raise 来抛出异常 297 | raise IndexError("This is an index error") 298 | except IndexError as e: 299 | pass # pass 就是什么都不做,不过通常这里会做一些恢复工作 300 | 301 | 302 | #################################################### 303 | ## 4. 函数 304 | #################################################### 305 | 306 | # 用 def 来新建函数 307 | def add(x, y): 308 | print "x is %s and y is %s" % (x, y) 309 | return x + y # 通过 return 来返回值 310 | 311 | # 调用带参数的函数 312 | add(5, 6) # => 输出 "x is 5 and y is 6" 返回 11 313 | 314 | # 通过关键字赋值来调用函数 315 | add(y=6, x=5) # 顺序是无所谓的 316 | 317 | # 我们也可以定义接受多个变量的函数,这些变量是按照顺序排列的 318 | def varargs(*args): 319 | return args 320 | 321 | varargs(1, 2, 3) # => (1,2,3) 322 | 323 | 324 | # 我们也可以定义接受多个变量的函数,这些变量是按照关键字排列的 325 | def keyword_args(**kwargs): 326 | return kwargs 327 | 328 | # 实际效果: 329 | keyword_args(big="foot", loch="ness") # => {"big": "foot", "loch": "ness"} 330 | 331 | # 你也可以同时将一个函数定义成两种形式 332 | def all_the_args(*args, **kwargs): 333 | print args 334 | print kwargs 335 | """ 336 | all_the_args(1, 2, a=3, b=4) prints: 337 | (1, 2) 338 | {"a": 3, "b": 4} 339 | """ 340 | 341 | # 当调用函数的时候,我们也可以进行相反的操作,把元组和字典展开为参数 342 | args = (1, 2, 3, 4) 343 | kwargs = {"a": 3, "b": 4} 344 | all_the_args(*args) # 等价于 foo(1, 2, 3, 4) 345 | all_the_args(**kwargs) # 等价于 foo(a=3, b=4) 346 | all_the_args(*args, **kwargs) # 等价于 foo(1, 2, 3, 4, a=3, b=4) 347 | 348 | # 函数在 python 中是一等公民 349 | def create_adder(x): 350 | def adder(y): 351 | return x + y 352 | return adder 353 | 354 | add_10 = create_adder(10) 355 | add_10(3) # => 13 356 | 357 | # 匿名函数 358 | (lambda x: x > 2)(3) # => True 359 | 360 | # 内置高阶函数 361 | map(add_10, [1, 2, 3]) # => [11, 12, 13] 362 | filter(lambda x: x > 5, [3, 4, 5, 6, 7]) # => [6, 7] 363 | 364 | # 可以用列表方法来对高阶函数进行更巧妙的引用 365 | [add_10(i) for i in [1, 2, 3]] # => [11, 12, 13] 366 | [x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7] 367 | 368 | #################################################### 369 | ## 5. 类 370 | #################################################### 371 | 372 | # 我们新建的类是从 object 类中继承的 373 | class Human(object): 374 | 375 | # 类属性,由所有类的对象共享 376 | species = "H. sapiens" 377 | 378 | # 基本构造函数 379 | def __init__(self, name): 380 | # 将参数赋给对象成员属性 381 | self.name = name 382 | 383 | # 成员方法,参数要有 self 384 | def say(self, msg): 385 | return "%s: %s" % (self.name, msg) 386 | 387 | # 类方法由所有类的对象共享 388 | # 这类方法在调用时,会把类本身传给第一个参数 389 | @classmethod 390 | def get_species(cls): 391 | return cls.species 392 | 393 | # 静态方法是不需要类和对象的引用就可以调用的方法 394 | @staticmethod 395 | def grunt(): 396 | return "*grunt*" 397 | 398 | 399 | # 实例化一个类 400 | i = Human(name="Ian") 401 | print i.say("hi") # 输出 "Ian: hi" 402 | 403 | j = Human("Joel") 404 | print j.say("hello") # 输出 "Joel: hello" 405 | 406 | # 访问类的方法 407 | i.get_species() # => "H. sapiens" 408 | 409 | # 改变共享属性 410 | Human.species = "H. neanderthalensis" 411 | i.get_species() # => "H. neanderthalensis" 412 | j.get_species() # => "H. neanderthalensis" 413 | 414 | # 访问静态变量 415 | Human.grunt() # => "*grunt*" 416 | 417 | 418 | #################################################### 419 | ## 6. 模块 420 | #################################################### 421 | 422 | # 我们可以导入其他模块 423 | import math 424 | print math.sqrt(16) # => 4 425 | 426 | # 我们也可以从一个模块中导入特定的函数 427 | from math import ceil, floor 428 | print ceil(3.7) # => 4.0 429 | print floor(3.7) # => 3.0 430 | 431 | # 从模块中导入所有的函数 432 | # 警告:不推荐使用 433 | from math import * 434 | 435 | # 简写模块名 436 | import math as m 437 | math.sqrt(16) == m.sqrt(16) # => True 438 | 439 | # Python的模块其实只是普通的python文件 440 | # 你也可以创建自己的模块,并且导入它们 441 | # 模块的名字就和文件的名字相同 442 | 443 | # 也可以通过下面的方法查看模块中有什么属性和方法 444 | import math 445 | dir(math) 446 | 447 | -------------------------------------------------------------------------------- /learnpython3-cn.py: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 用井字符开头的是单行注释 4 | 5 | """ 多行字符串用三个引号 6 | 包裹,也常被用来做多 7 | 行注释 8 | """ 9 | 10 | #################################################### 11 | ## 1. 原始数据类型和运算符 12 | #################################################### 13 | 14 | # 整数 15 | 3 # => 3 16 | 17 | # 算术没有什么出乎意料的 18 | 1 + 1 # => 2 19 | 8 - 1 # => 7 20 | 10 * 2 # => 20 21 | 22 | # 但是除法例外,会自动转换成浮点数 23 | 35 / 5 # => 7.0 24 | 5 / 3 # => 1.6666666666666667 25 | 26 | # 整数除法的结果都是向下取整 27 | 5 // 3 # => 1 28 | 5.0 // 3.0 # => 1.0 # 浮点数也可以 29 | -5 // 3 # => -2 30 | -5.0 // 3.0 # => -2.0 31 | 32 | # 浮点数的运算结果也是浮点数 33 | 3 * 2.0 # => 6.0 34 | 35 | # 模除 36 | 7 % 3 # => 1 37 | 38 | # x的y次方 39 | 2**4 # => 16 40 | 41 | # 用括号决定优先级 42 | (1 + 3) * 2 # => 8 43 | 44 | # 布尔值 45 | True 46 | False 47 | 48 | # 用not取非 49 | not True # => False 50 | not False # => True 51 | 52 | # 逻辑运算符,注意and和or都是小写 53 | True and False #=> False 54 | False or True #=> True 55 | 56 | # 整数也可以当作布尔值 57 | 0 and 2 #=> 0 58 | -5 or 0 #=> -5 59 | 0 == False #=> True 60 | 2 == True #=> False 61 | 1 == True #=> True 62 | 63 | # 用==判断相等 64 | 1 == 1 # => True 65 | 2 == 1 # => False 66 | 67 | # 用!=判断不等 68 | 1 != 1 # => False 69 | 2 != 1 # => True 70 | 71 | # 比较大小 72 | 1 < 10 # => True 73 | 1 > 10 # => False 74 | 2 <= 2 # => True 75 | 2 >= 2 # => True 76 | 77 | # 大小比较可以连起来! 78 | 1 < 2 < 3 # => True 79 | 2 < 3 < 2 # => False 80 | 81 | # 字符串用单引双引都可以 82 | "这是个字符串" 83 | '这也是个字符串' 84 | 85 | # 用加号连接字符串 86 | "Hello " + "world!" # => "Hello world!" 87 | 88 | # 字符串可以被当作字符列表 89 | "This is a string"[0] # => 'T' 90 | 91 | # 用.format来格式化字符串 92 | "{} can be {}".format("strings", "interpolated") 93 | 94 | # 可以重复参数以节省时间 95 | "{0} be nimble, {0} be quick, {0} jump over the {1}".format("Jack", "candle stick") 96 | #=> "Jack be nimble, Jack be quick, Jack jump over the candle stick" 97 | 98 | # 如果不想数参数,可以用关键字 99 | "{name} wants to eat {food}".format(name="Bob", food="lasagna") #=> "Bob wants to eat lasagna" 100 | 101 | # 如果你的Python3程序也要在Python2.5以下环境运行,也可以用老式的格式化语法 102 | "%s can be %s the %s way" % ("strings", "interpolated", "old") 103 | 104 | # None是一个对象 105 | None # => None 106 | 107 | # 当与None进行比较时不要用 ==,要用is。is是用来比较两个变量是否指向同一个对象。 108 | "etc" is None # => False 109 | None is None # => True 110 | 111 | # None,0,空字符串,空列表,空字典都算是False 112 | # 所有其他值都是True 113 | bool(0) # => False 114 | bool("") # => False 115 | bool([]) #=> False 116 | bool({}) #=> False 117 | 118 | 119 | #################################################### 120 | ## 2. 变量和集合 121 | #################################################### 122 | 123 | # print是内置的打印函数 124 | print("I'm Python. Nice to meet you!") 125 | 126 | # 在给变量赋值前不用提前声明 127 | # 传统的变量命名是小写,用下划线分隔单词 128 | some_var = 5 129 | some_var # => 5 130 | 131 | # 访问未赋值的变量会抛出异常 132 | # 参考流程控制一段来学习异常处理 133 | some_unknown_var # 抛出NameError 134 | 135 | # 用列表(list)储存序列 136 | li = [] 137 | # 创建列表时也可以同时赋给元素 138 | other_li = [4, 5, 6] 139 | 140 | # 用append在列表最后追加元素 141 | li.append(1) # li现在是[1] 142 | li.append(2) # li现在是[1, 2] 143 | li.append(4) # li现在是[1, 2, 4] 144 | li.append(3) # li现在是[1, 2, 4, 3] 145 | # 用pop从列表尾部删除 146 | li.pop() # => 3 且li现在是[1, 2, 4] 147 | # 把3再放回去 148 | li.append(3) # li变回[1, 2, 4, 3] 149 | 150 | # 列表存取跟数组一样 151 | li[0] # => 1 152 | # 取出最后一个元素 153 | li[-1] # => 3 154 | 155 | # 越界存取会造成IndexError 156 | li[4] # 抛出IndexError 157 | 158 | # 列表有切割语法 159 | li[1:3] # => [2, 4] 160 | # 取尾 161 | li[2:] # => [4, 3] 162 | # 取头 163 | li[:3] # => [1, 2, 4] 164 | # 隔一个取一个 165 | li[::2] # =>[1, 4] 166 | # 倒排列表 167 | li[::-1] # => [3, 4, 2, 1] 168 | # 可以用三个参数的任何组合来构建切割 169 | # li[始:终:步伐] 170 | 171 | # 用del删除任何一个元素 172 | del li[2] # li is now [1, 2, 3] 173 | 174 | # 列表可以相加 175 | # 注意:li和other_li的值都不变 176 | li + other_li # => [1, 2, 3, 4, 5, 6] 177 | 178 | # 用extend拼接列表 179 | li.extend(other_li) # li现在是[1, 2, 3, 4, 5, 6] 180 | 181 | # 用in测试列表是否包含值 182 | 1 in li # => True 183 | 184 | # 用len取列表长度 185 | len(li) # => 6 186 | 187 | 188 | # 元组是不可改变的序列 189 | tup = (1, 2, 3) 190 | tup[0] # => 1 191 | tup[0] = 3 # 抛出TypeError 192 | 193 | # 列表允许的操作元组大都可以 194 | len(tup) # => 3 195 | tup + (4, 5, 6) # => (1, 2, 3, 4, 5, 6) 196 | tup[:2] # => (1, 2) 197 | 2 in tup # => True 198 | 199 | # 可以把元组合列表解包,赋值给变量 200 | a, b, c = (1, 2, 3) # 现在a是1,b是2,c是3 201 | # 元组周围的括号是可以省略的 202 | d, e, f = 4, 5, 6 203 | # 交换两个变量的值就这么简单 204 | e, d = d, e # 现在d是5,e是4 205 | 206 | 207 | # 用字典表达映射关系 208 | empty_dict = {} 209 | # 初始化的字典 210 | filled_dict = {"one": 1, "two": 2, "three": 3} 211 | 212 | # 用[]取值 213 | filled_dict["one"] # => 1 214 | 215 | 216 | # 用keys获得所有的键。因为keys返回一个可迭代对象,所以在这里把结果包在list里。我们下面会详细介绍可迭代。 217 | # 注意:字典键的顺序是不定的,你得到的结果可能和以下不同。 218 | list(filled_dict.keys()) # => ["three", "two", "one"] 219 | 220 | 221 | # 用values获得所有的值。跟keys一样,要用list包起来,顺序也可能不同。 222 | list(filled_dict.values()) # => [3, 2, 1] 223 | 224 | 225 | # 用in测试一个字典是否包含一个键 226 | "one" in filled_dict # => True 227 | 1 in filled_dict # => False 228 | 229 | # 访问不存在的键会导致KeyError 230 | filled_dict["four"] # KeyError 231 | 232 | # 用get来避免KeyError 233 | filled_dict.get("one") # => 1 234 | filled_dict.get("four") # => None 235 | # 当键不存在的时候get方法可以返回默认值 236 | filled_dict.get("one", 4) # => 1 237 | filled_dict.get("four", 4) # => 4 238 | 239 | # setdefault方法只有当键不存在的时候插入新值 240 | filled_dict.setdefault("five", 5) # filled_dict["five"]设为5 241 | filled_dict.setdefault("five", 6) # filled_dict["five"]还是5 242 | 243 | # 字典赋值 244 | filled_dict.update({"four":4}) #=> {"one": 1, "two": 2, "three": 3, "four": 4} 245 | filled_dict["four"] = 4 # 另一种赋值方法 246 | 247 | # 用del删除 248 | del filled_dict["one"] # 从filled_dict中把one删除 249 | 250 | 251 | # 用set表达集合 252 | empty_set = set() 253 | # 初始化一个集合,语法跟字典相似。 254 | some_set = {1, 1, 2, 2, 3, 4} # some_set现在是{1, 2, 3, 4} 255 | 256 | # 可以把集合赋值于变量 257 | filled_set = some_set 258 | 259 | # 为集合添加元素 260 | filled_set.add(5) # filled_set现在是{1, 2, 3, 4, 5} 261 | 262 | # & 取交集 263 | other_set = {3, 4, 5, 6} 264 | filled_set & other_set # => {3, 4, 5} 265 | 266 | # | 取并集 267 | filled_set | other_set # => {1, 2, 3, 4, 5, 6} 268 | 269 | # - 取补集 270 | {1, 2, 3, 4} - {2, 3, 5} # => {1, 4} 271 | 272 | # in 测试集合是否包含元素 273 | 2 in filled_set # => True 274 | 10 in filled_set # => False 275 | 276 | 277 | #################################################### 278 | ## 3. 流程控制和迭代器 279 | #################################################### 280 | 281 | # 先随便定义一个变量 282 | some_var = 5 283 | 284 | # 这是个if语句。注意缩进在Python里是有意义的 285 | # 印出"some_var比10小" 286 | if some_var > 10: 287 | print("some_var比10大") 288 | elif some_var < 10: # elif句是可选的 289 | print("some_var比10小") 290 | else: # else也是可选的 291 | print("some_var就是10") 292 | 293 | 294 | """ 295 | 用for循环语句遍历列表 296 | 打印: 297 | dog is a mammal 298 | cat is a mammal 299 | mouse is a mammal 300 | """ 301 | for animal in ["dog", "cat", "mouse"]: 302 | print("{} is a mammal".format(animal)) 303 | 304 | """ 305 | "range(number)"返回数字列表从0到给的数字 306 | 打印: 307 | 0 308 | 1 309 | 2 310 | 3 311 | """ 312 | for i in range(4): 313 | print(i) 314 | 315 | """ 316 | while循环直到条件不满足 317 | 打印: 318 | 0 319 | 1 320 | 2 321 | 3 322 | """ 323 | x = 0 324 | while x < 4: 325 | print(x) 326 | x += 1 # x = x + 1 的简写 327 | 328 | # 用try/except块处理异常状况 329 | try: 330 | # 用raise抛出异常 331 | raise IndexError("This is an index error") 332 | except IndexError as e: 333 | pass # pass是无操作,但是应该在这里处理错误 334 | except (TypeError, NameError): 335 | pass # 可以同时处理不同类的错误 336 | else: # else语句是可选的,必须在所有的except之后 337 | print("All good!") # 只有当try运行完没有错误的时候这句才会运行 338 | 339 | 340 | # Python提供一个叫做可迭代(iterable)的基本抽象。一个可迭代对象是可以被当作序列 341 | # 的对象。比如说上面range返回的对象就是可迭代的。 342 | 343 | filled_dict = {"one": 1, "two": 2, "three": 3} 344 | our_iterable = filled_dict.keys() 345 | print(our_iterable) # => range(1,10) 是一个实现可迭代接口的对象 346 | 347 | # 可迭代对象可以遍历 348 | for i in our_iterable: 349 | print(i) # 打印 one, two, three 350 | 351 | # 但是不可以随机访问 352 | our_iterable[1] # 抛出TypeError 353 | 354 | # 可迭代对象知道怎么生成迭代器 355 | our_iterator = iter(our_iterable) 356 | 357 | # 迭代器是一个可以记住遍历的位置的对象 358 | # 用__next__可以取得下一个元素 359 | our_iterator.__next__() #=> "one" 360 | 361 | # 再一次调取__next__时会记得位置 362 | our_iterator.__next__() #=> "two" 363 | our_iterator.__next__() #=> "three" 364 | 365 | # 当迭代器所有元素都取出后,会抛出StopIteration 366 | our_iterator.__next__() # 抛出StopIteration 367 | 368 | # 可以用list一次取出迭代器所有的元素 369 | list(filled_dict.keys()) #=> Returns ["one", "two", "three"] 370 | 371 | 372 | 373 | #################################################### 374 | ## 4. 函数 375 | #################################################### 376 | 377 | # 用def定义新函数 378 | def add(x, y): 379 | print("x is {} and y is {}".format(x, y)) 380 | return x + y # 用return语句返回 381 | 382 | # 调用函数 383 | add(5, 6) # => 印出"x is 5 and y is 6"并且返回11 384 | 385 | # 也可以用关键字参数来调用函数 386 | add(y=6, x=5) # 关键字参数可以用任何顺序 387 | 388 | 389 | # 我们可以定义一个可变参数函数 390 | def varargs(*args): 391 | return args 392 | 393 | varargs(1, 2, 3) # => (1, 2, 3) 394 | 395 | 396 | # 我们也可以定义一个关键字可变参数函数 397 | def keyword_args(**kwargs): 398 | return kwargs 399 | 400 | # 我们来看看结果是什么: 401 | keyword_args(big="foot", loch="ness") # => {"big": "foot", "loch": "ness"} 402 | 403 | 404 | # 这两种可变参数可以混着用 405 | def all_the_args(*args, **kwargs): 406 | print(args) 407 | print(kwargs) 408 | """ 409 | all_the_args(1, 2, a=3, b=4) prints: 410 | (1, 2) 411 | {"a": 3, "b": 4} 412 | """ 413 | 414 | # 调用可变参数函数时可以做跟上面相反的,用*展开序列,用**展开字典。 415 | args = (1, 2, 3, 4) 416 | kwargs = {"a": 3, "b": 4} 417 | all_the_args(*args) # 相当于 foo(1, 2, 3, 4) 418 | all_the_args(**kwargs) # 相当于 foo(a=3, b=4) 419 | all_the_args(*args, **kwargs) # 相当于 foo(1, 2, 3, 4, a=3, b=4) 420 | 421 | 422 | # 函数作用域 423 | x = 5 424 | 425 | def setX(num): 426 | # 局部作用域的x和全局域的x是不同的 427 | x = num # => 43 428 | print (x) # => 43 429 | 430 | def setGlobalX(num): 431 | global x 432 | print (x) # => 5 433 | x = num # 现在全局域的x被赋值 434 | print (x) # => 6 435 | 436 | setX(43) 437 | setGlobalX(6) 438 | 439 | 440 | # 函数在Python是一等公民 441 | def create_adder(x): 442 | def adder(y): 443 | return x + y 444 | return adder 445 | 446 | add_10 = create_adder(10) 447 | add_10(3) # => 13 448 | 449 | # 也有匿名函数 450 | (lambda x: x > 2)(3) # => True 451 | 452 | # 内置的高阶函数 453 | map(add_10, [1, 2, 3]) # => [11, 12, 13] 454 | filter(lambda x: x > 5, [3, 4, 5, 6, 7]) # => [6, 7] 455 | 456 | # 用列表推导式可以简化映射和过滤。列表推导式的返回值是另一个列表。 457 | [add_10(i) for i in [1, 2, 3]] # => [11, 12, 13] 458 | [x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7] 459 | 460 | #################################################### 461 | ## 5. 类 462 | #################################################### 463 | 464 | 465 | # 定义一个继承object的类 466 | class Human(object): 467 | 468 | # 类属性,被所有此类的实例共用。 469 | species = "H. sapiens" 470 | 471 | # 构造方法,当实例被初始化时被调用。注意名字前后的双下划线,这是表明这个属 472 | # 性或方法对Python有特殊意义,但是允许用户自行定义。你自己取名时不应该用这 473 | # 种格式。 474 | def __init__(self, name): 475 | # Assign the argument to the instance's name attribute 476 | self.name = name 477 | 478 | # 实例方法,第一个参数总是self,就是这个实例对象 479 | def say(self, msg): 480 | return "{name}: {message}".format(name=self.name, message=msg) 481 | 482 | # 类方法,被所有此类的实例共用。第一个参数是这个类对象。 483 | @classmethod 484 | def get_species(cls): 485 | return cls.species 486 | 487 | # 静态方法。调用时没有实例或类的绑定。 488 | @staticmethod 489 | def grunt(): 490 | return "*grunt*" 491 | 492 | 493 | # 构造一个实例 494 | i = Human(name="Ian") 495 | print(i.say("hi")) # 印出 "Ian: hi" 496 | 497 | j = Human("Joel") 498 | print(j.say("hello")) # 印出 "Joel: hello" 499 | 500 | # 调用一个类方法 501 | i.get_species() # => "H. sapiens" 502 | 503 | # 改一个共用的类属性 504 | Human.species = "H. neanderthalensis" 505 | i.get_species() # => "H. neanderthalensis" 506 | j.get_species() # => "H. neanderthalensis" 507 | 508 | # 调用静态方法 509 | Human.grunt() # => "*grunt*" 510 | 511 | 512 | #################################################### 513 | ## 6. 模块 514 | #################################################### 515 | 516 | # 用import导入模块 517 | import math 518 | print(math.sqrt(16)) # => 4 519 | 520 | # 也可以从模块中导入个别值 521 | from math import ceil, floor 522 | print(ceil(3.7)) # => 4.0 523 | print(floor(3.7)) # => 3.0 524 | 525 | # 可以导入一个模块中所有值 526 | # 警告:不建议这么做 527 | from math import * 528 | 529 | # 如此缩写模块名字 530 | import math as m 531 | math.sqrt(16) == m.sqrt(16) # => True 532 | 533 | # Python模块其实就是普通的Python文件。你可以自己写,然后导入, 534 | # 模块的名字就是文件的名字。 535 | 536 | # 你可以这样列出一个模块里所有的值 537 | import math 538 | dir(math) 539 | 540 | 541 | #################################################### 542 | ## 7. 高级用法 543 | #################################################### 544 | 545 | # 用生成器(generators)方便地写惰性运算 546 | def double_numbers(iterable): 547 | for i in iterable: 548 | yield i + i 549 | 550 | # 生成器只有在需要时才计算下一个值。它们每一次循环只生成一个值,而不是把所有的 551 | # 值全部算好。这意味着double_numbers不会生成大于15的数字。 552 | # 553 | # range的返回值也是一个生成器,不然一个1到900000000的列表会花很多时间和内存。 554 | # 555 | # 如果你想用一个Python的关键字当作变量名,可以加一个下划线来区分。 556 | range_ = range(1, 900000000) 557 | # 当找到一个 >=30 的结果就会停 558 | for i in double_numbers(range_): 559 | print(i) 560 | if i >= 30: 561 | break 562 | 563 | 564 | # 装饰器(decorators) 565 | # 这个例子中,beg装饰say 566 | # beg会先调用say。如果返回的say_please为真,beg会改变返回的字符串。 567 | from functools import wraps 568 | 569 | 570 | def beg(target_function): 571 | @wraps(target_function) 572 | def wrapper(*args, **kwargs): 573 | msg, say_please = target_function(*args, **kwargs) 574 | if say_please: 575 | return "{} {}".format(msg, "Please! I am poor :(") 576 | return msg 577 | 578 | return wrapper 579 | 580 | 581 | @beg 582 | def say(say_please=False): 583 | msg = "Can you buy me a beer?" 584 | return msg, say_please 585 | 586 | 587 | print(say()) # Can you buy me a beer? 588 | print(say(say_please=True)) # Can you buy me a beer? Please! I am poor :( 589 | -------------------------------------------------------------------------------- /learnr-cn.r: -------------------------------------------------------------------------------- 1 | 2 | # 评论以 # 开始 3 | 4 | # R 语言原生不支持 多行注释 5 | # 但是你可以像这样来多行注释 6 | 7 | # 在窗口里按回车键可以执行一条命令 8 | 9 | 10 | ################################################################### 11 | # 不用懂编程就可以开始动手了 12 | ################################################################### 13 | 14 | data() # 浏览内建的数据集 15 | data(rivers) # 北美主要河流的长度(数据集) 16 | ls() # 在工作空间中查看「河流」是否出现 17 | head(rivers) # 撇一眼数据集 18 | # 735 320 325 392 524 450 19 | length(rivers) # 我们测量了多少条河流? 20 | # 141 21 | summary(rivers) 22 | # Min. 1st Qu. Median Mean 3rd Qu. Max. 23 | # 135.0 310.0 425.0 591.2 680.0 3710.0 24 | stem(rivers) # 茎叶图(一种类似于直方图的展现形式) 25 | # 26 | # The decimal point is 2 digit(s) to the right of the | 27 | # 28 | # 0 | 4 29 | # 2 | 011223334555566667778888899900001111223333344455555666688888999 30 | # 4 | 111222333445566779001233344567 31 | # 6 | 000112233578012234468 32 | # 8 | 045790018 33 | # 10 | 04507 34 | # 12 | 1471 35 | # 14 | 56 36 | # 16 | 7 37 | # 18 | 9 38 | # 20 | 39 | # 22 | 25 40 | # 24 | 3 41 | # 26 | 42 | # 28 | 43 | # 30 | 44 | # 32 | 45 | # 34 | 46 | # 36 | 1 47 | 48 | 49 | stem(log(rivers)) # 查看数据集的方式既不是标准形式,也不是取log后的结果! 看起来,是钟形曲线形式的基本数据集 50 | 51 | # The decimal point is 1 digit(s) to the left of the | 52 | # 53 | # 48 | 1 54 | # 50 | 55 | # 52 | 15578 56 | # 54 | 44571222466689 57 | # 56 | 023334677000124455789 58 | # 58 | 00122366666999933445777 59 | # 60 | 122445567800133459 60 | # 62 | 112666799035 61 | # 64 | 00011334581257889 62 | # 66 | 003683579 63 | # 68 | 0019156 64 | # 70 | 079357 65 | # 72 | 89 66 | # 74 | 84 67 | # 76 | 56 68 | # 78 | 4 69 | # 80 | 70 | # 82 | 2 71 | 72 | 73 | hist(rivers, col="#333333", border="white", breaks=25) # 试试用这些参数画画 (译者注:给 river 做统计频数直方图,包含了这些参数:数据源,颜色,边框,空格) 74 | hist(log(rivers), col="#333333", border="white", breaks=25) #你还可以做更多式样的绘图 75 | 76 | # 还有其他一些简单的数据集可以被用来加载。R 语言包括了大量这种 data() 77 | data(discoveries) 78 | plot(discoveries, col="#333333", lwd=3, xlab="Year", main="Number of important discoveries per year") 79 | # 译者注:参数为(数据源,颜色,线条宽度,X 轴名称,标题) 80 | plot(discoveries, col="#333333", lwd=3, type = "h", xlab="Year", main="Number of important discoveries per year") 81 | 82 | 83 | # 除了按照默认的年份排序,我们还可以排序来发现特征 84 | sort(discoveries) 85 | # [1] 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 86 | # [26] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 87 | # [51] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 88 | # [76] 4 4 4 4 5 5 5 5 5 5 5 6 6 6 6 6 6 7 7 7 7 8 9 10 12 89 | 90 | stem(discoveries, scale=2) # 译者注:茎叶图(数据,放大系数) 91 | # 92 | # The decimal point is at the | 93 | # 94 | # 0 | 000000000 95 | # 1 | 000000000000 96 | # 2 | 00000000000000000000000000 97 | # 3 | 00000000000000000000 98 | # 4 | 000000000000 99 | # 5 | 0000000 100 | # 6 | 000000 101 | # 7 | 0000 102 | # 8 | 0 103 | # 9 | 0 104 | # 10 | 0 105 | # 11 | 106 | # 12 | 0 107 | 108 | max(discoveries) 109 | # 12 110 | 111 | summary(discoveries) 112 | # Min. 1st Qu. Median Mean 3rd Qu. Max. 113 | # 0.0 2.0 3.0 3.1 4.0 12.0 114 | 115 | 116 | 117 | 118 | #基本的统计学操作也不需要任何编程知识 119 | 120 | #随机生成数据 121 | round(runif(7, min=.5, max=6.5)) 122 | # 译者注:runif 产生随机数,round 四舍五入 123 | # 1 4 6 1 4 6 4 124 | 125 | # 你输出的结果会和我们给出的不同,除非我们设置了相同的随机种子 random.seed(31337) 126 | 127 | 128 | #从标准高斯函数中随机生成 9 次 129 | rnorm(9) 130 | # [1] 0.07528471 1.03499859 1.34809556 -0.82356087 0.61638975 -1.88757271 131 | # [7] -0.59975593 0.57629164 1.08455362 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | ######################### 142 | # 基础编程 143 | ######################### 144 | 145 | # 数值 146 | 147 | #“数值”指的是双精度的浮点数 148 | 5 # 5 149 | class(5) # "numeric" 150 | 5e4 # 50000 # 用科学技术法方便的处理极大值、极小值或者可变的量级 151 | 6.02e23 # 阿伏伽德罗常数# 152 | 1.6e-35 # 布朗克长度 153 | 154 | # 长整数并用 L 结尾 155 | 5L # 5 156 | #输出5L 157 | class(5L) # "integer" 158 | 159 | # 可以自己试一试?用 class() 函数获取更多信息 160 | # 事实上,你可以找一些文件查阅 `xyz` 以及xyz的差别 161 | # `xyz` 用来查看源码实现,?xyz 用来看帮助 162 | 163 | # 算法 164 | 10 + 66 # 76 165 | 53.2 - 4 # 49.2 166 | 2 * 2.0 # 4 167 | 3L / 4 # 0.75 168 | 3 %% 2 # 1 169 | 170 | # 特殊数值类型 171 | class(NaN) # "numeric" 172 | class(Inf) # "numeric" 173 | class(-Inf) # "numeric" # 在以下场景中会用到 integrate( dnorm(x), 3, Inf ) -- 消除 Z 轴数据 174 | 175 | # 但要注意,NaN 并不是唯一的特殊数值类型…… 176 | class(NA) # 看上面 177 | class(NULL) # NULL 178 | 179 | 180 | # 简单列表 181 | c(6, 8, 7, 5, 3, 0, 9) # 6 8 7 5 3 0 9 182 | c('alef', 'bet', 'gimmel', 'dalet', 'he') 183 | c('Z', 'o', 'r', 'o') == "Zoro" # FALSE FALSE FALSE FALSE 184 | 185 | # 一些优雅的内置功能 186 | 5:15 # 5 6 7 8 9 10 11 12 13 14 15 187 | 188 | seq(from=0, to=31337, by=1337) 189 | # [1] 0 1337 2674 4011 5348 6685 8022 9359 10696 12033 13370 14707 190 | # [13] 16044 17381 18718 20055 21392 22729 24066 25403 26740 28077 29414 30751 191 | 192 | letters 193 | # [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" 194 | # [20] "t" "u" "v" "w" "x" "y" "z" 195 | 196 | month.abb # "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec" 197 | 198 | 199 | # Access the n'th element of a list with list.name[n] or sometimes list.name[[n]] 200 | # 使用 list.name[n] 来访问第 n 个列表元素,有时候需要使用 list.name[[n]] 201 | letters[18] # "r" 202 | LETTERS[13] # "M" 203 | month.name[9] # "September" 204 | c(6, 8, 7, 5, 3, 0, 9)[3] # 7 205 | 206 | 207 | 208 | # 字符串 209 | 210 | # 字符串和字符在 R 语言中没有区别 211 | "Horatio" # "Horatio" 212 | class("Horatio") # "character" 213 | substr("Fortuna multis dat nimis, nulli satis.", 9, 15) # "multis " 214 | gsub('u', 'ø', "Fortuna multis dat nimis, nulli satis.") # "Fortøna møltis dat nimis, nølli satis." 215 | 216 | 217 | 218 | # 逻辑值 219 | 220 | # 布尔值 221 | class(TRUE) # "logical" 222 | class(FALSE) # "logical" 223 | # 和我们预想的一样 224 | TRUE == TRUE # TRUE 225 | TRUE == FALSE # FALSE 226 | FALSE != FALSE # FALSE 227 | FALSE != TRUE # TRUE 228 | # 缺失数据(NA)也是逻辑值 229 | class(NA) # "logical" 230 | #定义NA为逻辑型 231 | 232 | 233 | 234 | # 因子 235 | # 因子是为数据分类排序设计的(像是排序小朋友们的年级或性别) 236 | levels(factor(c("female", "male", "male", "female", "NA", "female"))) # "female" "male" "NA" 237 | 238 | factor(c("female", "female", "male", "NA", "female")) 239 | # female female male NA female 240 | # Levels: female male NA 241 | 242 | data(infert) # 自然以及引产导致的不育症 243 | levels(infert$education) # "0-5yrs" "6-11yrs" "12+ yrs" 244 | 245 | 246 | 247 | # 变量 248 | 249 | # 有许多种方式用来赋值 250 | x = 5 # 这样可以 251 | y <- "1" # 更推荐这样 252 | TRUE -> z # 这样可行,但是很怪 253 | 254 | #我们还可以使用强制转型 255 | as.numeric(y) # 1 256 | as.character(x) # "5" 257 | 258 | # 循环 259 | 260 | # for 循环语句 261 | for (i in 1:4) { 262 | print(i) 263 | } 264 | 265 | # while 循环 266 | a <- 10 267 | while (a > 4) { 268 | cat(a, "...", sep = "") 269 | a <- a - 1 270 | } 271 | 272 | # 记住,在 R 语言中 for / while 循环都很慢 273 | # 建议使用 apply()(我们一会介绍)来错做一串数据(比如一列或者一行数据) 274 | 275 | # IF/ELSE 276 | 277 | # 再来看这些优雅的标准 278 | if (4 > 3) { 279 | print("Huzzah! It worked!") 280 | } else { 281 | print("Noooo! This is blatantly illogical!") 282 | } 283 | 284 | # => 285 | # [1] "Huzzah! It worked!" 286 | 287 | # 函数 288 | 289 | # 定义如下 290 | jiggle <- function(x) { 291 | x + rnorm(x, sd=.1) #add in a bit of (controlled) noise 292 | return(x) 293 | } 294 | 295 | # 和其他 R 语言函数一样调用 296 | jiggle(5) # 5±ε. 使用 set.seed(2716057) 后, jiggle(5)==5.005043 297 | 298 | ######################### 299 | # 数据容器:vectors, matrices, data frames, and arrays 300 | ######################### 301 | 302 | # 单维度 303 | # 你可以将目前我们学习到的任何类型矢量化,只要它们拥有相同的类型 304 | vec <- c(8, 9, 10, 11) 305 | vec # 8 9 10 11 306 | # 矢量的类型是这一组数据元素的类型 307 | class(vec) # "numeric" 308 | # If you vectorize items of different classes, weird coercions happen 309 | #如果你强制的将不同类型数值矢量化,会出现特殊值 310 | c(TRUE, 4) # 1 4 311 | c("dog", TRUE, 4) # "dog" "TRUE" "4" 312 | 313 | #我们这样来取内部数据,(R 的下标索引顺序 1 开始) 314 | vec[1] # 8 315 | # 我们可以根据条件查找特定数据 316 | which(vec %% 2 == 0) # 1 3 317 | # 抓取矢量中第一个和最后一个字符 318 | head(vec, 1) # 8 319 | tail(vec, 1) # 11 320 | #如果下标溢出或不存会得到 NA 321 | vec[6] # NA 322 | # 你可以使用 length() 获取矢量的长度 323 | length(vec) # 4 324 | 325 | # 你可以直接操作矢量或者矢量的子集 326 | vec * 4 # 16 20 24 28 327 | vec[2:3] * 5 # 25 30 328 | # 这里有许多内置的函数,来表现向量 329 | mean(vec) # 9.5 330 | var(vec) # 1.666667 331 | sd(vec) # 1.290994 332 | max(vec) # 11 333 | min(vec) # 8 334 | sum(vec) # 38 335 | 336 | # 二维(相同元素类型) 337 | 338 | #你可以为同样类型的变量建立矩阵 339 | mat <- matrix(nrow = 3, ncol = 2, c(1,2,3,4,5,6)) 340 | mat 341 | # => 342 | # [,1] [,2] 343 | # [1,] 1 4 344 | # [2,] 2 5 345 | # [3,] 3 6 346 | # 和 vector 不一样的是,一个矩阵的类型真的是 「matrix」,而不是内部元素的类型 347 | class(mat) # => "matrix" 348 | # 访问第一行的字符 349 | mat[1,] # 1 4 350 | # 操作第一行数据 351 | 3 * mat[,1] # 3 6 9 352 | # 访问一个特定数据 353 | mat[3,2] # 6 354 | # 转置整个矩阵(译者注:变成 2 行 3 列) 355 | t(mat) 356 | # => 357 | # [,1] [,2] [,3] 358 | # [1,] 1 2 3 359 | # [2,] 4 5 6 360 | 361 | # 使用 cbind() 函数把两个矩阵按列合并,形成新的矩阵 362 | mat2 <- cbind(1:4, c("dog", "cat", "bird", "dog")) 363 | mat2 364 | # => 365 | # [,1] [,2] 366 | # [1,] "1" "dog" 367 | # [2,] "2" "cat" 368 | # [3,] "3" "bird" 369 | # [4,] "4" "dog" 370 | class(mat2) # matrix 371 | # Again, note what happened! 372 | # 注意 373 | # 因为矩阵内部元素必须包含同样的类型 374 | # 所以现在每一个元素都转化成字符串 375 | c(class(mat2[,1]), class(mat2[,2])) 376 | 377 | # 按行合并两个向量,建立新的矩阵 378 | mat3 <- rbind(c(1,2,4,5), c(6,7,0,4)) 379 | mat3 380 | # => 381 | # [,1] [,2] [,3] [,4] 382 | # [1,] 1 2 4 5 383 | # [2,] 6 7 0 4 384 | # 哈哈,数据类型都一样的,没有发生强制转换,生活真美好 385 | 386 | # 二维(不同的元素类型) 387 | 388 | # 利用 data frame 可以将不同类型数据放在一起 389 | dat <- data.frame(c(5,2,1,4), c("dog", "cat", "bird", "dog")) 390 | names(dat) <- c("number", "species") # 给数据列命名 391 | class(dat) # "data.frame" 392 | dat 393 | # => 394 | # number species 395 | # 1 5 dog 396 | # 2 2 cat 397 | # 3 1 bird 398 | # 4 4 dog 399 | class(dat$number) # "numeric" 400 | class(dat[,2]) # "factor" 401 | # data.frame() 会将字符向量转换为 factor 向量 402 | 403 | # 有很多精妙的方法来获取 data frame 的子数据集 404 | dat$number # 5 2 1 4 405 | dat[,1] # 5 2 1 4 406 | dat[,"number"] # 5 2 1 4 407 | 408 | # 多维(相同元素类型) 409 | 410 | # 使用 arry 创造一个 n 维的表格 411 | # You can make a two-dimensional table (sort of like a matrix) 412 | # 你可以建立一个 2 维表格(有点像矩阵) 413 | array(c(c(1,2,4,5),c(8,9,3,6)), dim=c(2,4)) 414 | # => 415 | # [,1] [,2] [,3] [,4] 416 | # [1,] 1 4 8 3 417 | # [2,] 2 5 9 6 418 | #你也可以利用数组建立一个三维的矩阵 419 | array(c(c(c(2,300,4),c(8,9,0)),c(c(5,60,0),c(66,7,847))), dim=c(3,2,2)) 420 | # => 421 | # , , 1 422 | # 423 | # [,1] [,2] 424 | # [1,] 2 8 425 | # [2,] 300 9 426 | # [3,] 4 0 427 | # 428 | # , , 2 429 | # 430 | # [,1] [,2] 431 | # [1,] 5 66 432 | # [2,] 60 7 433 | # [3,] 0 847 434 | 435 | #列表(多维的,不同类型的) 436 | 437 | # R语言有列表的形式 438 | list1 <- list(time = 1:40) 439 | list1$price = c(rnorm(40,.5*list1$time,4)) # 随机 440 | list1 441 | 442 | # You can get items in the list like so 443 | # 你可以这样获得列表的元素 444 | list1$time 445 | # You can subset list items like vectors 446 | # 你也可以和矢量一样获取他们的子集 447 | list1$price[4] 448 | 449 | ######################### 450 | # apply()函数家族 451 | ######################### 452 | 453 | # 还记得 mat 么? 454 | mat 455 | # => 456 | # [,1] [,2] 457 | # [1,] 1 4 458 | # [2,] 2 5 459 | # [3,] 3 6 460 | # Use apply(X, MARGIN, FUN) to apply function FUN to a matrix X 461 | # 使用(X, MARGIN, FUN)将函数 FUN 应用到矩阵 X 的行 (MAR = 1) 或者 列 (MAR = 2) 462 | # That is, R does FUN to each row (or column) of X, much faster than a 463 | # R 在 X 的每一行/列使用 FUN,比循环要快很多 464 | apply(mat, MAR = 2, myFunc) 465 | # => 466 | # [,1] [,2] 467 | # [1,] 3 15 468 | # [2,] 7 19 469 | # [3,] 11 23 470 | # 还有其他家族函数 ?lapply, ?sapply 471 | 472 | # 不要被吓到,虽然许多人在此都被搞混 473 | # plyr 程序包的作用是用来改进 apply() 函数家族 474 | 475 | install.packages("plyr") 476 | require(plyr) 477 | ?plyr 478 | 479 | ######################### 480 | # 载入数据 481 | ######################### 482 | 483 | # "pets.csv" 是网上的一个文本 484 | pets <- read.csv("http://learnxinyminutes.com/docs/pets.csv") 485 | pets 486 | head(pets, 2) # 前两行 487 | tail(pets, 1) # 最后一行 488 | 489 | # 以 .csv 格式来保存数据集或者矩阵 490 | write.csv(pets, "pets2.csv") # 保存到新的文件 pets2.csv 491 | # set working directory with setwd(), look it up with getwd() 492 | # 使用 setwd() 改变工作目录,使用 getwd() 查看当前工作目录 493 | 494 | # 尝试使用 ?read.csv 和 ?write.csv 来查看更多信息 495 | 496 | ######################### 497 | # 画图 498 | ######################### 499 | 500 | # 散点图 501 | plot(list1$time, list1$price, main = "fake data") # 译者注:横轴 list1$time,纵轴 wlist1$price,标题 fake data 502 | # 回归图 503 | linearModel <- lm(price ~ time, data = list1) # 译者注:线性模型,数据集为list1,以价格对时间做相关分析模型 504 | linearModel # 拟合结果 505 | # 将拟合结果展示在图上,颜色设为红色 506 | abline(linearModel, col = "red") 507 | # 也可以获取各种各样漂亮的分析图 508 | plot(linearModel) 509 | 510 | # 直方图 511 | hist(rpois(n = 10000, lambda = 5), col = "thistle") # 译者注:统计频数直方图 512 | 513 | # 柱状图 514 | barplot(c(1,4,5,1,2), names.arg = c("red","blue","purple","green","yellow")) 515 | 516 | # 可以尝试着使用 ggplot2 程序包来美化图片 517 | install.packages("ggplot2") 518 | require(ggplot2) 519 | ?ggplot2 520 | -------------------------------------------------------------------------------- /learnruby-cn.rb: -------------------------------------------------------------------------------- 1 | 2 | # 这是单行注释 3 | 4 | =begin 5 | 这是多行注释 6 | 没人用这个 7 | 你也不该用 8 | =end 9 | 10 | # 首先,也是最重要的,所有东西都是对象 11 | 12 | # 数字是对象 13 | 14 | 3.class #=> Fixnum 15 | 16 | 3.to_s #=> "3" 17 | 18 | 19 | # 一些基本的算术符号 20 | 1 + 1 #=> 2 21 | 8 - 1 #=> 7 22 | 10 * 2 #=> 20 23 | 35 / 5 #=> 7 24 | 25 | # 算术符号只是语法糖而已 26 | # 实际上是调用对象的方法 27 | 1.+(3) #=> 4 28 | 10.* 5 #=> 50 29 | 30 | # 特殊的值也是对象 31 | nil # 空 32 | true # 真 33 | false # 假 34 | 35 | nil.class #=> NilClass 36 | true.class #=> TrueClass 37 | false.class #=> FalseClass 38 | 39 | # 相等运算符 40 | 1 == 1 #=> true 41 | 2 == 1 #=> false 42 | 43 | # 不等运算符 44 | 1 != 1 #=> false 45 | 2 != 1 #=> true 46 | !true #=> false 47 | !false #=> true 48 | 49 | # 除了false自己,nil是唯一的值为false的对象 50 | 51 | !nil #=> true 52 | !false #=> true 53 | !0 #=> false 54 | 55 | # 更多比较 56 | 1 < 10 #=> true 57 | 1 > 10 #=> false 58 | 2 <= 2 #=> true 59 | 2 >= 2 #=> true 60 | 61 | # 字符串是对象 62 | 63 | 'I am a string'.class #=> String 64 | "I am a string too".class #=> String 65 | 66 | placeholder = "use string interpolation" 67 | "I can #{placeholder} when using double quoted strings" 68 | #=> "I can use string interpolation when using double quoted strings" 69 | 70 | 71 | # 输出值 72 | puts "I'm printing!" 73 | 74 | # 变量 75 | x = 25 #=> 25 76 | x #=> 25 77 | 78 | # 注意赋值语句返回了赋的值 79 | # 这意味着你可以用多重赋值语句 80 | 81 | x = y = 10 #=> 10 82 | x #=> 10 83 | y #=> 10 84 | 85 | # 按照惯例,用 snake_case 作为变量名 86 | snake_case = true 87 | 88 | # 使用具有描述性的运算符 89 | path_to_project_root = '/good/name/' 90 | path = '/bad/name/' 91 | 92 | # 符号(Symbols,也是对象) 93 | # 符号是不可变的,内部用整数类型表示的可重用的值。 94 | # 通常用它代替字符串来有效地表示有意义的值。 95 | 96 | 97 | :pending.class #=> Symbol 98 | 99 | status = :pending 100 | 101 | status == :pending #=> true 102 | 103 | status == 'pending' #=> false 104 | 105 | status == :approved #=> false 106 | 107 | # 数组 108 | 109 | # 这是一个数组 110 | [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5] 111 | 112 | # 数组可以包含不同类型的元素 113 | 114 | array = [1, "hello", false] #=> => [1, "hello", false] 115 | 116 | # 数组可以被索引 117 | # 从前面开始 118 | array[0] #=> 1 119 | array[12] #=> nil 120 | 121 | # 像运算符一样,[var]形式的访问 122 | # 也就是一个语法糖 123 | # 实际上是调用对象的[] 方法 124 | array.[] 0 #=> 1 125 | array.[] 12 #=> nil 126 | 127 | # 从尾部开始 128 | array[-1] #=> 5 129 | 130 | # 同时指定开始的位置和结束的位置 131 | array[2, 4] #=> [3, 4, 5] 132 | 133 | # 或者指定一个范围 134 | array[1..3] #=> [2, 3, 4] 135 | 136 | # 像这样往数组增加一个元素 137 | array << 6 #=> [1, 2, 3, 4, 5, 6] 138 | 139 | # 哈希表是Ruby的键值对的基本数据结构 140 | # 哈希表由大括号定义 141 | hash = {'color' => 'green', 'number' => 5} 142 | 143 | hash.keys #=> ['color', 'number'] 144 | 145 | # 哈希表可以通过键快速地查询 146 | hash['color'] #=> 'green' 147 | hash['number'] #=> 5 148 | 149 | # 查询一个不存在地键将会返回nil 150 | hash['nothing here'] #=> nil 151 | 152 | # 用 #each 方法来枚举哈希表: 153 | hash.each do |k, v| 154 | puts "#{k} is #{v}" 155 | end 156 | 157 | # 从Ruby 1.9开始, 用符号作为键的时候有特别的记号表示: 158 | 159 | new_hash = { defcon: 3, action: true} 160 | 161 | new_hash.keys #=> [:defcon, :action] 162 | 163 | # 小贴士:数组和哈希表都是可枚举的 164 | # 它们可以共享一些有用的方法,比如each, map, count 等等 165 | 166 | # 控制流 167 | 168 | if true 169 | "if statement" 170 | elsif false 171 | "else if, optional" 172 | else 173 | "else, also optional" 174 | end 175 | 176 | for counter in 1..5 177 | puts "iteration #{counter}" 178 | end 179 | #=> iteration 1 180 | #=> iteration 2 181 | #=> iteration 3 182 | #=> iteration 4 183 | #=> iteration 5 184 | 185 | # 然而 186 | # 没人用for循环 187 | # 用`each`来代替,就像这样 188 | 189 | (1..5).each do |counter| 190 | puts "iteration #{counter}" 191 | end 192 | #=> iteration 1 193 | #=> iteration 2 194 | #=> iteration 3 195 | #=> iteration 4 196 | #=> iteration 5 197 | 198 | counter = 1 199 | while counter <= 5 do 200 | puts "iteration #{counter}" 201 | counter += 1 202 | end 203 | #=> iteration 1 204 | #=> iteration 2 205 | #=> iteration 3 206 | #=> iteration 4 207 | #=> iteration 5 208 | 209 | grade = 'B' 210 | 211 | case grade 212 | when 'A' 213 | puts "Way to go kiddo" 214 | when 'B' 215 | puts "Better luck next time" 216 | when 'C' 217 | puts "You can do better" 218 | when 'D' 219 | puts "Scraping through" 220 | when 'F' 221 | puts "You failed!" 222 | else 223 | puts "Alternative grading system, eh?" 224 | end 225 | 226 | # 函数 227 | 228 | def double(x) 229 | x * 2 230 | end 231 | 232 | # 函数 (以及所有的方法块) 隐式地返回了最后语句的值 233 | double(2) #=> 4 234 | 235 | # 当不存在歧义的时候括号是可有可无的 236 | double 3 #=> 6 237 | 238 | double double 3 #=> 12 239 | 240 | def sum(x,y) 241 | x + y 242 | end 243 | 244 | # 方法的参数通过逗号分隔 245 | sum 3, 4 #=> 7 246 | 247 | sum sum(3,4), 5 #=> 12 248 | 249 | # yield 250 | # 所有的方法都有一个隐式的块参数 251 | # 可以用yield参数调用 252 | 253 | def surround 254 | puts "{" 255 | yield 256 | puts "}" 257 | end 258 | 259 | surround { puts 'hello world' } 260 | 261 | # { 262 | # hello world 263 | # } 264 | 265 | 266 | # 用class关键字定义一个类 267 | class Human 268 | 269 | # 一个类变量,它被这个类地所有实例变量共享 270 | @@species = "H. sapiens" 271 | 272 | # 构造函数 273 | def initialize(name, age=0) 274 | # 将参数name的值赋给实例变量@name 275 | @name = name 276 | # 如果没有给出age, 那么会采用参数列表中地默认地值 277 | @age = age 278 | end 279 | 280 | # 基本的 setter 方法 281 | def name=(name) 282 | @name = name 283 | end 284 | 285 | # 基本地 getter 方法 286 | def name 287 | @name 288 | end 289 | 290 | # 一个类方法以self.开头 291 | # 它可以被类调用,但不能被类的实例调用 292 | def self.say(msg) 293 | puts "#{msg}" 294 | end 295 | 296 | def species 297 | @@species 298 | end 299 | 300 | end 301 | 302 | 303 | # 类的例子 304 | jim = Human.new("Jim Halpert") 305 | 306 | dwight = Human.new("Dwight K. Schrute") 307 | 308 | # 让我们来调用一些方法 309 | jim.species #=> "H. sapiens" 310 | jim.name #=> "Jim Halpert" 311 | jim.name = "Jim Halpert II" #=> "Jim Halpert II" 312 | jim.name #=> "Jim Halpert II" 313 | dwight.species #=> "H. sapiens" 314 | dwight.name #=> "Dwight K. Schrute" 315 | 316 | # 调用对象的方法 317 | Human.say("Hi") #=> "Hi" 318 | -------------------------------------------------------------------------------- /learnswift-cn.swift: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // 基础 4 | // 5 | 6 | println("Hello, world") 7 | var myVariable = 42 8 | let myConstant = 3.1415926 9 | let explicitDouble: Double = 70 10 | let label = "some text " + String(myVariable) // Casting 11 | let piText = "Pi = \(myConstant)" // String interpolation 12 | var optionalString: String? = "optional" // Can be nil 13 | optionalString = nil 14 | 15 | 16 | // 17 | // 数组与字典(关联数组) 18 | // 19 | 20 | // 数组 21 | var shoppingList = ["catfish", "water", "lemons"] 22 | shoppingList[1] = "bottle of water" 23 | let emptyArray = String[]() 24 | 25 | // 字典 26 | var occupations = [ 27 | "Malcolm": "Captain", 28 | "kaylee": "Mechanic" 29 | ] 30 | occupations["Jayne"] = "Public Relations" 31 | let emptyDictionary = Dictionary() 32 | 33 | 34 | // 35 | // 控制流 36 | // 37 | 38 | // 用于数组的for 循环 39 | let myArray = [1, 1, 2, 3, 5] 40 | for value in myArray { 41 | if value == 1 { 42 | println("One!") 43 | } else { 44 | println("Not one!") 45 | } 46 | } 47 | 48 | // 用于字典的for 循环 49 | for (key, value) in dict { 50 | println("\(key): \(value)") 51 | } 52 | 53 | // 用于区间的for 循环 54 | for i in -1...1 { // [-1, 0, 1] 55 | println(i) 56 | } 57 | // 使用 .. 表示的区间不包含最后一个元素 [-1,0,1) 58 | 59 | // while 循环 60 | var i = 1 61 | while i < 1000 { 62 | i *= 2 63 | } 64 | 65 | // do-while 循环 66 | do { 67 | println("hello") 68 | } while 1 == 2 69 | 70 | // Switch 71 | let vegetable = "red pepper" 72 | switch vegetable { 73 | case "celery": 74 | let vegetableComment = "Add some raisins and make ants on a log." 75 | case "cucumber", "watercress": 76 | let vegetableComment = "That would make a good tea sandwich." 77 | case let x where x.hasSuffix("pepper"): 78 | let vegetableComment = "Is it a spicy \(x)?" 79 | default: // 必须 (为了覆盖所有可能的输入) 80 | let vegetableComment = "Everything tastes good in soup." 81 | } 82 | 83 | 84 | // 85 | // 函数 86 | // 87 | 88 | // 函数是一等类型,这意味着可以在函数中构建函数 89 | // 并且可以被传递 90 | 91 | // 函数 92 | func greet(name: String, day: String) -> String { 93 | return "Hello \(name), today is \(day)." 94 | } 95 | greet("Bob", "Tuesday") 96 | 97 | // 使用多元数组返回多返回值的函数 98 | func getGasPrices() -> (Double, Double, Double) { 99 | return (3.59, 3.69, 3.79) 100 | } 101 | 102 | // 不定参数 103 | func setup(numbers: Int...) {} 104 | 105 | // 传递、返回函数 106 | func makeIncrementer() -> (Int -> Int) { 107 | func addOne(number: Int) -> Int { 108 | return 1 + number 109 | } 110 | return addOne 111 | } 112 | var increment = makeIncrementer() 113 | increment(7) 114 | 115 | 116 | // 117 | // 闭包 118 | // 119 | 120 | // 函数是特殊的闭包({}) 121 | 122 | // 闭包示例. 123 | // `->` 分隔参数和返回类型 124 | // `in` 分隔闭包头和闭包体 125 | numbers.map({ 126 | (number: Int) -> Int in 127 | let result = 3 * number 128 | return result 129 | }) 130 | 131 | // 当类型已知时,可以这样做: 132 | var numbers = [1, 2, 6] 133 | numbers = numbers.map({ number in 3 * number }) 134 | print(numbers) // [3, 6, 18] 135 | 136 | 137 | // 138 | // 类 139 | // 140 | 141 | // 类的全部方法和属性都是public 的 142 | // 如果你在一个数据结构中只需储存数据, 143 | // 应使用 `struct` 144 | 145 | // 集成自`Shape` 类的简单的类`Square 146 | class Rect: Shape { 147 | var sideLength: Int = 1 148 | 149 | // Custom getter and setter property 150 | var perimeter: Int { 151 | get { 152 | return 4 * sideLength 153 | } 154 | set { 155 | sideLength = newValue / 4 156 | } 157 | } 158 | 159 | init(sideLength: Int) { 160 | super.init() 161 | self.sideLength = sideLength 162 | } 163 | 164 | func shrink() { 165 | if sideLength > 0 { 166 | --sideLength 167 | } 168 | } 169 | 170 | override func getArea() -> Int { 171 | return sideLength * sideLength 172 | } 173 | } 174 | var mySquare = new Square(sideLength: 5) 175 | print(mySquare.getArea()) // 25 176 | mySquare.shrink() 177 | print(mySquare.sideLength) // 4 178 | 179 | // 如果你不需要自定义getter 和setter, 180 | // 但仍希望在获取或设置一个属性之前或之后运行 181 | // 一些代码,你可以使用`willSet` 和 `didSet` 182 | 183 | 184 | // 185 | // 枚举类型 186 | // 187 | 188 | // 枚举类型可以是某种指定的类型,抑或自成一种类型 189 | // 像类一样,枚举类型可以包含方法 190 | 191 | enum Suit { 192 | case Spades, Hearts, Diamonds, Clubs 193 | func getIcon() -> String { 194 | switch self { 195 | case .Spades: return "♤" 196 | case .Hearts: return "♡" 197 | case .Diamonds: return "♢" 198 | case .Clubs: return "♧" 199 | } 200 | } 201 | } 202 | 203 | 204 | // 205 | // 其它 206 | // 207 | 208 | // `协议(protocol)`: 与Java 的接口(Interface) 类似. 209 | // `扩展(extension)`: 为现有类型添加额外特性 210 | // 泛型: 与Java 相似。使用`where` 关键字指定 211 | // 泛型的要求. 212 | --------------------------------------------------------------------------------