├── .gitattributes ├── .gitignore ├── Algorithms ├── .gitignore ├── README.md ├── dynamic-programming-cn.html.markdown └── java-cn.html.markdown ├── CSAPP ├── c++-cn.html.markdown └── c-cn.html.markdown ├── Emacs ├── elisp-cn.html.markdown └── vim-cn.html.markdown ├── GitHub入门与实践 ├── README.md ├── git-cn.html.markdown └── 《GitHub入门与实践》 笔记.md ├── SICP ├── README.md ├── Racket │ ├── README.md │ ├── my-2048.rkt │ ├── qsort2.rkt │ └── utility.rkt ├── SICP终于看完了,有一些经验想分享出来.md ├── chapter 1 │ ├── 1.11.rkt │ ├── 1.16.rkt │ ├── 1.18.rkt │ ├── 1.19.rkt │ ├── 1.23.rkt │ ├── 1.28.rkt │ ├── 1.29.rkt │ ├── 1.32.rkt │ ├── 1.33.rkt │ ├── 1.37.rkt │ ├── 1.40.rkt │ ├── 1.42.rkt │ ├── 1.43.rkt │ ├── 1.44.rkt │ └── 1.8.rkt ├── chapter 2 │ ├── 2.17.rkt │ ├── 2.18.rkt │ ├── 2.2 Nested Mappings.rkt │ ├── 2.20.rkt │ ├── 2.27.rkt │ ├── 2.40.rkt │ └── 2.41.rkt ├── common-lisp-cn.html.markdown ├── common.rkt ├── racket-cn.html.markdown └── 程序设计技术和方法 │ ├── sicp00.pdf │ ├── sicp01-1.pdf │ ├── sicp01-2.pdf │ ├── sicp01-3.pdf │ ├── sicp02-1.pdf │ ├── sicp02-2.pdf │ ├── sicp02-3.pdf │ ├── sicp03-1.pdf │ ├── sicp03-2.pdf │ ├── sicp03-3.pdf │ ├── sicp03-4.pdf │ ├── sicp04-1.pdf │ ├── sicp04-2.pdf │ ├── sicp04-3.pdf │ ├── sicp04-4.pdf │ ├── sicp05-1.pdf │ ├── summary.pdf │ └── 《程序设计技术和方法》作业.png ├── readme.md └── web ├── csharp-cn.html.markdown ├── html-cn.html.markdown ├── javascript-cn.html.markdown ├── jquery-cn.html.markdown ├── php-cn.html.markdown ├── ruby-cn.html.markdown ├── sass-cn.html.markdown └── xml-cn.html.markdown /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | SICP/sicp/* 2 | SICP/.vscode/* 3 | -------------------------------------------------------------------------------- /Algorithms/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/* 2 | 3 | 4 | -------------------------------------------------------------------------------- /Algorithms/README.md: -------------------------------------------------------------------------------- 1 | [Algorithms, 4th Edition](http://algs4.cs.princeton.edu/home/) 2 | 3 | [算法(第4版)](http://www.ituring.com.cn/book/875) 4 | 5 | -------------------------------------------------------------------------------- /Algorithms/dynamic-programming-cn.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | category: Algorithms & Data Structures 3 | name: Dynamic Programming 4 | contributors: 5 | - ["Akashdeep Goel", "http://github.com/akashdeepgoel"] 6 | filename: dynamic-programming-cn.html.markdown 7 | lang: zh-cn 8 | translators: 9 | - ["EtaoinWu", "https://github.com/EtaoinWu"] 10 | --- 11 | 12 | # 动态规划 13 | 14 | ## 简介 15 | 16 | 动态规划是一种实用的技巧,它可以用来解决一系列特定问题。它的思路很简单,如果你对某个给定的输入解决了一个问题,那么你可以保存已有信息,以避免重复计算,节约计算时间。 17 | 18 | 记住,只有那些没有办法记住历史的才被迫做更多的苦力。(Fibonacci就是一个显然的例子) 19 | 20 | ## 解决问题的方式 21 | 22 | 1. *自顶向下* : 利用分支策略分解问题。如果你已经解决过当前子问题了,那么就返回已有信息。如果当前子问题没有计算过,那么就对它进行计算。这样的方法很易于思考、很直观。这被称作“记忆化”。 23 | 24 | 2. *自底向上* : 首先分析问题,将问题分解为不同规模的问题,并决定它们的顺序,按顺序计算,直到解决给定规模的问题。这样的流程可以保证在解决较大的问题之前解决(它所依赖的)较小的问题。这种流程被称作“动态规划”。 25 | 26 | ## 动态规划的例子 27 | 28 | 最长上升子序列问题。给定`S= {a[1] , a[2] , a[3], a[4], ............., a[n-1], a[n] }`,求出一个子序列,使得对于所有在这个子序列中所有满足`j a[j] and dp[i] 来声明变量 53 | // 字节类型 - 8位补码表示 54 | // (-128 <= 字节 <= 127) 55 | byte fooByte = 100; 56 | 57 | // 短整型 - 16位补码表示 58 | // (-32,768 <= 短整型 <= 32,767) 59 | short fooShort = 10000; 60 | 61 | // 整型 - 32位补码表示 62 | // (-2,147,483,648 <= 整型 <= 2,147,483,647) 63 | int fooInt = 1; 64 | 65 | // 长整型 - 64位补码表示 66 | // (-9,223,372,036,854,775,808 <= 长整型 <= 9,223,372,036,854,775,807) 67 | long fooLong = 100000L; 68 | // L可以用来表示一个数字是长整型的。 69 | // 其他的数字都默认为整型。 70 | 71 | // 注意:Java中没有无符号类型 72 | 73 | // 浮点型 - 即 IEEE 754 规定的32位单精度浮点类型 74 | float fooFloat = 234.5f; 75 | // f用来表示一个数字是浮点型的。 76 | // 否则会被默认当做是双精度浮点型。 77 | 78 | // 双精度浮点型 - 即 IEEE 754 规定的64位双精度浮点类型 79 | double fooDouble = 123.4; 80 | 81 | // 布尔类型 - true 与 false 82 | boolean fooBoolean = true; 83 | boolean barBoolean = false; 84 | 85 | // 字符类型 - 16位 Unicode编码字符 86 | char fooChar = 'A'; 87 | 88 | // 用 final 可以使一个常量不可更改 89 | final int HOURS_I_WORK_PER_WEEK = 9001; 90 | 91 | // 字符串 92 | String fooString = "My String Is Here!"; 93 | 94 | // \n 代表一个新的换行 95 | String barString = "Printing on a new line?\nNo Problem!"; 96 | // \t 代表一个新的制表符 97 | String bazString = "Do you want to add a tab?\tNo Problem!"; 98 | System.out.println(fooString); 99 | System.out.println(barString); 100 | System.out.println(bazString); 101 | 102 | // 数组 103 | // 数组在声明时大小必须已经确定 104 | // 数组的声明格式: 105 | //<数据类型> [] <变量名> = new <数据类型>[<数组大小>]; 106 | int [] intArray = new int[10]; 107 | String [] stringArray = new String[1]; 108 | boolean [] booleanArray = new boolean[100]; 109 | 110 | // 声明并初始化数组也可以这样: 111 | int [] intArray = {9000, 1000, 1337}; 112 | 113 | // 随机访问数组中的元素 114 | System.out.println("intArray @ 0: " + intArray[0]); 115 | 116 | // 数组下标从0开始并且可以被更改 117 | intArray[1] = 1; 118 | System.out.println("intArray @ 1: " + intArray[1]); // => 1 119 | 120 | // 其他数据类型 121 | // ArrayLists - 类似于数组,但是功能更多,并且大小也可以改变 122 | // LinkedLists 123 | // Maps 124 | // HashMaps 125 | 126 | /////////////////////////////////////// 127 | // 操作符 128 | /////////////////////////////////////// 129 | System.out.println("\n->Operators"); 130 | 131 | int i1 = 1, i2 = 2; // 多重声明可以简化 132 | 133 | // 算数运算 134 | System.out.println("1+2 = " + (i1 + i2)); // => 3 135 | System.out.println("2-1 = " + (i2 - i1)); // => 1 136 | System.out.println("2*1 = " + (i2 * i1)); // => 2 137 | System.out.println("1/2 = " + (i1 / i2)); // => 0 (0.5 truncated down) 138 | 139 | // 取余 140 | System.out.println("11%3 = "+(11 % 3)); // => 2 141 | 142 | // 比较操作符 143 | System.out.println("3 == 2? " + (3 == 2)); // => false 144 | System.out.println("3 != 2? " + (3 != 2)); // => true 145 | System.out.println("3 > 2? " + (3 > 2)); // => true 146 | System.out.println("3 < 2? " + (3 < 2)); // => false 147 | System.out.println("2 <= 2? " + (2 <= 2)); // => true 148 | System.out.println("2 >= 2? " + (2 >= 2)); // => true 149 | 150 | // 位运算操作符 151 | /* 152 | ~ 取反,求反码 153 | << 带符号左移 154 | >> 带符号右移 155 | >>> 无符号右移 156 | & 和 157 | ^ 异或 158 | | 相容或 159 | */ 160 | 161 | // 自增 162 | int i = 0; 163 | System.out.println("\n->Inc/Dec-rementation"); 164 | // ++ 和 -- 操作符使变量加或减1。放在变量前面或者后面的区别是整个表达 165 | // 式的返回值。操作符在前面时,先加减,后取值。操作符在后面时,先取值 166 | // 后加减。 167 | System.out.println(i++); // 后自增 i = 1, 输出0 168 | System.out.println(++i); // 前自增 i = 2, 输出2 169 | System.out.println(i--); // 后自减 i = 1, 输出2 170 | System.out.println(--i); // 前自减 i = 0, 输出0 171 | 172 | /////////////////////////////////////// 173 | // 控制结构 174 | /////////////////////////////////////// 175 | System.out.println("\n->Control Structures"); 176 | 177 | // If语句和C的类似 178 | int j = 10; 179 | if (j == 10){ 180 | System.out.println("I get printed"); 181 | } else if (j > 10) { 182 | System.out.println("I don't"); 183 | } else { 184 | System.out.println("I also don't"); 185 | } 186 | 187 | // While循环 188 | int fooWhile = 0; 189 | while(fooWhile < 100) 190 | { 191 | //System.out.println(fooWhile); 192 | //增加计数器 193 | //遍历99次, fooWhile 0->99 194 | fooWhile++; 195 | } 196 | System.out.println("fooWhile Value: " + fooWhile); 197 | 198 | // Do While循环 199 | int fooDoWhile = 0; 200 | do 201 | { 202 | //System.out.println(fooDoWhile); 203 | //增加计数器 204 | //遍历99次, fooDoWhile 0->99 205 | fooDoWhile++; 206 | }while(fooDoWhile < 100); 207 | System.out.println("fooDoWhile Value: " + fooDoWhile); 208 | 209 | // For 循环 210 | int fooFor; 211 | //for 循环结构 => for(<起始语句>; <循环进行的条件>; <步长>) 212 | for(fooFor=0; fooFor<10; fooFor++){ 213 | //System.out.println(fooFor); 214 | //遍历 10 次, fooFor 0->9 215 | } 216 | System.out.println("fooFor Value: " + fooFor); 217 | 218 | // Switch Case 语句 219 | // switch可以用来处理 byte, short, char, 和 int 数据类型 220 | // 也可以用来处理枚举类型,字符串类,和原始数据类型的包装类: 221 | // Character, Byte, Short, 和 Integer 222 | int month = 3; 223 | String monthString; 224 | switch (month){ 225 | case 1: 226 | monthString = "January"; 227 | break; 228 | case 2: 229 | monthString = "February"; 230 | break; 231 | case 3: 232 | monthString = "March"; 233 | break; 234 | default: 235 | monthString = "Some other month"; 236 | break; 237 | } 238 | System.out.println("Switch Case Result: " + monthString); 239 | 240 | 241 | /////////////////////////////////////// 242 | // 类型转换 243 | /////////////////////////////////////// 244 | 245 | // 数据转换 246 | 247 | // 将字符串转换为整型 248 | Integer.parseInt("123");//返回整数123 249 | 250 | // 将整型转换为字符串 251 | Integer.toString(123);//返回字符串"123" 252 | 253 | // 其他的数据也可以进行互相转换: 254 | // Double 255 | // Long 256 | // String 257 | 258 | // 类型转换 259 | // 你也可以对java对象进行类型转换, 但其中会牵扯到很多概念 260 | // 在这里可以查看更详细的信息: 261 | // http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html 262 | 263 | 264 | /////////////////////////////////////// 265 | // 类与函数 266 | /////////////////////////////////////// 267 | 268 | System.out.println("\n->Classes & Functions"); 269 | 270 | // (Bicycle类定义如下) 271 | 272 | // 用new来实例化一个类 273 | Bicycle trek = new Bicycle(); 274 | 275 | // 调用对象的方法 276 | trek.speedUp(3); // 需用getter和setter方法 277 | trek.setCadence(100); 278 | 279 | // toString 可以把对象转换为字符串 280 | System.out.println("trek info: " + trek.toString()); 281 | 282 | } // main 方法结束 283 | } // LearnJava 类结束 284 | 285 | 286 | // 你也可以把其他的非public类放入到.java文件中 287 | 288 | 289 | // 类定义的语法: 290 | // class <类名>{ 291 | // //成员变量, 构造函数, 函数 292 | // //Java中函数被称作方法 293 | // } 294 | 295 | class Bicycle { 296 | 297 | // Bicycle 类的成员变量和方法 298 | public int cadence; // Public: 任意位置均可访问 299 | private int speed; // Private: 只在同类中可以访问 300 | protected int gear; // Protected: 可以在同类与子类中可以访问 301 | String name; // default: 可以在包内中可以访问 302 | 303 | // 构造函数是初始化一个对象的方式 304 | // 以下是一个默认构造函数 305 | public Bicycle() { 306 | gear = 1; 307 | cadence = 50; 308 | speed = 5; 309 | name = "Bontrager"; 310 | } 311 | 312 | // 以下是一个含有参数的构造函数 313 | public Bicycle(int startCadence, int startSpeed, int startGear, String name) { 314 | this.gear = startGear; 315 | this.cadence = startCadence; 316 | this.speed = startSpeed; 317 | this.name = name; 318 | } 319 | 320 | // 函数语法: 321 | // <返回值类型> <函数名称>(<参数列表>) 322 | 323 | // Java类中经常会用getter和setter来对成员变量进行操作 324 | 325 | // 方法声明的语法: 326 | // <作用域> <返回值类型> <方法名>(<参数列表>) 327 | public int getCadence() { 328 | return cadence; 329 | } 330 | 331 | // void返回值函数没有返回值 332 | public void setCadence(int newValue) { 333 | cadence = newValue; 334 | } 335 | 336 | public void setGear(int newValue) { 337 | gear = newValue; 338 | } 339 | 340 | public void speedUp(int increment) { 341 | speed += increment; 342 | } 343 | 344 | public void slowDown(int decrement) { 345 | speed -= decrement; 346 | } 347 | 348 | public void setName(String newName) { 349 | name = newName; 350 | } 351 | 352 | public String getName() { 353 | return name; 354 | } 355 | 356 | //返回对象属性的方法 357 | @Override 358 | public String toString() { 359 | return "gear: " + gear + 360 | " cadence: " + cadence + 361 | " speed: " + speed + 362 | " name: " + name; 363 | } 364 | } // Bicycle 类结束 365 | 366 | // PennyFarthing 是 Bicycle 的子类 367 | class PennyFarthing extends Bicycle { 368 | // (Penny Farthings 是前轮很大的 Bicycle, 并且没有齿轮) 369 | 370 | public PennyFarthing(int startCadence, int startSpeed){ 371 | // 通过super调用父类的构造函数 372 | super(startCadence, startSpeed, 0, "PennyFarthing"); 373 | } 374 | 375 | // 你可以用@注释来表示需要重载的方法 376 | // 了解更多的注释使用方法,可以访问下面的地址: 377 | // http://docs.oracle.com/javase/tutorial/java/annotations/ 378 | @Override 379 | public void setGear(int gear) { 380 | gear = 0; 381 | } 382 | 383 | } 384 | 385 | ``` 386 | 387 | ## 更多阅读 388 | 389 | 下面的链接只是为了便于大家理解这些主题而给出的,对于具体的例子请大家自行Google 390 | 391 | 其他主题: 392 | 393 | * [Java 官方教程](http://docs.oracle.com/javase/tutorial/index.html) 394 | 395 | * [Java 访问修饰符](http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html) 396 | 397 | * [面向对象程序设计概念](http://docs.oracle.com/javase/tutorial/java/concepts/index.html): 398 | * [继承](http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html) 399 | * [多态](http://docs.oracle.com/javase/tutorial/java/IandI/polymorphism.html) 400 | * [抽象](http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html) 401 | 402 | * [异常](http://docs.oracle.com/javase/tutorial/essential/exceptions/index.html) 403 | 404 | * [接口](http://docs.oracle.com/javase/tutorial/java/IandI/createinterface.html) 405 | 406 | * [泛型](http://docs.oracle.com/javase/tutorial/java/generics/index.html) 407 | 408 | * [Java代码规范](http://www.oracle.com/technetwork/java/codeconvtoc-136057.html) 409 | -------------------------------------------------------------------------------- /CSAPP/c++-cn.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | language: c++ 3 | filename: learncpp-cn.cpp 4 | contributors: 5 | - ["Steven Basart", "http://github.com/xksteven"] 6 | - ["Matt Kline", "https://github.com/mrkline"] 7 | translators: 8 | - ["Arnie97", "https://github.com/Arnie97"] 9 | lang: zh-cn 10 | --- 11 | 12 | C++是一种系统编程语言。用它的发明者, 13 | [Bjarne Stroustrup的话](http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2014/Keynote)来说,C++的设计目标是: 14 | 15 | - 成为“更好的C语言” 16 | - 支持数据的抽象与封装 17 | - 支持面向对象编程 18 | - 支持泛型编程 19 | 20 | C++提供了对硬件的紧密控制(正如C语言一样), 21 | 能够编译为机器语言,由处理器直接执行。 22 | 与此同时,它也提供了泛型、异常和类等高层功能。 23 | 虽然C++的语法可能比某些出现较晚的语言更复杂,它仍然得到了人们的青睞—— 24 | 功能与速度的平衡使C++成为了目前应用最广泛的系统编程语言之一。 25 | 26 | ```c++ 27 | //////////////// 28 | // 与C语言的比较 29 | //////////////// 30 | 31 | // C++_几乎_是C语言的一个超集,它与C语言的基本语法有许多相同之处, 32 | // 例如变量和函数的声明,原生数据类型等等。 33 | 34 | // 和C语言一样,在C++中,你的程序会从main()开始执行, 35 | // 该函数的返回值应当为int型,这个返回值会作为程序的退出状态值。 36 | // 不过,大多数的编译器(gcc,clang等)也接受 void main() 的函数原型。 37 | // (参见 http://en.wikipedia.org/wiki/Exit_status 来获取更多信息) 38 | int main(int argc, char** argv) 39 | { 40 | // 和C语言一样,命令行参数通过argc和argv传递。 41 | // argc代表命令行参数的数量, 42 | // 而argv是一个包含“C语言风格字符串”(char *)的数组, 43 | // 其中每个字符串代表一个命令行参数的内容, 44 | // 首个命令行参数是调用该程序时所使用的名称。 45 | // 如果你不关心命令行参数的值,argc和argv可以被忽略。 46 | // 此时,你可以用int main()作为函数原型。 47 | 48 | // 退出状态值为0时,表示程序执行成功 49 | return 0; 50 | } 51 | 52 | // 然而,C++和C语言也有一些区别: 53 | 54 | // 在C++中,字符字面量的大小是一个字节。 55 | sizeof('c') == 1 56 | 57 | // 在C语言中,字符字面量的大小与int相同。 58 | sizeof('c') == sizeof(10) 59 | 60 | 61 | // C++的函数原型与函数定义是严格匹配的 62 | void func(); // 这个函数不能接受任何参数 63 | 64 | // 而在C语言中 65 | void func(); // 这个函数能接受任意数量的参数 66 | 67 | // 在C++中,用nullptr代替C语言中的NULL 68 | int* ip = nullptr; 69 | 70 | // C++也可以使用C语言的标准头文件, 71 | // 但是需要加上前缀“c”并去掉末尾的“.h”。 72 | #include 73 | 74 | int main() 75 | { 76 | printf("Hello, world!\n"); 77 | return 0; 78 | } 79 | 80 | /////////// 81 | // 函数重载 82 | /////////// 83 | 84 | // C++支持函数重载,你可以定义一组名称相同而参数不同的函数。 85 | 86 | void print(char const* myString) 87 | { 88 | printf("String %s\n", myString); 89 | } 90 | 91 | void print(int myInt) 92 | { 93 | printf("My int is %d", myInt); 94 | } 95 | 96 | int main() 97 | { 98 | print("Hello"); // 解析为 void print(const char*) 99 | print(15); // 解析为 void print(int) 100 | } 101 | 102 | /////////////////// 103 | // 函数参数的默认值 104 | /////////////////// 105 | 106 | // 你可以为函数的参数指定默认值, 107 | // 它们将会在调用者没有提供相应参数时被使用。 108 | 109 | void doSomethingWithInts(int a = 1, int b = 4) 110 | { 111 | // 对两个参数进行一些操作 112 | } 113 | 114 | int main() 115 | { 116 | doSomethingWithInts(); // a = 1, b = 4 117 | doSomethingWithInts(20); // a = 20, b = 4 118 | doSomethingWithInts(20, 5); // a = 20, b = 5 119 | } 120 | 121 | // 默认参数必须放在所有的常规参数之后。 122 | 123 | void invalidDeclaration(int a = 1, int b) // 这是错误的! 124 | { 125 | } 126 | 127 | 128 | /////////// 129 | // 命名空间 130 | /////////// 131 | 132 | // 命名空间为变量、函数和其他声明提供了分离的的作用域。 133 | // 命名空间可以嵌套使用。 134 | 135 | namespace First { 136 | namespace Nested { 137 | void foo() 138 | { 139 | printf("This is First::Nested::foo\n"); 140 | } 141 | } // 结束嵌套的命名空间Nested 142 | } // 结束命名空间First 143 | 144 | namespace Second { 145 | void foo() 146 | { 147 | printf("This is Second::foo\n") 148 | } 149 | } 150 | 151 | void foo() 152 | { 153 | printf("This is global foo\n"); 154 | } 155 | 156 | int main() 157 | { 158 | // 如果没有特别指定,就从“Second”中取得所需的内容。 159 | using namespace Second; 160 | 161 | foo(); // 显示“This is Second::foo” 162 | First::Nested::foo(); // 显示“This is First::Nested::foo” 163 | ::foo(); // 显示“This is global foo” 164 | } 165 | 166 | //////////// 167 | // 输入/输出 168 | //////////// 169 | 170 | // C++使用“流”来输入输出。<<是流的插入运算符,>>是流提取运算符。 171 | // cin、cout、和cerr分别代表 172 | // stdin(标准输入)、stdout(标准输出)和stderr(标准错误)。 173 | 174 | #include // 引入包含输入/输出流的头文件 175 | 176 | using namespace std; // 输入输出流在std命名空间(也就是标准库)中。 177 | 178 | int main() 179 | { 180 | int myInt; 181 | 182 | // 在标准输出(终端/显示器)中显示 183 | cout << "Enter your favorite number:\n"; 184 | // 从标准输入(键盘)获得一个值 185 | cin >> myInt; 186 | 187 | // cout也提供了格式化功能 188 | cout << "Your favorite number is " << myInt << "\n"; 189 | // 显示“Your favorite number is ” 190 | 191 | cerr << "Used for error messages"; 192 | } 193 | 194 | ///////// 195 | // 字符串 196 | ///////// 197 | 198 | // C++中的字符串是对象,它们有很多成员函数 199 | #include 200 | 201 | using namespace std; // 字符串也在std命名空间(标准库)中。 202 | 203 | string myString = "Hello"; 204 | string myOtherString = " World"; 205 | 206 | // + 可以用于连接字符串。 207 | cout << myString + myOtherString; // "Hello World" 208 | 209 | cout << myString + " You"; // "Hello You" 210 | 211 | // C++中的字符串是可变的,具有“值语义”。 212 | myString.append(" Dog"); 213 | cout << myString; // "Hello Dog" 214 | 215 | 216 | ///////////// 217 | // 引用 218 | ///////////// 219 | 220 | // 除了支持C语言中的指针类型以外,C++还提供了_引用_。 221 | // 引用是一种特殊的指针类型,一旦被定义就不能重新赋值,并且不能被设置为空值。 222 | // 使用引用时的语法与原变量相同: 223 | // 也就是说,对引用类型进行解引用时,不需要使用*; 224 | // 赋值时也不需要用&来取地址。 225 | 226 | using namespace std; 227 | 228 | string foo = "I am foo"; 229 | string bar = "I am bar"; 230 | 231 | 232 | string& fooRef = foo; // 建立了一个对foo的引用。 233 | fooRef += ". Hi!"; // 通过引用来修改foo的值 234 | cout << fooRef; // "I am foo. Hi!" 235 | 236 | // 这句话的并不会改变fooRef的指向,其效果与“foo = bar”相同。 237 | // 也就是说,在执行这条语句之后,foo == "I am bar"。 238 | fooRef = bar; 239 | 240 | const string& barRef = bar; // 建立指向bar的常量引用。 241 | // 和C语言中一样,(指针和引用)声明为常量时,对应的值不能被修改。 242 | barRef += ". Hi!"; // 这是错误的,不能修改一个常量引用的值。 243 | 244 | /////////////////// 245 | // 类与面向对象编程 246 | /////////////////// 247 | 248 | // 有关类的第一个示例 249 | #include 250 | 251 | // 声明一个类。 252 | // 类通常在头文件(.h或.hpp)中声明。 253 | class Dog { 254 | // 成员变量和成员函数默认情况下是私有(private)的。 255 | std::string name; 256 | int weight; 257 | 258 | // 在这个标签之后,所有声明都是公有(public)的, 259 | // 直到重新指定“private:”(私有继承)或“protected:”(保护继承)为止 260 | public: 261 | 262 | // 默认的构造器 263 | Dog(); 264 | 265 | // 这里是成员函数声明的一个例子。 266 | // 可以注意到,我们在此处使用了std::string,而不是using namespace std 267 | // 语句using namespace绝不应当出现在头文件当中。 268 | void setName(const std::string& dogsName); 269 | 270 | void setWeight(int dogsWeight); 271 | 272 | // 如果一个函数不对对象的状态进行修改, 273 | // 应当在声明中加上const。 274 | // 这样,你就可以对一个以常量方式引用的对象执行该操作。 275 | // 同时可以注意到,当父类的成员函数需要被子类重写时, 276 | // 父类中的函数必须被显式声明为_虚函数(virtual)_。 277 | // 考虑到性能方面的因素,函数默认情况下不会被声明为虚函数。 278 | virtual void print() const; 279 | 280 | // 函数也可以在class body内部定义。 281 | // 这样定义的函数会自动成为内联函数。 282 | void bark() const { std::cout << name << " barks!\n" } 283 | 284 | // 除了构造器以外,C++还提供了析构器。 285 | // 当一个对象被删除或者脱离其定义域时,它的析构函数会被调用。 286 | // 这使得RAII这样的强大范式(参见下文)成为可能。 287 | // 为了衍生出子类来,基类的析构函数必须定义为虚函数。 288 | virtual ~Dog(); 289 | 290 | }; // 在类的定义之后,要加一个分号 291 | 292 | // 类的成员函数通常在.cpp文件中实现。 293 | void Dog::Dog() 294 | { 295 | std::cout << "A dog has been constructed\n"; 296 | } 297 | 298 | // 对象(例如字符串)应当以引用的形式传递, 299 | // 对于不需要修改的对象,最好使用常量引用。 300 | void Dog::setName(const std::string& dogsName) 301 | { 302 | name = dogsName; 303 | } 304 | 305 | void Dog::setWeight(int dogsWeight) 306 | { 307 | weight = dogsWeight; 308 | } 309 | 310 | // 虚函数的virtual关键字只需要在声明时使用,不需要在定义时重复 311 | void Dog::print() const 312 | { 313 | std::cout << "Dog is " << name << " and weighs " << weight << "kg\n"; 314 | } 315 | 316 | void Dog::~Dog() 317 | { 318 | std::cout << "Goodbye " << name << "\n"; 319 | } 320 | 321 | int main() { 322 | Dog myDog; // 此时显示“A dog has been constructed” 323 | myDog.setName("Barkley"); 324 | myDog.setWeight(10); 325 | myDog.print(); // 显示“Dog is Barkley and weighs 10 kg” 326 | return 0; 327 | } // 显示“Goodbye Barkley” 328 | 329 | // 继承: 330 | 331 | // 这个类继承了Dog类中的公有(public)和保护(protected)对象 332 | class OwnedDog : public Dog { 333 | 334 | void setOwner(const std::string& dogsOwner) 335 | 336 | // 重写OwnedDogs类的print方法。 337 | // 如果你不熟悉子类多态的话,可以参考这个页面中的概述: 338 | // http://zh.wikipedia.org/wiki/%E5%AD%90%E7%B1%BB%E5%9E%8B 339 | 340 | // override关键字是可选的,它确保你所重写的是基类中的方法。 341 | void print() const override; 342 | 343 | private: 344 | std::string owner; 345 | }; 346 | 347 | // 与此同时,在对应的.cpp文件里: 348 | 349 | void OwnedDog::setOwner(const std::string& dogsOwner) 350 | { 351 | owner = dogsOwner; 352 | } 353 | 354 | void OwnedDog::print() const 355 | { 356 | Dog::print(); // 调用基类Dog中的print方法 357 | // "Dog is and weights " 358 | 359 | std::cout << "Dog is owned by " << owner << "\n"; 360 | // "Dog is owned by " 361 | } 362 | 363 | ///////////////////// 364 | // 初始化与运算符重载 365 | ///////////////////// 366 | 367 | // 在C++中,通过定义一些特殊名称的函数, 368 | // 你可以重载+、-、*、/等运算符的行为。 369 | // 当运算符被使用时,这些特殊函数会被调用,从而实现运算符重载。 370 | 371 | #include 372 | using namespace std; 373 | 374 | class Point { 375 | public: 376 | // 可以以这样的方式为成员变量设置默认值。 377 | double x = 0; 378 | double y = 0; 379 | 380 | // 定义一个默认的构造器。 381 | // 除了将Point初始化为(0, 0)以外,这个函数什么都不做。 382 | Point() { }; 383 | 384 | // 下面使用的语法称为初始化列表, 385 | // 这是初始化类中成员变量的正确方式。 386 | Point (double a, double b) : 387 | x(a), 388 | y(b) 389 | { /* 除了初始化成员变量外,什么都不做 */ } 390 | 391 | // 重载 + 运算符 392 | Point operator+(const Point& rhs) const; 393 | 394 | // 重载 += 运算符 395 | Point& operator+=(const Point& rhs); 396 | 397 | // 增加 - 和 -= 运算符也是有意义的,但这里不再赘述。 398 | }; 399 | 400 | Point Point::operator+(const Point& rhs) const 401 | { 402 | // 创建一个新的点, 403 | // 其横纵坐标分别为这个点与另一点在对应方向上的坐标之和。 404 | return Point(x + rhs.x, y + rhs.y); 405 | } 406 | 407 | Point& Point::operator+=(const Point& rhs) 408 | { 409 | x += rhs.x; 410 | y += rhs.y; 411 | return *this; 412 | } 413 | 414 | int main () { 415 | Point up (0,1); 416 | Point right (1,0); 417 | // 这里使用了Point类型的运算符“+” 418 | // 调用up(Point类型)的“+”方法,并以right作为函数的参数 419 | Point result = up + right; 420 | // 显示“Result is upright (1,1)” 421 | cout << "Result is upright (" << result.x << ',' << result.y << ")\n"; 422 | return 0; 423 | } 424 | 425 | /////////// 426 | // 异常处理 427 | /////////// 428 | 429 | // 标准库中提供了一些基本的异常类型 430 | // (参见http://en.cppreference.com/w/cpp/error/exception) 431 | // 但是,其他任何类型也可以作为一个异常被拋出 432 | #include 433 | 434 | // 在_try_代码块中拋出的异常可以被随后的_catch_捕获。 435 | try { 436 | // 不要用 _new_关键字在堆上为异常分配空间。 437 | throw std::exception("A problem occurred"); 438 | } 439 | // 如果拋出的异常是一个对象,可以用常量引用来捕获它 440 | catch (const std::exception& ex) 441 | { 442 | std::cout << ex.what(); 443 | // 捕获尚未被_catch_处理的所有错误 444 | } catch (...) 445 | { 446 | std::cout << "Unknown exception caught"; 447 | throw; // 重新拋出异常 448 | } 449 | 450 | /////// 451 | // RAII 452 | /////// 453 | 454 | // RAII指的是“资源获取就是初始化”(Resource Allocation Is Initialization), 455 | // 它被视作C++中最强大的编程范式之一。 456 | // 简单说来,它指的是,用构造函数来获取一个对象的资源, 457 | // 相应的,借助析构函数来释放对象的资源。 458 | 459 | // 为了理解这一范式的用处,让我们考虑某个函数使用文件句柄时的情况: 460 | void doSomethingWithAFile(const char* filename) 461 | { 462 | // 首先,让我们假设一切都会顺利进行。 463 | 464 | FILE* fh = fopen(filename, "r"); // 以只读模式打开文件 465 | 466 | doSomethingWithTheFile(fh); 467 | doSomethingElseWithIt(fh); 468 | 469 | fclose(fh); // 关闭文件句柄 470 | } 471 | 472 | // 不幸的是,随着错误处理机制的引入,事情会变得复杂。 473 | // 假设fopen函数有可能执行失败, 474 | // 而doSomethingWithTheFile和doSomethingElseWithIt会在失败时返回错误代码。 475 | // (虽然异常是C++中处理错误的推荐方式, 476 | // 但是某些程序员,尤其是有C语言背景的,并不认可异常捕获机制的作用)。 477 | // 现在,我们必须检查每个函数调用是否成功执行,并在问题发生的时候关闭文件句柄。 478 | bool doSomethingWithAFile(const char* filename) 479 | { 480 | FILE* fh = fopen(filename, "r"); // 以只读模式打开文件 481 | if (fh == nullptr) // 当执行失败是,返回的指针是nullptr 482 | return false; // 向调用者汇报错误 483 | 484 | // 假设每个函数会在执行失败时返回false 485 | if (!doSomethingWithTheFile(fh)) { 486 | fclose(fh); // 关闭文件句柄,避免造成内存泄漏。 487 | return false; // 反馈错误 488 | } 489 | if (!doSomethingElseWithIt(fh)) { 490 | fclose(fh); // 关闭文件句柄 491 | return false; // 反馈错误 492 | } 493 | 494 | fclose(fh); // 关闭文件句柄 495 | return true; // 指示函数已成功执行 496 | } 497 | 498 | // C语言的程序员通常会借助goto语句简化上面的代码: 499 | bool doSomethingWithAFile(const char* filename) 500 | { 501 | FILE* fh = fopen(filename, "r"); 502 | if (fh == nullptr) 503 | return false; 504 | 505 | if (!doSomethingWithTheFile(fh)) 506 | goto failure; 507 | 508 | if (!doSomethingElseWithIt(fh)) 509 | goto failure; 510 | 511 | fclose(fh); // 关闭文件 512 | return true; // 执行成功 513 | 514 | failure: 515 | fclose(fh); 516 | return false; // 反馈错误 517 | } 518 | 519 | // 如果用异常捕获机制来指示错误的话, 520 | // 代码会变得清晰一些,但是仍然有优化的余地。 521 | void doSomethingWithAFile(const char* filename) 522 | { 523 | FILE* fh = fopen(filename, "r"); // 以只读模式打开文件 524 | if (fh == nullptr) 525 | throw std::exception("Could not open the file."); 526 | 527 | try { 528 | doSomethingWithTheFile(fh); 529 | doSomethingElseWithIt(fh); 530 | } 531 | catch (...) { 532 | fclose(fh); // 保证出错的时候文件被正确关闭 533 | throw; // 之后,重新抛出这个异常 534 | } 535 | 536 | fclose(fh); // 关闭文件 537 | // 所有工作顺利完成 538 | } 539 | 540 | // 相比之下,使用C++中的文件流类(fstream)时, 541 | // fstream会利用自己的析构器来关闭文件句柄。 542 | // 只要离开了某一对象的定义域,它的析构函数就会被自动调用。 543 | void doSomethingWithAFile(const std::string& filename) 544 | { 545 | // ifstream是输入文件流(input file stream)的简称 546 | std::ifstream fh(filename); // 打开一个文件 547 | 548 | // 对文件进行一些操作 549 | doSomethingWithTheFile(fh); 550 | doSomethingElseWithIt(fh); 551 | 552 | } // 文件已经被析构器自动关闭 553 | 554 | // 与上面几种方式相比,这种方式有着_明显_的优势: 555 | // 1. 无论发生了什么情况,资源(此例当中是文件句柄)都会被正确关闭。 556 | // 只要你正确使用了析构器,就_不会_因为忘记关闭句柄,造成资源的泄漏。 557 | // 2. 可以注意到,通过这种方式写出来的代码十分简洁。 558 | // 析构器会在后台关闭文件句柄,不再需要你来操心这些琐事。 559 | // 3. 这种方式的代码具有异常安全性。 560 | // 无论在函数中的何处拋出异常,都不会阻碍对文件资源的释放。 561 | 562 | // 地道的C++代码应当把RAII的使用扩展到各种类型的资源上,包括: 563 | // - 用unique_ptr和shared_ptr管理的内存 564 | // - 各种数据容器,例如标准库中的链表、向量(容量自动扩展的数组)、散列表等; 565 | // 当它们脱离作用域时,析构器会自动释放其中储存的内容。 566 | // - 用lock_guard和unique_lock实现的互斥 567 | ``` 568 | 扩展阅读: 569 | 570 | 提供了最新的语法参考。 571 | 572 | 可以在 找到一些补充资料。 573 | -------------------------------------------------------------------------------- /CSAPP/c-cn.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | language: c 3 | filename: learnc-cn.c 4 | contributors: 5 | - ["Adam Bard", "http://adambard.com/"] 6 | translators: 7 | - ["Chenbo Li", "http://binarythink.net/"] 8 | - ["Jakukyo Friel", "http://weakish.github.io"] 9 | lang: zh-cn 10 | --- 11 | 12 | C语言在今天仍然是高性能计算的主要选择。 13 | 14 | C大概是大多数程序员用到的最接近底层的语言了,C语言原生的速度就很高了,但是别忘了C的手动内存管理,它会让你将性能发挥到极致。 15 | 16 | ```c 17 | // 单行注释以//开始。(仅适用于C99或更新的版本。) 18 | 19 | /* 20 | 多行注释是这个样子的。(C89也适用。) 21 | */ 22 | 23 | // 常数: #define 关键词 24 | #define DAYS_IN_YEAR 365 25 | 26 | // 以枚举的方式定义常数 27 | enum days {SUN = 1, MON, TUE, WED, THU, FRI, SAT}; 28 | // MON自动被定义为2,TUE被定义为3,以此类推。 29 | 30 | // 用#include来导入头文件 31 | #include 32 | #include 33 | #include 34 | 35 | // <尖括号>间的文件名是C标准库的头文件。 36 | // 标准库以外的头文件,使用双引号代替尖括号。 37 | #include "my_header.h" 38 | 39 | // 函数的签名可以事先在.h文件中定义, 40 | // 也可以直接在.c文件的头部定义。 41 | void function_1(char c); 42 | void function_2(void); 43 | 44 | // 如果函数出现在main()之后,那么必须在main()之前 45 | // 先声明一个函数原型 46 | int add_two_ints(int x1, int x2); // 函数原型 47 | 48 | // 你的程序的入口是一个返回值为整型的main函数 49 | int main() { 50 | 51 | // 用printf打印到标准输出,可以设定格式, 52 | // %d 代表整数, \n 代表换行 53 | printf("%d\n", 0); // => 打印 0 54 | // 所有的语句都要以分号结束 55 | 56 | /////////////////////////////////////// 57 | // 类型 58 | /////////////////////////////////////// 59 | 60 | // 在使用变量之前我们必须先声明它们。 61 | // 变量在声明时需要指明其类型,而类型能够告诉系统这个变量所占用的空间 62 | 63 | // int型(整型)变量一般占用4个字节 64 | int x_int = 0; 65 | 66 | // short型(短整型)变量一般占用2个字节 67 | short x_short = 0; 68 | 69 | // char型(字符型)变量会占用1个字节 70 | char x_char = 0; 71 | char y_char = 'y'; // 字符变量的字面值需要用单引号包住 72 | 73 | // long型(长整型)一般需要4个字节到8个字节; 而long long型则至少需要8个字节(64位) 74 | 75 | long x_long = 0; 76 | long long x_long_long = 0; 77 | 78 | // float一般是用32位表示的浮点数字 79 | float x_float = 0.0; 80 | 81 | // double一般是用64位表示的浮点数字 82 | double x_double = 0.0; 83 | 84 | // 整数类型也可以有无符号的类型表示。这样这些变量就无法表示负数 85 | // 但是无符号整数所能表示的范围就可以比原来的整数大一些 86 | 87 | unsigned short ux_short; 88 | unsigned int ux_int; 89 | unsigned long long ux_long_long; 90 | 91 | // 单引号内的字符是机器的字符集中的整数。 92 | '0' // => 在ASCII字符集中是48 93 | 'A' // => 在ASCII字符集中是65 94 | 95 | // char类型一定会占用1个字节,但是其他的类型却会因具体机器的不同而各异 96 | // sizeof(T) 可以返回T类型在运行的机器上占用多少个字节 97 | // 这样你的代码就可以在各处正确运行了 98 | // sizeof(obj)返回表达式(变量、字面量等)的尺寸 99 | printf("%zu\n", sizeof(int)); // => 4 (大多数的机器字长为4) 100 | 101 | // 如果`sizeof`的参数是一个表达式,那么这个参数不会被演算(VLA例外,见下) 102 | // 它产生的值是编译期的常数 103 | int a = 1; 104 | // size_t是一个无符号整型,表示对象的尺寸,至少2个字节 105 | size_t size = sizeof(a++); // a++ 不会被演算 106 | printf("sizeof(a++) = %zu where a = %d\n", size, a); 107 | // 打印 "sizeof(a++) = 4 where a = 1" (在32位架构上) 108 | 109 | // 数组必须要被初始化为具体的长度 110 | char my_char_array[20]; // 这个数组占据 1 * 20 = 20 个字节 111 | int my_int_array[20]; // 这个数组占据 4 * 20 = 80 个字节 112 | // (这里我们假设字长为4) 113 | 114 | 115 | // 可以用下面的方法把数组初始化为0: 116 | char my_array[20] = {0}; 117 | 118 | // 索引数组和其他语言类似 -- 好吧,其实是其他的语言像C 119 | my_array[0]; // => 0 120 | 121 | // 数组是可变的,其实就是内存的映射! 122 | my_array[1] = 2; 123 | printf("%d\n", my_array[1]); // => 2 124 | 125 | // 在C99 (C11中是可选特性),变长数组(VLA)也可以声明长度。 126 | // 其长度不用是编译期常量。 127 | printf("Enter the array size: "); // 询问用户数组长度 128 | char buf[0x100]; 129 | fgets(buf, sizeof buf, stdin); 130 | 131 | // stroul 将字符串解析为无符号整数 132 | size_t size = strtoul(buf, NULL, 10); 133 | int var_length_array[size]; // 声明VLA 134 | printf("sizeof array = %zu\n", sizeof var_length_array); 135 | 136 | // 上述程序可能的输出为: 137 | // > Enter the array size: 10 138 | // > sizeof array = 40 139 | 140 | // 字符串就是以 NUL (0x00) 这个字符结尾的字符数组, 141 | // NUL可以用'\0'来表示. 142 | // (在字符串字面量中我们不必输入这个字符,编译器会自动添加的) 143 | char a_string[20] = "This is a string"; 144 | printf("%s\n", a_string); // %s 可以对字符串进行格式化 145 | /* 146 | 也许你会注意到 a_string 实际上只有16个字节长. 147 | 第17个字节是一个空字符(NUL) 148 | 而第18, 19 和 20 个字符的值是未定义。 149 | */ 150 | 151 | printf("%d\n", a_string[16]); // => 0 152 | // byte #17值为0(18,19,20同样为0) 153 | 154 | // 单引号间的字符是字符字面量 155 | // 它的类型是`int`,而 *不是* `char` 156 | // (由于历史原因) 157 | int cha = 'a'; // 合法 158 | char chb = 'a'; // 同样合法 (隐式类型转换 159 | 160 | // 多维数组 161 | int multi_array[2][5] = { 162 | {1, 2, 3, 4, 5}, 163 | {6, 7, 8, 9, 0} 164 | } 165 | // 获取元素 166 | int array_int = multi_array[0][2]; // => 3 167 | 168 | /////////////////////////////////////// 169 | // 操作符 170 | /////////////////////////////////////// 171 | 172 | // 多个变量声明的简写 173 | int i1 = 1, i2 = 2; 174 | float f1 = 1.0, f2 = 2.0; 175 | 176 | int a, b, c; 177 | a = b = c = 0; 178 | 179 | // 算数运算直截了当 180 | i1 + i2; // => 3 181 | i2 - i1; // => 1 182 | i2 * i1; // => 2 183 | i1 / i2; // => 0 (0.5,但会被化整为 0) 184 | 185 | f1 / f2; // => 0.5, 也许会有很小的误差 186 | // 浮点数和浮点数运算都是近似值 187 | 188 | // 取余运算 189 | 11 % 3; // => 2 190 | 191 | // 你多半会觉得比较操作符很熟悉, 不过C中没有布尔类型 192 | // 而是用整形替代 193 | // (C99中有_Bool或bool。) 194 | // 0为假, 其他均为真. (比较操作符的返回值总是返回0或1) 195 | 3 == 2; // => 0 (false) 196 | 3 != 2; // => 1 (true) 197 | 3 > 2; // => 1 198 | 3 < 2; // => 0 199 | 2 <= 2; // => 1 200 | 2 >= 2; // => 1 201 | 202 | // C不是Python —— 连续比较不合法 203 | int a = 1; 204 | // 错误 205 | int between_0_and_2 = 0 < a < 2; 206 | // 正确 207 | int between_0_and_2 = 0 < a && a < 2; 208 | 209 | // 逻辑运算符适用于整数 210 | !3; // => 0 (非) 211 | !0; // => 1 212 | 1 && 1; // => 1 (且) 213 | 0 && 1; // => 0 214 | 0 || 1; // => 1 (或) 215 | 0 || 0; // => 0 216 | 217 | // 条件表达式 ( ? : ) 218 | int a = 5; 219 | int b = 10; 220 | int z; 221 | z = (a > b) ? a : b; // 10 “若a > b返回a,否则返回b。” 222 | 223 | // 增、减 224 | char *s = "iLoveC" 225 | int j = 0; 226 | s[j++]; // "i" 返回s的第j项,然后增加j的值。 227 | j = 0; 228 | s[++j]; // => "L" 增加j的值,然后返回s的第j项。 229 | // j-- 和 --j 同理 230 | 231 | // 位运算 232 | ~0x0F; // => 0xF0 (取反) 233 | 0x0F & 0xF0; // => 0x00 (和) 234 | 0x0F | 0xF0; // => 0xFF (或) 235 | 0x04 ^ 0x0F; // => 0x0B (异或) 236 | 0x01 << 1; // => 0x02 (左移1位) 237 | 0x02 >> 1; // => 0x01 (右移1位) 238 | 239 | // 对有符号整数进行移位操作要小心 —— 以下未定义: 240 | // 有符号整数位移至符号位 int a = 1 << 32 241 | // 左移位一个负数 int a = -1 << 2 242 | // 移位超过或等于该类型数值的长度 243 | // int a = 1 << 32; // 假定int32位 244 | 245 | 246 | /////////////////////////////////////// 247 | // 控制结构 248 | /////////////////////////////////////// 249 | 250 | if (0) { 251 | printf("I am never run\n"); 252 | } else if (0) { 253 | printf("I am also never run\n"); 254 | } else { 255 | printf("I print\n"); 256 | } 257 | 258 | // While循环 259 | int ii = 0; 260 | while (ii < 10) { // 任何非0的值均为真 261 | printf("%d, ", ii++); // ii++ 在取值过后自增 262 | } // => 打印 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " 263 | 264 | printf("\n"); 265 | 266 | int kk = 0; 267 | do { 268 | printf("%d, ", kk); 269 | } while (++kk < 10); // ++kk 先自增,再被取值 270 | // => 打印 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " 271 | 272 | printf("\n"); 273 | 274 | // For 循环 275 | int jj; 276 | for (jj=0; jj < 10; jj++) { 277 | printf("%d, ", jj); 278 | } // => 打印 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, " 279 | 280 | printf("\n"); 281 | 282 | // *****注意*****: 283 | // 循环和函数必须有主体部分,如果不需要主体部分: 284 | int i; 285 | for (i = 0; i <= 5; i++) { 286 | ; // 使用分号表达主体(null语句) 287 | } 288 | 289 | // 多重分支:switch() 290 | switch (some_integral_expression) { 291 | case 0: // 标签必须是整数常量表达式 292 | do_stuff(); 293 | break; // 如果不使用break,控制结构会继续执行下面的标签 294 | case 1: 295 | do_something_else(); 296 | break; 297 | default: 298 | // 假设 `some_integral_expression` 不匹配任何标签 299 | fputs("error!\n", stderr); 300 | exit(-1); 301 | break; 302 | } 303 | 304 | /////////////////////////////////////// 305 | // 类型转换 306 | /////////////////////////////////////// 307 | 308 | // 在C中每个变量都有类型,你可以将变量的类型进行转换 309 | // (有一定限制) 310 | 311 | int x_hex = 0x01; // 可以用16进制字面量赋值 312 | 313 | // 在类型转换时,数字本身的值会被保留下来 314 | printf("%d\n", x_hex); // => 打印 1 315 | printf("%d\n", (short) x_hex); // => 打印 1 316 | printf("%d\n", (char) x_hex); // => 打印 1 317 | 318 | // 类型转换时可能会造成溢出,而且不会抛出警告 319 | printf("%d\n", (char) 257); // => 1 (char的最大值为255,假定char为8位长) 320 | 321 | // 使用提供的CHAR_MAX、SCHAR_MAX和UCHAR_MAX宏可以确定`char`、`signed_char`和`unisigned char`的最大值。 322 | 323 | 324 | // 整数型和浮点型可以互相转换 325 | printf("%f\n", (float)100); // %f 格式化单精度浮点 326 | printf("%lf\n", (double)100); // %lf 格式化双精度浮点 327 | printf("%d\n", (char)100.0); 328 | 329 | /////////////////////////////////////// 330 | // 指针 331 | /////////////////////////////////////// 332 | 333 | // 指针变量是用来储存内存地址的变量 334 | // 指针变量的声明也会告诉它所指向的数据的类型 335 | // 你可以使用得到你的变量的地址,并把它们搞乱,;-) 336 | 337 | int x = 0; 338 | printf("%p\n", &x); // 用 & 来获取变量的地址 339 | // (%p 格式化一个类型为 void *的指针) 340 | // => 打印某个内存地址 341 | 342 | // 指针类型在声明中以*开头 343 | int* px, not_a_pointer; // px是一个指向int型的指针 344 | px = &x; // 把x的地址保存到px中 345 | printf("%p\n", (void *)px); // => 输出内存中的某个地址 346 | printf("%zu, %zu\n", sizeof(px), sizeof(not_a_pointer)); 347 | // => 在64位系统上打印“8, 4”。 348 | 349 | // 要得到某个指针指向的内容的值,可以在指针前加一个*来取得(取消引用) 350 | // 注意: 是的,这可能让人困惑,'*'在用来声明一个指针的同时取消引用它。 351 | printf("%d\n", *px); // => 输出 0, 即x的值 352 | 353 | // 你也可以改变指针所指向的值 354 | // 此时你需要取消引用上添加括号,因为++比*的优先级更高 355 | (*px)++; // 把px所指向的值增加1 356 | printf("%d\n", *px); // => 输出 1 357 | printf("%d\n", x); // => 输出 1 358 | 359 | // 数组是分配一系列连续空间的常用方式 360 | int x_array[20]; 361 | int xx; 362 | for (xx=0; xx<20; xx++) { 363 | x_array[xx] = 20 - xx; 364 | } // 初始化 x_array 为 20, 19, 18,... 2, 1 365 | 366 | // 声明一个整型的指针,并初始化为指向x_array 367 | int* x_ptr = x_array; 368 | // x_ptr现在指向了数组的第一个元素(即整数20). 369 | // 这是因为数组通常衰减为指向它们的第一个元素的指针。 370 | // 例如,当一个数组被传递给一个函数或者绑定到一个指针时, 371 | //它衰减为(隐式转化为)一个指针。 372 | // 例外: 当数组是`&`操作符的参数: 373 | int arr[10]; 374 | int (*ptr_to_arr)[10] = &arr; // &arr的类型不是`int *`! 375 | // 它的类型是指向数组的指针(数组由10个int组成) 376 | // 或者当数组是字符串字面量(初始化字符数组) 377 | char arr[] = "foobarbazquirk"; 378 | // 或者当它是`sizeof`或`alignof`操作符的参数时: 379 | int arr[10]; 380 | int *ptr = arr; // 等价于 int *ptr = &arr[0]; 381 | printf("%zu, %zu\n", sizeof arr, sizeof ptr); // 应该会输出"40, 4"或"40, 8" 382 | 383 | // 指针的增减多少是依据它本身的类型而定的 384 | // (这被称为指针算术) 385 | printf("%d\n", *(x_ptr + 1)); // => 打印 19 386 | printf("%d\n", x_array[1]); // => 打印 19 387 | 388 | // 你也可以通过标准库函数malloc来实现动态分配 389 | // 这个函数接受一个代表容量的参数,参数类型为`size_t` 390 | // 系统一般会从堆区分配指定容量字节大小的空间 391 | // (在一些系统,例如嵌入式系统中这点不一定成立 392 | // C标准对此未置一词。) 393 | int *my_ptr = malloc(sizeof(*my_ptr) * 20); 394 | for (xx=0; xx<20; xx++) { 395 | *(my_ptr + xx) = 20 - xx; // my_ptr[xx] = 20-xx 396 | } // 初始化内存为 20, 19, 18, 17... 2, 1 (类型为int) 397 | 398 | // 对未分配的内存进行取消引用会产生未定义的结果 399 | printf("%d\n", *(my_ptr + 21)); // => 谁知道会输出什么 400 | 401 | // malloc分配的区域需要手动释放 402 | // 否则没人能够再次使用这块内存,直到程序结束为止 403 | free(my_ptr); 404 | 405 | // 字符串通常是字符数组,但是经常用字符指针表示 406 | // (它是指向数组的第一个元素的指针) 407 | // 一个优良的实践是使用`const char *`来引用一个字符串字面量, 408 | // 因为字符串字面量不应当被修改(即"foo"[0] = 'a'犯了大忌) 409 | const char* my_str = "This is my very own string"; 410 | printf("%c\n", *my_str); // => 'T' 411 | 412 | // 如果字符串是数组,(多半是用字符串字面量初始化的) 413 | // 情况就不一样了,字符串位于可写的内存中 414 | char foo[] = "foo"; 415 | foo[0] = 'a'; // 这是合法的,foo现在包含"aoo" 416 | 417 | function_1(); 418 | } // main函数结束 419 | 420 | /////////////////////////////////////// 421 | // 函数 422 | /////////////////////////////////////// 423 | 424 | // 函数声明语法: 425 | // <返回值类型> <函数名称>(<参数>) 426 | 427 | int add_two_ints(int x1, int x2){ 428 | return x1 + x2; // 用return来返回一个值 429 | } 430 | 431 | /* 432 | 函数是按值传递的。当调用一个函数的时候,传递给函数的参数 433 | 是原有值的拷贝(数组除外)。你在函数内对参数所进行的操作 434 | 不会改变该参数原有的值。 435 | 436 | 但是你可以通过指针来传递引用,这样函数就可以更改值 437 | 438 | 例子:字符串本身翻转 439 | */ 440 | 441 | // 类型为void的函数没有返回值 442 | void str_reverse(char *str_in){ 443 | char tmp; 444 | int ii = 0; 445 | size_t len = strlen(str_in); // `strlen()`` 是C标准库函数 446 | for(ii = 0; ii < len / 2; ii++){ 447 | tmp = str_in[ii]; 448 | str_in[ii] = str_in[len - ii - 1]; // 从倒数第ii个开始 449 | str_in[len - ii - 1] = tmp; 450 | } 451 | } 452 | 453 | /* 454 | char c[] = "This is a test."; 455 | str_reverse(c); 456 | printf("%s\n", c); // => ".tset a si sihT" 457 | */ 458 | 459 | // 如果引用函数之外的变量,必须使用extern关键字 460 | int i = 0; 461 | void testFunc() { 462 | extern int i; // 使用外部变量 i 463 | } 464 | 465 | // 使用static确保external变量为源文件私有 466 | static int i = 0; // 其他使用 testFunc()的文件无法访问变量i 467 | void testFunc() { 468 | extern int i; 469 | } 470 | //**你同样可以声明函数为static** 471 | 472 | 473 | /////////////////////////////////////// 474 | // 用户自定义类型和结构 475 | /////////////////////////////////////// 476 | 477 | // Typedefs可以创建类型别名 478 | typedef int my_type; 479 | my_type my_type_var = 0; 480 | 481 | // struct是数据的集合,成员依序分配,按照 482 | // 编写的顺序 483 | struct rectangle { 484 | int width; 485 | int height; 486 | }; 487 | 488 | // 一般而言,以下断言不成立: 489 | // sizeof(struct rectangle) == sizeof(int) + sizeof(int) 490 | //这是因为structure成员之间可能存在潜在的间隙(为了对齐)[1] 491 | 492 | void function_1(){ 493 | 494 | struct rectangle my_rec; 495 | 496 | // 通过 . 来访问结构中的数据 497 | my_rec.width = 10; 498 | my_rec.height = 20; 499 | 500 | // 你也可以声明指向结构体的指针 501 | struct rectangle *my_rec_ptr = &my_rec; 502 | 503 | // 通过取消引用来改变结构体的成员... 504 | (*my_rec_ptr).width = 30; 505 | 506 | // ... 或者用 -> 操作符作为简写提高可读性 507 | my_rec_ptr->height = 10; // Same as (*my_rec_ptr).height = 10; 508 | } 509 | 510 | // 你也可以用typedef来给一个结构体起一个别名 511 | typedef struct rectangle rect; 512 | 513 | int area(rect r){ 514 | return r.width * r.height; 515 | } 516 | 517 | // 如果struct较大,你可以通过指针传递,避免 518 | // 复制整个struct。 519 | int area(const rect *r) 520 | { 521 | return r->width * r->height; 522 | } 523 | 524 | /////////////////////////////////////// 525 | // 函数指针 526 | /////////////////////////////////////// 527 | /* 528 | 在运行时,函数本身也被存放到某块内存区域当中 529 | 函数指针就像其他指针一样(不过是存储一个内存地址) 但却可以被用来直接调用函数, 530 | 并且可以四处传递回调函数 531 | 但是,定义的语法初看令人有些迷惑 532 | 533 | 例子:通过指针调用str_reverse 534 | */ 535 | void str_reverse_through_pointer(char *str_in) { 536 | // 定义一个函数指针 f. 537 | void (*f)(char *); // 签名一定要与目标函数相同 538 | f = &str_reverse; // 将函数的地址在运行时赋给指针 539 | (*f)(str_in); // 通过指针调用函数 540 | // f(str_in); // 等价于这种调用方式 541 | } 542 | 543 | /* 544 | 只要函数签名是正确的,任何时候都能将任何函数赋给某个函数指针 545 | 为了可读性和简洁性,函数指针经常和typedef搭配使用: 546 | */ 547 | 548 | typedef void (*my_fnp_type)(char *); 549 | 550 | // 实际声明函数指针会这么用: 551 | // ... 552 | // my_fnp_type f; 553 | 554 | // 特殊字符 555 | '\a' // bell 556 | '\n' // 换行 557 | '\t' // tab 558 | '\v' // vertical tab 559 | '\f' // formfeed 560 | '\r' // 回车 561 | '\b' // 退格 562 | '\0' // null,通常置于字符串的最后。 563 | // hello\n\0. 按照惯例,\0用于标记字符串的末尾。 564 | '\\' // 反斜杠 565 | '\?' // 问号 566 | '\'' // 单引号 567 | '\"' // 双引号 568 | '\xhh' // 十六进制数字. 例子: '\xb' = vertical tab 569 | '\ooo' // 八进制数字. 例子: '\013' = vertical tab 570 | 571 | // 打印格式: 572 | "%d" // 整数 573 | "%3d" // 3位以上整数 (右对齐文本) 574 | "%s" // 字符串 575 | "%f" // float 576 | "%ld" // long 577 | "%3.2f" // 左3位以上、右2位以上十进制浮 578 | "%7.4s" // (字符串同样适用) 579 | "%c" // 字母 580 | "%p" // 指针 581 | "%x" // 十六进制 582 | "%o" // 八进制 583 | "%%" // 打印 % 584 | 585 | /////////////////////////////////////// 586 | // 演算优先级 587 | /////////////////////////////////////// 588 | //---------------------------------------------------// 589 | // 操作符 | 组合 // 590 | //---------------------------------------------------// 591 | // () [] -> . | 从左到右 // 592 | // ! ~ ++ -- + = *(type)sizeof | 从右到左 // 593 | // * / % | 从左到右 // 594 | // + - | 从左到右 // 595 | // << >> | 从左到右 // 596 | // < <= > >= | 从左到右 // 597 | // == != | 从左到右 // 598 | // & | 从左到右 // 599 | // ^ | 从左到右 // 600 | // | | 从左到右 // 601 | // && | 从左到右 // 602 | // || | 从左到右 // 603 | // ?: | 从右到左 // 604 | // = += -= *= /= %= &= ^= |= <<= >>= | 从右到左 // 605 | // , | 从左到右 // 606 | //---------------------------------------------------// 607 | 608 | ``` 609 | 610 | ## 更多阅读 611 | 612 | 最好找一本 [K&R, aka "The C Programming Language", “C程序设计语言”](https://en.wikipedia.org/wiki/The_C_Programming_Language)。它是关于C最重要的一本书,由C的创作者撰写。不过需要留意的是它比较古老了,因此有些不准确的地方。 613 | 614 | 615 | 另一个比较好的资源是 [Learn C the hard way](http://c.learncodethehardway.org/book/) 616 | 617 | 如果你有问题,请阅读[compl.lang.c Frequently Asked Questions](http://c-faq.com/)。 618 | 619 | 使用合适的空格、缩进,保持一致的代码风格非常重要。可读性强的代码比聪明的代码、高速的代码更重要。可以参考下[Linux内核编码风格](https://www.kernel.org/doc/Documentation/CodingStyle) 620 | 。 621 | 除了这些,多多Google吧 622 | 623 | [1] http://stackoverflow.com/questions/119123/why-isnt-sizeof-for-a-struct-equal-to-the-sum-of-sizeof-of-each-member 624 | -------------------------------------------------------------------------------- /Emacs/elisp-cn.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | language: elisp 3 | contributors: 4 | - ["Bastien Guerry", "http://bzg.fr"] 5 | translators: 6 | - ["Chenbo Li", "http://binarythink.net"] 7 | filename: learn-emacs-lisp-zh.el 8 | lang: zh-cn 9 | --- 10 | 11 | ```scheme 12 | ;; 15分钟学会Emacs Lisp (v0.2a) 13 | ;;(作者:bzg,https://github.com/bzg 14 | ;; 译者:lichenbo,http://douban.com/people/lichenbo) 15 | ;; 16 | ;; 请先阅读Peter Norvig的一篇好文: 17 | ;; http://norvig.com/21-days.html 18 | ;; (译者注:中文版请见http://blog.youxu.info/21-days/) 19 | ;; 20 | ;; 之后安装GNU Emacs 24.3: 21 | ;; 22 | ;; Debian: apt-get install emacs (视具体发行版而定) 23 | ;; MacOSX: http://emacsformacosx.com/emacs-builds/Emacs-24.3-universal-10.6.8.dmg 24 | ;; Windows: http://ftp.gnu.org/gnu/windows/emacs/emacs-24.3-bin-i386.zip 25 | ;; 26 | ;; 更多信息可以在这里找到: 27 | ;; http://www.gnu.org/software/emacs/#Obtaining 28 | 29 | ;; 很重要的警告: 30 | ;; 31 | ;; 按照这个教程来学习并不会对你的电脑有任何损坏 32 | ;; 除非你自己在学习的过程中愤怒地把它砸了 33 | ;; 如果出现了这种情况,我不会承担任何责任 34 | ;; 35 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 36 | ;; 37 | ;; 打开emacs 38 | ;; 39 | ;; 按'q'消除欢迎界面 40 | ;; 41 | ;; 现在请注意窗口底部的那一个灰色长条 42 | ;; 43 | ;; "*scratch*" 是你现在编辑界面的名字。 44 | ;; 这个编辑界面叫做一个"buffer"。 45 | ;; 46 | ;; 每当你打开Emacs时,都会默认打开这个scratch buffer 47 | ;; 此时你并没有在编辑任何文件,而是在编辑一个buffer 48 | ;; 之后你可以将这个buffer保存到一个文件中。 49 | ;; 50 | ;; 之后的"Lisp interaction" 则是表明我们可以用的某组命令 51 | ;; 52 | ;; Emacs在每个buffer中都有一组内置的命令 53 | ;; 而当你激活某种特定的模式时,就可以使用相应的命令 54 | ;; 这里我们使用`lisp-interaction-mode', 55 | ;; 这样我们就可以使用内置的Emacs Lisp(以下简称Elisp)命令了。 56 | 57 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 58 | ;; 59 | ;; 分号是注释开始的标志 60 | ;; 61 | ;; Elisp 是由符号表达式构成的 (即"s-表达式"或"s式"): 62 | (+ 2 2) 63 | 64 | ;; 这个s式的意思是 "对2进行加2操作". 65 | 66 | ;; s式周围有括号,而且也可以嵌套: 67 | (+ 2 (+ 1 1)) 68 | 69 | ;; 一个s式可以包含原子符号或者其他s式 70 | ;; 在上面的例子中,1和2是原子符号 71 | ;; (+ 2 (+ 1 1)) 和 (+ 1 1) 是s式. 72 | 73 | ;; 在 `lisp-interaction-mode' 中你可以计算s式. 74 | ;; 把光标移到闭括号后,之后按下ctrl+j(以后简写为'C-j') 75 | 76 | (+ 3 (+ 1 2)) 77 | ;; ^ 光标放到这里 78 | ;; 按下`C-j' 就会输出 6 79 | 80 | ;; `C-j' 会在buffer中插入当前运算的结果 81 | 82 | ;; 而`C-xC-e' 则会在emacs最底部显示结果,也就是被称作"minibuffer"的区域 83 | ;; 为了避免把我们的buffer填满无用的结果,我们以后会一直用`C-xC-e' 84 | 85 | ;; `setq' 可以将一个值赋给一个变量 86 | (setq my-name "Bastien") 87 | ;; `C-xC-e' 输出 "Bastien" (在 mini-buffer 中显示) 88 | 89 | ;; `insert' 会在光标处插入字符串: 90 | (insert "Hello!") 91 | ;; `C-xC-e' 输出 "Hello!" 92 | 93 | ;; 在这里我们只传给了insert一个参数"Hello!", 但是 94 | ;; 我们也可以传给它更多的参数,比如2个: 95 | 96 | (insert "Hello" " world!") 97 | ;; `C-xC-e' 输出 "Hello world!" 98 | 99 | ;; 你也可以用变量名来代替字符串 100 | (insert "Hello, I am " my-name) 101 | ;; `C-xC-e' 输出 "Hello, I am Bastien" 102 | 103 | ;; 你可以把s式嵌入函数中 104 | (defun hello () (insert "Hello, I am " my-name)) 105 | ;; `C-xC-e' 输出 hello 106 | 107 | ;; 现在执行这个函数 108 | (hello) 109 | ;; `C-xC-e' 输出 Hello, I am Bastien 110 | 111 | ;; 函数中空括号的意思是我们不需要接受任何参数 112 | ;; 但是我们不能一直总是用my-name这个变量 113 | ;; 所以我们现在使我们的函数接受一个叫做"name"的参数 114 | 115 | (defun hello (name) (insert "Hello " name)) 116 | ;; `C-xC-e' 输出 hello 117 | 118 | ;; 现在我们调用这个函数,并且将"you"作为参数传递 119 | 120 | (hello "you") 121 | ;; `C-xC-e' 输出 "Hello you" 122 | 123 | ;; 成功! 124 | 125 | ;; 现在我们可以休息一下 126 | 127 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 128 | ;; 129 | ;; 下面我们在新的窗口中新建一个名为 "*test*" 的buffer: 130 | 131 | (switch-to-buffer-other-window "*test*") 132 | ;; `C-xC-e' 这时屏幕上会显示两个窗口,而光标此时位于*test* buffer内 133 | 134 | ;; 用鼠标单击上面的buffer就会使光标移回。 135 | ;; 或者你可以使用 `C-xo' 使得光标跳到另一个窗口中 136 | 137 | ;; 你可以用 `progn'命令将s式结合起来: 138 | (progn 139 | (switch-to-buffer-other-window "*test*") 140 | (hello "you")) 141 | ;; `C-xC-e' 此时屏幕分为两个窗口,并且在*test* buffer中显示"Hello you" 142 | 143 | ;; 现在为了简洁,我们需要在每个s式后面都使用`C-xC-e'来执行,后面就不再说明了 144 | 145 | ;; 记得可以用过鼠标或者`C-xo'回到*scratch*这个buffer。 146 | 147 | ;; 清除当前buffer也是常用操作之一: 148 | (progn 149 | (switch-to-buffer-other-window "*test*") 150 | (erase-buffer) 151 | (hello "there")) 152 | 153 | ;; 也可以回到其他的窗口中 154 | (progn 155 | (switch-to-buffer-other-window "*test*") 156 | (erase-buffer) 157 | (hello "you") 158 | (other-window 1)) 159 | 160 | ;; 你可以用 `let' 将一个值和一个局部变量绑定: 161 | (let ((local-name "you")) 162 | (switch-to-buffer-other-window "*test*") 163 | (erase-buffer) 164 | (hello local-name) 165 | (other-window 1)) 166 | 167 | ;; 这里我们就不需要使用 `progn' 了, 因为 `let' 也可以将很多s式组合起来。 168 | 169 | ;; 格式化字符串的方法: 170 | (format "Hello %s!\n" "visitor") 171 | 172 | ;; %s 是字符串占位符,这里被"visitor"替代. 173 | ;; \n 是换行符。 174 | 175 | ;; 现在我们用格式化的方法再重写一下我们的函数: 176 | (defun hello (name) 177 | (insert (format "Hello %s!\n" name))) 178 | 179 | (hello "you") 180 | 181 | ;; 我们再用`let'新建另一个函数: 182 | (defun greeting (name) 183 | (let ((your-name "Bastien")) 184 | (insert (format "Hello %s!\n\nI am %s." 185 | name ; the argument of the function 186 | your-name ; the let-bound variable "Bastien" 187 | )))) 188 | 189 | ;; 之后执行: 190 | (greeting "you") 191 | 192 | ;; 有些函数可以和用户交互: 193 | (read-from-minibuffer "Enter your name: ") 194 | 195 | ;; 这个函数会返回在执行时用户输入的信息 196 | 197 | ;; 现在我们让`greeting'函数显示你的名字: 198 | (defun greeting (from-name) 199 | (let ((your-name (read-from-minibuffer "Enter your name: "))) 200 | (insert (format "Hello!\n\nI am %s and you are %s." 201 | from-name ; the argument of the function 202 | your-name ; the let-bound var, entered at prompt 203 | )))) 204 | 205 | (greeting "Bastien") 206 | 207 | ;; 我们让结果在另一个窗口中显示: 208 | (defun greeting (from-name) 209 | (let ((your-name (read-from-minibuffer "Enter your name: "))) 210 | (switch-to-buffer-other-window "*test*") 211 | (erase-buffer) 212 | (insert (format "Hello %s!\n\nI am %s." your-name from-name)) 213 | (other-window 1))) 214 | 215 | ;; 测试一下: 216 | (greeting "Bastien") 217 | 218 | ;; 第二节结束,休息一下吧。 219 | 220 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 221 | ;; 222 | ;; 我们将一些名字存到列表中: 223 | (setq list-of-names '("Sarah" "Chloe" "Mathilde")) 224 | 225 | ;; 用 `car'来取得第一个名字: 226 | (car list-of-names) 227 | 228 | ;; 用 `cdr'取得剩下的名字: 229 | (cdr list-of-names) 230 | 231 | ;; 用 `push'把名字添加到列表的开头: 232 | (push "Stephanie" list-of-names) 233 | 234 | ;; 注意: `car' 和 `cdr' 并不修改列表本身, 但是 `push' 却会对列表本身进行操作. 235 | ;; 这个区别是很重要的: 有些函数没有任何副作用(比如`car') 236 | ;; 但还有一些却是有的 (比如 `push'). 237 | 238 | ;; 我们来对`list-of-names'列表中的每一个元素都使用hello函数: 239 | (mapcar 'hello list-of-names) 240 | 241 | ;; 将 `greeting' 改进,使的我们能够对`list-of-names'中的所有名字执行: 242 | (defun greeting () 243 | (switch-to-buffer-other-window "*test*") 244 | (erase-buffer) 245 | (mapcar 'hello list-of-names) 246 | (other-window 1)) 247 | 248 | (greeting) 249 | 250 | ;; 记得我们之前定义的 `hello' 函数吗? 这个函数接受一个参数,名字。 251 | ;; `mapcar' 调用 `hello', 并将`list-of-names'作为参数先后传给`hello' 252 | 253 | ;; 现在我们对显示的buffer中的内容进行一些更改: 254 | 255 | (defun replace-hello-by-bonjour () 256 | (switch-to-buffer-other-window "*test*") 257 | (goto-char (point-min)) 258 | (while (search-forward "Hello") 259 | (replace-match "Bonjour")) 260 | (other-window 1)) 261 | 262 | ;; (goto-char (point-min)) 将光标移到buffer的开始 263 | ;; (search-forward "Hello") 查找字符串"Hello" 264 | ;; (while x y) 当x返回某个值时执行y这个s式 265 | ;; 当x返回`nil' (空), 退出循环 266 | 267 | (replace-hello-by-bonjour) 268 | 269 | ;; 你会看到所有在*test* buffer中出现的"Hello"字样都被换成了"Bonjour" 270 | 271 | ;; 你也会得到以下错误提示: "Search failed: Hello". 272 | ;; 273 | ;; 如果要避免这个错误, 你需要告诉 `search-forward' 这个命令是否在 274 | ;; buffer的某个地方停止查找, 并且在什么都没找到时是否应该不给出错误提示 275 | 276 | ;; (search-forward "Hello" nil t) 可以达到这个要求: 277 | 278 | ;; `nil' 参数的意思是 : 查找并不限于某个范围内 279 | ;; `t' 参数的意思是: 当什么都没找到时,不给出错误提示 280 | 281 | ;; 在下面的函数中,我们用到了s式,并且不给出任何错误提示: 282 | 283 | (defun hello-to-bonjour () 284 | (switch-to-buffer-other-window "*test*") 285 | (erase-buffer) 286 | ;; 为`list-of-names'中的每个名字调用hello 287 | (mapcar 'hello list-of-names) 288 | (goto-char (point-min)) 289 | ;; 将"Hello" 替换为"Bonjour" 290 | (while (search-forward "Hello" nil t) 291 | (replace-match "Bonjour")) 292 | (other-window 1)) 293 | 294 | (hello-to-bonjour) 295 | 296 | ;; 给这些名字上个色: 297 | 298 | (defun boldify-names () 299 | (switch-to-buffer-other-window "*test*") 300 | (goto-char (point-min)) 301 | (while (re-search-forward "Bonjour \\(.+\\)!" nil t) 302 | (add-text-properties (match-beginning 1) 303 | (match-end 1) 304 | (list 'face 'bold))) 305 | (other-window 1)) 306 | 307 | ;; 这个函数使用了 `re-search-forward': 308 | ;; 和查找一个字符串不同,你用这个命令可以查找一个模式,即正则表达式 309 | 310 | ;; 正则表达式 "Bonjour \\(.+\\)!" 的意思是: 311 | ;; 字符串 "Bonjour ", 之后跟着 312 | ;; 一组 | \\( ... \\) 结构 313 | ;; 任意字符 | . 的含义 314 | ;; 有可能重复的 | + 的含义 315 | ;; 之后跟着 "!" 这个字符串 316 | 317 | ;; 准备好了?试试看。 318 | 319 | (boldify-names) 320 | 321 | ;; `add-text-properties' 可以添加文字属性, 比如文字样式 322 | 323 | ;; 好的,我们成功了! 324 | 325 | ;; 如果你想对一个变量或者函数有更多的了解: 326 | ;; 327 | ;; C-h v 变量 回车 328 | ;; C-h f 函数 回车 329 | ;; 330 | ;; 阅读Emacs Lisp官方文档: 331 | ;; 332 | ;; C-h i m elisp 回车 333 | ;; 334 | ;; 在线阅读Emacs Lisp文档: 335 | ;; https://www.gnu.org/software/emacs/manual/html_node/eintr/index.html 336 | 337 | ;; 感谢以下同学的建议和反馈: 338 | ;; - Wes Hardaker 339 | ;; - notbob 340 | ;; - Kevin Montuori 341 | ;; - Arne Babenhauserheide 342 | ;; - Alan Schmitt 343 | ``` 344 | 345 | -------------------------------------------------------------------------------- /Emacs/vim-cn.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | category: tool 3 | tool: vim 4 | filename: LearnVim-cn.txt 5 | contributors: 6 | - ["RadhikaG", "https://github.com/RadhikaG"] 7 | translators: 8 | - ["Jiang Haiyun", "https://github.com/haiiiiiyun"] 9 | lang: zh-cn 10 | --- 11 | 12 | 13 | [Vim](http://www.vim.org) 14 | (Vi IMproved) 是 Unix 上的流行编辑器 vi 的克隆版本。这个文本编辑器 15 | 是为性能和提升效率而设计的,并且在大多数基于 unix 的系统上普遍存在。 16 | 它有大量的快捷键可用来快速导航到文件的特定位置,以便进行快速编辑。 17 | 18 | ## Vim 导航基础 19 | 20 | ``` 21 | vim # 在 Vim 中打开 22 | :q # 退出 Vim 23 | :w # 保存当前文件 24 | :wq # 保存文件并退出 Vim 25 | :q! # 退出 Vim 并且不保存文件 26 | # ! *强制* 执行 :q, 因此没有保存就退出 Vim 27 | :x # 保存文件并且退出 Vim, 是 :wq 的简写版本 28 | 29 | u # 撤销 30 | CTRL+R # 重做 31 | 32 | h # 左移一个字符 33 | j # 下移一行 34 | k # 上移一行 35 | l # 右移一个字符 36 | 37 | # 在行内移动 38 | 39 | 0 # 移到行首 40 | $ # 移到行尾 41 | ^ # 移到行内的第一个非空白字符处 42 | 43 | # 在文本中查找 44 | 45 | /word # 光标之后的所有该词都高亮显示 46 | ?word # 光标之前的所有该词都高亮显示 47 | n # 查找后将光标移到该词的下一个出现位置 48 | N # 光标移到该词的上一个出现位置 49 | 50 | :%s/foo/bar/g # 将文件每一行上的所有 'foo' 都改成 'bar' 51 | :s/foo/bar/g # 将当前行上的所有 'foo' 都改成 'bar' 52 | 53 | # 跳到字符处 54 | 55 | f<字符> # 向前跳移到 <字符> 上 56 | t<字符> # 向前跳移到 <字符> 的左侧 57 | 58 | # 例如, 59 |    f<               # 向前跳移到 < 上 60 | t< # 向前跳移到 < 的左侧 61 | 62 | # 按词移动 63 | # 默认一个单词由字母,数字和下划线组成 64 | 65 |    w               # 移动到下一个词首 66 |    b               # 移动到前一个词首 67 |    e               # 移动到下一个词尾 68 | 69 | 70 | # 移动的其它命令 71 | 72 | gg # 移到文件顶部 73 | G # 移到文件末尾 74 | :NUM # 移到第 NUM 行 (NUM 是任意数字) 75 | H # 移到屏幕顶部 76 | M # 移到屏幕中间位置 77 | L # 移到屏幕末尾 78 | ``` 79 | 80 | ## 模式: 81 | 82 | Vim 基于 **模式** 这个概念。 83 | 84 | 命令模式 - Vim 启动后就处于这个模式,用于导航和操作命令 85 | 插入模式 - 用于在你的文件中进行修改 86 | 可视模式 - 用于高亮文本并对它们进行操作 87 | Ex 模式 - 用于跳到底部的 ':' 提示行上输入命令 88 | 89 | ``` 90 | i # 在光标位置前,将 Vim 切换到插入模式 91 | a # 在光标位置后,将 Vim 切换到插入模式 92 | v # 将 Vim 切换到可视模式 93 | : # 将 Vim 切换到 ex 模式 94 | # 无论你当前处于什么模式,都返回到命令模式 95 | 96 | # 复制和粘贴文本 97 | 98 | y # 复制所选的内容 99 | yy # 复制当前行 100 | d # 删除所选的内容 101 | dd # 删除当前行 102 | p # 在当前光标位置后粘贴复制的文本 103 | P # 在当前光标位置前粘贴复制的文本 104 | x # 删除当前光标位置处的字符 105 | ``` 106 | 107 | ## Vim 的 '语法' 108 | 109 | Vim 可以被认为是按 '动词-修饰词-名词' 格式编排的一组命令: 110 | 111 | 动词 - 你的动作 112 | 修饰词 - 你如何执行你的动作 113 | 名词 - 你的动作所作用于的对象 114 | 115 | 关于 '动词','修饰词',和 '名词' 的几个重要例子: 116 | 117 | ``` 118 | # '动词' 119 | 120 | d # 删除 121 | c # 修改 122 | y # 复制 123 | v # 可视化选择 124 | 125 | # '修饰词' 126 | 127 | i # 内部的 128 | a # 周围的 129 | NUM # 数字 (NUM 是任意数字) 130 | f # 查找文本并位于其上 131 | t # 查找文本并停于其前面 132 | / # 从光标处开始查找字符串 133 | ? # 在光标前查找字符串 134 | 135 | # '名词' 136 | 137 | w # 词 138 | s # 句子 139 | p # 段落 140 | b # 块 141 | 142 | # 示例 '语句' 或命令 143 | 144 | d2w # 删除 2 个词 145 | cis # 修改段落内的内容 146 | yip # 复制段落内的内容 (复制你所在的段落) 147 | ct< # 修改直到括号开启处 148 | # 对你的当前位置直到下个括号开启处的内容进行修改 149 | d$ # 删除直到行尾 150 | ``` 151 | 152 | ## 一些快捷键和技巧 153 | 154 | 155 | ``` 156 | > # 将所选内容缩进一级 157 | < # 将所选内容取消缩进一级 158 | :earlier 15m # 将文档还原到 15 分钟前的状态 159 | :later 15m # 逆转上述命令 160 | ddp # 相邻行交换位置,先 dd 再 p 161 | . # 重复之前动作 162 | ``` 163 | 164 | ## 宏 165 | 166 | 宏基本上来说就是可录制的动作。 167 | 当你开始录制宏时,它会记录你使用的 **每个** 动作和命令, 168 | 直到你停止录制。当调用宏时,它会将这个完全相同的动作和命令序列 169 | 再次应用于所选文本之上。 170 | 171 | ``` 172 | qa # 开始录制一个叫 'a' 的宏 173 | q # 停止录制 174 | @a # 重播宏 175 | ``` 176 | 177 | ### 配置 ~/.vimrc 178 | 179 | .vimrc 可用于在启动时对 Vim 进行配置。 180 | 181 | 这里是一个示例 ~/.vimrc 文件: 182 | 183 | ``` 184 | " 示例 ~/.vimrc 185 | " 2015.10 186 | 187 | " 需要 Vim iMproved 版本 188 | set nocompatible 189 | 190 | " 根据文件名检测文件类型,以便能进行智能自动缩进等操作。 191 | filetype indent plugin on 192 | 193 | " 开启语法高亮 194 | syntax on 195 | 196 | " 更好的命令行补全 197 | set wildmenu 198 | 199 | " 除了当使用大写字母时使用大小写无关查找 200 | set ignorecase 201 | set smartcase 202 | 203 | " 当新开一行时,如果没有开启文件特定的缩进规则, 204 | " 则缩进保持与你当前行一致 205 | set autoindent 206 | 207 | " 在左侧显示行号 208 | set number 209 | 210 | " 缩进选项,根据个人偏好进行修改 211 | 212 | " 每个 TAB 的可视空格数 213 | set tabstop=4 214 | 215 | " 编辑时 TAB 对应的空格数 216 | set softtabstop=4 217 | 218 | " 当使用缩进操作 (>> 和 <<) 时缩进的空格数 219 | set shiftwidth=4 220 | 221 | " 将 TAB 转换成空格 222 | set expandtab 223 | 224 | " 为缩进和对齐开启智能化的 TAB 和空格切换功能 225 | set smarttab 226 | ``` 227 | 228 | ### 参考 229 | 230 | [Vim | Home](http://www.vim.org/index.php) 231 | 232 | `$ vimtutor` 233 | 234 | [A vim Tutorial and Primer](https://danielmiessler.com/study/vim/) 235 | 236 | [What are the dark corners of Vim your mom never told you about? (Stack Overflow thread)](http://stackoverflow.com/questions/726894/what-are-the-dark-corners-of-vim-your-mom-never-told-you-about) 237 | 238 | [Arch Linux Wiki](https://wiki.archlinux.org/index.php/Vim) 239 | -------------------------------------------------------------------------------- /GitHub入门与实践/README.md: -------------------------------------------------------------------------------- 1 | # learn-git 2 | 3 | 4 | 5 | 6 | 7 | [《GitHub入门与实践》](https://book.douban.com/subject/26462816/) 8 | 9 | [GitHub Tips (很实用,值得收藏)—— 《GitHub入门与实践》笔记](http://www.ituring.com.cn/article/264697) 10 | 11 | [Git 教程 | 菜鸟教程](http://www.runoob.com/git/git-tutorial.html) 12 | 13 | 14 | 15 | [free-programming-books](https://github.com/EbookFoundation/free-programming-books/blob/master/free-programming-books-zh.md) 16 | 17 | 版本控制 18 | 19 | * [Git - 简易指南](http://rogerdudler.github.io/git-guide/index.zh.html) 20 | * [Git-Cheat-Sheet](https://github.com/flyhigher139/Git-Cheat-Sheet) (感谢 @flyhigher139 翻译了中文版) 21 | * [Git Community Book 中文版](http://gitbook.liuhui998.com) 22 | * [git-flow 备忘清单](http://danielkummer.github.io/git-flow-cheatsheet/index.zh_CN.html) 23 | * [Git Magic](http://www-cs-students.stanford.edu/~blynn/gitmagic/intl/zh_cn/) 24 | * [Git 参考手册](http://gitref.justjavac.com) 25 | * [Github帮助文档](https://github.com/waylau/github-help) 26 | * [GitHub秘籍](https://snowdream86.gitbooks.io/github-cheat-sheet/content/zh/) 27 | * [Git教程](http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000) (本文由 [@廖雪峰](http://weibo.com/liaoxuefeng) 创作,如果觉得本教程对您有帮助,可以去 [iTunes](https://itunes.apple.com/cn/app/git-jiao-cheng/id876420437) 购买) 28 | * [Got GitHub](https://github.com/gotgit/gotgithub) 29 | * [GotGitHub](http://www.worldhello.net/gotgithub/index.html) 30 | * [HgInit (中文版)](https://zh-hginit.readthedocs.io/en/latest/) 31 | * [Mercurial 使用教程](https://www.mercurial-scm.org/wiki/ChineseTutorial) 32 | * [Pro Git](https://git-scm.com/book/zh/v2) 33 | * [Pro Git 中文版](https://www.gitbook.com/book/0532/progit/details) (整理在gitbook上) 34 | * [svn 手册](http://svnbook.red-bean.com/nightly/zh/index.html) 35 | * [学习 Git 分支](http://pcottle.github.io/learnGitBranching/) (点击右下角按钮可切换至简体及正体中文) 36 | * [沉浸式学 Git](http://igit.linuxtoy.org/index.html) 37 | * [猴子都能懂的GIT入门](http://backlogtool.com/git-guide/cn/) 38 | 39 | 40 | 程序员杂谈 41 | 42 | * [程序员的自我修养](http://www.kancloud.cn/kancloud/a-programmer-prepares) 43 | 44 | -------------------------------------------------------------------------------- /GitHub入门与实践/git-cn.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | category: tool 3 | tool: git 4 | contributors: 5 | - ["Jake Prather", "http://github.com/JakeHP"] 6 | translators: 7 | - ["Chenbo Li", "http://binarythink.net"] 8 | lang: zh-cn 9 | --- 10 | 11 | Git是一个分布式版本控制及源代码管理工具 12 | 13 | Git可以为你的项目保存若干快照,以此来对整个项目进行版本管理 14 | 15 | ## 版本 16 | 17 | ### 什么是版本控制 18 | 19 | 版本控制系统就是根据时间来记录一个或多个文件的更改情况的系统。 20 | 21 | ### 集中式版本控制 VS 分布式版本控制 22 | 23 | * 集中式版本控制的主要功能为同步,跟踪以及备份文件 24 | * 分布式版本控制则更注重共享更改。每一次更改都有唯一的标识 25 | * 分布式系统没有预定的结构。你也可以用git很轻松的实现SVN风格的集中式系统控制 26 | 27 | [更多信息](http://git-scm.com/book/en/Getting-Started-About-Version-Control) 28 | 29 | ### 为什么要使用Git 30 | 31 | * 可以离线工作 32 | * 和他人协同工作变得简单 33 | * 分支很轻松 34 | * 合并很容易 35 | * Git系统速度快,也很灵活 36 | 37 | ## Git 架构 38 | 39 | 40 | ### 版本库 41 | 42 | 一系列文件,目录,历史记录,提交记录和头指针。 43 | 可以把它视作每个源代码文件都带有历史记录属性数据结构 44 | 45 | 一个Git版本库包括一个 .git 目录和其工作目录 46 | 47 | ### .git 目录(版本库的一部分) 48 | 49 | .git 目录包含所有的配置、日志、分支信息、头指针等 50 | [详细列表](http://gitready.com/advanced/2009/03/23/whats-inside-your-git-directory.html) 51 | 52 | ### 工作目录 (版本库的一部分) 53 | 54 | 版本库中的目录和文件,可以看做就是你工作时的目录 55 | 56 | ### 索引(.git 目录) 57 | 58 | 索引就是git中的 staging 区. 可以算作是把你的工作目录与Git版本库分割开的一层 59 | 这使得开发者能够更灵活的决定要将要在版本库中添加什么内容 60 | 61 | ### 提交 62 | 63 | 一个 git 提交就是一组更改或者对工作目录操作的快照 64 | 比如你添加了5个文件,删除了2个文件,那么这些变化就会被写入一个提交比如你添加了5个文件,删除了2个文件,那么这些变化就会被写入一个提交中 65 | 而这个提交之后也可以被决定是否推送到另一个版本库中 66 | 67 | ### 分支 68 | 69 | 分支其实就是一个指向你最后一次的提交的指针 70 | 当你提交时,这个指针就会自动指向最新的提交 71 | 72 | ### 头指针 与 头(.git 文件夹的作用) 73 | 74 | 头指针是一个指向当前分支的指针,一个版本库只有一个当前活动的头指针 75 | 而头则可以指向版本库中任意一个提交,每个版本库也可以有多个头 76 | 77 | ### 其他形象化解释 78 | 79 | * [给计算机科学家的解释](http://eagain.net/articles/git-for-computer-scientists/) 80 | * [给设计师的解释](http://hoth.entp.com/output/git_for_designers.html) 81 | 82 | 83 | ## 命令 84 | 85 | 86 | ### 初始化 87 | 88 | 创建一个新的git版本库。这个版本库的配置、存储等信息会被保存到.git文件夹中 89 | 90 | ```bash 91 | $ git init 92 | ``` 93 | 94 | ### 配置 95 | 96 | 更改设置。可以是版本库的设置,也可以是系统的或全局的 97 | 98 | 99 | ```bash 100 | # 输出、设置基本的全局变量 101 | $ git config --global user.email 102 | $ git config --global user.name 103 | 104 | $ git config --global user.email "MyEmail@Zoho.com" 105 | $ git config --global user.name "My Name" 106 | ``` 107 | 108 | [关于git的更多设置](http://git-scm.com/docs/git-config) 109 | 110 | ### 帮助 111 | 112 | git内置了对命令非常详细的解释,可以供我们快速查阅 113 | 114 | ```bash 115 | # 查找可用命令 116 | $ git help 117 | 118 | # 查找所有可用命令 119 | $ git help -a 120 | 121 | # 在文档当中查找特定的命令 122 | # git help <命令> 123 | $ git help add 124 | $ git help commit 125 | $ git help init 126 | ``` 127 | 128 | ### 状态 129 | 130 | 显示索引文件(也就是当前工作空间)和当前的头指针指向的提交的不同 131 | 132 | 133 | ```bash 134 | # 显示分支,为跟踪文件,更改和其他不同 135 | $ git status 136 | 137 | # 查看其他的git status的用法 138 | $ git help status 139 | ``` 140 | 141 | ### 添加 142 | 143 | 添加文件到当前工作空间中。如果你不使用 `git add` 将文件添加进去, 144 | 那么这些文件也不会添加到之后的提交之中 145 | 146 | ```bash 147 | # 添加一个文件 148 | $ git add HelloWorld.java 149 | 150 | # 添加一个子目录中的文件 151 | $ git add /path/to/file/HelloWorld.c 152 | 153 | # 支持正则表达式 154 | $ git add ./*.java 155 | ``` 156 | 157 | ### 分支 158 | 159 | 管理分支,可以通过下列命令对分支进行增删改查 160 | 161 | ```bash 162 | # 查看所有的分支和远程分支 163 | $ git branch -a 164 | 165 | # 创建一个新的分支 166 | $ git branch myNewBranch 167 | 168 | # 删除一个分支 169 | $ git branch -d myBranch 170 | 171 | # 重命名分支 172 | # git branch -m <旧名称> <新名称> 173 | $ git branch -m myBranchName myNewBranchName 174 | 175 | # 编辑分支的介绍 176 | $ git branch myBranchName --edit-description 177 | ``` 178 | 179 | ### 检出 180 | 181 | 将当前工作空间更新到索引所标识的或者某一特定的工作空间 182 | 183 | ```bash 184 | # 检出一个版本库,默认将更新到master分支 185 | $ git checkout 186 | # 检出到一个特定的分支 187 | $ git checkout branchName 188 | # 新建一个分支,并且切换过去,相当于"git branch <名字>; git checkout <名字>" 189 | $ git checkout -b newBranch 190 | ``` 191 | 192 | ### clone 193 | 194 | 这个命令就是将一个版本库拷贝到另一个目录中,同时也将 195 | 分支都拷贝到新的版本库中。这样就可以在新的版本库中提交到远程分支 196 | 197 | ```bash 198 | # clone learnxinyminutes-docs 199 | $ git clone https://github.com/adambard/learnxinyminutes-docs.git 200 | ``` 201 | 202 | ### commit 203 | 204 | 将当前索引的更改保存为一个新的提交,这个提交包括用户做出的更改与信息 205 | 206 | ```bash 207 | # 提交时附带提交信息 208 | $ git commit -m "Added multiplyNumbers() function to HelloWorld.c" 209 | ``` 210 | 211 | ### diff 212 | 213 | 显示当前工作空间和提交的不同 214 | 215 | ```bash 216 | # 显示工作目录和索引的不同 217 | $ git diff 218 | 219 | # 显示索引和最近一次提交的不同 220 | $ git diff --cached 221 | 222 | # 显示工作目录和最近一次提交的不同 223 | $ git diff HEAD 224 | ``` 225 | 226 | ### grep 227 | 228 | 可以在版本库中快速查找 229 | 230 | 可选配置: 231 | 232 | ```bash 233 | # 感谢Travis Jeffery提供的以下用法: 234 | # 在搜索结果中显示行号 235 | $ git config --global grep.lineNumber true 236 | 237 | # 是搜索结果可读性更好 238 | $ git config --global alias.g "grep --break --heading --line-number" 239 | ``` 240 | 241 | ```bash 242 | # 在所有的java中查找variableName 243 | $ git grep 'variableName' -- '*.java' 244 | 245 | # 搜索包含 "arrayListName" 和, "add" 或 "remove" 的所有行 246 | $ git grep -e 'arrayListName' --and \( -e add -e remove \) 247 | ``` 248 | 249 | 更多的例子可以查看: 250 | [Git Grep Ninja](http://travisjeffery.com/b/2012/02/search-a-git-repo-like-a-ninja) 251 | 252 | ### log 253 | 254 | 显示这个版本库的所有提交 255 | 256 | ```bash 257 | # 显示所有提交 258 | $ git log 259 | 260 | # 显示某几条提交信息 261 | $ git log -n 10 262 | 263 | # 仅显示合并提交 264 | $ git log --merges 265 | ``` 266 | 267 | ### merge 268 | 269 | 合并就是将外部的提交合并到自己的分支中 270 | 271 | ```bash 272 | # 将其他分支合并到当前分支 273 | $ git merge branchName 274 | 275 | # 在合并时创建一个新的合并后的提交 276 | $ git merge --no-ff branchName 277 | ``` 278 | 279 | ### mv 280 | 281 | 重命名或移动一个文件 282 | 283 | ```bash 284 | # 重命名 285 | $ git mv HelloWorld.c HelloNewWorld.c 286 | 287 | # 移动 288 | $ git mv HelloWorld.c ./new/path/HelloWorld.c 289 | 290 | # 强制重命名或移动 291 | # 这个文件已经存在,将要覆盖掉 292 | $ git mv -f myFile existingFile 293 | ``` 294 | 295 | ### pull 296 | 297 | 从远端版本库合并到当前分支 298 | 299 | ```bash 300 | # 从远端origin的master分支更新版本库 301 | # git pull <远端> <分支> 302 | $ git pull origin master 303 | ``` 304 | 305 | ### push 306 | 307 | 把远端的版本库更新 308 | 309 | ```bash 310 | # 把本地的分支更新到远端origin的master分支上 311 | # git push <远端> <分支> 312 | # git push 相当于 git push origin master 313 | $ git push origin master 314 | ``` 315 | 316 | ### rebase (谨慎使用) 317 | 318 | 将一个分支上所有的提交历史都应用到另一个分支上 319 | *不要在一个已经公开的远端分支上使用rebase*. 320 | 321 | ```bash 322 | # 将experimentBranch应用到master上面 323 | # git rebase 324 | $ git rebase master experimentBranch 325 | ``` 326 | 327 | [更多阅读](http://git-scm.com/book/en/Git-Branching-Rebasing) 328 | 329 | ### reset (谨慎使用) 330 | 331 | 将当前的头指针复位到一个特定的状态。这样可以使你撤销merge、pull、commits、add等 332 | 这是个很强大的命令,但是在使用时一定要清楚其所产生的后果 333 | 334 | ```bash 335 | # 使 staging 区域恢复到上次提交时的状态,不改变现在的工作目录 336 | $ git reset 337 | 338 | # 使 staging 区域恢复到上次提交时的状态,覆盖现在的工作目录 339 | $ git reset --hard 340 | 341 | # 将当前分支恢复到某次提交,不改变现在的工作目录 342 | # 在工作目录中所有的改变仍然存在 343 | $ git reset 31f2bb1 344 | 345 | # 将当前分支恢复到某次提交,覆盖现在的工作目录 346 | # 并且删除所有未提交的改变和指定提交之后的所有提交 347 | $ git reset --hard 31f2bb1 348 | ``` 349 | 350 | ### rm 351 | 352 | 和add相反,从工作空间中去掉某个文件 353 | 354 | ```bash 355 | # 移除 HelloWorld.c 356 | $ git rm HelloWorld.c 357 | 358 | # 移除子目录中的文件 359 | $ git rm /pather/to/the/file/HelloWorld.c 360 | ``` 361 | 362 | ## 更多阅读 363 | 364 | * [tryGit - 学习Git的有趣方式](http://try.github.io/levels/1/challenges/1) 365 | 366 | * [git-scm - 视频教程](http://git-scm.com/videos) 367 | 368 | * [git-scm - 文档](http://git-scm.com/docs) 369 | 370 | * [Atlassian Git - 教程与工作流程](https://www.atlassian.com/git/) 371 | 372 | * [SalesForce Cheat Sheet](https://na1.salesforce.com/help/doc/en/salesforce_git_developer_cheatsheet.pdf) 373 | 374 | * [GitGuys](http://www.gitguys.com/) 375 | -------------------------------------------------------------------------------- /GitHub入门与实践/《GitHub入门与实践》 笔记.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | `Upload Files`上传文件 4 | 趋势 https://github.com/trending 5 | 不需要在Git仓库中版本管理的文件记录在`.gitignore `文件中 6 | `.git`目录存储这管理当前目录内容所需的仓库数据,目录内容称为`附属于该仓库的工作树 ` 7 | `commit`简述提交的更改,`description`记述更改的原因和详细内容,`commit`有指向该提交的哈希值 8 | `Gist`用于管理和发布一些小的代码片段 9 | `Download Zip`将当前阅读分支的文件单纯以ZIP形式打包下载,和`clone`不同 10 | `README.py`记录该仓库中软件的说明或使用方法及许可协议等信息 11 | 点击代码某行,URL末尾自动添`#L10-15` 12 | 按`t`打开file finder,用部分名称搜索 13 | 14 | ### 改URL查看差别 15 | ``` 16 | https://github.com/rails/rails/compare/4-0-stable...3-2-stable 17 | https://github.com/rails/rails/compare/master@{7.day.ago}...master 18 | day 19 | week 20 | month 21 | year 22 | https://github.com/rails/rails/compare/master@{2013-01-01}...master 23 | ``` 24 | 25 | ### Issue 26 | bug报告,询问探讨,To-Do list 27 | GFM语法,图片拖到文本框可粘贴,添加`Lable`在左侧显示标签,里程碑 28 | ``` 29 | Tasklist语法 30 | # 本月要做的任务 31 | - [ ] 完成图片 32 | - [x] 完成部署工具的设置 33 | - [ ] 实现抽签功能 34 | ``` 35 | 在提交信息中加入`#编号`连接到仓库对应的Issue编号,`用户名/仓库名/编号` 36 | `close Issue`方法`fix #编号` 37 | 编号与`Pull Request`通用 38 | 选中评论按`r`引用可回复 39 | 40 | ### 其他功能 41 | GitHub Pages 42 | GitHub Jobs 43 | GitHub API 44 | 45 | ### Keyboard shortcuts 46 | 47 | | | Site wide shortcuts | 48 | | --------- | ------------------------- | 49 | | s | Focus search bar | 50 | | g n | Go to Notifications | 51 | | g d | Go to Dashboard | 52 | | ? | Bring up this help dialog | 53 | | j | Move selection down | 54 | | k | Move selection up | 55 | | x | Toggle selection | 56 | | o / enter | Open selection | 57 | 58 | | | Repositories | 59 | | ---- | ------------------- | 60 | | g c | Go to Code | 61 | | g i | Go to Issues | 62 | | g p | Go to Pull Requests | 63 | | g w | Go to Wiki | 64 | 65 | | | Source code browsing | 66 | | ---- | -------------------------------- | 67 | | t | Activates the file finder | 68 | | l | Jump to line | 69 | | w | Switch branch/tag | 70 | | y | Expand URL to its canonical form | 71 | | i | Show/hide all inline notes | 72 | 73 | | | Dashboards | 74 | | ---- | ------------------------ | 75 | | g i | Go to your issues | 76 | | g p | Go to your pull requests | -------------------------------------------------------------------------------- /SICP/README.md: -------------------------------------------------------------------------------- 1 | #### 编译原理 SICP 2 | 3 | [豆瓣 《计算机程序的构造和解释》](https://book.douban.com/subject/1148282/) 4 | 5 | [Structure and Interpretation of Computer Program 英文原书链接](http://mitpress.mit.edu/sicp/) 6 | 7 | [裘宗燕 程序设计技术和方法](http://www.math.pku.edu.cn/teachers/qiuzy/progtech/) 8 | 9 | [SICP 的魔法](https://github.com/lfkdsk/SICP-Magical-Book) 10 | 11 | [SICP Python 描述 中文版](https://github.com/wizardforcel/sicp-py-zh) 12 | 13 | [sicp-pdf](https://github.com/sarabander/sicp-pdf) 14 | 15 | 16 | 17 | 18 | > #### [ 编程入门指南](https://zhuanlan.zhihu.com/p/19959253) SICP辅助资源: 19 | > 20 | > 1. [Udacity CS212 Design of Computer Program](https://cn.udacity.com/course/design-of-computer-programs--cs212) 21 | > 22 | > 2. [How to Design Programs, Second Edition](http://www.ccs.neu.edu/home/matthias/HtDP2e/Draft/index.html) 23 | > 24 | > 3. [cs61a:Structure and Interpretation of Computer Program](https://cs61a.org/) [CS61A: Online Textbook](http://www-inst.eecs.berkeley.edu/~cs61a/sp12/book/index.html) [《计算机程序的结构和解释》公开课 翻译项目](https://github.com/DeathKing/Learning-SICP) 25 | > 26 | > 4. [Composing Programs](http://composingprograms.com/) 27 | > 28 | > 5. [SICP 解题集](http://sicp.readthedocs.io/en/latest/index.html) 29 | > 30 | > - [Mega Project List](https://github.com/karan/Projects/) 31 | 32 | [SICP终于看完了,有一些经验想分享出来](http://cocode.cc/t/sicp/3397) -------------------------------------------------------------------------------- /SICP/Racket/README.md: -------------------------------------------------------------------------------- 1 | ## [Racket语言入门](http://racket.tchen.me/index.html) 2 | 3 | by Tyr Chen 4 | 5 | ![img](http://racket.tchen.me/cover.jpg) -------------------------------------------------------------------------------- /SICP/Racket/my-2048.rkt: -------------------------------------------------------------------------------- 1 | #lang racket 2 | 3 | (require "utility.rkt" 4 | (rename-in 2htdp/image [rotate rotate-1]) 5 | 2htdp/universe) 6 | 7 | (define PIECE_DIST '(2 2 2 2 2 2 2 2 2 4)) 8 | 9 | (define (make-board n) 10 | (make-list n (make-list n 0))) 11 | 12 | (define (init-board n) 13 | (put-random-piece (put-random-piece (make-board n)))) 14 | 15 | (define (get-a-piece) 16 | (choice PIECE_DIST)) 17 | 18 | ; e.g. '((2 0) (2 4)) -> #t 19 | (define (avail? lst) 20 | (if (list? lst) 21 | (ormap avail? lst) 22 | (zero? lst))) 23 | 24 | ; e.g. '((2 2) (2 0) (0 0)) -> '(1 2) 25 | (define (get-empty-refs lst zero-fun?) 26 | (for/list ([item lst] 27 | [i (range (length lst))] 28 | #:when (zero-fun? item)) 29 | i)) 30 | 31 | ; e.g. '(0 2 0 0) -> '(0 2 0 2) 32 | ; e.g. '((0 2 0 0) (2 4 8 16) (0 4 4 8) (2 0 0 0)) -> 33 | ; '((0 2 0 0) (2 4 8 16) (0 4 4 8) (2 0 2 0)) 34 | (define (put-random-piece lst) 35 | (if (avail? lst) 36 | (if (list? lst) 37 | (let* ([i (choice (get-empty-refs lst avail?))] 38 | [v (list-ref lst i)]) 39 | (append (take lst i) 40 | (cons (put-random-piece v) (drop lst (add1 i))))) 41 | (get-a-piece)) 42 | lst)) 43 | 44 | ; e.g. '(2 2 2 4 4 4 8) -> '(4 2 8 4 8) 45 | (define (merge row) 46 | (cond [(<= (length row) 1) row] 47 | [(= (first row) (second row)) 48 | (cons (* 2 (first row)) (merge (drop row 2)))] 49 | [else (cons (first row) (merge (rest row)))])) 50 | 51 | ; e.g. '(2 0 4 4) #f -> (0 0 2 8) 52 | (define (move-row row v left?) 53 | (if left? 54 | (let* ([n (length row)] 55 | [l (merge (filter (λ (x) (not (zero? x))) row))] 56 | [padding (make-list (- n (length l)) v)]) 57 | (append l padding)) 58 | (reverse (move-row (reverse row) v (not left?))))) 59 | 60 | (define (move lst v left?) 61 | (map (λ (x) (move-row x v left?)) lst)) 62 | 63 | (define (move-left lst) 64 | (put-random-piece (move lst 0 #t))) 65 | 66 | (define (move-right lst) 67 | (put-random-piece (move lst 0 #f))) 68 | 69 | (define (move-up lst) 70 | ((compose1 rotate move-left rotate) lst)) 71 | 72 | (define (move-down lst) 73 | ((compose1 rotate move-right rotate) lst)) 74 | 75 | (define ALL-OPS (list move-right move-down move-left move-up)) 76 | 77 | ; '((2 8 4 2) (8 4 8 16) (4 32 2 4) (2 16 4 2)) -> #t 78 | (define (finished? lst) 79 | (andmap (λ (op) (equal? lst (op lst))) ALL-OPS)) 80 | 81 | (define (test-play lst step) 82 | (if (and (not (avail? lst)) (finished? lst)) 83 | (values lst step) 84 | (test-play ((choice ALL-OPS) lst) (add1 step)))) 85 | 86 | 87 | ;; game 88 | (define ALPHA #xb8) 89 | 90 | (define GRID-COLOR (hex->rgb "#bbada0")) 91 | 92 | (define TILE-BG 93 | (make-hash (map (λ (item) (cons (first item) (hex->rgb (second item)))) 94 | '((0 "#ccc0b3") (2 "#eee4da") (4 "#ede0c8") 95 | (8 "#f2b179") (16 "#f59563") (32 "#f67c5f") 96 | (64 "#f65e3b") (128 "#edcf72") (256 "#edcc61") 97 | (512 "#edc850") (1024 "#edc53f") (2048 "#edc22e"))))) 98 | 99 | (define TILE-FG 'white) 100 | 101 | (define TILE-SIZE 80) 102 | (define TILE-TEXT-SIZE 50) 103 | (define MAX-TEXT-SIZE 65) 104 | (define TILE-SPACING 5) 105 | 106 | (define (make-tile n) 107 | (define (text-content n) 108 | (if (zero? n) "" 109 | (number->string n))) 110 | 111 | (overlay (let* ([t (text (text-content n) TILE-TEXT-SIZE TILE-FG)] 112 | [v (max (image-width t) (image-height t))] 113 | [s (if (> v MAX-TEXT-SIZE) (/ MAX-TEXT-SIZE v) 1)]) 114 | (scale s t)) 115 | (square TILE-SIZE 'solid (hash-ref TILE-BG n)) 116 | (square (+ TILE-SIZE (* 2 TILE-SPACING)) 'solid GRID-COLOR))) 117 | 118 | (define (show-board b) 119 | (let ([images (for/list ([row b]) 120 | (hc-append (map make-tile row) TILE-SPACING))]) 121 | (vc-append images TILE-SPACING))) 122 | 123 | (define (show-board-over b) 124 | (let* ([board (show-board b)] 125 | [layer (square (image-width board) 'solid (color 0 0 0 90))]) 126 | (overlay (text "Game over!" 40 TILE-FG) 127 | layer board))) 128 | 129 | (define (key->ops a-key) 130 | (cond 131 | [(key=? a-key "left") move-left] 132 | [(key=? a-key "right") move-right] 133 | [(key=? a-key "up") move-up] 134 | [(key=? a-key "down") move-down] 135 | [else (λ (x) x)])) 136 | 137 | (define (change b key) 138 | ((key->ops key) b)) 139 | 140 | (define (start n) 141 | (big-bang (init-board n) 142 | (to-draw show-board) 143 | (on-key change) 144 | (stop-when finished? show-board-over) 145 | (name "2048 - racket"))) 146 | (start 4) -------------------------------------------------------------------------------- /SICP/Racket/qsort2.rkt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/racket 2 | #lang racket 3 | 4 | (define lst (list 234 123 68 74 100 1 3 5 8 4 2)) 5 | 6 | ( 7 | define (qsort2 l cmp) 8 | ( 9 | if(or (empty? l) (empty? (cdr l))) l 10 | ( 11 | let*-values 12 | ( 13 | [(key) (car l)] 14 | [(small big) 15 | ( 16 | partition (lambda (x) (cmp x key)) (cdr l) 17 | ) 18 | ] 19 | ) 20 | ( 21 | append (qsort2 small cmp) (list key) (qsort2 big cmp) 22 | ) 23 | ) 24 | ) 25 | ) 26 | (qsort2 lst <) 27 | (qsort2 lst >) 28 | (qsort2 (list "hello" "world" "baby") string) 74 | 75 | (newline) 76 | (sort lst <) 77 | (sort (list "hello" "world" "babay") string '(170 187 204) 15 | (define (hex->rgb hex [alpha 255]) 16 | (define r (regexp-match #px"^#(\\w{2})(\\w{2})(\\w{2})$" hex)) 17 | (define (append-hex s) (string-append "#x" s)) 18 | (define (color-alpha c) (apply color (append c (list alpha)))) 19 | (if r 20 | (color-alpha (map (compose1 string->number append-hex) (cdr r))) 21 | #f)) 22 | 23 | (define (image-append images get-pos overlap) 24 | (if (<= (length images) 1) 25 | (car images) 26 | (let* ([a (first images)] 27 | [b (second images)] 28 | [img (apply overlay/xy 29 | (append (list a) (get-pos a overlap) (list b)))]) 30 | (image-append (cons img (drop images 2)) get-pos overlap)))) 31 | 32 | (define (hc-append images [overlap 0]) 33 | (image-append images 34 | (λ (img o) (list (- (image-width img) o) 0)) 35 | overlap)) 36 | 37 | (define (vc-append images [overlap 0]) 38 | (image-append images 39 | (λ (img o) (list 0 (- (image-height img) o))) 40 | overlap)) -------------------------------------------------------------------------------- /SICP/SICP终于看完了,有一些经验想分享出来.md: -------------------------------------------------------------------------------- 1 | # [SICP终于看完了,有一些经验想分享出来](http://cocode.cc/t/sicp/3397) 2 | 3 | [学习资料](http://cocode.cc/tags/%E5%AD%A6%E4%B9%A0%E8%B5%84%E6%96%99) 4 | 5 | [galaxy21](http://cocode.cc/users/galaxy21) 6 | 7 | ##### 2015.11.14 部分错误更新 加入镇楼图(๑•ᴗ•๑) 8 | 9 | ![img](http://cocode.cc/uploads/default/optimized/2X/a/a399e135871accf399e0f5640f5d2308b5bd6a43_1_500x500.jpg) 10 | 11 | ### 工具 12 | 13 | 最开始的时候我用的是[DrRacket](http://racket-lang.org/)和racket方言。[DrRacket](http://racket-lang.org/)使用简单,自带中文,相比于emacs更加容易让新手接受。而关于racket方言因为有实时错误提示和类名归属,所以在前两章的大部分情况下都是使用racket方言。使用racket时候只需要将`#lang racket`放入第一行即可。 14 | 15 | 但是因为racket取消了set-car!和set-cdr!,所以从第二章末开始使用这两个函数的文件都需要将第一行改为`#lang planet neil/sicp`,这样就能保证程序正常运行。 16 | 在2.2.4中使用了图形编辑,只需要在第二行加入`(require ( planet "sicp.ss" ( "soegaard" "sicp.plt" 2 1)))`即可。 17 | 18 | 随着写的文件越来越大,在使用`#lang planet neil/sicp`的时候编译速度有点慢,因此从第四章开始就开始使用[Emacs](http://www.gnu.org/software/emacs/emacs.html)编辑[MIT Scheme](http://www.gnu.org/software/mit-scheme/)编译了。当然这个并不是必须的,所以关于[Emacs](http://www.gnu.org/software/emacs/emacs.html)和[MIT Scheme](http://www.gnu.org/software/mit-scheme/)以后再说。 19 | 20 | ### 参考资料 21 | 22 | [SICP英文原版](https://mitpress.mit.edu/sicp/full-text/book/book.html):SICP中文版虽然相比较其他计算机科学类的中翻书极为良心,但是难免一些小错误。而且参考原版也能更有利于理解。 23 | 24 | [正文源码](https://mitpress.mit.edu/sicp/code/index.html):有些正文中模糊和省略的地方可以参考。 25 | 26 | [SICP公开课](http://i.youku.com/u/UNTcxODk3ODQw):翻译良心 27 | 28 | [MIT 6.001官网](http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-001-structure-and-interpretation-of-computer-programs-spring-2005/):除了课程视频,还提供了大量的笔记和两次考试题,配合视频和书事半功倍。 29 | 30 | [SICP 解题集](http://sicp.readthedocs.org/en/latest/index.html):(到习题4.14)前两章讲解详细,如果有错误后面评论也会指出来。但是到了第三章答案和讲解质量就大幅下降,建议不要看。 31 | 32 | [sicp-solutions](http://community.schemewiki.org/?sicp-solutions):习题答案集(全),除了一些画图题和项目太大的没有答案外,基本都有答案。但是因为网站问题,有的答案排版有些问题。 33 | 34 | [@uents blog](http://uents.hatenablog.com/entry/sicp/index):日语博客(到第4章),讲解详细,会日语的同学可以看一下。他的[GitHub](https://github.com/Galaxy21Yang/sicp)是用DrRacket写的,而且能够保证每个题目都能跑起来。 35 | 36 | [spacemanaki](https://github.com/spacemanaki/sicp):sicp-solutions答案提供者的GitHub。 37 | 38 | [ivanjovanovic](https://github.com/ivanjovanovic/sicp):另一个答案比较全的GitHub。 39 | 40 | ##### 其他资料 41 | 42 | [Weiqun Zhang's Blog](https://wqzhang.wordpress.com/sicp-solutions/):(到习题4.49)部分答案见解独到。 43 | 44 | [How to Design Programs63](http://www.htdp.org/2003-09-26/Book/):另一本scheme经典教材,相当于SICP的前三章的详细版。 45 | 46 | [Sample Programming Assignments](https://mitpress.mit.edu/sicp/psets/index.html):书中一些比较大的项目的完整源码 47 | 48 | ### 其他 49 | 50 | 关于我的读书深度,在前三章中,内容还算比较简单,所以尽量做到正文读完,习题能够尽量自己完成。后两章难度明显上升,所以能做到完全理解正文就已经尽力了,习题方面前几题尽量先做,虽然大部分情况下很难完美做出来。最后一题就直接放弃,能看懂答案就不错了。 (๑•ᴗ•๑) 51 | 虽然书看完了,但是里面有很多东西自己并没有真正掌握,用scheme编程也还没结束,所以以后还有可能二刷SICP,所以这篇文章今后还会持续更新。 52 | 当然也欢迎大家能够提出建议和问题,我也会尽力回答。 53 | 54 | 持续更新地址: http://blog.yangyize.com/2015/11/02/sicp/ 55 | GitHub: https://github.com/Galaxy21Yang -------------------------------------------------------------------------------- /SICP/chapter 1/1.11.rkt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/racket 2 | #lang racket 3 | 4 | (define (f n) 5 | (if (< n 3) 6 | n 7 | (+ (f (- n 1)) 8 | (* 2 (f (- n 2))) 9 | (* 3 (f (- n 3)))))) 10 | 11 | (f 0) 12 | (f 1) 13 | (f 2) 14 | (f 3) 15 | (f 4) 16 | (f 5) 17 | ;;;;;; 18 | ;; 0 19 | ;; 1 20 | ;; 2 21 | ;; 4 22 | ;; 11 23 | ;; 25 24 | ;;;;;; 25 | (define (g n) 26 | (define (g-iter x y z count) 27 | (if (< count 3) 28 | (if (< count 2) count z) 29 | (g-iter y z (+ z (* 2 y) (* 3 x)) (- count 1)))) 30 | (g-iter 0 1 2 n)) 31 | 32 | (g 0) 33 | (g 1) 34 | (g 2) 35 | (g 3) 36 | (g 4) 37 | (g 5) -------------------------------------------------------------------------------- /SICP/chapter 1/1.16.rkt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/racket 2 | #lang racket 3 | 4 | (define (square x) 5 | (* x x)) 6 | (define (even? x) 7 | (= (remainder x 2) 0)) 8 | 9 | (define (fast-expt b n) 10 | (define (fast-expt-iter a b count) 11 | (cond((= count 0) a) 12 | ((even? count) (fast-expt-iter a (square b) (/ count 2))) 13 | (else (fast-expt-iter (* a b) b (- count 1))))) 14 | (fast-expt-iter 1 b n)) 15 | 16 | (fast-expt 2 11) -------------------------------------------------------------------------------- /SICP/chapter 1/1.18.rkt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/racket 2 | #lang racket 3 | 4 | (define (even? x) 5 | (= (remainder x 2) 0)) 6 | (define (double x) 7 | (+ x x)) 8 | (define (halve x) 9 | (/ x 2) 10 | ) 11 | 12 | (define (fast* x y) 13 | (define (fast*-iter a x y) 14 | (cond((= y 0) a) 15 | ((even? y) (fast*-iter a (double x) (halve y))) 16 | (else (fast*-iter (+ a x) x (- y 1))))) 17 | (fast*-iter 0 x y)) 18 | 19 | (fast* 10 11) -------------------------------------------------------------------------------- /SICP/chapter 1/1.19.rkt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/racket 2 | #lang racket 3 | 4 | ;http://sicp.readthedocs.io/en/latest/chp1/19.html 5 | (define (square x) 6 | (* x x)) 7 | 8 | (define (fib n) 9 | (fib-iter 1 0 0 1 n)) 10 | 11 | (define (fib-iter a b p q n) 12 | (cond ((= n 0) 13 | b) 14 | ((even? n) 15 | (fib-iter a 16 | b 17 | (+ (square p) (square q)) ; compute p' 18 | (+ (* 2 p q) (square q)) ; compute q' 19 | (/ n 2))) 20 | (else 21 | (fib-iter (+ (* b q) (* a q) (* a p)) 22 | (+ (* b p) (* a q)) 23 | p 24 | q 25 | (- n 1))))) 26 | 27 | (fib 0) 28 | (fib 5) 29 | (fib 8) -------------------------------------------------------------------------------- /SICP/chapter 1/1.23.rkt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/racket 2 | #lang racket 3 | 4 | (define (square x) 5 | (* x x)) 6 | 7 | (define (prime? n) 8 | 9 | (define (next t) 10 | (if (= t 2) 11 | 3 12 | (+ t 2))) 13 | 14 | (define (divides? a b) 15 | (= (remainder b a) 0)) 16 | 17 | (define (find-divisor n test-divisor) 18 | (cond ((> (square test-divisor) n) 19 | n) 20 | ((divides? test-divisor n) 21 | test-divisor) 22 | (else 23 | (find-divisor n (next test-divisor))))) 24 | 25 | (define (smallest-divisor n) 26 | (find-divisor n 2)) 27 | 28 | (= n (smallest-divisor n))) 29 | 30 | (prime? 15) 31 | (prime? 11) -------------------------------------------------------------------------------- /SICP/chapter 1/1.28.rkt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/racket 2 | #lang racket 3 | 4 | (define (even? x) 5 | (= (remainder x 2) 0)) 6 | (define (square x) 7 | (* x x)) 8 | (define (!= a b) 9 | (not (= a b))) 10 | 11 | (define (nontrivial-square-root? a n) 12 | (and (!= a 1) 13 | (!= a (- n 1)) 14 | (= 1 (remainder (square a) n)))) 15 | 16 | (define (expmod base exp m) 17 | (cond 18 | ((= exp 0) 1) 19 | ((nontrivial-square-root? base m) 0) 20 | ((even? exp) 21 | (remainder (square (expmod base (/ exp 2) m)) 22 | m)) 23 | (else 24 | (remainder (* base (expmod base (- exp 1) m)) 25 | m)))) 26 | 27 | (define (MR-test n) 28 | (define (try-it a) 29 | (= (expmod a (- n 1) n) 1)) 30 | (try-it (+ 1 (random (- n 1))))) 31 | 32 | (define (fast-primer? n times) 33 | (cond ((= times 0) #t) 34 | ((MR-test n)(fast-primer? n (- times 1))) 35 | (else #f) 36 | )) 37 | 38 | (define (Miller-Rabin-test n) 39 | (fast-primer? n (ceiling (/ n 2)))) 40 | 41 | (Miller-Rabin-test 561) 42 | (Miller-Rabin-test 1105) 43 | (Miller-Rabin-test 1729) 44 | (Miller-Rabin-test 2465) 45 | (Miller-Rabin-test 2821) 46 | (Miller-Rabin-test 6601) 47 | (newline) 48 | (Miller-Rabin-test 7) 49 | (Miller-Rabin-test 17) 50 | (Miller-Rabin-test 19) -------------------------------------------------------------------------------- /SICP/chapter 1/1.29.rkt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/racket 2 | #lang racket 3 | 4 | (define (cube x) 5 | (* x x x)) 6 | 7 | (define (sum term a next b) 8 | (define (iter a r) 9 | (if (> a b) 10 | r 11 | (iter (next a) (+ (term a) r)))) 12 | (iter a 0)) 13 | 14 | (define (simpson-integral f a b n) 15 | (define h 16 | (/ (- b a) n)) 17 | (define (y k) 18 | (f (+ a (* k h)))) 19 | (define (next x) 20 | (+ x 2)) 21 | (* 1.0 22 | (/ h 3) 23 | (+ (* 4 (sum y 1 next (- n 1))) 24 | (* 2 (sum y 2 next (- n 2))) 25 | (y 0) 26 | (y n)))) 27 | 28 | (simpson-integral cube 0 1 100) 29 | (simpson-integral cube 0 1 1000) 30 | -------------------------------------------------------------------------------- /SICP/chapter 1/1.32.rkt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/racket 2 | #lang racket 3 | 4 | (define (accumulate combiner null-value term a next b) 5 | (if (> a b) 6 | null-value 7 | (combiner (term a) 8 | (accumulate combiner null-value term (next a) next b)))) 9 | 10 | (define (accumulate-iter combiner null-value term a next b) 11 | (define (iter a result) 12 | (if (> a b) 13 | result 14 | (iter (next a) 15 | (combiner result (term a))))) 16 | (iter a null-value)) 17 | 18 | (define (sum term a next b ) 19 | (accumulate-iter + 0 term a next b)) 20 | 21 | (define (product term a next b ) 22 | (accumulate-iter * 1 term a next b)) 23 | 24 | 25 | (sum (lambda (x) x) 26 | 1 27 | (lambda (i) (+ i 1)) 28 | 5) 29 | 30 | (product (lambda (x) x) 31 | 1 32 | (lambda (i) (+ i 1)) 33 | 5) 34 | -------------------------------------------------------------------------------- /SICP/chapter 1/1.33.rkt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/racket 2 | #lang racket 3 | 4 | (define (square x) 5 | (* x x)) 6 | 7 | (define (prime? n) 8 | 9 | (define (next n) 10 | (if (= n 2) 11 | 3 12 | (+ n 2))) 13 | 14 | (define (smallest-divisor n) 15 | (find-divisor n 2)) 16 | 17 | (define (find-divisor n test-divisor) 18 | (cond ((> (square test-divisor) n) 19 | n) 20 | ((divides? test-divisor n) 21 | test-divisor) 22 | (else 23 | (find-divisor n (next test-divisor))))) 24 | 25 | (define (divides? a b) 26 | (= (remainder b a) 0)) 27 | 28 | (= n (smallest-divisor n))) 29 | 30 | 31 | 32 | (define (filtered-accumulate combiner null-value term a next b predicate?) 33 | (if (> a b) 34 | null-value 35 | (let ( 36 | (rest (filtered-accumulate combiner null-value term (next a) next b predicate?)) 37 | ) 38 | (if (predicate? a) 39 | (combiner (term a) rest) 40 | rest)))) 41 | 42 | (define (filtered-accumulate-iter combine null-value term a next b valid?) 43 | (define (iter i result) 44 | (cond ((> i b) 45 | result) 46 | ((valid? i) 47 | (iter (next i) (combine (term i) result))) 48 | (else 49 | (iter (next i) result)))) 50 | (iter a null-value)) 51 | 52 | (define (primes-sum a b) 53 | (filtered-accumulate + 54 | 0 55 | square 56 | a 57 | (lambda (i) (+ i 1)) 58 | b 59 | prime?)) 60 | 61 | (primes-sum 1 10) ;;88 62 | 63 | (define (gcd a b) 64 | (if (= b 0) 65 | a 66 | (gcd b (remainder a b)))) 67 | 68 | (define (coprime? i n) 69 | (and 70 | (< i n) 71 | (= 1 (gcd i n)))) 72 | 73 | (define (product-of-coprimes n) 74 | (filtered-accumulate * 75 | 1 76 | (lambda (x) x) 77 | 1 78 | (lambda (i) (+ i 1)) 79 | n 80 | (lambda (x) (coprime? x n)))) 81 | 82 | (product-of-coprimes 10) ;;189 83 | -------------------------------------------------------------------------------- /SICP/chapter 1/1.37.rkt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/racket 2 | #lang racket 3 | 4 | (define (cont-frac n d k) 5 | (define (cf i) 6 | (if (= k i) 7 | (/ (n i) (d i) ) 8 | (/ (n i) 9 | (+ (d i) (cf (+ i 1)))))) 10 | (cf 1)) 11 | 12 | (cont-frac 13 | (lambda (i) 1.0) 14 | (lambda (i) 1.0) 15 | 11) ;;0.6180555555555556 16 | 17 | (define (cont-frac-iter n d k) 18 | (define (cf-iter i truncation) 19 | (if (= i 1) 20 | truncation 21 | (cf-iter (- i 1) 22 | (/ (n i) 23 | (+ (d i) truncation))))) 24 | (cf-iter k 25 | (/ (n k) (d k)))) 26 | 27 | 28 | (cont-frac-iter 29 | (lambda (i) 1.0) 30 | (lambda (i) 1.0) 31 | 11) ;;0.6180555555555556 32 | -------------------------------------------------------------------------------- /SICP/chapter 1/1.40.rkt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/racket 2 | #lang racket 3 | 4 | (define (deriv g) 5 | (lambda (x) 6 | (/ (- (g (+ x dx)) (g x)) 7 | dx))) 8 | (define dx 0.00001) 9 | (define (newtons-transform g) 10 | (lambda (x) 11 | (- x (/ (g x) 12 | ((deriv g) x))))) 13 | (define (newtons-method g guess) 14 | (fixed-point (newtons-transform g) guess)) 15 | 16 | (define (fixed-point f first-guess) 17 | (define tolerance 0.00001) 18 | (define (enuf? v1 v2) 19 | (< (abs (- v1 v2)) tolerance)) 20 | (define (try guess) 21 | (if (enuf? guess (f guess)) 22 | (f guess) 23 | (try (f guess)))) 24 | (try first-guess)) 25 | 26 | (define (cube x) 27 | (* x x x)) 28 | (define (square x) 29 | (* x x)) 30 | 31 | (define (cubic a b c ) 32 | (lambda (x) 33 | (+ (cube x) 34 | (* a (square x)) 35 | (* b x) 36 | c))) 37 | 38 | (newtons-method (cubic 3 2 1) 1.0) 39 | ;-2.3247179572447267 40 | (newtons-method (cubic 2 5 5) 1.0) 41 | ;-1.2332293376819243 42 | -------------------------------------------------------------------------------- /SICP/chapter 1/1.42.rkt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/racket 2 | #lang racket 3 | 4 | (define (square x) 5 | (* x x)) 6 | 7 | (define (inc x) 8 | (+ x 1)) 9 | 10 | (define (compose f g) 11 | (lambda (x) 12 | (f (g x)))) 13 | 14 | ((compose square inc) 6) 15 | ;49 -------------------------------------------------------------------------------- /SICP/chapter 1/1.43.rkt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/racket 2 | #lang racket 3 | 4 | (define (square x) 5 | (* x x)) 6 | 7 | (define (compose f g) 8 | (lambda (x) 9 | (f (g x)))) 10 | 11 | (define (repeated f n) 12 | (if (= n 1) 13 | f 14 | (compose f (repeated f (- n 1))))) 15 | 16 | (define (repeated-iter f n) 17 | (define (iter i rf) 18 | (if (= i 1) 19 | rf 20 | (iter (- i 1) (compose f rf)))) 21 | (iter n f)) 22 | 23 | ((repeated square 2) 5) ;625 24 | ((repeated-iter square 2) 5) ;625 -------------------------------------------------------------------------------- /SICP/chapter 1/1.44.rkt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/racket 2 | #lang racket 3 | 4 | (define dx 0.00001) 5 | (define (square x) 6 | (* x x)) 7 | (define (compose f g) 8 | (lambda (x) 9 | (f (g x)))) 10 | (define (repeated f n) 11 | (if (= n 1) 12 | f 13 | (compose f (repeated f (- n 1))))) 14 | 15 | (define (smooth f) 16 | (lambda (x) 17 | (/ (+ (f x) 18 | (f (- x dx)) 19 | (f (+ x dx))) 20 | 3))) 21 | 22 | (define (smooth-n f n) 23 | ((repeated smooth n) f)) 24 | 25 | ((smooth square) 5) 26 | ; 25.000000000066663 27 | ((smooth-n square 2) 5) 28 | ; 25.00000000013333 29 | -------------------------------------------------------------------------------- /SICP/chapter 1/1.8.rkt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/racket 2 | #lang racket 3 | 4 | (define (cube x) 5 | (* x x x)) 6 | 7 | (define (cbrt x) 8 | (define (cbrt-iter guess) 9 | (let ((new-guess (improve guess))) 10 | (if (good-enough? guess new-guess) 11 | new-guess 12 | (cbrt-iter new-guess)))) 13 | (define (improve guess) 14 | (/ (+ (/ x (* guess guess)) 15 | (* 2 guess)) 16 | 3)) 17 | (define (good-enough? old-guess new-guess) 18 | (> 0.01 19 | (/ (abs (- new-guess old-guess)) 20 | old-guess))) 21 | (cbrt-iter 1.0)) 22 | 23 | (cbrt 0.008) 24 | (cube (cbrt 8)) -------------------------------------------------------------------------------- /SICP/chapter 2/2.17.rkt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/racket 2 | #lang racket 3 | 4 | (define (last-pair L) 5 | (cond ((null? L) 6 | (error "list empty")) 7 | ((null? (cdr L)) 8 | L) 9 | (else 10 | (last-pair (cdr L))))) 11 | 12 | (last-pair (list 23)) 13 | (last-pair (list 23 72 149 34)) 14 | -------------------------------------------------------------------------------- /SICP/chapter 2/2.18.rkt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/racket 2 | #lang racket 3 | 4 | (define (reverse L) 5 | (define (iter L result) 6 | (if (null? L) 7 | result 8 | (iter 9 | (cdr L) 10 | (cons (car L) result)))) 11 | (iter L '())) 12 | 13 | (reverse (list 1 4 9 16 25)) 14 | -------------------------------------------------------------------------------- /SICP/chapter 2/2.2 Nested Mappings.rkt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/racket 2 | #lang racket 3 | 4 | (define (map2 proc items) 5 | (if (null? items) 6 | '() 7 | (cons (proc (car items)) 8 | (map2 proc (cdr items))))) 9 | 10 | (define (filter predicate sequence) 11 | (cond 12 | ((null? sequence) 13 | '()) 14 | ((predicate (car sequence)) 15 | (cons (car sequence) (filter predicate (cdr sequence)))) 16 | (else 17 | (filter predicate (cdr sequence))))) 18 | 19 | (define (accumulate op initial sequence) 20 | (if (null? sequence) 21 | initial 22 | (op (car sequence) 23 | (accumulate op initial (cdr sequence))))) 24 | 25 | (define (enumerate-interval low high) 26 | (if (> low high) 27 | '() 28 | (cons low (enumerate-interval (+ 1 low) high)))) 29 | 30 | (define (enumerate-tree tree) 31 | (cond 32 | ((null? tree) 33 | '()) 34 | ((not (pair? tree)) 35 | (list tree)) 36 | (else 37 | (append (enumerate-tree (car tree)) 38 | (enumerate-tree (cdr tree)))))) 39 | 40 | (define (square x) 41 | (* x x)) 42 | 43 | (define (prime? n) 44 | 45 | (define (next t) 46 | (if (= t 2) 47 | 3 48 | (+ t 2))) 49 | 50 | (define (divides? a b) 51 | (= (remainder b a) 0)) 52 | 53 | (define (find-divisor n test-divisor) 54 | (cond ((> (square test-divisor) n) 55 | n) 56 | ((divides? test-divisor n) 57 | test-divisor) 58 | (else 59 | (find-divisor n (next test-divisor))))) 60 | 61 | (define (smallest-divisor n) 62 | (find-divisor n 2)) 63 | 64 | (= n (smallest-divisor n))) 65 | 66 | ;(map (lambda (x) (* 2 x)) (list 1 2 3)) 67 | ;(define (odd? x) 68 | ; (= (remainder x 2) 1)) 69 | ;(filter odd? (list 1 2 3 4 5)) 70 | ;(accumulate + 0 (list 1 2 3 4 5)) 71 | ;(enumerate-interval 2 7) 72 | ;(enumerate-tree (list 1 (list 2 (list 3 4)) 5)) 73 | 74 | (define (flatmap proc seq) 75 | (accumulate append 76 | '() 77 | (map proc seq))) 78 | 79 | (define (prime-pair? pair) 80 | (prime? (+ (car pair) (cadr pair)))) 81 | 82 | (define (make-pair-sum pair) 83 | (list (car pair) 84 | (cadr pair) 85 | (+ (car pair) (cadr pair)))) 86 | 87 | (define (prime-sum-pairs n) 88 | (map make-pair-sum ;组合 89 | (filter prime-pair? ;过滤 90 | (flatmap (lambda (i) 91 | (map (lambda (j) (list i j)) 92 | (enumerate-interval 1 (- i 1)))) 93 | (enumerate-interval 1 n))))) 94 | 95 | (prime-sum-pairs 6) -------------------------------------------------------------------------------- /SICP/chapter 2/2.20.rkt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/racket 2 | #lang racket 3 | 4 | (define (parity? a b) 5 | (= (remainder (- a b) 2) 0)) 6 | 7 | (define (same-parity x . y) 8 | (define (iter L result) 9 | (if (null? L) 10 | result 11 | (iter 12 | (cdr L) 13 | (cons 14 | result 15 | (if (parity? x (car L)) 16 | (car L) 17 | '()))))) 18 | (iter y x)) 19 | 20 | (same-parity 1 2 3 4 5 6 7 ) 21 | (same-parity 2 3 4 5 6 7 ) -------------------------------------------------------------------------------- /SICP/chapter 2/2.27.rkt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/racket 2 | #lang racket 3 | 4 | (define (reverse L) 5 | (define (iter L result) 6 | (if (null? L) 7 | result 8 | (iter 9 | (cdr L) 10 | (cons (car L) result)))) 11 | (iter L '())) 12 | 13 | (define (deep-reverse t) 14 | (cond ((null? t) '()) 15 | ((not (pair? t)) t) 16 | (else (reverse (list (deep-reverse (car t)) 17 | (deep-reverse (cadr t))))))) 18 | 19 | (define (tree-reverse t) 20 | (define (iter i result) 21 | (if (null? i) 22 | result 23 | (iter 24 | (cdr i) 25 | (cons (if (pair? (car i)) 26 | (tree-reverse (car i)) 27 | (car i)) 28 | result)))) 29 | (iter t '())) 30 | 31 | (define x (list (list 1 2) (list 3 4) (list 5 6))) 32 | x 33 | (reverse x) 34 | (deep-reverse x) 35 | (tree-reverse x) -------------------------------------------------------------------------------- /SICP/chapter 2/2.40.rkt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/racket 2 | #lang racket 3 | 4 | (define (map2 proc items) 5 | (if (null? items) 6 | '() 7 | (cons (proc (car items)) 8 | (map2 proc (cdr items))))) 9 | 10 | (define (filter predicate sequence) 11 | (cond 12 | ((null? sequence) 13 | '()) 14 | ((predicate (car sequence)) 15 | (cons (car sequence) (filter predicate (cdr sequence)))) 16 | (else 17 | (filter predicate (cdr sequence))))) 18 | 19 | (define (accumulate op initial sequence) 20 | (if (null? sequence) 21 | initial 22 | (op (car sequence) 23 | (accumulate op initial (cdr sequence))))) 24 | 25 | (define (enumerate-interval low high) 26 | (if (> low high) 27 | '() 28 | (cons low (enumerate-interval (+ 1 low) high)))) 29 | 30 | (define (enumerate-tree tree) 31 | (cond 32 | ((null? tree) 33 | '()) 34 | ((not (pair? tree)) 35 | (list tree)) 36 | (else 37 | (append (enumerate-tree (car tree)) 38 | (enumerate-tree (cdr tree)))))) 39 | 40 | (define (square x) 41 | (* x x)) 42 | 43 | (define (prime? n) 44 | 45 | (define (next t) 46 | (if (= t 2) 47 | 3 48 | (+ t 2))) 49 | 50 | (define (divides? a b) 51 | (= (remainder b a) 0)) 52 | 53 | (define (find-divisor n test-divisor) 54 | (cond ((> (square test-divisor) n) 55 | n) 56 | ((divides? test-divisor n) 57 | test-divisor) 58 | (else 59 | (find-divisor n (next test-divisor))))) 60 | 61 | (define (smallest-divisor n) 62 | (find-divisor n 2)) 63 | 64 | (= n (smallest-divisor n))) 65 | 66 | (define (prime-pair? pair) 67 | (prime? (+ (car pair) (cadr pair)))) 68 | 69 | (define (make-pair-sum pair) 70 | (list (car pair) 71 | (cadr pair) 72 | (+ (car pair) (cadr pair)))) 73 | 74 | (define (unique-pairs n) ;所有序对(i,j), 1 <= i < j <= n 75 | (accumulate append 76 | '() 77 | (map (lambda (i) 78 | (map (lambda (j) (list i j)) 79 | (enumerate-interval 1 (- i 1)))) 80 | (enumerate-interval 1 n)))) 81 | 82 | (define (prime-sum-pairs n) 83 | (map make-pair-sum ;组合 84 | (filter prime-pair? ;过滤 85 | (unique-pairs n)))) 86 | 87 | (unique-pairs 6) 88 | (prime-sum-pairs 6) -------------------------------------------------------------------------------- /SICP/chapter 2/2.41.rkt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/racket 2 | #lang racket 3 | 4 | (define (accumulate op initial sequence) 5 | (if (null? sequence) 6 | initial 7 | (op (car sequence) 8 | (accumulate op initial (cdr sequence))))) 9 | 10 | (define (flatmap proc seq) 11 | (accumulate append 12 | '() 13 | (map proc seq))) 14 | 15 | (define (enumerate-interval low high) 16 | (if (> low high) 17 | '() 18 | (cons low (enumerate-interval (+ 1 low) high)))) 19 | 20 | (define (filter predicate sequence) 21 | (cond 22 | ((null? sequence) 23 | '()) 24 | ((predicate (car sequence)) 25 | (cons (car sequence) (filter predicate (cdr sequence)))) 26 | (else 27 | (filter predicate (cdr sequence))))) 28 | 29 | (define (unique-pairs n) ;所有序对(i,j), 1 <= i < j <= n 30 | (flatmap (lambda (i) 31 | (map (lambda (j) (list i j)) 32 | (enumerate-interval 1 (- i 1)))) 33 | (enumerate-interval 1 n))) 34 | 35 | (define (unique-triples n) 36 | (flatmap (lambda (i) 37 | (map (lambda (j) (cons i j)) ; cons 起 i 元素和二元组 j ,组成三元组 38 | (unique-pairs (- i 1)))) ; 生成不大于 i 的所有相异整数二元组 39 | (enumerate-interval 1 n))) ; 生成 1 至 n 的所有整数,作为 i 40 | 41 | (define (same? sum triple) 42 | (= sum 43 | (+ (car triple) (cadr triple) (caddr triple)))) 44 | 45 | (define (make-triples n sum) 46 | (filter (lambda (t) 47 | (same? sum t)) 48 | (unique-triples n))) 49 | 50 | (make-triples 10 13) -------------------------------------------------------------------------------- /SICP/common-lisp-cn.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | language: "Common Lisp" 3 | filename: commonlisp-cn.lisp 4 | contributors: 5 | - ["Paul Nathan", "https://github.com/pnathan"] 6 | translators: 7 | - ["Mac David", "http://macdavid313.com"] 8 | - ["mut0u", "http://github.com/mut0u"] 9 | lang: zh-cn 10 | --- 11 | 12 | ANSI Common Lisp 是一个广泛通用于各个工业领域的、支持多种范式的编程语言。 13 | 这门语言也经常被引用作“可编程的编程语言”(可以写代码的代码)。 14 | 15 | 免费的经典的入门书籍[《实用 Common Lisp 编程》](http://www.gigamonkeys.com/book/) 16 | 17 | 许多人都抱怨上面这本书的翻译。[《ANSI Common Lisp》](http://acl.readthedocs.org/en/latest/)也许对中文读者更友好一些。 18 | 19 | 另外还有一本热门的近期出版的 20 | [Land of Lisp](http://landoflisp.com/). 21 | 22 | ```common-lisp 23 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 24 | ;;; 0. 语法 25 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 26 | 27 | ;;; 一般形式 28 | 29 | ;; Lisp有两个基本的语法单元:原子(atom),以及S-表达式。 30 | ;; 一般的,一组S-表达式被称为“组合式”。 31 | 32 | 10 ; 一个原子; 它对自身进行求值 33 | 34 | :THING ;同样是一个原子;它被求值为一个符号 :thing 35 | 36 | t ;还是一个原子,代表逻辑真值。 37 | 38 | (+ 1 2 3 4) ; 一个S-表达式。 39 | 40 | '(4 :foo t) ;同样是一个S-表达式。 41 | 42 | 43 | ;;; 注释 44 | 45 | ;; 一个分号开头的注释表示仅用于此行(单行);两个分号开头的则表示一个所谓标准注释; 46 | ;; 三个分号开头的意味着段落注释; 47 | ;; 而四个分号开头的注释用于文件头注释(译者注:即对该文件的说明)。 48 | 49 | #| 块注释 50 | 可以涵盖多行,而且... 51 | #| 52 | 他们可以被嵌套! 53 | |# 54 | |# 55 | 56 | ;;; 运行环境 57 | 58 | ;; 有很多不同的Common Lisp的实现;并且大部分的实现是一致(可移植)的。 59 | ;; 对于入门学习来说,CLISP是个不错的选择。 60 | 61 | ;; 可以通过QuickLisp.org的Quicklisp系统管理你的库。 62 | 63 | ;; 通常,使用文本编辑器和“REPL”来开发Common Lisp; 64 | ;; (译者注:“REPL”指读取-求值-打印循环)。 65 | ;; “REPL”允许对程序进行交互式的运行、调试,就好像在系统“现场”操作。 66 | 67 | 68 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 69 | ;;; 1. 基本数据类型以及运算符 70 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 71 | 72 | ;;; 符号 73 | 74 | 'foo ; => FOO 注意到这个符号被自动转换成大写了。 75 | 76 | ;; `intern`由一个给定的字符串而创建相应的符号 77 | 78 | (intern "AAAA") ; => AAAA 79 | 80 | (intern "aaa") ; => |aaa| 81 | 82 | ;;; 数字 83 | 9999999999999999999999 ; 整型数 84 | #b111 ; 二进制 => 7 85 | #o111 ; 八进制 => 73 86 | #x111 ; 十六进制 => 273 87 | 3.14159s0 ; 单精度 88 | 3.14159d0 ; 双精度 89 | 1/2 ; 分数 90 | #C(1 2) ; 复数 91 | 92 | 93 | ;; 使用函数时,应当写成这样的形式:(f x y z ...); 94 | ;; 其中,f是一个函数(名),x, y, z为参数; 95 | ;; 如果你想创建一个“字面”意义上(即不求值)的列表, 只需使用单引号 ' , 96 | ;; 从而避免接下来的表达式被求值。即,只“引用”这个数据(而不求值)。 97 | '(+ 1 2) ; => (+ 1 2) 98 | ;; 你同样也可以手动地调用一个函数(译者注:即使用函数对象来调用函数): 99 | (funcall #'+ 1 2 3) ; => 6 100 | ;; 一些算术运算符 101 | (+ 1 1) ; => 2 102 | (- 8 1) ; => 7 103 | (* 10 2) ; => 20 104 | (expt 2 3) ; => 8 105 | (mod 5 2) ; => 1 106 | (/ 35 5) ; => 7 107 | (/ 1 3) ; => 1/3 108 | (+ #C(1 2) #C(6 -4)) ; => #C(7 -2) 109 | 110 | ;;; 布尔运算 111 | t ; 逻辑真(任何不是nil的值都被视为真值) 112 | nil ; 逻辑假,或者空列表 113 | (not nil) ; => t 114 | (and 0 t) ; => t 115 | (or 0 nil) ; => 0 116 | 117 | ;;; 字符 118 | #\A ; => #\A 119 | #\λ ; => #\GREEK_SMALL_LETTER_LAMDA(希腊字母Lambda的小写) 120 | #\u03BB ; => #\GREEK_SMALL_LETTER_LAMDA(Unicode形式的小写希腊字母Lambda) 121 | 122 | ;;; 字符串被视为一个定长字符数组 123 | "Hello, world!" 124 | "Benjamin \"Bugsy\" Siegel" ;反斜杠用作转义字符 125 | 126 | ;; 可以拼接字符串 127 | (concatenate 'string "Hello " "world!") ; => "Hello world!" 128 | 129 | ;; 一个字符串也可被视作一个字符序列 130 | (elt "Apple" 0) ; => #\A 131 | 132 | ;; `format`被用于格式化字符串 133 | (format nil "~a can be ~a" "strings" "formatted") 134 | 135 | ;; 利用`format`打印到屏幕上是非常简单的 136 | ;;(译者注:注意到第二个参数是t,不同于刚刚的nil);~% 代表换行符 137 | (format t "Common Lisp is groovy. Dude.~%") 138 | 139 | 140 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 141 | ;; 2. 变量 142 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 143 | ;; 你可以通过`defparameter`创建一个全局(动态)变量 144 | ;; 变量名可以是除了:()[]{}",'`;#|\ 这些字符之外的其他任何字符 145 | 146 | ;; 动态变量名应该由*号开头与结尾! 147 | ;; (译者注:这个只是一个习惯) 148 | 149 | (defparameter *some-var* 5) 150 | *some-var* ; => 5 151 | 152 | ;; 你也可以使用Unicode字符: 153 | (defparameter *AΛB* nil) 154 | 155 | 156 | ;; 访问一个在之前从未被绑定的变量是一种不规范的行为(即使依然是可能发生的); 157 | ;; 不要尝试那样做。 158 | 159 | 160 | ;; 局部绑定:在(let ...)语句内,'me'被绑定到"dance with you"上。 161 | ;; `let`总是返回在其作用域内最后一个表达式的值 162 | 163 | (let ((me "dance with you")) 164 | me) 165 | ;; => "dance with you" 166 | 167 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 168 | ;; 3. 结构体和集合 169 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 170 | 171 | ;; 结构体 172 | (defstruct dog name breed age) 173 | (defparameter *rover* 174 | (make-dog :name "rover" 175 | :breed "collie" 176 | :age 5)) 177 | *rover* ; => #S(DOG :NAME "rover" :BREED "collie" :AGE 5) 178 | 179 | (dog-p *rover*) ; => t ;; ewww) 180 | (dog-name *rover*) ; => "rover" 181 | 182 | ;; Dog-p,make-dog,以及 dog-name都是由defstruct创建的! 183 | 184 | ;;; 点对单元(Pairs) 185 | ;; `cons`可用于生成一个点对单元, 利用`car`以及`cdr`将分别得到第一个和第二个元素 186 | (cons 'SUBJECT 'VERB) ; => '(SUBJECT . VERB) 187 | (car (cons 'SUBJECT 'VERB)) ; => SUBJECT 188 | (cdr (cons 'SUBJECT 'VERB)) ; => VERB 189 | 190 | ;;; 列表 191 | 192 | ;; 所有列表都是由点对单元构成的“链表”。它以'nil'(或者'())作为列表的最后一个元素。 193 | (cons 1 (cons 2 (cons 3 nil))) ; => '(1 2 3) 194 | ;; `list`是一个生成列表的便利途径 195 | (list 1 2 3) ; => '(1 2 3) 196 | ;; 并且,一个引用也可被用做字面意义上的列表值 197 | '(1 2 3) ; => '(1 2 3) 198 | 199 | ;; 同样的,依然可以用`cons`来添加一项到列表的起始位置 200 | (cons 4 '(1 2 3)) ; => '(4 1 2 3) 201 | 202 | ;; 而`append`也可用于连接两个列表 203 | (append '(1 2) '(3 4)) ; => '(1 2 3 4) 204 | 205 | ;; 或者使用`concatenate` 206 | 207 | (concatenate 'list '(1 2) '(3 4)) 208 | 209 | ;; 列表是一种非常核心的数据类型,所以有非常多的处理列表的函数 210 | ;; 例如: 211 | (mapcar #'1+ '(1 2 3)) ; => '(2 3 4) 212 | (mapcar #'+ '(1 2 3) '(10 20 30)) ; => '(11 22 33) 213 | (remove-if-not #'evenp '(1 2 3 4)) ; => '(2 4) 214 | (every #'evenp '(1 2 3 4)) ; => nil 215 | (some #'oddp '(1 2 3 4)) ; => T 216 | (butlast '(subject verb object)) ; => (SUBJECT VERB) 217 | 218 | 219 | ;;; 向量 220 | 221 | ;; 向量的字面意义是一个定长数组 222 | ;;(译者注:此处所谓“字面意义”,即指#(......)的形式,下文还会出现) 223 | #(1 2 3) ; => #(1 2 3) 224 | 225 | ;; 使用`concatenate`来将两个向量首尾连接在一起 226 | (concatenate 'vector #(1 2 3) #(4 5 6)) ; => #(1 2 3 4 5 6) 227 | 228 | ;;; 数组 229 | 230 | ;; 向量和字符串只不过是数组的特例 231 | 232 | ;; 二维数组 233 | 234 | (make-array (list 2 2)) 235 | 236 | ;; (make-array '(2 2)) 也是可以的 237 | 238 | ; => #2A((0 0) (0 0)) 239 | 240 | (make-array (list 2 2 2)) 241 | 242 | ; => #3A(((0 0) (0 0)) ((0 0) (0 0))) 243 | 244 | ;; 注意:数组的默认初始值是可以指定的 245 | ;; 下面是如何指定的示例: 246 | 247 | (make-array '(2) :initial-element 'unset) 248 | 249 | ; => #(UNSET UNSET) 250 | 251 | ;; 若想获取数组[1][1][1]上的元素: 252 | (aref (make-array (list 2 2 2)) 1 1 1) 253 | 254 | ; => 0 255 | 256 | ;;; 变长向量 257 | 258 | ;; 若将变长向量打印出来,那么它的字面意义上的值和定长向量的是一样的 259 | 260 | (defparameter *adjvec* (make-array '(3) :initial-contents '(1 2 3) 261 | :adjustable t :fill-pointer t)) 262 | 263 | *adjvec* ; => #(1 2 3) 264 | 265 | ;; 添加新的元素: 266 | (vector-push-extend 4 *adjvec*) ; => 3 267 | 268 | *adjvec* ; => #(1 2 3 4) 269 | 270 | 271 | 272 | ;;; 不怎么严谨地说,集合也可被视为列表 273 | 274 | (set-difference '(1 2 3 4) '(4 5 6 7)) ; => (3 2 1) 275 | (intersection '(1 2 3 4) '(4 5 6 7)) ; => 4 276 | (union '(1 2 3 4) '(4 5 6 7)) ; => (3 2 1 4 5 6 7) 277 | (adjoin 4 '(1 2 3 4)) ; => (1 2 3 4) 278 | 279 | ;; 然而,你可能想使用一个更好的数据结构,而并非一个链表 280 | 281 | ;;; 在Common Lisp中,“字典”和哈希表的实现是一样的。 282 | 283 | ;; 创建一个哈希表 284 | (defparameter *m* (make-hash-table)) 285 | 286 | ;; 给定键,设置对应的值 287 | (setf (gethash 'a *m*) 1) 288 | 289 | ;; (通过键)检索对应的值 290 | (gethash 'a *m*) ; => 1, t 291 | 292 | ;; 注意此处有一细节:Common Lisp往往返回多个值。`gethash`返回的第二个值是t,代表找到了这个元素;返回nil表示没有找到这个元素。 293 | ;;(译者注:返回的第一个值表示给定的键所对应的值或者nil;) 294 | ;;(第二个是一个布尔值,表示在哈希表中是否存在这个给定的键) 295 | ;; 例如,如果可以找到给定的键所对应的值,则返回一个t,否则返回nil 296 | 297 | ;; 由给定的键检索一个不存在的值,则返回nil 298 | ;;(译者注:这个nil是第一个nil,第二个nil其实是指该键在哈希表中也不存在) 299 | (gethash 'd *m*) ;=> nil, nil 300 | 301 | ;; 给定一个键,你可以指定其对应的默认值: 302 | (gethash 'd *m* :not-found) ; => :NOT-FOUND 303 | 304 | ;; 在此,让我们看一看怎样处理`gethash`的多个返回值。 305 | 306 | (multiple-value-bind 307 | (a b) 308 | (gethash 'd *m*) 309 | (list a b)) 310 | ; => (NIL NIL) 311 | 312 | (multiple-value-bind 313 | (a b) 314 | (gethash 'a *m*) 315 | (list a b)) 316 | ; => (1 T) 317 | 318 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 319 | ;; 3. 函数 320 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 321 | 322 | ;; 使用`lambda`来创建一个匿名函数。 323 | ;; 一个函数总是返回其形式体内最后一个表达式的值。 324 | ;; 将一个函数对象打印出来后的形式是多种多样的... 325 | 326 | (lambda () "Hello World") ; => # 327 | 328 | ;; 使用`funcall`来调用lambda函数 329 | (funcall (lambda () "Hello World")) ; => "Hello World" 330 | 331 | ;; 或者使用`apply` 332 | (apply (lambda () "Hello World") nil) ; => "Hello World" 333 | 334 | ;; 显式地定义一个函数(译者注:即非匿名的) 335 | (defun hello-world () 336 | "Hello World") 337 | (hello-world) ; => "Hello World" 338 | 339 | ;; 刚刚上面函数名"hello-world"后的()其实是函数的参数列表 340 | (defun hello (name) 341 | (format nil "Hello, ~a " name)) 342 | 343 | (hello "Steve") ; => "Hello, Steve" 344 | 345 | ;; 函数可以有可选形参并且其默认值都为nil 346 | 347 | (defun hello (name &optional from) 348 | (if from 349 | (format t "Hello, ~a, from ~a" name from) 350 | (format t "Hello, ~a" name))) 351 | 352 | (hello "Jim" "Alpacas") ;; => Hello, Jim, from Alpacas 353 | 354 | ;; 你也可以指定那些可选形参的默认值 355 | (defun hello (name &optional (from "The world")) 356 | (format t "Hello, ~a, from ~a" name from)) 357 | 358 | (hello "Steve") 359 | ; => Hello, Steve, from The world 360 | 361 | (hello "Steve" "the alpacas") 362 | ; => Hello, Steve, from the alpacas 363 | 364 | 365 | ;; 当然,你也可以设置所谓关键字形参; 366 | ;; 关键字形参往往比可选形参更具灵活性。 367 | 368 | (defun generalized-greeter (name &key (from "the world") (honorific "Mx")) 369 | (format t "Hello, ~a ~a, from ~a" honorific name from)) 370 | 371 | (generalized-greeter "Jim") ; => Hello, Mx Jim, from the world 372 | 373 | (generalized-greeter "Jim" :from "the alpacas you met last summer" :honorific "Mr") 374 | ; => Hello, Mr Jim, from the alpacas you met last summer 375 | 376 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 377 | ;; 4. 等式 378 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 379 | 380 | ;; Common Lisp具有一个十分复杂的用于判断等价的系统,下面只是其中一部分的例子 381 | 382 | ;; 若要比较数值是否等价,使用`=` 383 | (= 3 3.0) ; => t 384 | (= 2 1) ; => nil 385 | 386 | ;; 若要比较对象的类型,则使用`eql` 387 | ;;(译者注:抱歉,翻译水平实在有限,下面是我个人的补充说明) 388 | ;;(`eq` 返回真,如果对象的内存地址相等) 389 | ;;(`eql` 返回真,如果两个对象内存地址相等,或者对象的类型相同,并且值相等) 390 | ;;(例如同为整形数或浮点数,并且他们的值相等时,二者`eql`等价) 391 | ;;(想要弄清`eql`,其实有必要先了解`eq`) 392 | ;;([可以参考](http://stackoverflow.com/questions/547436/whats-the-difference-between-eq-eql-equal-and-equalp-in-common-lisp)) 393 | ;;(可以去CLHS上分别查看两者的文档) 394 | ;;(另外,《实用Common Lisp编程》的4.8节也提到了两者的区别) 395 | (eql 3 3) ; => t 396 | (eql 3 3.0) ; => nil 397 | (eql (list 3) (list 3)) ; => nil 398 | 399 | ;; 对于列表、字符串、以及位向量,使用`equal` 400 | (equal (list 'a 'b) (list 'a 'b)) ; => t 401 | (equal (list 'a 'b) (list 'b 'a)) ; => nil 402 | 403 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 404 | ;; 5. 控制流 405 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 406 | 407 | ;;; 条件判断语句 408 | 409 | (if t ; “test”,即判断语句 410 | "this is true" ; “then”,即判断条件为真时求值的表达式 411 | "this is false") ; “else”,即判断条件为假时求值的表达式 412 | ; => "this is true" 413 | 414 | ;; 在“test”(判断)语句中,所有非nil或者非()的值都被视为真值 415 | (member 'Groucho '(Harpo Groucho Zeppo)) ; => '(GROUCHO ZEPPO) 416 | (if (member 'Groucho '(Harpo Groucho Zeppo)) 417 | 'yep 418 | 'nope) 419 | ; => 'YEP 420 | 421 | ;; `cond`将一系列测试语句串联起来,并对相应的表达式求值 422 | (cond ((> 2 2) (error "wrong!")) 423 | ((< 2 2) (error "wrong again!")) 424 | (t 'ok)) ; => 'OK 425 | 426 | ;; 对于给定值的数据类型,`typecase`会做出相应地判断 427 | (typecase 1 428 | (string :string) 429 | (integer :int)) 430 | 431 | ; => :int 432 | 433 | ;;; 迭代 434 | 435 | ;; 当然,递归是肯定被支持的: 436 | 437 | (defun walker (n) 438 | (if (zerop n) 439 | :walked 440 | (walker (1- n)))) 441 | 442 | (walker) ; => :walked 443 | 444 | ;; 而大部分场合下,我们使用`DOLIST`或者`LOOP`来进行迭代 445 | 446 | 447 | (dolist (i '(1 2 3 4)) 448 | (format t "~a" i)) 449 | 450 | ; => 1234 451 | 452 | (loop for i from 0 below 10 453 | collect i) 454 | 455 | ; => (0 1 2 3 4 5 6 7 8 9) 456 | 457 | 458 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 459 | ;; 6. 可变性 460 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 461 | 462 | ;; 使用`setf`可以对一个已经存在的变量进行赋值; 463 | ;; 事实上,刚刚在哈希表的例子中我们已经示范过了。 464 | 465 | (let ((variable 10)) 466 | (setf variable 2)) 467 | ; => 2 468 | 469 | 470 | ;; 所谓好的Lisp编码风格就是为了减少使用破坏性函数,防止发生副作用。 471 | 472 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 473 | ;; 7. 类与对象 474 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 475 | 476 | ;; 我们就不写什么有关动物的类了,下面给出的人力车的类 477 | 478 | (defclass human-powered-conveyance () 479 | ((velocity 480 | :accessor velocity 481 | :initarg :velocity) 482 | (average-efficiency 483 | :accessor average-efficiency 484 | :initarg :average-efficiency)) 485 | (:documentation "A human powered conveyance")) 486 | 487 | ;; `defclass`,后面接类名,以及超类列表 488 | ;; 再接着是槽的列表(槽有点像Java里的成员变量),最后是一些可选的特性 489 | ;; 例如文档说明“:documentation” 490 | 491 | ;; 如果超类列表为空,则默认该类继承于“standard-object”类(standard-object又是T的子类) 492 | ;; 这种默认行为是可以改变的,但你最好有一定的基础并且知道自己到底在干什么; 493 | ;; 参阅《The Art of the Metaobject Protocol》来了解更多信息。 494 | 495 | (defclass bicycle (human-powered-conveyance) 496 | ((wheel-size 497 | :accessor wheel-size 498 | :initarg :wheel-size 499 | :documentation "Diameter of the wheel.") 500 | (height 501 | :accessor height 502 | :initarg :height))) 503 | 504 | (defclass recumbent (bicycle) 505 | ((chain-type 506 | :accessor chain-type 507 | :initarg :chain-type))) 508 | 509 | (defclass unicycle (human-powered-conveyance) nil) 510 | 511 | (defclass canoe (human-powered-conveyance) 512 | ((number-of-rowers 513 | :accessor number-of-rowers 514 | :initarg :number-of-rowers))) 515 | 516 | 517 | ;; 在REPL中对human-powered-conveyance类调用`DESCRIBE`后结果如下: 518 | 519 | (describe 'human-powered-conveyance) 520 | 521 | ; COMMON-LISP-USER::HUMAN-POWERED-CONVEYANCE 522 | ; [symbol] 523 | ; 524 | ; HUMAN-POWERED-CONVEYANCE names the standard-class #: 526 | ; Documentation: 527 | ; A human powered conveyance 528 | ; Direct superclasses: STANDARD-OBJECT 529 | ; Direct subclasses: UNICYCLE, BICYCLE, CANOE 530 | ; Not yet finalized. 531 | ; Direct slots: 532 | ; VELOCITY 533 | ; Readers: VELOCITY 534 | ; Writers: (SETF VELOCITY) 535 | ; AVERAGE-EFFICIENCY 536 | ; Readers: AVERAGE-EFFICIENCY 537 | ; Writers: (SETF AVERAGE-EFFICIENCY) 538 | 539 | ;; 注意到这些有用的返回信息——Common Lisp一直是一个交互式的系统。 540 | 541 | ;; 若要定义一个方法; 542 | ;; 注意,我们计算自行车轮子周长时使用了这样一个公式:C = d * pi 543 | 544 | (defmethod circumference ((object bicycle)) 545 | (* pi (wheel-size object))) 546 | 547 | ;; pi在Common Lisp中已经是一个内置的常量。 548 | 549 | ;; 假设我们已经知道了效率值(“efficiency value”)和船桨数大概呈对数关系; 550 | ;; 那么效率值的定义应当在构造器/初始化过程中就被完成。 551 | 552 | ;; 下面是一个Common Lisp构造实例时初始化实例的例子: 553 | 554 | (defmethod initialize-instance :after ((object canoe) &rest args) 555 | (setf (average-efficiency object) (log (1+ (number-of-rowers object))))) 556 | 557 | ;; 接着初构造一个实例并检查平均效率... 558 | 559 | (average-efficiency (make-instance 'canoe :number-of-rowers 15)) 560 | ; => 2.7725887 561 | 562 | 563 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 564 | ;; 8. 宏 565 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 566 | 567 | ;; 宏可以让你扩展语法 568 | 569 | ;; 例如,Common Lisp并没有自带WHILE循环——所以让我们自己来为他添加一个; 570 | ;; 如果按照汇编程序的直觉来看,我们会这样写: 571 | 572 | (defmacro while (condition &body body) 573 | "While `condition` is true, `body` is executed. 574 | 575 | `condition` is tested prior to each execution of `body`" 576 | (let ((block-name (gensym))) 577 | `(tagbody 578 | (unless ,condition 579 | (go ,block-name)) 580 | (progn 581 | ,@body) 582 | ,block-name))) 583 | 584 | ;; 让我们来看看它的高级版本: 585 | 586 | (defmacro while (condition &body body) 587 | "While `condition` is true, `body` is executed. 588 | 589 | `condition` is tested prior to each execution of `body`" 590 | `(loop while ,condition 591 | do 592 | (progn 593 | ,@body))) 594 | 595 | ;; 然而,在一个比较现代化的编译环境下,这样的WHILE是没有必要的; 596 | ;; LOOP形式的循环和这个WHILE同样的好,并且更易于阅读。 597 | 598 | ;; 注意反引号'`',逗号','以及'@'这三个符号; 599 | ;; 反引号'`'是一种所谓“quasiquote”的引用类型的运算符,有了它,之后的逗号“,”才有意义。 600 | ;; 逗号“,”意味着解除引用(unquote,即开始求值); 601 | ;; “@”符号则表示将当前的参数插入到当前整个列表中。 602 | ;;(译者注:要想真正用好、用对这三个符号,需要下一番功夫) 603 | ;;(甚至光看《实用 Common Lisp 编程》中关于宏的介绍都是不够的) 604 | ;;(建议再去读一读Paul Graham的两本著作《ANSI Common Lisp》和《On Lisp》) 605 | 606 | ;; 函数`gensym`创建一个唯一的符号——这个符号确保不会出现在其他任何地方。 607 | ;; 这样做是因为,宏是在编译期展开的 608 | ;; 而在宏中声明的变量名极有可能和常规代码中使用的变量名发生冲突。 609 | 610 | ;; 可以去《实用 Common Lisp 编程》中阅读更多有关宏的内容。 611 | ``` 612 | 613 | 614 | ## 拓展阅读 615 | 616 | [继续阅读《实用 Common Lisp 编程》一书](http://www.gigamonkeys.com/book/) 617 | 618 | 619 | ## 致谢 620 | 621 | 非常感谢Scheme社区的人们,我基于他们的成果得以迅速的写出这篇有关Common Lisp的快速入门 622 | 同时也感谢 623 | - [Paul Khuong](https://github.com/pkhuong) ,他提出了很多有用的点评。 624 | 625 | ##译者寄语 626 | “祝福那些将思想镶嵌在重重括号之内的人们。” 627 | -------------------------------------------------------------------------------- /SICP/common.rkt: -------------------------------------------------------------------------------- 1 | ; Library of common procedures used in exercises which do not particularly participate 2 | ; in solution design but are used only as helpers and can be shared among. 3 | ; https://github.com/ivanjovanovic/sicp/blob/master/common.scm 4 | ; #lang racket/load 5 | ; (load "common.rkt") 6 | (define true #t) 7 | (define false #f) 8 | 9 | (define (square x) 10 | (* x x)) 11 | 12 | (define (cube x) 13 | (* x x x)) 14 | 15 | (define (double x) 16 | (* x 2)) 17 | 18 | (define (halve x) 19 | (/ x 2)) 20 | 21 | (define (even? n) 22 | (= (remainder n 2) 0)) 23 | 24 | (define (div a b) 25 | (floor (/ a b))) 26 | 27 | (define (divides? a b) 28 | (= (remainder b a) 0)) 29 | 30 | (define (identity x) x) 31 | 32 | (define close-enough? 33 | (lambda (a b delta) (< (abs (- a b)) delta))) 34 | 35 | ; average of 2 values 36 | (define (average x y) 37 | (/ (+ x y) 2.0)) 38 | 39 | ; avergae of 3.0 40 | (define (average-of-3 x y z) 41 | (/ (+ x y z) 3.0)) 42 | 43 | (define (inc x) 44 | (+ x 1)) 45 | 46 | (define (gcd a b) 47 | (if (= b 0) 48 | a 49 | (gcd b (remainder a b)))) 50 | 51 | ; define nil as empty list. 52 | (define nil '()) 53 | 54 | ;;;; standard sequence procedures 55 | 56 | (define (accumulate op initial sequence) 57 | (if (null? sequence) 58 | initial 59 | (op (car sequence) 60 | (accumulate op initial (cdr sequence))))) 61 | 62 | (define (filter predicate sequence) 63 | (cond ((null? sequence) nil) 64 | ((predicate (car sequence)) 65 | (cons (car sequence) (filter predicate (cdr sequence)))) 66 | (else (filter predicate (cdr sequence))))) 67 | 68 | (define (enumerate-leaves tree) 69 | (cond ((null? tree) nil) 70 | ((not (pair? tree)) (list tree)) 71 | (else (append (enumerate-leaves (car tree)) 72 | (enumerate-leaves (cdr tree)))))) 73 | 74 | (define (enumerate-interval low high) 75 | (if (> low high) 76 | nil 77 | (cons low (enumerate-interval (+ low 1) high)))) 78 | 79 | (define (accumulate-n op init seqs) 80 | (if (null? (car seqs)) 81 | nil 82 | (cons (accumulate op init (map car seqs)) ; get cars of every list inside 83 | (accumulate-n op init (map cdr seqs))))) ; proceed with cadrs in next recursion 84 | 85 | ; Folding to left and right are standard operations 86 | (define (fold-left op initial sequence) 87 | (define (iter result rest) 88 | (if (null? rest) 89 | result 90 | (iter (op result (car rest)) 91 | (cdr rest)))) 92 | (iter initial sequence)) 93 | 94 | ; folding right is the standard accumulation 95 | (define fold-right accumulate) 96 | 97 | (define (reverse sequence) 98 | (fold-right (lambda (x y) (append y (list x))) nil sequence)) -------------------------------------------------------------------------------- /SICP/racket-cn.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | language: racket 4 | lang: zh-cn 5 | filename: learnracket-zh.rkt 6 | contributors: 7 | - ["th3rac25", "https://github.com/voila"] 8 | - ["Eli Barzilay", "https://github.com/elibarzilay"] 9 | - ["Gustavo Schmidt", "https://github.com/gustavoschmidt"] 10 | translators: 11 | - ["lyuehh", "https://github.com/lyuehh"] 12 | --- 13 | 14 | Racket是Lisp/Scheme家族中的一个通用的,多范式的编程语言。 15 | 非常期待您的反馈!你可以通过[@th3rac25](http://twitter.com/th3rac25)或以用户名为 th3rac25 的Google邮箱服务和我取得联系 16 | 17 | ```racket 18 | #lang racket ; 声明我们使用的语言 19 | 20 | ;;; 注释 21 | 22 | ;; 单行注释以分号开始 23 | 24 | #| 块注释 25 | 可以横跨很多行而且... 26 | #| 27 | 可以嵌套 28 | |# 29 | |# 30 | 31 | ;; S表达式注释忽略剩下的表达式 32 | ;; 在调试的时候会非常有用 33 | #; (被忽略的表达式) 34 | 35 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 36 | ;; 1. 原始数据类型和操作符 37 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 38 | 39 | ;;; 数字 40 | 9999999999999999999999 ; 整数 41 | #b111 ; 二进制数字 => 7 42 | #o111 ; 八进制数字 => 73 43 | #x111 ; 十六进制数字 => 273 44 | 3.14 ; 实数 45 | 6.02e+23 46 | 1/2 ; 有理数 47 | 1+2i ; 复数 48 | 49 | ;; 函数调用写作(f x y z ...) 50 | ;; 在这里 f 是一个函数, x, y, z, ... 是参数 51 | ;; 如果你想创建一个列表数据的字面量, 使用 ' 来阻止它们 52 | ;; 被求值 53 | '(+ 1 2) ; => (+ 1 2) 54 | ;; 接下来,是一些数学运算 55 | (+ 1 1) ; => 2 56 | (- 8 1) ; => 7 57 | (* 10 2) ; => 20 58 | (expt 2 3) ; => 8 59 | (quotient 5 2) ; => 2 60 | (remainder 5 2) ; => 1 61 | (/ 35 5) ; => 7 62 | (/ 1 3) ; => 1/3 63 | (exact->inexact 1/3) ; => 0.3333333333333333 64 | (+ 1+2i 2-3i) ; => 3-1i 65 | 66 | ;;; 布尔类型 67 | #t ; 为真 68 | #f ; 为假,#f 之外的任何值都是真 69 | (not #t) ; => #f 70 | (and 0 #f (error "doesn't get here")) ; => #f 71 | (or #f 0 (error "doesn't get here")) ; => 0 72 | 73 | ;;; 字符 74 | #\A ; => #\A 75 | #\λ ; => #\λ 76 | #\u03BB ; => #\λ 77 | 78 | ;;; 字符串是字符组成的定长数组 79 | "Hello, world!" 80 | "Benjamin \"Bugsy\" Siegel" ; \是转义字符 81 | "Foo\tbar\41\x21\u0021\a\r\n" ; 包含C语言的转义字符,和Unicode 82 | "λx:(μα.α→α).xx" ; 字符串可以包含Unicode字符 83 | 84 | ;; 字符串可以相加 85 | (string-append "Hello " "world!") ; => "Hello world!" 86 | 87 | ;; 一个字符串可以看做是一个包含字符的列表 88 | (string-ref "Apple" 0) ; => #\A 89 | 90 | ;; format 可以用来格式化字符串 91 | (format "~a can be ~a" "strings" "formatted") 92 | 93 | ;; 打印字符串非常简单 94 | (printf "I'm Racket. Nice to meet you!\n") 95 | 96 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 97 | ;; 2. 变量 98 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 99 | ;; 你可以使用 define 定义一个变量 100 | ;; 变量的名字可以使用任何字符除了: ()[]{}",'`;#|\ 101 | (define some-var 5) 102 | some-var ; => 5 103 | 104 | ;; 你也可以使用Unicode字符 105 | (define ⊆ subset?) 106 | (⊆ (set 3 2) (set 1 2 3)) ; => #t 107 | 108 | ;; 访问未赋值的变量会引发一个异常 109 | ; x ; => x: undefined ... 110 | 111 | ;; 本地绑定: `me' 被绑定到 "Bob",并且只在 let 中生效 112 | (let ([me "Bob"]) 113 | "Alice" 114 | me) ; => "Bob" 115 | 116 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 117 | ;; 3. 结构和集合 118 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 119 | 120 | ;; 结构体 121 | (struct dog (name breed age)) 122 | (define my-pet 123 | (dog "lassie" "collie" 5)) 124 | my-pet ; => # 125 | (dog? my-pet) ; => #t 126 | (dog-name my-pet) ; => "lassie" 127 | 128 | ;;; 对 (不可变的) 129 | ;; `cons' 返回对, `car' 和 `cdr' 从对中提取第1个 130 | ;; 和第2个元素 131 | (cons 1 2) ; => '(1 . 2) 132 | (car (cons 1 2)) ; => 1 133 | (cdr (cons 1 2)) ; => 2 134 | 135 | ;;; 列表 136 | 137 | ;; 列表由链表构成, 由 `cons' 的结果 138 | ;; 和一个 `null' (或者 '()) 构成,后者标记了这个列表的结束 139 | (cons 1 (cons 2 (cons 3 null))) ; => '(1 2 3) 140 | ;; `list' 给列表提供了一个非常方便的可变参数的生成器 141 | (list 1 2 3) ; => '(1 2 3) 142 | ;; 一个单引号也可以用来表示一个列表字面量 143 | '(1 2 3) ; => '(1 2 3) 144 | 145 | ;; 仍然可以使用 `cons' 在列表的开始处添加一项 146 | (cons 4 '(1 2 3)) ; => '(4 1 2 3) 147 | 148 | ;; `append' 函数可以将两个列表合并 149 | (append '(1 2) '(3 4)) ; => '(1 2 3 4) 150 | 151 | ;; 列表是非常基础的类型,所以有*很多*操作列表的方法 152 | ;; 下面是一些例子: 153 | (map add1 '(1 2 3)) ; => '(2 3 4) 154 | (map + '(1 2 3) '(10 20 30)) ; => '(11 22 33) 155 | (filter even? '(1 2 3 4)) ; => '(2 4) 156 | (count even? '(1 2 3 4)) ; => 2 157 | (take '(1 2 3 4) 2) ; => '(1 2) 158 | (drop '(1 2 3 4) 2) ; => '(3 4) 159 | 160 | ;;; 向量 161 | 162 | ;; 向量是定长的数组 163 | #(1 2 3) ; => '#(1 2 3) 164 | 165 | ;; 使用 `vector-append' 方法将2个向量合并 166 | (vector-append #(1 2 3) #(4 5 6)) ; => #(1 2 3 4 5 6) 167 | 168 | ;;; Set(翻译成集合也不太合适,所以不翻译了..) 169 | 170 | ;; 从一个列表创建一个Set 171 | (list->set '(1 2 3 1 2 3 3 2 1 3 2 1)) ; => (set 1 2 3) 172 | 173 | ;; 使用 `set-add' 增加一个成员 174 | ;; (函数式特性: 这里会返回一个扩展后的Set,而不是修改输入的值) 175 | (set-add (set 1 2 3) 4) ; => (set 1 2 3 4) 176 | 177 | ;; 使用 `set-remove' 移除一个成员 178 | (set-remove (set 1 2 3) 1) ; => (set 2 3) 179 | 180 | ;; 使用 `set-member?' 测试成员是否存在 181 | (set-member? (set 1 2 3) 1) ; => #t 182 | (set-member? (set 1 2 3) 4) ; => #f 183 | 184 | ;;; 散列表 185 | 186 | ;; 创建一个不变的散列表 (可变散列表的例子在下面) 187 | (define m (hash 'a 1 'b 2 'c 3)) 188 | 189 | ;; 根据键取得值 190 | (hash-ref m 'a) ; => 1 191 | 192 | ;; 获取一个不存在的键是一个异常 193 | ; (hash-ref m 'd) => 没有找到元素 194 | 195 | ;; 你可以给不存在的键提供一个默认值 196 | (hash-ref m 'd 0) ; => 0 197 | 198 | ;; 使用 `hash-set' 来扩展一个不可变的散列表 199 | ;; (返回的是扩展后的散列表而不是修改它) 200 | (define m2 (hash-set m 'd 4)) 201 | m2 ; => '#hash((b . 2) (a . 1) (d . 4) (c . 3)) 202 | 203 | ;; 记住,使用 `hash` 创建的散列表是不可变的 204 | m ; => '#hash((b . 2) (a . 1) (c . 3)) <-- no `d' 205 | 206 | ;; 使用 `hash-remove' 移除一个键值对 (函数式特性,m并不变) 207 | (hash-remove m 'a) ; => '#hash((b . 2) (c . 3)) 208 | 209 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 210 | ;; 3. 函数 211 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 212 | 213 | ;; 使用 `lambda' 创建函数 214 | ;; 函数总是返回它最后一个表达式的值 215 | (lambda () "Hello World") ; => # 216 | ;; 也可以使用 Unicode 字符 `λ' 217 | (λ () "Hello World") ; => 同样的函数 218 | 219 | ;; 使用括号调用一个函数,也可以直接调用一个 lambda 表达式 220 | ((lambda () "Hello World")) ; => "Hello World" 221 | ((λ () "Hello World")) ; => "Hello World" 222 | 223 | ;; 将函数赋值为一个变量 224 | (define hello-world (lambda () "Hello World")) 225 | (hello-world) ; => "Hello World" 226 | 227 | ;; 你可以使用函数定义的语法糖来简化代码 228 | (define (hello-world2) "Hello World") 229 | 230 | ;; `()`是函数的参数列表 231 | (define hello 232 | (lambda (name) 233 | (string-append "Hello " name))) 234 | (hello "Steve") ; => "Hello Steve" 235 | ;; 同样的,可以使用语法糖来定义: 236 | (define (hello2 name) 237 | (string-append "Hello " name)) 238 | 239 | ;; 你也可以使用可变参数, `case-lambda' 240 | (define hello3 241 | (case-lambda 242 | [() "Hello World"] 243 | [(name) (string-append "Hello " name)])) 244 | (hello3 "Jake") ; => "Hello Jake" 245 | (hello3) ; => "Hello World" 246 | ;; ... 或者给参数指定一个可选的默认值 247 | (define (hello4 [name "World"]) 248 | (string-append "Hello " name)) 249 | 250 | ;; 函数可以将多余的参数放到一个列表里 251 | (define (count-args . args) 252 | (format "You passed ~a args: ~a" (length args) args)) 253 | (count-args 1 2 3) ; => "You passed 3 args: (1 2 3)" 254 | ;; ... 也可以使用不带语法糖的 `lambda' 形式: 255 | (define count-args2 256 | (lambda args 257 | (format "You passed ~a args: ~a" (length args) args))) 258 | 259 | ;; 你可以混用两种用法 260 | (define (hello-count name . args) 261 | (format "Hello ~a, you passed ~a extra args" name (length args))) 262 | (hello-count "Finn" 1 2 3) 263 | ; => "Hello Finn, you passed 3 extra args" 264 | ;; ... 不带语法糖的形式: 265 | (define hello-count2 266 | (lambda (name . args) 267 | (format "Hello ~a, you passed ~a extra args" name (length args)))) 268 | 269 | ;; 使用关键字 270 | (define (hello-k #:name [name "World"] #:greeting [g "Hello"] . args) 271 | (format "~a ~a, ~a extra args" g name (length args))) 272 | (hello-k) ; => "Hello World, 0 extra args" 273 | (hello-k 1 2 3) ; => "Hello World, 3 extra args" 274 | (hello-k #:greeting "Hi") ; => "Hi World, 0 extra args" 275 | (hello-k #:name "Finn" #:greeting "Hey") ; => "Hey Finn, 0 extra args" 276 | (hello-k 1 2 3 #:greeting "Hi" #:name "Finn" 4 5 6) 277 | ; => "Hi Finn, 6 extra args" 278 | 279 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 280 | ;; 4. 判断是否相等 281 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 282 | 283 | ;; 判断数字使用 `=' 284 | (= 3 3.0) ; => #t 285 | (= 2 1) ; => #f 286 | 287 | ;; 判断对象使用 `eq?' 288 | (eq? 3 3) ; => #t 289 | (eq? 3 3.0) ; => #f 290 | (eq? (list 3) (list 3)) ; => #f 291 | 292 | ;; 判断集合使用 `equal?' 293 | (equal? (list 'a 'b) (list 'a 'b)) ; => #t 294 | (equal? (list 'a 'b) (list 'b 'a)) ; => #f 295 | 296 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 297 | ;; 5. 控制结构 298 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 299 | 300 | ;;; 条件判断 301 | 302 | (if #t ; 测试表达式 303 | "this is true" ; 为真的表达式 304 | "this is false") ; 为假的表达式 305 | ; => "this is true" 306 | 307 | ;; 注意, 除 `#f` 之外的所有值都认为是真 308 | (member 'Groucho '(Harpo Groucho Zeppo)) ; => '(Groucho Zeppo) 309 | (if (member 'Groucho '(Harpo Groucho Zeppo)) 310 | 'yep 311 | 'nope) 312 | ; => 'yep 313 | 314 | ;; `cond' 会进行一系列的判断来选择一个结果 315 | (cond [(> 2 2) (error "wrong!")] 316 | [(< 2 2) (error "wrong again!")] 317 | [else 'ok]) ; => 'ok 318 | 319 | ;;; 模式匹配 320 | 321 | (define (fizzbuzz? n) 322 | (match (list (remainder n 3) (remainder n 5)) 323 | [(list 0 0) 'fizzbuzz] 324 | [(list 0 _) 'fizz] 325 | [(list _ 0) 'buzz] 326 | [_ #f])) 327 | 328 | (fizzbuzz? 15) ; => 'fizzbuzz 329 | (fizzbuzz? 37) ; => #f 330 | 331 | ;;; 循环 332 | 333 | ;; 循环可以使用递归(尾递归) 334 | (define (loop i) 335 | (when (< i 10) 336 | (printf "i=~a\n" i) 337 | (loop (add1 i)))) 338 | (loop 5) ; => i=5, i=6, ... 339 | 340 | ;; 类似的,可以使用 `let` 定义 341 | (let loop ((i 0)) 342 | (when (< i 10) 343 | (printf "i=~a\n" i) 344 | (loop (add1 i)))) ; => i=0, i=1, ... 345 | 346 | ;; 看上面的例子怎么增加一个新的 `loop' 形式, 但是 Racket 已经有了一个非常 347 | ;; 灵活的 `for' 了: 348 | (for ([i 10]) 349 | (printf "i=~a\n" i)) ; => i=0, i=1, ... 350 | (for ([i (in-range 5 10)]) 351 | (printf "i=~a\n" i)) ; => i=5, i=6, ... 352 | 353 | ;;; 其他形式的迭代 354 | ;; `for' 允许在很多数据结构中迭代: 355 | ;; 列表, 向量, 字符串, Set, 散列表, 等... 356 | 357 | (for ([i (in-list '(l i s t))]) 358 | (displayln i)) 359 | 360 | (for ([i (in-vector #(v e c t o r))]) 361 | (displayln i)) 362 | 363 | (for ([i (in-string "string")]) 364 | (displayln i)) 365 | 366 | (for ([i (in-set (set 'x 'y 'z))]) 367 | (displayln i)) 368 | 369 | (for ([(k v) (in-hash (hash 'a 1 'b 2 'c 3 ))]) 370 | (printf "key:~a value:~a\n" k v)) 371 | 372 | ;;; 更多复杂的迭代 373 | 374 | ;; 并行扫描多个序列 (遇到长度小的就停止) 375 | (for ([i 10] [j '(x y z)]) (printf "~a:~a\n" i j)) 376 | ; => 0:x 1:y 2:z 377 | 378 | ;; 嵌套循环 379 | (for* ([i 2] [j '(x y z)]) (printf "~a:~a\n" i j)) 380 | ; => 0:x, 0:y, 0:z, 1:x, 1:y, 1:z 381 | 382 | ;; 带有条件判断的 `for` 383 | (for ([i 1000] 384 | #:when (> i 5) 385 | #:unless (odd? i) 386 | #:break (> i 10)) 387 | (printf "i=~a\n" i)) 388 | ; => i=6, i=8, i=10 389 | 390 | ;;; 更多的例子帮助你加深理解.. 391 | ;; 和 `for' 循环非常像 -- 收集结果 392 | 393 | (for/list ([i '(1 2 3)]) 394 | (add1 i)) ; => '(2 3 4) 395 | 396 | (for/list ([i '(1 2 3)] #:when (even? i)) 397 | i) ; => '(2) 398 | 399 | (for/list ([i 10] [j '(x y z)]) 400 | (list i j)) ; => '((0 x) (1 y) (2 z)) 401 | 402 | (for/list ([i 1000] #:when (> i 5) #:unless (odd? i) #:break (> i 10)) 403 | i) ; => '(6 8 10) 404 | 405 | (for/hash ([i '(1 2 3)]) 406 | (values i (number->string i))) 407 | ; => '#hash((1 . "1") (2 . "2") (3 . "3")) 408 | 409 | ;; 也有很多其他的内置方法来收集循环中的值: 410 | (for/sum ([i 10]) (* i i)) ; => 285 411 | (for/product ([i (in-range 1 11)]) (* i i)) ; => 13168189440000 412 | (for/and ([i 10] [j (in-range 10 20)]) (< i j)) ; => #t 413 | (for/or ([i 10] [j (in-range 0 20 2)]) (= i j)) ; => #t 414 | ;; 如果需要合并计算结果, 使用 `for/fold' 415 | (for/fold ([sum 0]) ([i '(1 2 3 4)]) (+ sum i)) ; => 10 416 | ;; (这个函数可以在大部分情况下替代普通的命令式循环) 417 | 418 | ;;; 异常 419 | 420 | ;; 要捕获一个异常,使用 `with-handlers' 形式 421 | (with-handlers ([exn:fail? (lambda (exn) 999)]) 422 | (+ 1 "2")) ; => 999 423 | (with-handlers ([exn:break? (lambda (exn) "no time")]) 424 | (sleep 3) 425 | "phew") ; => "phew", 如果你打断了它,那么结果 => "no time" 426 | 427 | ;; 使用 `raise' 抛出一个异常后者其他任何值 428 | (with-handlers ([number? ; 捕获抛出的数字类型的值 429 | identity]) ; 将它们作为普通值 430 | (+ 1 (raise 2))) ; => 2 431 | 432 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 433 | ;; 6. 可变的值 434 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 435 | 436 | ;; 使用 `set!' 给一个已经存在的变量赋一个新值 437 | (define n 5) 438 | (set! n (add1 n)) 439 | n ; => 6 440 | 441 | ;; 给那些明确地需要变化的值使用 `boxes` (在其他语言里类似指针 442 | ;; 或者引用) 443 | (define n* (box 5)) 444 | (set-box! n* (add1 (unbox n*))) 445 | (unbox n*) ; => 6 446 | 447 | ;; 很多 Racket 诗句类型是不可变的 (对,列表,等),有一些既是可变的 448 | ;; 又是不可变的 (字符串,向量,散列表 449 | ;; 等...) 450 | 451 | ;; 使用 `vector' 或者 `make-vector' 创建一个可变的向量 452 | (define vec (vector 2 2 3 4)) 453 | (define wall (make-vector 100 'bottle-of-beer)) 454 | ;; 使用 `vector-set!` 更新一项 455 | (vector-set! vec 0 1) 456 | (vector-set! wall 99 'down) 457 | vec ; => #(1 2 3 4) 458 | 459 | ;; 创建一个空的可变散列表,然后操作它 460 | (define m3 (make-hash)) 461 | (hash-set! m3 'a 1) 462 | (hash-set! m3 'b 2) 463 | (hash-set! m3 'c 3) 464 | (hash-ref m3 'a) ; => 1 465 | (hash-ref m3 'd 0) ; => 0 466 | (hash-remove! m3 'a) 467 | 468 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 469 | ;; 7. 模块 470 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 471 | 472 | ;; 模块让你将你的代码组织为多个文件,成为可重用的模块, 473 | ;; 在这里,我们使用嵌套在本文的整个大模块 474 | ;; 里的子模块(从 "#lang" 这一行开始) 475 | 476 | (module cake racket/base ; 基于 racket/base 定义一个 `cake` 模块 477 | 478 | (provide print-cake) ; 这个模块导出的函数 479 | 480 | (define (print-cake n) 481 | (show " ~a " n #\.) 482 | (show " .-~a-. " n #\|) 483 | (show " | ~a | " n #\space) 484 | (show "---~a---" n #\-)) 485 | 486 | (define (show fmt n ch) ; 内部函数 487 | (printf fmt (make-string n ch)) 488 | (newline))) 489 | 490 | ;; 使用 `require` 从模块中得到所有 `provide` 的函数 491 | (require 'cake) ; 这里的 `'`表示是本地的子模块 492 | (print-cake 3) 493 | ; (show "~a" 1 #\A) ; => 报错, `show' 没有被导出,不存在 494 | 495 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 496 | ;; 8. 类和对象 497 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 498 | 499 | ;; 创建一个 fish% 类(%是给类绑定用的) 500 | (define fish% 501 | (class object% 502 | (init size) ; 初始化的参数 503 | (super-new) ; 父类的初始化 504 | ;; 域 505 | (define current-size size) 506 | ;; 公共方法 507 | (define/public (get-size) 508 | current-size) 509 | (define/public (grow amt) 510 | (set! current-size (+ amt current-size))) 511 | (define/public (eat other-fish) 512 | (grow (send other-fish get-size))))) 513 | 514 | ;; 创建一个 fish% 类的示例 515 | (define charlie 516 | (new fish% [size 10])) 517 | 518 | ;; 使用 `send' 调用一个对象的方法 519 | (send charlie get-size) ; => 10 520 | (send charlie grow 6) 521 | (send charlie get-size) ; => 16 522 | 523 | ;; `fish%' 是一个普通的值,我们可以用它来混入 524 | (define (add-color c%) 525 | (class c% 526 | (init color) 527 | (super-new) 528 | (define my-color color) 529 | (define/public (get-color) my-color))) 530 | (define colored-fish% (add-color fish%)) 531 | (define charlie2 (new colored-fish% [size 10] [color 'red])) 532 | (send charlie2 get-color) 533 | ;; 或者,不带名字 534 | (send (new (add-color fish%) [size 10] [color 'red]) get-color) 535 | 536 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 537 | ;; 9. 宏 538 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 539 | 540 | ;; 宏让你扩展这门语言的语法 541 | 542 | ;; 让我们定义一个while循环 543 | (define-syntax-rule (while condition body ...) 544 | (let loop () 545 | (when condition 546 | body ... 547 | (loop)))) 548 | 549 | (let ([i 0]) 550 | (while (< i 10) 551 | (displayln i) 552 | (set! i (add1 i)))) 553 | 554 | ;; 宏是安全的,你不能修改现有的变量 555 | (define-syntax-rule (swap! x y) ; !表示会修改 556 | (let ([tmp x]) 557 | (set! x y) 558 | (set! y tmp))) 559 | 560 | (define tmp 2) 561 | (define other 3) 562 | (swap! tmp other) 563 | (printf "tmp = ~a; other = ~a\n" tmp other) 564 | ;; 变量 `tmp` 被重命名为 `tmp_1` 565 | ;; 避免名字冲突 566 | ;; (let ([tmp_1 tmp]) 567 | ;; (set! tmp other) 568 | ;; (set! other tmp_1)) 569 | 570 | ;; 但它们仍然会导致错误代码,比如: 571 | (define-syntax-rule (bad-while condition body ...) 572 | (when condition 573 | body ... 574 | (bad-while condition body ...))) 575 | ;; 这个宏会挂掉,它产生了一个无限循环,如果你试图去使用它 576 | ;; 编译器会进入死循环 577 | 578 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 579 | ;; 10. 契约 580 | ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 581 | 582 | ;; 契约限制变量从模块中导入 583 | 584 | (module bank-account racket 585 | (provide (contract-out 586 | [deposit (-> positive? any)] ; 数量一直是正值 587 | [balance (-> positive?)])) 588 | 589 | (define amount 0) 590 | (define (deposit a) (set! amount (+ amount a))) 591 | (define (balance) amount) 592 | ) 593 | 594 | (require 'bank-account) 595 | (deposit 5) 596 | 597 | (balance) ; => 5 598 | 599 | ;; 客户端尝试存储一个负值时会出错 600 | ;; (deposit -5) ; => deposit: contract violation 601 | ;; expected: positive? 602 | ;; given: -5 603 | ;; more details.... 604 | ``` 605 | 606 | ## 进一步阅读 607 | 608 | 想知道更多吗? 尝试 [Getting Started with Racket](http://docs.racket-lang.org/getting-started/) 609 | -------------------------------------------------------------------------------- /SICP/程序设计技术和方法/sicp00.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajava/books/1e5e02ccee96b1024dcc1aed571478040d849d04/SICP/程序设计技术和方法/sicp00.pdf -------------------------------------------------------------------------------- /SICP/程序设计技术和方法/sicp01-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajava/books/1e5e02ccee96b1024dcc1aed571478040d849d04/SICP/程序设计技术和方法/sicp01-1.pdf -------------------------------------------------------------------------------- /SICP/程序设计技术和方法/sicp01-2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajava/books/1e5e02ccee96b1024dcc1aed571478040d849d04/SICP/程序设计技术和方法/sicp01-2.pdf -------------------------------------------------------------------------------- /SICP/程序设计技术和方法/sicp01-3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajava/books/1e5e02ccee96b1024dcc1aed571478040d849d04/SICP/程序设计技术和方法/sicp01-3.pdf -------------------------------------------------------------------------------- /SICP/程序设计技术和方法/sicp02-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajava/books/1e5e02ccee96b1024dcc1aed571478040d849d04/SICP/程序设计技术和方法/sicp02-1.pdf -------------------------------------------------------------------------------- /SICP/程序设计技术和方法/sicp02-2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajava/books/1e5e02ccee96b1024dcc1aed571478040d849d04/SICP/程序设计技术和方法/sicp02-2.pdf -------------------------------------------------------------------------------- /SICP/程序设计技术和方法/sicp02-3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajava/books/1e5e02ccee96b1024dcc1aed571478040d849d04/SICP/程序设计技术和方法/sicp02-3.pdf -------------------------------------------------------------------------------- /SICP/程序设计技术和方法/sicp03-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajava/books/1e5e02ccee96b1024dcc1aed571478040d849d04/SICP/程序设计技术和方法/sicp03-1.pdf -------------------------------------------------------------------------------- /SICP/程序设计技术和方法/sicp03-2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajava/books/1e5e02ccee96b1024dcc1aed571478040d849d04/SICP/程序设计技术和方法/sicp03-2.pdf -------------------------------------------------------------------------------- /SICP/程序设计技术和方法/sicp03-3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajava/books/1e5e02ccee96b1024dcc1aed571478040d849d04/SICP/程序设计技术和方法/sicp03-3.pdf -------------------------------------------------------------------------------- /SICP/程序设计技术和方法/sicp03-4.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajava/books/1e5e02ccee96b1024dcc1aed571478040d849d04/SICP/程序设计技术和方法/sicp03-4.pdf -------------------------------------------------------------------------------- /SICP/程序设计技术和方法/sicp04-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajava/books/1e5e02ccee96b1024dcc1aed571478040d849d04/SICP/程序设计技术和方法/sicp04-1.pdf -------------------------------------------------------------------------------- /SICP/程序设计技术和方法/sicp04-2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajava/books/1e5e02ccee96b1024dcc1aed571478040d849d04/SICP/程序设计技术和方法/sicp04-2.pdf -------------------------------------------------------------------------------- /SICP/程序设计技术和方法/sicp04-3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajava/books/1e5e02ccee96b1024dcc1aed571478040d849d04/SICP/程序设计技术和方法/sicp04-3.pdf -------------------------------------------------------------------------------- /SICP/程序设计技术和方法/sicp04-4.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajava/books/1e5e02ccee96b1024dcc1aed571478040d849d04/SICP/程序设计技术和方法/sicp04-4.pdf -------------------------------------------------------------------------------- /SICP/程序设计技术和方法/sicp05-1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajava/books/1e5e02ccee96b1024dcc1aed571478040d849d04/SICP/程序设计技术和方法/sicp05-1.pdf -------------------------------------------------------------------------------- /SICP/程序设计技术和方法/summary.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajava/books/1e5e02ccee96b1024dcc1aed571478040d849d04/SICP/程序设计技术和方法/summary.pdf -------------------------------------------------------------------------------- /SICP/程序设计技术和方法/《程序设计技术和方法》作业.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xiajava/books/1e5e02ccee96b1024dcc1aed571478040d849d04/SICP/程序设计技术和方法/《程序设计技术和方法》作业.png -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | Booklist 2 | - [ ] SICP 3 | - [ ] CSAPP 4 | - [ ] Algorithms 5 | -------------------------------------------------------------------------------- /web/html-cn.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | language: html 3 | filename: learnhtml-cn.html 4 | contributors: 5 | - ["Christophe THOMAS", "https://github.com/WinChris"] 6 | translators: 7 | - ["zxyqwe", "https://github.com/zxyqwe"] 8 | lang: zh-cn 9 | --- 10 | 11 | HTML是超文本标记语言的缩写。 12 | 这门语言可以让我们为万维网创造页面。 13 | 这是一门标记语言,它允许我们用代码来指示网页上文字和数据应该如何显示。 14 | 实际上html文件是简单的文本文件。 15 | 什么是标记?标记是通过使用开始和结束标签包围数据的方法,来组织管理页面上的数据。 16 | 这些标记对它们环绕的文本有重要的意义。 17 | 和其它计算机语言意义,HTML有很多版本。这里我们将讨论HTML5。 18 | 19 | **注意:** 你可以在类似[codepen](http://codepen.io/pen/)的网站上的教程中,尝试不同的标签和元素带来的效果,理解它们如何起效,并且逐渐熟悉这门语言。 20 | 本文主要关注HTML的语法和一些有用的小窍门。 21 | 22 | 23 | ```html 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 我的网站 34 | 35 | 36 |

Hello, world!

37 | 来看看这里有什么 38 |

这是一个段落。

39 |

这是另外一个段落。

40 |
    41 |
  • 这是一个非计数列表的一项(项目符合列表)
  • 42 |
  • 这是另一项
  • 43 |
  • 这是列表中的最后一项
  • 44 |
45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 我的网站 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 |

Hello, world!

74 | 75 | 来看看这里有什么 76 |

这是一个段落。

77 |

这是另外一个段落。

78 |
    79 | 80 |
  • 这是一个非计数列表的一项(项目符合列表)
  • 81 |
  • 这是另一项
  • 82 |
  • 这是列表中的最后一项
  • 83 |
84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 |
第一个表头 第二个表头
第一行第一列 第一行第二列
第二行第一列第二行第二列
110 | 111 | ``` 112 | 113 | ## 使用 114 | 115 | HTML文件使用`.html`后缀。 116 | 117 | ## 扩展阅读 118 | 119 | * [维基百科](https://en.wikipedia.org/wiki/HTML) 120 | * [HTML tutorial](https://developer.mozilla.org/en-US/docs/Web/HTML) 121 | * [W3School](http://www.w3schools.com/html/html_intro.asp) 122 | -------------------------------------------------------------------------------- /web/javascript-cn.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | language: javascript 3 | category: language 4 | name: javascript 5 | filename: javascript-zh.js 6 | contributors: 7 | - ["Adam Brenecki", "http://adam.brenecki.id.au"] 8 | - ["Ariel Krakowski", "http://www.learneroo.com"] 9 | translators: 10 | - ["Chenbo Li", "http://binarythink.net"] 11 | - ["Guodong Qu", "https://github.com/jasonqu"] 12 | lang: zh-cn 13 | --- 14 | 15 | Javascript于1995年由网景公司的Brendan Eich发明。 16 | 最初发明的目的是作为一个简单的网站脚本语言,来作为 17 | 复杂网站应用java的补充。但由于它与网页结合度很高并且由浏览器内置支持, 18 | 所以javascript变得比java在前端更为流行了。 19 | 20 | 不过 JavaScript 可不仅仅只用于浏览器: Node.js,一个基于Google Chrome V8引擎的独立运行时环境,也越来越流行。 21 | 22 | 很欢迎来自您的反馈,您可以通过下列方式联系到我: 23 | [@adambrenecki](https://twitter.com/adambrenecki), 或者 24 | [adam@brenecki.id.au](mailto:adam@brenecki.id.au). 25 | 26 | ```js 27 | // 注释方式和C很像,这是单行注释 28 | /* 这是多行 29 | 注释 */ 30 | 31 | // 语句可以以分号结束 32 | doStuff(); 33 | 34 | // ... 但是分号也可以省略,每当遇到一个新行时,分号会自动插入(除了一些特殊情况)。 35 | doStuff() 36 | 37 | // 因为这些特殊情况会导致意外的结果,所以我们在这里保留分号。 38 | 39 | /////////////////////////////////// 40 | // 1. 数字、字符串与操作符 41 | 42 | // Javascript 只有一种数字类型(即 64位 IEEE 754 双精度浮点 double)。 43 | // double 有 52 位表示尾数,足以精确存储大到 9✕10¹⁵ 的整数。 44 | 3; // = 3 45 | 1.5; // = 1.5 46 | 47 | // 所有基本的算数运算都如你预期。 48 | 1 + 1; // = 2 49 | 0.1 + 0.2; // = 0.30000000000000004 50 | 8 - 1; // = 7 51 | 10 * 2; // = 20 52 | 35 / 5; // = 7 53 | 54 | // 包括无法整除的除法。 55 | 5 / 2; // = 2.5 56 | 57 | // 位运算也和其他语言一样;当你对浮点数进行位运算时, 58 | // 浮点数会转换为*至多* 32 位的无符号整数。 59 | 1 << 2; // = 4 60 | 61 | // 括号可以决定优先级。 62 | (1 + 3) * 2; // = 8 63 | 64 | // 有三种非数字的数字类型 65 | Infinity; // 1/0 的结果 66 | -Infinity; // -1/0 的结果 67 | NaN; // 0/0 的结果 68 | 69 | // 也有布尔值。 70 | true; 71 | false; 72 | 73 | // 可以通过单引号或双引号来构造字符串。 74 | 'abc'; 75 | "Hello, world"; 76 | 77 | // 用!来取非 78 | !true; // = false 79 | !false; // = true 80 | 81 | // 相等 === 82 | 1 === 1; // = true 83 | 2 === 1; // = false 84 | 85 | // 不等 != 86 | 1 !== 1; // = false 87 | 2 !== 1; // = true 88 | 89 | // 更多的比较操作符 90 | 1 < 10; // = true 91 | 1 > 10; // = false 92 | 2 <= 2; // = true 93 | 2 >= 2; // = true 94 | 95 | // 字符串用+连接 96 | "Hello " + "world!"; // = "Hello world!" 97 | 98 | // 字符串也可以用 < 、> 来比较 99 | "a" < "b"; // = true 100 | 101 | // 使用“==”比较时会进行类型转换... 102 | "5" == 5; // = true 103 | null == undefined; // = true 104 | 105 | // ...除非你是用 === 106 | "5" === 5; // = false 107 | null === undefined; // = false 108 | 109 | // ...但会导致奇怪的行为 110 | 13 + !0; // 14 111 | "13" + !0; // '13true' 112 | 113 | // 你可以用`charAt`来得到字符串中的字符 114 | "This is a string".charAt(0); // = 'T' 115 | 116 | // ...或使用 `substring` 来获取更大的部分。 117 | "Hello world".substring(0, 5); // = "Hello" 118 | 119 | // `length` 是一个属性,所以不要使用 (). 120 | "Hello".length; // = 5 121 | 122 | // 还有两个特殊的值:`null`和`undefined` 123 | null; // 用来表示刻意设置的空值 124 | undefined; // 用来表示还没有设置的值(尽管`undefined`自身实际是一个值) 125 | 126 | // false, null, undefined, NaN, 0 和 "" 都是假的;其他的都视作逻辑真 127 | // 注意 0 是逻辑假而 "0"是逻辑真,尽管 0 == "0"。 128 | 129 | /////////////////////////////////// 130 | // 2. 变量、数组和对象 131 | 132 | // 变量需要用`var`关键字声明。Javascript是动态类型语言, 133 | // 所以你无需指定类型。 赋值需要用 `=` 134 | var someVar = 5; 135 | 136 | // 如果你在声明时没有加var关键字,你也不会得到错误... 137 | someOtherVar = 10; 138 | 139 | // ...但是此时这个变量就会在全局作用域被创建,而非你定义的当前作用域 140 | 141 | // 没有被赋值的变量都会被设置为undefined 142 | var someThirdVar; // = undefined 143 | 144 | // 对变量进行数学运算有一些简写法: 145 | someVar += 5; // 等价于 someVar = someVar + 5; someVar 现在是 10 146 | someVar *= 10; // 现在 someVar 是 100 147 | 148 | // 自增和自减也有简写 149 | someVar++; // someVar 是 101 150 | someVar--; // 回到 100 151 | 152 | // 数组是任意类型组成的有序列表 153 | var myArray = ["Hello", 45, true]; 154 | 155 | // 数组的元素可以用方括号下标来访问。 156 | // 数组的索引从0开始。 157 | myArray[1]; // = 45 158 | 159 | // 数组是可变的,并拥有变量 length。 160 | myArray.push("World"); 161 | myArray.length; // = 4 162 | 163 | // 在指定下标添加/修改 164 | myArray[3] = "Hello"; 165 | 166 | // javascript中的对象相当于其他语言中的“字典”或“映射”:是键-值对的无序集合。 167 | var myObj = {key1: "Hello", key2: "World"}; 168 | 169 | // 键是字符串,但如果键本身是合法的js标识符,则引号并非是必须的。 170 | // 值可以是任意类型。 171 | var myObj = {myKey: "myValue", "my other key": 4}; 172 | 173 | // 对象属性的访问可以通过下标 174 | myObj["my other key"]; // = 4 175 | 176 | // ... 或者也可以用 . ,如果属性是合法的标识符 177 | myObj.myKey; // = "myValue" 178 | 179 | // 对象是可变的;值也可以被更改或增加新的键 180 | myObj.myThirdKey = true; 181 | 182 | // 如果你想要获取一个还没有被定义的值,那么会返回undefined 183 | myObj.myFourthKey; // = undefined 184 | 185 | /////////////////////////////////// 186 | // 3. 逻辑与控制结构 187 | 188 | // 本节介绍的语法与Java的语法几乎完全相同 189 | 190 | // `if`语句和其他语言中一样。 191 | var count = 1; 192 | if (count == 3){ 193 | // count 是 3 时执行 194 | } else if (count == 4){ 195 | // count 是 4 时执行 196 | } else { 197 | // 其他情况下执行 198 | } 199 | 200 | // while循环 201 | while (true) { 202 | // 无限循环 203 | } 204 | 205 | // Do-while 和 While 循环很像 ,但前者会至少执行一次 206 | var input; 207 | do { 208 | input = getInput(); 209 | } while (!isValid(input)) 210 | 211 | // `for`循环和C、Java中的一样: 212 | // 初始化; 继续执行的条件; 迭代。 213 | for (var i = 0; i < 5; i++){ 214 | // 遍历5次 215 | } 216 | 217 | // && 是逻辑与, || 是逻辑或 218 | if (house.size == "big" && house.colour == "blue"){ 219 | house.contains = "bear"; 220 | } 221 | if (colour == "red" || colour == "blue"){ 222 | // colour是red或者blue时执行 223 | } 224 | 225 | // && 和 || 是“短路”语句,它在设定初始化值时特别有用 226 | var name = otherName || "default"; 227 | 228 | // `switch`语句使用`===`检查相等性。 229 | // 在每一个case结束时使用 'break' 230 | // 否则其后的case语句也将被执行。 231 | grade = 'B'; 232 | switch (grade) { 233 | case 'A': 234 | console.log("Great job"); 235 | break; 236 | case 'B': 237 | console.log("OK job"); 238 | break; 239 | case 'C': 240 | console.log("You can do better"); 241 | break; 242 | default: 243 | console.log("Oy vey"); 244 | break; 245 | } 246 | 247 | /////////////////////////////////// 248 | // 4. 函数、作用域、闭包 249 | 250 | // JavaScript 函数由`function`关键字定义 251 | function myFunction(thing){ 252 | return thing.toUpperCase(); 253 | } 254 | myFunction("foo"); // = "FOO" 255 | 256 | // 注意被返回的值必须开始于`return`关键字的那一行, 257 | // 否则由于自动的分号补齐,你将返回`undefined`。 258 | // 在使用Allman风格的时候要注意. 259 | function myFunction() 260 | { 261 | return // <- 分号自动插在这里 262 | { 263 | thisIsAn: 'object literal' 264 | } 265 | } 266 | myFunction(); // = undefined 267 | 268 | // javascript中函数是一等对象,所以函数也能够赋给一个变量, 269 | // 并且被作为参数传递 —— 比如一个事件处理函数: 270 | function myFunction(){ 271 | // 这段代码将在5秒钟后被调用 272 | } 273 | setTimeout(myFunction, 5000); 274 | // 注意:setTimeout不是js语言的一部分,而是由浏览器和Node.js提供的。 275 | 276 | // 函数对象甚至不需要声明名称 —— 你可以直接把一个函数定义写到另一个函数的参数中 277 | setTimeout(function(){ 278 | // 这段代码将在5秒钟后被调用 279 | }, 5000); 280 | 281 | // JavaScript 有函数作用域;函数有其自己的作用域而其他的代码块则没有。 282 | if (true){ 283 | var i = 5; 284 | } 285 | i; // = 5 - 并非我们在其他语言中所期望得到的undefined 286 | 287 | // 这就导致了人们经常使用的“立即执行匿名函数”的模式, 288 | // 这样可以避免一些临时变量扩散到全局作用域去。 289 | (function(){ 290 | var temporary = 5; 291 | // 我们可以访问修改全局对象("global object")来访问全局作用域, 292 | // 在web浏览器中是`window`这个对象。 293 | // 在其他环境如Node.js中这个对象的名字可能会不同。 294 | window.permanent = 10; 295 | })(); 296 | temporary; // 抛出引用异常ReferenceError 297 | permanent; // = 10 298 | 299 | // javascript最强大的功能之一就是闭包。 300 | // 如果一个函数在另一个函数中定义,那么这个内部函数就拥有外部函数的所有变量的访问权, 301 | // 即使在外部函数结束之后。 302 | function sayHelloInFiveSeconds(name){ 303 | var prompt = "Hello, " + name + "!"; 304 | // 内部函数默认是放在局部作用域的, 305 | // 就像是用`var`声明的。 306 | function inner(){ 307 | alert(prompt); 308 | } 309 | setTimeout(inner, 5000); 310 | // setTimeout是异步的,所以 sayHelloInFiveSeconds 函数会立即退出, 311 | // 而 setTimeout 会在后面调用inner 312 | // 然而,由于inner是由sayHelloInFiveSeconds“闭合包含”的, 313 | // 所以inner在其最终被调用时仍然能够访问`prompt`变量。 314 | } 315 | sayHelloInFiveSeconds("Adam"); // 会在5秒后弹出 "Hello, Adam!" 316 | 317 | 318 | /////////////////////////////////// 319 | // 5. 对象、构造函数与原型 320 | 321 | // 对象可以包含方法。 322 | var myObj = { 323 | myFunc: function(){ 324 | return "Hello world!"; 325 | } 326 | }; 327 | myObj.myFunc(); // = "Hello world!" 328 | 329 | // 当对象中的函数被调用时,这个函数可以通过`this`关键字访问其依附的这个对象。 330 | myObj = { 331 | myString: "Hello world!", 332 | myFunc: function(){ 333 | return this.myString; 334 | } 335 | }; 336 | myObj.myFunc(); // = "Hello world!" 337 | 338 | // 但这个函数访问的其实是其运行时环境,而非定义时环境,即取决于函数是如何调用的。 339 | // 所以如果函数被调用时不在这个对象的上下文中,就不会运行成功了。 340 | var myFunc = myObj.myFunc; 341 | myFunc(); // = undefined 342 | 343 | // 相应的,一个函数也可以被指定为一个对象的方法,并且可以通过`this`访问 344 | // 这个对象的成员,即使在函数被定义时并没有依附在对象上。 345 | var myOtherFunc = function(){ 346 | return this.myString.toUpperCase(); 347 | } 348 | myObj.myOtherFunc = myOtherFunc; 349 | myObj.myOtherFunc(); // = "HELLO WORLD!" 350 | 351 | // 当我们通过`call`或者`apply`调用函数的时候,也可以为其指定一个执行上下文。 352 | var anotherFunc = function(s){ 353 | return this.myString + s; 354 | } 355 | anotherFunc.call(myObj, " And Hello Moon!"); // = "Hello World! And Hello Moon!" 356 | 357 | // `apply`函数几乎完全一样,只是要求一个array来传递参数列表。 358 | anotherFunc.apply(myObj, [" And Hello Sun!"]); // = "Hello World! And Hello Sun!" 359 | 360 | // 当一个函数接受一系列参数,而你想传入一个array时特别有用。 361 | Math.min(42, 6, 27); // = 6 362 | Math.min([42, 6, 27]); // = NaN (uh-oh!) 363 | Math.min.apply(Math, [42, 6, 27]); // = 6 364 | 365 | // 但是`call`和`apply`只是临时的。如果我们希望函数附着在对象上,可以使用`bind`。 366 | var boundFunc = anotherFunc.bind(myObj); 367 | boundFunc(" And Hello Saturn!"); // = "Hello World! And Hello Saturn!" 368 | 369 | // `bind` 也可以用来部分应用一个函数(柯里化)。 370 | var product = function(a, b){ return a * b; } 371 | var doubler = product.bind(this, 2); 372 | doubler(8); // = 16 373 | 374 | // 当你通过`new`关键字调用一个函数时,就会创建一个对象, 375 | // 而且可以通过this关键字访问该函数。 376 | // 设计为这样调用的函数就叫做构造函数。 377 | var MyConstructor = function(){ 378 | this.myNumber = 5; 379 | } 380 | myNewObj = new MyConstructor(); // = {myNumber: 5} 381 | myNewObj.myNumber; // = 5 382 | 383 | // 每一个js对象都有一个‘原型’。当你要访问一个实际对象中没有定义的一个属性时, 384 | // 解释器就回去找这个对象的原型。 385 | 386 | // 一些JS实现会让你通过`__proto__`属性访问一个对象的原型。 387 | // 这虽然对理解原型很有用,但是它并不是标准的一部分; 388 | // 我们后面会介绍使用原型的标准方式。 389 | var myObj = { 390 | myString: "Hello world!" 391 | }; 392 | var myPrototype = { 393 | meaningOfLife: 42, 394 | myFunc: function(){ 395 | return this.myString.toLowerCase() 396 | } 397 | }; 398 | 399 | myObj.__proto__ = myPrototype; 400 | myObj.meaningOfLife; // = 42 401 | 402 | // 函数也可以工作。 403 | myObj.myFunc() // = "hello world!" 404 | 405 | // 当然,如果你要访问的成员在原型当中也没有定义的话,解释器就会去找原型的原型,以此类推。 406 | myPrototype.__proto__ = { 407 | myBoolean: true 408 | }; 409 | myObj.myBoolean; // = true 410 | 411 | // 这其中并没有对象的拷贝;每个对象实际上是持有原型对象的引用。 412 | // 这意味着当我们改变对象的原型时,会影响到其他以这个原型为原型的对象。 413 | myPrototype.meaningOfLife = 43; 414 | myObj.meaningOfLife; // = 43 415 | 416 | // 我们知道 `__proto__` 并非标准规定,实际上也没有标准办法来修改一个已存在对象的原型。 417 | // 然而,我们有两种方式为指定原型创建一个新的对象。 418 | 419 | // 第一种方式是 Object.create,这个方法是在最近才被添加到Js中的, 420 | // 因此并不是所有的JS实现都有这个方法 421 | var myObj = Object.create(myPrototype); 422 | myObj.meaningOfLife; // = 43 423 | 424 | // 第二种方式可以在任意版本中使用,不过必须通过构造函数。 425 | // 构造函数有一个属性prototype。但是它 *不是* 构造函数本身的原型;相反, 426 | // 是通过构造函数和new关键字创建的新对象的原型。 427 | MyConstructor.prototype = { 428 | myNumber: 5, 429 | getMyNumber: function(){ 430 | return this.myNumber; 431 | } 432 | }; 433 | var myNewObj2 = new MyConstructor(); 434 | myNewObj2.getMyNumber(); // = 5 435 | myNewObj2.myNumber = 6 436 | myNewObj2.getMyNumber(); // = 6 437 | 438 | // 字符串和数字等内置类型也有通过构造函数来创建的包装类型 439 | var myNumber = 12; 440 | var myNumberObj = new Number(12); 441 | myNumber == myNumberObj; // = true 442 | 443 | // 但是它们并非严格等价 444 | typeof myNumber; // = 'number' 445 | typeof myNumberObj; // = 'object' 446 | myNumber === myNumberObj; // = false 447 | if (0){ 448 | // 这段代码不会执行,因为0代表假 449 | } 450 | 451 | // 不过,包装类型和内置类型共享一个原型, 452 | // 所以你实际可以给内置类型也增加一些功能,例如对string: 453 | String.prototype.firstCharacter = function(){ 454 | return this.charAt(0); 455 | } 456 | "abc".firstCharacter(); // = "a" 457 | 458 | // 这个技巧经常用在“代码填充”中,来为老版本的javascript子集增加新版本js的特性, 459 | // 这样就可以在老的浏览器中使用新功能了。 460 | 461 | // 比如,我们知道Object.create并没有在所有的版本中都实现, 462 | // 但是我们仍然可以通过“代码填充”来实现兼容: 463 | if (Object.create === undefined){ // 如果存在则不覆盖 464 | Object.create = function(proto){ 465 | // 用正确的原型来创建一个临时构造函数 466 | var Constructor = function(){}; 467 | Constructor.prototype = proto; 468 | // 之后用它来创建一个新的对象 469 | return new Constructor(); 470 | } 471 | } 472 | ``` 473 | 474 | ## 更多阅读 475 | 476 | [Mozilla 开发者 477 | 网络](https://developer.mozilla.org/en-US/docs/Web/JavaScript) 提供了优秀的介绍 478 | Javascript如何在浏览器中使用的文档。而且它是wiki,所以你也可以自行编辑来分享你的知识。 479 | 480 | MDN的 [A re-introduction to 481 | JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript) 482 | 覆盖了这里提到的绝大多数话题的细节。该导引的大多数内容被限定在只是Javascript这个语言本身; 483 | 如果你想了解Javascript是如何在网页中被应用的,那么可以查看 484 | [Document Object 485 | Model](https://developer.mozilla.org/en-US/docs/Using_the_W3C_DOM_Level_1_Core) 486 | 487 | [Learn Javascript by Example and with Challenges](http://www.learneroo.com/modules/64/nodes/350) 是本参考的另一个版本,并包含了挑战习题。 488 | 489 | [Javascript Garden](http://bonsaiden.github.io/JavaScript-Garden/) 是一个深入 490 | 讲解所有Javascript反直觉部分的导引。 491 | 492 | [JavaScript: The Definitive Guide](http://www.amazon.com/gp/product/0596805527/) 是一个经典的指导参考书。 493 | 494 | 除了这篇文章的直接贡献者之外,这篇文章也参考了这个网站上 495 | Louie Dinh 的 Python 教程,以及 Mozilla开发者网络上的[JS 496 | Tutorial](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript)。 497 | -------------------------------------------------------------------------------- /web/jquery-cn.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | category: tool 3 | tool: jquery 4 | contributors: 5 | - ["Sawyer Charles", "https://github.com/xssc"] 6 | translators: 7 | - ["zxyqwe", "https://github.com/zxyqwe"] 8 | lang: zh-cn 9 | filename: jquery-cn.js 10 | --- 11 | 12 | jQuery是JavaScript的一个函数库,它可以帮你“写更少,做更多”。它集成了很多常见的JavaScript任务并且很容易调用。jQuery被世界各地的很多的大公司和开发者使用。它包括了AJAX,事件处理,文档操作以及很多其它功能,并且更加简单和快速。 13 | 14 | 正因为jQuery是JavaScript的一个函数库,所以你需要[首先学习JavaScript](https://learnxinyminutes.com/docs/javascript/) 15 | 16 | ```js 17 | 18 | 19 | /////////////////////////////////// 20 | // 1. 选择器 21 | 22 | // jQuery中的选择器被用来选择一个元素 23 | var page = $(window); // 选择整个视窗 24 | 25 | // 选择器可以作为CSS选择器使用 26 | var paragraph = $('p'); // 选择所有段落元素 27 | var table1 = $('#table1'); // 选择id为table1的元素 28 | var squares = $('.square'); // 选择所有类是square的元素 29 | var square_p = $('p.square') // 选择具有square类的所有段落 30 | 31 | 32 | /////////////////////////////////// 33 | // 2. 事件和效果 34 | // jQuery非常善于处理当事件触发的时候应该做什么 35 | // 一个非常常见的事件就是文档的就绪事件 36 | // 你可以用ready方法,在所有元素完成加载的时候执行 37 | $(document).ready(function(){ 38 | // 只有文档加载完成以后代码才会执行 39 | }); 40 | // 你也可以用定义了的函数 41 | function onAction() { 42 | // 本函数在事件触发的时候被执行 43 | } 44 | $('#btn').click(onAction); // 当点击的时候调用onAction函数 45 | 46 | // 其它常见的事件: 47 | $('#btn').dblclick(onAction); // 双击 48 | $('#btn').hover(onAction); // 划过 49 | $('#btn').focus(onAction); // 聚焦 50 | $('#btn').blur(onAction); // 失焦 51 | $('#btn').submit(onAction); // 提交 52 | $('#btn').select(onAction); // 当元素被选中 53 | $('#btn').keydown(onAction); // 当一个按键被按下 54 | $('#btn').keyup(onAction); // 当一个按键被抬起 55 | $('#btn').keypress(onAction); // 当一个按键被按住 56 | $('#btn').mousemove(onAction); // 当鼠标在移动 57 | $('#btn').mouseenter(onAction); // 鼠标移入元素 58 | $('#btn').mouseleave(onAction); // 鼠标离开元素 59 | 60 | 61 | // 如果不提供任何参数的话,那么这些方法可以触发事件 62 | // 而不是定义处理事件的方法 63 | $('#btn').dblclick(); // 触发元素上的双击 64 | 65 | // 你可以只用选择器一次而处理多个事件 66 | $('#btn').on( 67 | {dblclick: myFunction1} // 双击的时候触发 68 | {blur: myFunction1} // 失焦的时候触发 69 | ); 70 | 71 | // 你可以用一些效果函数来移动或隐藏元素 72 | $('.table').hide(); // 隐藏元素 73 | 74 | // 注意:在这些方法中调用函数会仍然隐藏元素 75 | $('.table').hide(function(){ 76 | // 元素先隐藏然后函数被执行 77 | }); 78 | 79 | // 你可以在变量中储存选择器 80 | var tables = $('.table'); 81 | 82 | // 一些基本的文档操作方法有: 83 | tables.hide(); // 隐藏元素 84 | tables.show(); // 显示元素 85 | tables.toggle(); // 对被选元素进行隐藏和显示的切换 86 | tables.fadeOut(); // 淡出 87 | tables.fadeIn(); // 淡入 88 | tables.fadeToggle(); // 对被选元素进行淡入和淡出显示的切换 89 | tables.fadeTo(0.5); // 把被选元素逐渐改变至给定的不透明度(0和1之间) 90 | tables.slideUp(); // 通过调整高度来滑动隐藏被选元素 91 | tables.slideDown(); // 对被选元素进行滑动隐藏和滑动显示的切换 92 | tables.slideToggle(); // 对被选元素进行滑动隐藏和滑动显示的切换 93 | 94 | // 上面所有的方法接受速度参数(毫秒)和一个回调函数 95 | tables.hide(1000, myFunction); // 持续一秒的隐藏动画然后执行函数 96 | 97 | // fadeTo要求提供透明度参数作为第二个参数 98 | tables.fadeTo(2000, 0.1, myFunction); // 通过2秒钟将透明度变为0.1然后执行函数 99 | 100 | // 你可以用animate方法实现一些略微高级的效果 101 | tables.animate({margin-top:"+=50", height: "100px"}, 500, myFunction); 102 | // animate方法接受一个包含CSS和值的对象作为目标, 103 | // 其次是可选的速度参数, 104 | // 以及最后的回调函数 105 | 106 | /////////////////////////////////// 107 | // 3. 操作 108 | 109 | // 这些类似效果函数但是可以做更多 110 | $('div').addClass('taming-slim-20'); // 给所有div添加类taming-slim-20 111 | 112 | // 常见操作方法 113 | $('p').append('Hello world'); // 添加到元素末尾 114 | $('p').attr('class'); // 获取属性 115 | $('p').attr('class', 'content'); // 设置属性 116 | $('p').hasClass('taming-slim-20'); // 如果有类则为真 117 | $('p').height(); // 获取和设置元素的高度 118 | 119 | 120 | // 对于很多的操作函数来说,获取元素的信息 121 | // 仅仅是第一个符合元素的 122 | $('p').height(); // 仅仅获取第一个p标签的高度 123 | 124 | // 你可以用each来迭代所有元素 125 | var heights = []; 126 | $('p').each(function() { 127 | heights.push($(this).height()); // 把所有p标签的高度加入数组 128 | }); 129 | 130 | 131 | ``` 132 | -------------------------------------------------------------------------------- /web/php-cn.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | language: PHP 3 | contributors: 4 | - ["Malcolm Fell", "http://emarref.net/"] 5 | - ["Trismegiste", "https://github.com/Trismegiste"] 6 | translators: 7 | - ["Chenbo Li", "http://binarythink.net"] 8 | filename: learnphp-zh.php 9 | lang: zh-cn 10 | --- 11 | 12 | 这份教程所使用的版本是 PHP 5+. 13 | 14 | ```php 15 | 之中 16 | 17 | // 如果你的文件中只有php代码,那么最好省略结束括号标记 18 | 19 | // 这是单行注释的标志 20 | 21 | # 井号也可以,但是//更常见 22 | 23 | /* 24 | 这是多行注释 25 | */ 26 | 27 | // 使用 "echo" 或者 "print" 来输出信息到标准输出 28 | print('Hello '); // 输出 "Hello " 并且没有换行符 29 | 30 | // () 对于echo和print是可选的 31 | echo "World\n"; // 输出 "World" 并且换行 32 | // (每个语句必须以分号结尾) 33 | 34 | // 在 Hello World Again! 36 | 12 52 | $int2 = -12; // => -12 53 | $int3 = 012; // => 10 (0开头代表八进制数) 54 | $int4 = 0x0F; // => 15 (0x开头代表十六进制数) 55 | 56 | // 浮点型 (即双精度浮点型) 57 | $float = 1.234; 58 | $float = 1.2e3; 59 | $float = 7E-10; 60 | 61 | // 算数运算 62 | $sum = 1 + 1; // 2 63 | $difference = 2 - 1; // 1 64 | $product = 2 * 2; // 4 65 | $quotient = 2 / 1; // 2 66 | 67 | // 算数运算的简写 68 | $number = 0; 69 | $number += 1; // $number 自增1 70 | echo $number++; // 输出1 (运算后自增) 71 | echo ++$number; // 输出3 (自增后运算) 72 | $number /= $float; // 先除后赋值给 $number 73 | 74 | // 字符串需要被包含在单引号之中 75 | $sgl_quotes = '$String'; // => '$String' 76 | 77 | // 如果需要在字符串中引用变量,就需要使用双引号 78 | $dbl_quotes = "This is a $sgl_quotes."; // => 'This is a $String.' 79 | 80 | // 特殊字符只有在双引号中有用 81 | $escaped = "This contains a \t tab character."; 82 | $unescaped = 'This just contains a slash and a t: \t'; 83 | 84 | // 可以把变量包含在一对大括号中 85 | $money = "I have $${number} in the bank."; 86 | 87 | // 自 PHP 5.3 开始, nowdocs 可以被用作多行非计算型字符串 88 | $nowdoc = <<<'END' 89 | Multi line 90 | string 91 | END; 92 | 93 | // 而Heredocs则可以用作多行计算型字符串 94 | $heredoc = << 1, 'Two' => 2, 'Three' => 3); 111 | 112 | // PHP 5.4 中引入了新的语法 113 | $associative = ['One' => 1, 'Two' => 2, 'Three' => 3]; 114 | 115 | echo $associative['One']; // 输出 1 116 | 117 | // 声明为列表实际上是给每个值都分配了一个整数键(key) 118 | $array = ['One', 'Two', 'Three']; 119 | echo $array[0]; // => "One" 120 | 121 | 122 | /******************************** 123 | * 输出 124 | */ 125 | 126 | echo('Hello World!'); 127 | // 输出到标准输出 128 | // 此时标准输出就是浏览器中的网页 129 | 130 | print('Hello World!'); // 和echo相同 131 | 132 | // echo和print实际上也属于这个语言本身,所以我们省略括号 133 | echo 'Hello World!'; 134 | print 'Hello World!'; 135 | 136 | $paragraph = 'paragraph'; 137 | 138 | echo 100; // 直接输出标量 139 | echo $paragraph; // 或者输出变量 140 | 141 | // 如果你配置了短标签,或者使用5.4.0及以上的版本 142 | // 你就可以使用简写的echo语法 143 | ?> 144 |

145 | 2 155 | echo $z; // => 2 156 | $y = 0; 157 | echo $x; // => 2 158 | echo $z; // => 0 159 | 160 | 161 | /******************************** 162 | * 逻辑 163 | */ 164 | $a = 0; 165 | $b = '0'; 166 | $c = '1'; 167 | $d = '1'; 168 | 169 | // 如果assert的参数为假,就会抛出警告 170 | 171 | // 下面的比较都为真,不管它们的类型是否匹配 172 | assert($a == $b); // 相等 173 | assert($c != $a); // 不等 174 | assert($c <> $a); // 另一种不等的表示 175 | assert($a < $c); 176 | assert($c > $b); 177 | assert($a <= $b); 178 | assert($c >= $d); 179 | 180 | // 下面的比较只有在类型相同、值相同的情况下才为真 181 | assert($c === $d); 182 | assert($a !== $d); 183 | assert(1 === '1'); 184 | assert(1 !== '1'); 185 | 186 | // 变量可以根据其使用来进行类型转换 187 | 188 | $integer = 1; 189 | echo $integer + $integer; // => 2 190 | 191 | $string = '1'; 192 | echo $string + $string; // => 2 (字符串在此时被转化为整数) 193 | 194 | $string = 'one'; 195 | echo $string + $string; // => 0 196 | // 输出0,因为'one'这个字符串无法被转换为整数 197 | 198 | // 类型转换可以将一个类型视作另一种类型 199 | 200 | $boolean = (boolean) 1; // => true 201 | 202 | $zero = 0; 203 | $boolean = (boolean) $zero; // => false 204 | 205 | // 还有一些专用的函数来进行类型转换 206 | $integer = 5; 207 | $string = strval($integer); 208 | 209 | $var = null; // 空值 210 | 211 | 212 | /******************************** 213 | * 控制结构 214 | */ 215 | 216 | if (true) { 217 | print 'I get printed'; 218 | } 219 | 220 | if (false) { 221 | print 'I don\'t'; 222 | } else { 223 | print 'I get printed'; 224 | } 225 | 226 | if (false) { 227 | print 'Does not get printed'; 228 | } elseif(true) { 229 | print 'Does'; 230 | } 231 | 232 | // 三目运算符 233 | print (false ? 'Does not get printed' : 'Does'); 234 | 235 | $x = 0; 236 | if ($x === '0') { 237 | print 'Does not print'; 238 | } elseif($x == '1') { 239 | print 'Does not print'; 240 | } else { 241 | print 'Does print'; 242 | } 243 | 244 | 245 | 246 | // 下面的语法常用于模板中: 247 | ?> 248 | 249 | 250 | This is displayed if the test is truthy. 251 | 252 | This is displayed otherwise. 253 | 254 | 255 | 2, 'car' => 4]; 293 | 294 | // Foreach 循环可以遍历数组 295 | foreach ($wheels as $wheel_count) { 296 | echo $wheel_count; 297 | } // 输出 "24" 298 | 299 | echo "\n"; 300 | 301 | // 也可以同时遍历键和值 302 | foreach ($wheels as $vehicle => $wheel_count) { 303 | echo "A $vehicle has $wheel_count wheels"; 304 | } 305 | 306 | echo "\n"; 307 | 308 | $i = 0; 309 | while ($i < 5) { 310 | if ($i === 3) { 311 | break; // 退出循环 312 | } 313 | echo $i++; 314 | } // 输出 "012" 315 | 316 | for ($i = 0; $i < 5; $i++) { 317 | if ($i === 3) { 318 | continue; // 跳过此次遍历 319 | } 320 | echo $i; 321 | } // 输出 "0124" 322 | 323 | 324 | /******************************** 325 | * 函数 326 | */ 327 | 328 | // 通过"function"定义函数: 329 | function my_function () { 330 | return 'Hello'; 331 | } 332 | 333 | echo my_function(); // => "Hello" 334 | 335 | // 函数名需要以字母或者下划线开头, 336 | // 后面可以跟着任意的字母、下划线、数字. 337 | 338 | function add ($x, $y = 1) { // $y 是可选参数,默认值为 1 339 | $result = $x + $y; 340 | return $result; 341 | } 342 | 343 | echo add(4); // => 5 344 | echo add(4, 2); // => 6 345 | 346 | // $result 在函数外部不可访问 347 | // print $result; // 抛出警告 348 | 349 | // 从 PHP 5.3 起我们可以定义匿名函数 350 | $inc = function ($x) { 351 | return $x + 1; 352 | }; 353 | 354 | echo $inc(2); // => 3 355 | 356 | function foo ($x, $y, $z) { 357 | echo "$x - $y - $z"; 358 | } 359 | 360 | // 函数也可以返回一个函数 361 | function bar ($x, $y) { 362 | // 用 'use' 将外部的参数引入到里面 363 | return function ($z) use ($x, $y) { 364 | foo($x, $y, $z); 365 | }; 366 | } 367 | 368 | $bar = bar('A', 'B'); 369 | $bar('C'); // 输出 "A - B - C" 370 | 371 | // 你也可以通过字符串调用函数 372 | $function_name = 'add'; 373 | echo $function_name(1, 2); // => 3 374 | // 在通过程序来决定调用哪个函数时很有用 375 | // 或者,使用 call_user_func(callable $callback [, $parameter [, ... ]]); 376 | 377 | /******************************** 378 | * 导入 379 | */ 380 | 381 | instanceProp = $instanceProp; 431 | } 432 | 433 | // 方法就是类中定义的函数 434 | public function myMethod() 435 | { 436 | print 'MyClass'; 437 | } 438 | 439 | final function youCannotOverrideMe() 440 | { 441 | } 442 | 443 | public static function myStaticMethod() 444 | { 445 | print 'I am static'; 446 | } 447 | } 448 | 449 | echo MyClass::MY_CONST; // 输出 'value'; 450 | echo MyClass::$staticVar; // 输出 'static'; 451 | MyClass::myStaticMethod(); // 输出 'I am static'; 452 | 453 | // 通过new来新建实例 454 | $my_class = new MyClass('An instance property'); 455 | // 如果不传递参数,那么括号可以省略 456 | 457 | // 用 -> 来访问成员 458 | echo $my_class->property; // => "public" 459 | echo $my_class->instanceProp; // => "An instance property" 460 | $my_class->myMethod(); // => "MyClass" 461 | 462 | 463 | // 使用extends来生成子类 464 | class MyOtherClass extends MyClass 465 | { 466 | function printProtectedProperty() 467 | { 468 | echo $this->prot; 469 | } 470 | 471 | // 方法覆盖 472 | function myMethod() 473 | { 474 | parent::myMethod(); 475 | print ' > MyOtherClass'; 476 | } 477 | } 478 | 479 | $my_other_class = new MyOtherClass('Instance prop'); 480 | $my_other_class->printProtectedProperty(); // => 输出 "protected" 481 | $my_other_class->myMethod(); // 输出 "MyClass > MyOtherClass" 482 | 483 | final class YouCannotExtendMe 484 | { 485 | } 486 | 487 | // 你可以使用“魔法方法”来生成getter和setter方法 488 | class MyMapClass 489 | { 490 | private $property; 491 | 492 | public function __get($key) 493 | { 494 | return $this->$key; 495 | } 496 | 497 | public function __set($key, $value) 498 | { 499 | $this->$key = $value; 500 | } 501 | } 502 | 503 | $x = new MyMapClass(); 504 | echo $x->property; // 会使用 __get() 方法 505 | $x->property = 'Something'; // 会使用 __set() 方法 506 | 507 | // 类可以是被定义成抽象类 (使用 abstract 关键字) 或者 508 | // 去实现接口 (使用 implements 关键字). 509 | // 接口需要通过interface关键字来定义 510 | 511 | interface InterfaceOne 512 | { 513 | public function doSomething(); 514 | } 515 | 516 | interface InterfaceTwo 517 | { 518 | public function doSomethingElse(); 519 | } 520 | 521 | // 接口可以被扩展 522 | interface InterfaceThree extends InterfaceTwo 523 | { 524 | public function doAnotherContract(); 525 | } 526 | 527 | abstract class MyAbstractClass implements InterfaceOne 528 | { 529 | public $x = 'doSomething'; 530 | } 531 | 532 | class MyConcreteClass extends MyAbstractClass implements InterfaceTwo 533 | { 534 | public function doSomething() 535 | { 536 | echo $x; 537 | } 538 | 539 | public function doSomethingElse() 540 | { 541 | echo 'doSomethingElse'; 542 | } 543 | } 544 | 545 | 546 | // 一个类可以实现多个接口 547 | class SomeOtherClass implements InterfaceOne, InterfaceTwo 548 | { 549 | public function doSomething() 550 | { 551 | echo 'doSomething'; 552 | } 553 | 554 | public function doSomethingElse() 555 | { 556 | echo 'doSomethingElse'; 557 | } 558 | } 559 | 560 | 561 | /******************************** 562 | * 特征 563 | */ 564 | 565 | // 特征 从 PHP 5.4.0 开始包括,需要用 "trait" 这个关键字声明 566 | 567 | trait MyTrait 568 | { 569 | public function myTraitMethod() 570 | { 571 | print 'I have MyTrait'; 572 | } 573 | } 574 | 575 | class MyTraitfulClass 576 | { 577 | use MyTrait; 578 | } 579 | 580 | $cls = new MyTraitfulClass(); 581 | $cls->myTraitMethod(); // 输出 "I have MyTrait" 582 | 583 | 584 | /******************************** 585 | * 命名空间 586 | */ 587 | 588 | // 这部分是独立于这个文件的 589 | // 因为命名空间必须在一个文件的开始处。 590 | 591 | Fixnum 30 | 31 | 3.to_s #=> "3" 32 | 33 | 34 | # 一些基本的算术符号 35 | 1 + 1 #=> 2 36 | 8 - 1 #=> 7 37 | 10 * 2 #=> 20 38 | 35 / 5 #=> 7 39 | 2**5 #=> 32 40 | 5 % 3 #=> 2 41 | 42 | # 位运算符 43 | 3 & 5 #=> 1 44 | 3 | 5 #=> 7 45 | 3 ^ 5 #=> 6 46 | 47 | # 算术符号只是语法糖而已 48 | # 实际上是调用对象的方法 49 | 1.+(3) #=> 4 50 | 10.* 5 #=> 50 51 | 52 | # 特殊的值也是对象 53 | nil # 相当于其它语言中的 null 54 | true # 真 55 | false # 假 56 | 57 | nil.class #=> NilClass 58 | true.class #=> TrueClass 59 | false.class #=> FalseClass 60 | 61 | # 相等运算符 62 | 1 == 1 #=> true 63 | 2 == 1 #=> false 64 | 65 | # 不相等运算符 66 | 1 != 1 #=> false 67 | 2 != 1 #=> true 68 | 69 | # 除了false自己,nil是唯一的另一个值为false的对象 70 | 71 | !nil #=> true 72 | !false #=> true 73 | !0 #=> false 74 | 75 | # 更多比较 76 | 1 < 10 #=> true 77 | 1 > 10 #=> false 78 | 2 <= 2 #=> true 79 | 2 >= 2 #=> true 80 | 81 | 82 | # 组合比较运算符 83 | 1 <=> 10 #=> -1 84 | 10 <=> 1 #=> 1 85 | 1 <=> 1 #=> 0 86 | 87 | # 逻辑运算符 88 | true && false #=> false 89 | true || false #=> true 90 | !true #=> false 91 | 92 | # 也有优先级更低的逻辑运算符 93 | # 它们用于控制流结构中,用来串接语句,直到返回true或false。 94 | 95 | # `do_something_else` 只当 `do_something` 返回true时才会被调用 96 | do_something() and do_something_else() 97 | # `log_error` 只当 `do_something` 返回false时才会被调用 98 | do_something() or log_error() 99 | 100 | 101 | # 字符串是对象 102 | 103 | 'I am a string'.class #=> String 104 | "I am a string too".class #=> String 105 | 106 | placeholder = "use string interpolation" 107 | "I can #{placeholder} when using double quoted strings" 108 | #=> "I can use string interpolation when using double quoted strings" 109 | 110 | # 尽可能优先使用单引号的字符串 111 | # 双引号的字符串会进行一些额外的内部处理 112 | 113 | # 合并字符串,但不能和数字合并 114 | 'hello ' + 'world' #=> "hello world" 115 | 'hello ' + 3 #=> TypeError: can't convert Fixnum into String 116 | 'hello ' + 3.to_s #=> "hello 3" 117 | 118 | # 合并字符串及其运算符 119 | 'hello ' * 3 #=> "hello hello hello " 120 | 121 | # 字符串追加 122 | 'hello' << ' world' #=> "hello world" 123 | 124 | # 打印输出,并在末尾加换行符 125 | puts "I'm printing!" 126 | #=> I'm printing! 127 | #=> nil 128 | 129 | # 打印输出,不加换行符 130 | print "I'm printing!" 131 | #=> I'm printing! => nil 132 | 133 | # 变量 134 | x = 25 #=> 25 135 | x #=> 25 136 | 137 | # 注意赋值语句返回了赋的值 138 | # 这意味着你可以用多重赋值语句 139 | 140 | x = y = 10 #=> 10 141 | x #=> 10 142 | y #=> 10 143 | 144 | # 按照惯例,使用类似snake_case风格的变量名 145 | snake_case = true 146 | 147 | # 使用有意义的变量名 148 | path_to_project_root = '/good/name/' 149 | path = '/bad/name/' 150 | 151 | # 符号(Symbols,也是对象) 152 | # 符号是不可变的,内部用整数值表示的可重用的常数 153 | # 通常用它代替字符串来有效地表示有意义的值 154 | 155 | :pending.class #=> Symbol 156 | 157 | status = :pending 158 | 159 | status == :pending #=> true 160 | 161 | status == 'pending' #=> false 162 | 163 | status == :approved #=> false 164 | 165 | # 数组 166 | 167 | # 这是一个数组 168 | array = [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5] 169 | 170 | # 数组可以包含不同类型的元素 171 | 172 | [1, "hello", false] #=> [1, "hello", false] 173 | 174 | # 数组可以被索引 175 | # 从前面开始 176 | array[0] #=> 1 177 | array[12] #=> nil 178 | 179 | # 像运算符一样,[var] 形式的访问 180 | # 也只是语法糖 181 | # 实际上是调用对象的 [] 方法 182 | array.[] 0 #=> 1 183 | array.[] 12 #=> nil 184 | 185 | # 从尾部开始 186 | array[-1] #=> 5 187 | array.last #=> 5 188 | 189 | # 同时指定开始的位置和长度 190 | array[2, 3] #=> [3, 4, 5] 191 | 192 | # 将数组逆序 193 | a=[1,2,3] 194 | a.reverse! #=> [3,2,1] 195 | 196 | # 或者指定一个区间 197 | array[1..3] #=> [2, 3, 4] 198 | 199 | # 像这样往数组增加一个元素 200 | array << 6 #=> [1, 2, 3, 4, 5, 6] 201 | # 或者像这样 202 | array.push(6) #=> [1, 2, 3, 4, 5, 6] 203 | 204 | # 检查元素是否包含在数组中 205 | array.include?(1) #=> true 206 | 207 | # 哈希表是 Ruby 的主要键/值对表示法 208 | # 哈希表由大括号表示 209 | hash = {'color' => 'green', 'number' => 5} 210 | 211 | hash.keys #=> ['color', 'number'] 212 | 213 | # 哈希表可以通过键快速地查询 214 | hash['color'] #=> 'green' 215 | hash['number'] #=> 5 216 | 217 | # 查询一个不存在的键将会返回nil 218 | hash['nothing here'] #=> nil 219 | 220 | # 从Ruby 1.9开始,用符号作为键的时候有特别的记号表示: 221 | 222 | new_hash = { defcon: 3, action: true } 223 | 224 | new_hash.keys #=> [:defcon, :action] 225 | 226 | # 小贴士:数组和哈希表都是可枚举的 227 | # 它们共享一些有用的方法,比如each,map,count等等 228 | 229 | # 控制流 230 | 231 | if true 232 | "if statement" 233 | elsif false 234 | "else if, optional" 235 | else 236 | "else, also optional" 237 | end 238 | 239 | for counter in 1..5 240 | puts "iteration #{counter}" 241 | end 242 | #=> iteration 1 243 | #=> iteration 2 244 | #=> iteration 3 245 | #=> iteration 4 246 | #=> iteration 5 247 | 248 | 249 | # 但是,没有人用for循环。 250 | # 你应该使用"each"方法,然后再传给它一个块。 251 | # 所谓块就是可以传给像"each"这样的方法的代码段。 252 | # 它类似于其它语言中的lambdas, 匿名函数或闭包。 253 | # 254 | # 区间上的"each"方法会对区间中的每个元素运行一次块代码。 255 | # 我们将counter作为一个参数传给了块。 256 | # 调用带有块的"each"方法看起来如下: 257 | 258 | (1..5).each do |counter| 259 | puts "iteration #{counter}" 260 | end 261 | #=> iteration 1 262 | #=> iteration 2 263 | #=> iteration 3 264 | #=> iteration 4 265 | #=> iteration 5 266 | 267 | # 你也可以将块包含在一个大括号中: 268 | (1..5).each { |counter| puts "iteration #{counter}" } 269 | 270 | # 数据结构中的内容也可以使用each来遍历。 271 | array.each do |element| 272 | puts "#{element} is part of the array" 273 | end 274 | hash.each do |key, value| 275 | puts "#{key} is #{value}" 276 | end 277 | 278 | # 如果你还需要索引值,可以使用"each_with_index",并且定义 279 | # 一个索引变量 280 | array.each_with_index do |element, index| 281 | puts "#{element} is number #{index} in the array" 282 | end 283 | 284 | counter = 1 285 | while counter <= 5 do 286 | puts "iteration #{counter}" 287 | counter += 1 288 | end 289 | #=> iteration 1 290 | #=> iteration 2 291 | #=> iteration 3 292 | #=> iteration 4 293 | #=> iteration 5 294 | 295 | # Ruby 中还有很多有用的循环遍历函数, 296 | # 如"map","reduce","inject"等等。 297 | # 以map为例,它会遍历数组,并根据你在 298 | # 块中定义的逻辑对它进行处理,然后返回 299 | # 一个全新的数组。 300 | array = [1,2,3,4,5] 301 | doubled = array.map do |element| 302 | element * 2 303 | end 304 | puts doubled 305 | #=> [2,4,6,8,10] 306 | puts array 307 | #=> [1,2,3,4,5] 308 | 309 | grade = 'B' 310 | 311 | case grade 312 | when 'A' 313 | puts "Way to go kiddo" 314 | when 'B' 315 | puts "Better luck next time" 316 | when 'C' 317 | puts "You can do better" 318 | when 'D' 319 | puts "Scraping through" 320 | when 'F' 321 | puts "You failed!" 322 | else 323 | puts "Alternative grading system, eh?" 324 | end 325 | #=> "Better luck next time" 326 | 327 | # case也可以用区间 328 | grade = 82 329 | case grade 330 | when 90..100 331 | puts 'Hooray!' 332 | when 80...90 333 | puts 'OK job' 334 | else 335 | puts 'You failed!' 336 | end 337 | #=> "OK job" 338 | 339 | # 异常处理: 340 | begin 341 | # 这里的代码可能会抛出异常 342 | raise NoMemoryError, 'You ran out of memory.' 343 | rescue NoMemoryError => exception_variable 344 | puts 'NoMemoryError was raised', exception_variable 345 | rescue RuntimeError => other_exception_variable 346 | puts 'RuntimeError was raised now' 347 | else 348 | puts 'This runs if no exceptions were thrown at all' 349 | ensure 350 | puts 'This code always runs no matter what' 351 | end 352 | 353 | # 函数 354 | 355 | def double(x) 356 | x * 2 357 | end 358 | 359 | # 函数 (以及所有的块) 隐式地返回最后语句的值 360 | double(2) #=> 4 361 | 362 | # 当不存在歧义的时候括号是可有可无的 363 | double 3 #=> 6 364 | 365 | double double 3 #=> 12 366 | 367 | def sum(x,y) 368 | x + y 369 | end 370 | 371 | # 方法的参数通过逗号分隔 372 | sum 3, 4 #=> 7 373 | 374 | sum sum(3,4), 5 #=> 12 375 | 376 | # yield 377 | # 所有的方法都有一个隐式的,可选的块参数 378 | # 可以用 'yield' 关键字调用 379 | 380 | def surround 381 | puts "{" 382 | yield 383 | puts "}" 384 | end 385 | 386 | surround { puts 'hello world' } 387 | 388 | # { 389 | # hello world 390 | # } 391 | 392 | # 可以向函数传递一个块 393 | # "&"标记传递的块是一个引用 394 | def guests(&block) 395 | block.call 'some_argument' 396 | end 397 | 398 | # 可以传递多个参数,这些参数会转成一个数组, 399 | # 这也是使用星号符 ("*") 的原因: 400 | def guests(*array) 401 | array.each { |guest| puts guest } 402 | end 403 | 404 | # 如果函数返回一个数组,在赋值时可以进行拆分: 405 | def foods 406 | ['pancake', 'sandwich', 'quesadilla'] 407 | end 408 | breakfast, lunch, dinner = foods 409 | breakfast #=> 'pancake' 410 | dinner #=> 'quesadilla' 411 | 412 | # 按照惯例,所有返回布尔值的方法都以?结尾 413 | 5.even? # false 414 | 5.odd? # true 415 | 416 | # 如果方法名末尾有!,表示会做一些破坏性的操作,比如修改调用者自身。 417 | # 很多方法都会有一个!的版本来进行修改,和一个非!的版本 418 | # 只用来返回更新了的结果 419 | company_name = "Dunder Mifflin" 420 | company_name.upcase #=> "DUNDER MIFFLIN" 421 | company_name #=> "Dunder Mifflin" 422 | company_name.upcase! # we're mutating company_name this time! 423 | company_name #=> "DUNDER MIFFLIN" 424 | 425 | 426 | # 用class关键字定义一个类 427 | class Human 428 | 429 | # 一个类变量,它被这个类的所有实例变量共享 430 | @@species = "H. sapiens" 431 | 432 | # 基本构造函数 433 | def initialize(name, age = 0) 434 | # 将参数值赋给实例变量"name" 435 | @name = name 436 | # 如果没有给出age,那么会采用参数列表中的默认值 437 | @age = age 438 | end 439 | 440 | # 基本的setter方法 441 | def name=(name) 442 | @name = name 443 | end 444 | 445 | # 基本地getter方法 446 | def name 447 | @name 448 | end 449 | 450 | # 以上的功能也可以用下面的attr_accessor来封装 451 | attr_accessor :name 452 | 453 | # Getter/setter方法也可以像这样单独创建 454 | attr_reader :name 455 | attr_writer :name 456 | 457 | # 类方法通过使用self与实例方法区别开来。 458 | # 它只能通过类来调用,不能通过实例调用。 459 | def self.say(msg) 460 | puts "#{msg}" 461 | end 462 | 463 | def species 464 | @@species 465 | end 466 | end 467 | 468 | 469 | # 初始化一个类 470 | jim = Human.new("Jim Halpert") 471 | 472 | dwight = Human.new("Dwight K. Schrute") 473 | 474 | # 让我们来调用一些方法 475 | jim.species #=> "H. sapiens" 476 | jim.name #=> "Jim Halpert" 477 | jim.name = "Jim Halpert II" #=> "Jim Halpert II" 478 | jim.name #=> "Jim Halpert II" 479 | dwight.species #=> "H. sapiens" 480 | dwight.name #=> "Dwight K. Schrute" 481 | 482 | # 调用类方法 483 | Human.say('Hi') #=> "Hi" 484 | 485 | # 变量的作用域由它们的名字格式定义 486 | # 以$开头的变量具有全局域 487 | $var = "I'm a global var" 488 | defined? $var #=> "global-variable" 489 | 490 | # 以@开头的变量具有实例作用域 491 | @var = "I'm an instance var" 492 | defined? @var #=> "instance-variable" 493 | 494 | # 以@@开头的变量具有类作用域 495 | @@var = "I'm a class var" 496 | defined? @@var #=> "class variable" 497 | 498 | # 以大写字母开头的变量是常数 499 | Var = "I'm a constant" 500 | defined? Var #=> "constant" 501 | 502 | # 类也是对象。因此类也可以有实例变量。 503 | # 类变量在类以及其继承者之间共享。 504 | 505 | # 基类 506 | class Human 507 | @@foo = 0 508 | 509 | def self.foo 510 | @@foo 511 | end 512 | 513 | def self.foo=(value) 514 | @@foo = value 515 | end 516 | end 517 | 518 | # 派生类 519 | class Worker < Human 520 | end 521 | 522 | Human.foo # 0 523 | Worker.foo # 0 524 | 525 | Human.foo = 2 # 2 526 | Worker.foo # 2 527 | 528 | # 类实例变量不能在继承类间共享。 529 | 530 | class Human 531 | @bar = 0 532 | 533 | def self.bar 534 | @bar 535 | end 536 | 537 | def self.bar=(value) 538 | @bar = value 539 | end 540 | end 541 | 542 | class Doctor < Human 543 | end 544 | 545 | Human.bar # 0 546 | Doctor.bar # nil 547 | 548 | module ModuleExample 549 | def foo 550 | 'foo' 551 | end 552 | end 553 | 554 | # '包含'模块后,模块的方法会绑定为类的实例方法 555 | # '扩展'模块后,模块的方法会绑定为类方法 556 | 557 | class Person 558 | include ModuleExample 559 | end 560 | 561 | class Book 562 | extend ModuleExample 563 | end 564 | 565 | Person.foo # => NoMethodError: undefined method `foo' for Person:Class 566 | Person.new.foo # => 'foo' 567 | Book.foo # => 'foo' 568 | Book.new.foo # => NoMethodError: undefined method `foo' 569 | 570 | # 当包含或扩展一个模块时,相应的回调代码会被执行。 571 | 572 | module ConcernExample 573 | def self.included(base) 574 | base.extend(ClassMethods) 575 | base.send(:include, InstanceMethods) 576 | end 577 | 578 | module ClassMethods 579 | def bar 580 | 'bar' 581 | end 582 | end 583 | 584 | module InstanceMethods 585 | def qux 586 | 'qux' 587 | end 588 | end 589 | end 590 | 591 | class Something 592 | include ConcernExample 593 | end 594 | 595 | Something.bar # => 'bar' 596 | Something.qux # => NoMethodError: undefined method `qux' 597 | Something.new.bar # => NoMethodError: undefined method `bar' 598 | Something.new.qux # => 'qux' 599 | ``` 600 | 601 | 602 | ## 其它资源 603 | 604 | - [Learn Ruby by Example with Challenges](http://www.learneroo.com/modules/61/nodes/338) - A variant of this reference with in-browser challenges. 605 | - [An Interactive Tutorial for Ruby](https://rubymonk.com/) - Learn Ruby through a series of interactive tutorials. 606 | - [Official Documentation](http://ruby-doc.org/core) 607 | - [Ruby from other languages](https://www.ruby-lang.org/en/documentation/ruby-from-other-languages/) 608 | - [Programming Ruby](http://www.amazon.com/Programming-Ruby-1-9-2-0-Programmers/dp/1937785491/) - An older [free edition](http://ruby-doc.com/docs/ProgrammingRuby/) is available online. 609 | - [Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide) - A community-driven Ruby coding style guide. 610 | - [Try Ruby](http://tryruby.org) - Learn the basic of Ruby programming language, interactive in the browser. 611 | -------------------------------------------------------------------------------- /web/sass-cn.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | language: sass 3 | filename: learnsass-cn.scss 4 | contributors: 5 | - ["Laura Kyle", "https://github.com/LauraNK"] 6 | - ["Sean Corrales", "https://github.com/droidenator"] 7 | - ["Kyle Mendes", "https://github.com/pink401k"] 8 | - ["Keith Miyake", "https://github.com/kaymmm"] 9 | translators: 10 | - ["Jiang Haiyun", "http://www.atjiang.com"] 11 | lang: zh-cn 12 | --- 13 | 14 | Sass是一种CSS扩展语言,它增加了诸如变量、嵌套、mixin等功能。 15 | Sass(以及其它预处理器,如[Less](http://lesscss.org/)等) 能帮助开发人员编写易维护和 DRY (Don't Repeat Yourself)的代码。 16 | 17 | Sass有两种不同的语法可选用。SCSS的语法和CSS的相同,但增加了Sass的额外功能。或者Sass(原来的语法),它使用缩进而非大括号和分号。 18 | 19 | 本教程使用SCSS编写。 20 | 21 | 如果你已熟悉CSS3,你可能相对能较快地掌握Sass。它并没有提供任何新的类型属性,而只是提供了一些工具使你能更高效的编写CSS,并且使维护更加容易。 22 | 23 | ```scss 24 | 25 | 26 | // 单行注释当Sass被编译成CSS后会被删除。 27 | 28 | /* 多行注释将保留. */ 29 | 30 | /* 变量 31 | ============================== */ 32 | 33 | 34 | 35 | /* 你可以将一个CSS值(如一个颜色值)保存到变量中。 36 | 使用'$'符号来创建一个变量。*/ 37 | 38 | $primary-color: #A3A4FF; 39 | $secondary-color: #51527F; 40 | $body-font: 'Roboto', sans-serif; 41 | 42 | /* 你可以在你的样式文件中使用变量。 43 | 现在假如你想修改颜色,你只需修改一次即可。*/ 44 | 45 | body { 46 | background-color: $primary-color; 47 | color: $secondary-color; 48 | font-family: $body-font; 49 | } 50 | 51 | /* 以上将编译成: */ 52 | body { 53 | background-color: #A3A4FF; 54 | color: #51527F; 55 | font-family: 'Roboto', sans-serif; 56 | } 57 | 58 | /* 相比于在你的样式文件中逐个进行修改,这种方式维护性更好。 */ 59 | 60 | 61 | 62 | /* 控制指令 63 | ============================== */ 64 | 65 | /* Sass允许你使用@if, @else, @for, @while, 和 @each 来控制 66 | 你的代码如何编译成CSS */ 67 | 68 | /* @if/@else块的行为和你可能预想的会完全相同 */ 69 | 70 | $debug: true !default; 71 | 72 | @mixin debugmode { 73 | @if $debug { 74 | @debug "Debug mode enabled"; 75 | 76 | display: inline-block; 77 | } 78 | @else { 79 | display: none; 80 | } 81 | } 82 | 83 | .info { 84 | @include debugmode; 85 | } 86 | 87 | /* 如果$debug设置为了true, .info 将会显示; 如果设置为false那么 88 | .info 将不显示。 89 | 90 | 注意: @debug将在命令行中输出调试信息。 91 | 在调试你的SCSS时它对于检查变量很有用。*/ 92 | 93 | .info { 94 | display: inline-block; 95 | } 96 | 97 | /* @for是控制循环,它能遍历区间值。 98 | 它对于设置一组元素的类型特别有用。 99 | 有两种形式,"through"和"to"。前者包括最末那个值, 100 | 而后者止于最末那个值。 101 | */ 102 | 103 | @for $c from 1 to 4 { 104 | div:nth-of-type(#{$c}) { 105 | left: ($c - 1) * 900 / 3; 106 | } 107 | } 108 | 109 | @for $c from 1 through 3 { 110 | .myclass-#{$c} { 111 | color: rgb($c * 255 / 3, $c * 255 / 3, $c * 255 / 3); 112 | } 113 | } 114 | 115 | /* 将编译成: */ 116 | 117 | div:nth-of-type(1) { 118 | left: 0; 119 | } 120 | 121 | div:nth-of-type(2) { 122 | left: 300; 123 | } 124 | 125 | div:nth-of-type(3) { 126 | left: 600; 127 | } 128 | 129 | .myclass-1 { 130 | color: #555555; 131 | } 132 | 133 | .myclass-2 { 134 | color: #aaaaaa; 135 | } 136 | 137 | .myclass-3 { 138 | color: white; 139 | // SASS automatically converts #FFFFFF to white 140 | } 141 | 142 | /* @while也非常直白: */ 143 | 144 | $columns: 4; 145 | $column-width: 80px; 146 | 147 | @while $columns > 0 { 148 | .col-#{$columns} { 149 | width: $column-width; 150 | left: $column-width * ($columns - 1); 151 | } 152 | 153 | $columns: $columns - 1; 154 | } 155 | 156 | /* 将输出以下CSS: */ 157 | 158 | .col-4 { 159 | width: 80px; 160 | left: 240px; 161 | } 162 | 163 | .col-3 { 164 | width: 80px; 165 | left: 160px; 166 | } 167 | 168 | .col-2 { 169 | width: 80px; 170 | left: 80px; 171 | } 172 | 173 | .col-1 { 174 | width: 80px; 175 | left: 0px; 176 | } 177 | 178 | /* @each函数类似@for, 除了它使用一个列表而不是序列值 179 | 注意: 你指定列表的方式和指定其它变量一样, 180 | 用空格作为分隔符。 */ 181 | 182 | $social-links: facebook twitter linkedin reddit; 183 | 184 | .social-links { 185 | @each $sm in $social-links { 186 | .icon-#{$sm} { 187 | background-image: url("images/#{$sm}.png"); 188 | } 189 | } 190 | } 191 | 192 | /* 将输出: */ 193 | 194 | .social-links .icon-facebook { 195 | background-image: url("images/facebook.png"); 196 | } 197 | 198 | .social-links .icon-twitter { 199 | background-image: url("images/twitter.png"); 200 | } 201 | 202 | .social-links .icon-linkedin { 203 | background-image: url("images/linkedin.png"); 204 | } 205 | 206 | .social-links .icon-reddit { 207 | background-image: url("images/reddit.png"); 208 | } 209 | 210 | 211 | /* Mixins 212 | ==============================*/ 213 | 214 | /* 如果你发现你要为多个元素编写相同的代码, 215 | 你可能想将那些代码保存到一个mixin中。 216 | 217 | 使用'@mixin'指令,再为你的mixin加上一个名称。*/ 218 | 219 | @mixin center { 220 | display: block; 221 | margin-left: auto; 222 | margin-right: auto; 223 | left: 0; 224 | right: 0; 225 | } 226 | 227 | /* 你可以通过'@include'及mixin名来调用mixin。 */ 228 | 229 | div { 230 | @include center; 231 | background-color: $primary-color; 232 | } 233 | 234 | /* 将编译成: */ 235 | div { 236 | display: block; 237 | margin-left: auto; 238 | margin-right: auto; 239 | left: 0; 240 | right: 0; 241 | background-color: #A3A4FF; 242 | } 243 | 244 | /* 你可以使用mixin来创建一个快捷属性。*/ 245 | 246 | @mixin size($width, $height) { 247 | width: $width; 248 | height: $height; 249 | } 250 | 251 | /* 你可以通过传入width和height参数来调用它。*/ 252 | 253 | .rectangle { 254 | @include size(100px, 60px); 255 | } 256 | 257 | .square { 258 | @include size(40px, 40px); 259 | } 260 | 261 | /* 编译成: */ 262 | .rectangle { 263 | width: 100px; 264 | height: 60px; 265 | } 266 | 267 | .square { 268 | width: 40px; 269 | height: 40px; 270 | } 271 | 272 | 273 | 274 | /* 函数 275 | ============================== */ 276 | 277 | 278 | 279 | /* Sass提供的函数可以用来完成各种各样的任务。 280 | 考虑以下情况 */ 281 | 282 | /* 函数可以通过其名称及传入其所需的参数来调用 */ 283 | body { 284 | width: round(10.25px); 285 | } 286 | 287 | .footer { 288 | background-color: fade_out(#000000, 0.25); 289 | } 290 | 291 | /* 编译成: */ 292 | 293 | body { 294 | width: 10px; 295 | } 296 | 297 | .footer { 298 | background-color: rgba(0, 0, 0, 0.75); 299 | } 300 | 301 | /* 你也可以定义你自己的函数。函数非常类似于mixin。 302 | 当你在函数和mixin之间抉择时,记住mixin最适合于创建CSS而函数更适合于 303 | 处理那些可能在你的Sass代码中使用的逻辑。'数学运算符'部分的例子 304 | 是转成可重用函数的最理想选择。 */ 305 | 306 | /* 该函数将接收一个目标尺寸大小和父结点尺寸大小,然后计算并 307 | 返回百分数 */ 308 | 309 | @function calculate-percentage($target-size, $parent-size) { 310 | @return $target-size / $parent-size * 100%; 311 | } 312 | 313 | $main-content: calculate-percentage(600px, 960px); 314 | 315 | .main-content { 316 | width: $main-content; 317 | } 318 | 319 | .sidebar { 320 | width: calculate-percentage(300px, 960px); 321 | } 322 | 323 | /* 编译成: */ 324 | 325 | .main-content { 326 | width: 62.5%; 327 | } 328 | 329 | .sidebar { 330 | width: 31.25%; 331 | } 332 | 333 | 334 | 335 | /* 扩展 (继承) 336 | ============================== */ 337 | 338 | 339 | 340 | /* 扩展是在选择子间共享属性的一种方法。 */ 341 | 342 | .display { 343 | @include size(5em, 5em); 344 | border: 5px solid $secondary-color; 345 | } 346 | 347 | .display-success { 348 | @extend .display; 349 | border-color: #22df56; 350 | } 351 | 352 | /* 编译成: */ 353 | .display, .display-success { 354 | width: 5em; 355 | height: 5em; 356 | border: 5px solid #51527F; 357 | } 358 | 359 | .display-success { 360 | border-color: #22df56; 361 | } 362 | 363 | /* 扩展一条CSS语句优于创建一个mixin, 364 | 这是由Sass组合所有共享相同基样式的类的方式决定的。 365 | 如果使用mixin完成,width, height, 和border将会在 366 | 调用了该mixin的每条语句中重复。虽然它不至于会影响你的工作流, 367 | 但它会在由Sass编译器生成的的文件中添加不必要的代码。*/ 368 | 369 | 370 | /* 嵌套 371 | ============================== */ 372 | 373 | 374 | 375 | /* Sass允许在选择子中嵌套选择子 */ 376 | 377 | ul { 378 | list-style-type: none; 379 | margin-top: 2em; 380 | 381 | li { 382 | background-color: #FF0000; 383 | } 384 | } 385 | 386 | /* '&'将被父选择子替换。*/ 387 | /* 你也可以嵌套伪类。 */ 388 | /* 注意过度嵌套将导致你的代码难以维护。 389 | 最佳实践推荐在嵌套时不超过3层。 390 | 例如: */ 391 | 392 | ul { 393 | list-style-type: none; 394 | margin-top: 2em; 395 | 396 | li { 397 | background-color: red; 398 | 399 | &:hover { 400 | background-color: blue; 401 | } 402 | 403 | a { 404 | color: white; 405 | } 406 | } 407 | } 408 | 409 | /* 编译成: */ 410 | 411 | ul { 412 | list-style-type: none; 413 | margin-top: 2em; 414 | } 415 | 416 | ul li { 417 | background-color: red; 418 | } 419 | 420 | ul li:hover { 421 | background-color: blue; 422 | } 423 | 424 | ul li a { 425 | color: white; 426 | } 427 | 428 | 429 | 430 | /* 片段与导入 431 | ============================== */ 432 | 433 | 434 | 435 | /* Sass允许你创建片段文件。它有助于你的Sass代码保持模块化。 436 | 片段文件应该以 '_' 开头,例如 _reset.css。 437 | 片段不会输出到CSS中。*/ 438 | 439 | /* 考虑以下的CSS,我们会将它们放入一个叫作_reset.css的文件中 */ 440 | 441 | html, 442 | body, 443 | ul, 444 | ol { 445 | margin: 0; 446 | padding: 0; 447 | } 448 | 449 | /* Sass提供的@import能用来将片段导入到文件中。 450 | 它与传统的CSS @import语句不同,不需要通过 451 | 另外的HTTP请求来获取导入的文件。 452 | Sass提取导入文件并将它与编译后的代码结合起来。 */ 453 | 454 | @import 'reset'; 455 | 456 | body { 457 | font-size: 16px; 458 | font-family: Helvetica, Arial, Sans-serif; 459 | } 460 | 461 | /* 编译成: */ 462 | 463 | html, body, ul, ol { 464 | margin: 0; 465 | padding: 0; 466 | } 467 | 468 | body { 469 | font-size: 16px; 470 | font-family: Helvetica, Arial, Sans-serif; 471 | } 472 | 473 | 474 | 475 | /* 占位符选择子 476 | ============================== */ 477 | 478 | 479 | 480 | /* 占位符在创建用于扩展的CSS语句时非常有用。 481 | 如果你想创建一条只通过@extend使用的CSS语句,你可以利用占位符来实现。 482 | 占位符以'%'而非'.'或'#'开头。占位符不会出现在编译后的CSS中 */ 483 | 484 | %content-window { 485 | font-size: 14px; 486 | padding: 10px; 487 | color: #000; 488 | border-radius: 4px; 489 | } 490 | 491 | .message-window { 492 | @extend %content-window; 493 | background-color: #0000ff; 494 | } 495 | 496 | /* 编译成: */ 497 | 498 | .message-window { 499 | font-size: 14px; 500 | padding: 10px; 501 | color: #000; 502 | border-radius: 4px; 503 | } 504 | 505 | .message-window { 506 | background-color: #0000ff; 507 | } 508 | 509 | 510 | 511 | /* 数学运算 512 | ============================== */ 513 | 514 | 515 | 516 | /* Sass提供以下的运算符: +, -, *, /, 和 %。它们 517 | 相比于使用你事先手工计算好了的数值,它们 518 | 对于直接在你的Sass文件中计算数值很有用。 519 | 以下是设置一个简单的两列设计的例子。*/ 520 | 521 | $content-area: 960px; 522 | $main-content: 600px; 523 | $sidebar-content: 300px; 524 | 525 | $main-size: $main-content / $content-area * 100%; 526 | $sidebar-size: $sidebar-content / $content-area * 100%; 527 | $gutter: 100% - ($main-size + $sidebar-size); 528 | 529 | body { 530 | width: 100%; 531 | } 532 | 533 | .main-content { 534 | width: $main-size; 535 | } 536 | 537 | .sidebar { 538 | width: $sidebar-size; 539 | } 540 | 541 | .gutter { 542 | width: $gutter; 543 | } 544 | 545 | /* 编译成: */ 546 | 547 | body { 548 | width: 100%; 549 | } 550 | 551 | .main-content { 552 | width: 62.5%; 553 | } 554 | 555 | .sidebar { 556 | width: 31.25%; 557 | } 558 | 559 | .gutter { 560 | width: 6.25%; 561 | } 562 | 563 | ``` 564 | 565 | ## SASS还是Sass? 566 | 该语言的名字,“Sass”,是一个词,不是一个缩写。 567 | 你有没想过Sass是否是一个缩写词?你可能没有,但我反正会告诉你。 568 | 该语言的名字是一个单词,不是一个缩写词。 569 | 由于人们老是将它写成"SASS",语言的作者开玩笑地称它为"Syntactically Awesome StyleSheets"。 570 | 571 | 572 | ## 实践Sass 573 | 如果你想在你的浏览器中尝试Sass,参阅[SassMeister](http://sassmeister.com/)。 574 | 你可以选用任一种语法,只需进到设置页然后选择Sass或SCSS。 575 | 576 | 577 | ## 兼容性 578 | Sass可以用于任何项目中,只要你有程序能将它编译成CSS即可。你还需要验证你所使用的CSS是否与你的目标浏览器兼容。 579 | 580 | [QuirksMode CSS](http://www.quirksmode.org/css/)和[CanIUse](http://caniuse.com)对于检查兼容性来说都是不错的资源。 581 | 582 | 583 | ## 延伸阅读资料 584 | * [Official Documentation](http://sass-lang.com/documentation/file.SASS_REFERENCE.html) 585 | * [The Sass Way](http://thesassway.com/) 上提供了教程(初学者-高级)和文章。 586 | -------------------------------------------------------------------------------- /web/xml-cn.html.markdown: -------------------------------------------------------------------------------- 1 | --- 2 | language: xml 3 | contributors: 4 | - ["João Farias", "https://github.com/JoaoGFarias"] 5 | translators: 6 | - ["Zach Zhang", "https://github.com/checkcheckzz"] 7 | filename: learnxml-cn.xml 8 | lang: zh-cn 9 | --- 10 | 11 | XML是一种标记语言,被设计用来存储数据和传输数据。 12 | 13 | 不像HTML, XML不指定怎样显示或格式化数据,只是携带它。 14 | 15 | 16 | * XML 语法 17 | 18 | ```xml 19 | 20 | 21 | 22 | 23 | 24 | Everyday Italian 25 | Giada De Laurentiis 26 | 2005 27 | 30.00 28 | 29 | 30 | Harry Potter 31 | J K. Rowling 32 | 2005 33 | 29.99 34 | 35 | 36 | Learning XML 37 | Erik T. Ray 38 | 2003 39 | 39.95 40 | 41 | 42 | 43 | 50 | 51 | 52 | 53 | 60 | 61 | 62 | 63 | computer.gif 64 | 65 | 66 | ``` 67 | 68 | * 良好格式的文件 x 验证 69 | 70 | 一个XML文件是良好格式的如果它是语法正确的。 71 | 但是, 使用文件定义,比如DTD和XML概要,在文件中插入更多的限制是可能的。 72 | 73 | 一个遵守一个文件定义的XML文件被叫做有效的,对于那个文件来说。 74 | 75 | 有了这个工具,你能够在应用逻辑之外检查XML数据。 76 | 77 | ```xml 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | Everyday Italian 86 | 30.00 87 | 88 | 89 | 90 | 91 | 92 | 95 | 96 | 97 | 98 | 99 | ]> 100 | 101 | 102 | 107 | 108 | 109 | 110 | 111 | 112 | 115 | 116 | 117 | 118 | 119 | ]> 120 | 121 | 122 | 123 | Everyday Italian 124 | 30.00 125 | 126 | 127 | ``` --------------------------------------------------------------------------------