├── README.md
├── learnperl-cn.pl
├── learnbash-cn.sh
├── learncss-cn.css
├── learnswift-cn.swift
├── learnruby-cn.rb
├── learngo-cn.go
├── learnpython-cn.py
├── learnlua-cn.lua
├── learnr-cn.r
├── learnphp-cn.php
├── learnpython3-cn.py
├── learnc-cn.c
└── learncsharp-cn.cs
/README.md:
--------------------------------------------------------------------------------
1 | # Learn X in Y minutes
2 | 在线编程语言速学网,C++、CSS、java、json、PHP、python、swift等各种语言的快速学习教程。
3 | - [C](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learnc-cn.c)
4 | - [C#](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learncsharp-cn.cs)
5 | - [Go](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learngo-cn.go)
6 | - [Lua](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learnlua-cn.lua)
7 | - [Perl](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learnperl-cn.pl)
8 | - [PHP](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learnphp-cn.php)
9 | - [Python](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learnpython-cn.py)
10 | - [Python3](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learnpython3-cn.py)
11 | - [R](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learnr-cn.r)
12 | - [Ruby](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learnruby-cn.rb)
13 | - [Swift](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learnswift-cn.swift)
14 | - [CSS](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learncss-cn.css)
15 | - [Bash](https://github.com/Y-Dian/LearnXinYminutes/blob/master/learnbash-cn.sh)
16 |
--------------------------------------------------------------------------------
/learnperl-cn.pl:
--------------------------------------------------------------------------------
1 | # 单行注释以#号开头
2 |
3 |
4 | #### Perl的变量类型
5 |
6 | # 变量以$号开头。
7 | # 合法变量名以英文字母或者下划线起始,
8 | # 后接任意数目的字母、数字或下划线。
9 |
10 | ### Perl有三种主要的变量类型:标量、数组和哈希。
11 |
12 | ## 标量
13 | # 标量类型代表单个值:
14 | my $animal = "camel";
15 | my $answer = 42;
16 |
17 | # 标量类型值可以是字符串、整型或浮点类型,Perl会根据需要自动进行类型转换。
18 |
19 | ## 数组
20 | # 数组类型代表一列值:
21 | my @animals = ("camel", "llama", "owl");
22 | my @numbers = (23, 42, 69);
23 | my @mixed = ("camel", 42, 1.23);
24 |
25 |
26 |
27 | ## 哈希
28 | # 哈希类型代表一个键/值对的集合:
29 |
30 | my %fruit_color = ("apple", "red", "banana", "yellow");
31 |
32 | # 可以使用空格和“=>”操作符更清晰的定义哈希:
33 |
34 | my %fruit_color = (
35 | apple => "red",
36 | banana => "yellow",
37 | );
38 | # perldata中有标量、数组和哈希更详细的介绍。 (perldoc perldata).
39 |
40 | # 可以用引用构建更复杂的数据类型,比如嵌套的列表和哈希。
41 |
42 | #### 逻辑和循环结构
43 |
44 | # Perl有大多数常见的逻辑和循环控制结构
45 |
46 | if ( $var ) {
47 | ...
48 | } elsif ( $var eq 'bar' ) {
49 | ...
50 | } else {
51 | ...
52 | }
53 |
54 | unless ( condition ) {
55 | ...
56 | }
57 | # 上面这个比"if (!condition)"更可读。
58 |
59 | # 有Perl特色的后置逻辑结构
60 | print "Yow!" if $zippy;
61 | print "We have no bananas" unless $bananas;
62 |
63 | # while
64 | while ( condition ) {
65 | ...
66 | }
67 |
68 |
69 | # for和foreach
70 | for ($i = 0; $i <= $max; $i++) {
71 | ...
72 | }
73 |
74 | foreach (@array) {
75 | print "This element is $_\n";
76 | }
77 |
78 |
79 | #### 正则表达式
80 |
81 | # Perl对正则表达式有深入广泛的支持,perlrequick和perlretut等文档有详细介绍。简单来说:
82 |
83 | # 简单匹配
84 | if (/foo/) { ... } # 如果 $_ 包含"foo"逻辑为真
85 | if ($a =~ /foo/) { ... } # 如果 $a 包含"foo"逻辑为真
86 |
87 | # 简单替换
88 |
89 | $a =~ s/foo/bar/; # 将$a中的foo替换为bar
90 | $a =~ s/foo/bar/g; # 将$a中所有的foo替换为bar
91 |
92 |
93 | #### 文件和输入输出
94 |
95 | # 可以使用“open()”函数打开文件用于输入输出。
96 |
97 | open(my $in, "<", "input.txt") or die "Can't open input.txt: $!";
98 | open(my $out, ">", "output.txt") or die "Can't open output.txt: $!";
99 | open(my $log, ">>", "my.log") or die "Can't open my.log: $!";
100 |
101 | # 可以用"<>"操作符读取一个打开的文件句柄。 在标量语境下会读取一行,
102 | # 在列表环境下会将整个文件读入并将每一行赋给列表的一个元素:
103 |
104 | my $line = <$in>;
105 | my @lines = <$in>;
106 |
107 | #### 子程序
108 |
109 | # 写子程序很简单:
110 |
111 | sub logger {
112 | my $logmessage = shift;
113 | open my $logfile, ">>", "my.log" or die "Could not open my.log: $!";
114 | print $logfile $logmessage;
115 | }
116 |
117 | # 现在可以像内置函数一样调用子程序:
118 |
119 | logger("We have a logger subroutine!");
120 |
--------------------------------------------------------------------------------
/learnbash-cn.sh:
--------------------------------------------------------------------------------
1 |
2 | #!/bin/bash
3 | # 脚本的第一行叫 shebang,用来告知系统如何执行该脚本:
4 | # 参见: http://en.wikipedia.org/wiki/Shebang_(Unix)
5 | # 如你所见,注释以 # 开头,shebang 也是注释。
6 |
7 | # 显示 “Hello world!”
8 | echo Hello, world!
9 |
10 | # 每一句指令以换行或分号隔开:
11 | echo 'This is the first line'; echo 'This is the second line'
12 |
13 | # 声明一个变量:
14 | VARIABLE="Some string"
15 |
16 | # 下面是错误的做法:
17 | VARIABLE = "Some string"
18 | # Bash 会把 VARIABLE 当做一个指令,由于找不到该指令,因此这里会报错。
19 |
20 |
21 | # 使用变量:
22 | echo $VARIABLE
23 | echo "$VARIABLE"
24 | echo '$VARIABLE'
25 | # 当你赋值 (assign) 、导出 (export),或者以其他方式使用变量时,变量名前不加 $。
26 | # 如果要使用变量的值, 则要加 $。
27 | # 注意: ' (单引号) 不会展开变量(即会屏蔽掉变量)。
28 |
29 |
30 | # 在变量内部进行字符串代换
31 | echo ${VARIABLE/Some/A}
32 | # 会把 VARIABLE 中首次出现的 "some" 替换成 “A”。
33 |
34 | # 内置变量:
35 | # 下面的内置变量很有用
36 | echo "Last program return value: $?"
37 | echo "Script's PID: $$"
38 | echo "Number of arguments: $#"
39 | echo "Scripts arguments: $@"
40 | echo "Scripts arguments separeted in different variables: $1 $2..."
41 |
42 | # 读取输入:
43 | echo "What's your name?"
44 | read NAME # 这里不需要声明新变量
45 | echo Hello, $NAME!
46 |
47 | # 通常的 if 结构看起来像这样:
48 | # 'man test' 可查看更多的信息
49 | if [ $NAME -ne $USER ]
50 | then
51 | echo "Your name is you username"
52 | else
53 | echo "Your name isn't you username"
54 | fi
55 |
56 | # 根据上一个指令执行结果决定是否执行下一个指令
57 | echo "Always executed" || echo "Only executed if first command fail"
58 | echo "Always executed" && echo "Only executed if first command does NOT fail"
59 |
60 | # 表达式的格式如下:
61 | echo $(( 10 + 5 ))
62 |
63 | # 与其他编程语言不同的是,bash 运行时依赖上下文。比如,使用 ls 时,列出当前目录。
64 | ls
65 |
66 | # 指令可以带有选项:
67 | ls -l # 列出文件和目录的详细信息
68 |
69 | # 前一个指令的输出可以当作后一个指令的输入。grep 用来匹配字符串。
70 | # 用下面的指令列出当前目录下所有的 txt 文件:
71 | ls -l | grep "\.txt"
72 |
73 | # 重定向可以到输出,输入和错误输出。
74 | python2 hello.py < "input.in"
75 | python2 hello.py > "output.out"
76 | python2 hello.py 2> "error.err"
77 | # > 会覆盖已存在的文件, >> 会以累加的方式输出文件中。
78 |
79 | # 一个指令可用 $( ) 嵌套在另一个指令内部:
80 | # 以下的指令会打印当前目录下的目录和文件总数
81 | echo "There are $(ls | wc -l) items here."
82 |
83 | # Bash 的 case 语句与 Java 和 C++ 中的 switch 语句类似:
84 | case "$VARIABLE" in
85 | # 列出需要匹配的字符串
86 | 0) echo "There is a zero.";;
87 | 1) echo "There is a one.";;
88 | *) echo "It is not null.";;
89 | esac
90 |
91 | # 循环遍历给定的参数序列:
92 | # 变量$VARIABLE 的值会被打印 3 次。
93 | # 注意 ` ` 和 $( ) 等价。seq 返回长度为 3 的数组。
94 | for VARIABLE in `seq 3`
95 | do
96 | echo "$VARIABLE"
97 | done
98 |
99 | # 你也可以使用函数
100 | # 定义函数:
101 | function foo ()
102 | {
103 | echo "Arguments work just like script arguments: $@"
104 | echo "And: $1 $2..."
105 | echo "This is a function"
106 | return 0
107 | }
108 |
109 | # 更简单的方法
110 | bar ()
111 | {
112 | echo "Another way to declare functions!"
113 | return 0
114 | }
115 |
116 | # 调用函数
117 | foo "My name is" $NAME
118 |
119 | # 有很多有用的指令需要学习:
120 | tail -n 10 file.txt
121 | # 打印 file.txt 的最后 10 行
122 | head -n 10 file.txt
123 | # 打印 file.txt 的前 10 行
124 | sort file.txt
125 | # 将 file.txt 按行排序
126 | uniq -d file.txt
127 | # 报告或忽略重复的行,用选项 -d 打印重复的行
128 | cut -d ',' -f 1 file.txt
129 | # 打印每行中 ',' 之前内容
130 |
--------------------------------------------------------------------------------
/learncss-cn.css:
--------------------------------------------------------------------------------
1 |
2 | /* 注释 */
3 |
4 | /* ####################
5 | ## 选择器
6 | ####################*/
7 |
8 | /* 一般而言,CSS的声明语句非常简单。 */
9 | 选择器 { 属性: 值; /* 更多属性...*/ }
10 |
11 | /* 选择器用于指定页面上的元素。
12 |
13 | 针对页面上的所有元素。 */
14 | * { color:red; }
15 |
16 | /*
17 | 假定页面上有这样一个元素
18 |
19 |
20 | */
21 |
22 | /* 你可以通过类名来指定它 */
23 | .some-class { }
24 |
25 | /* 给出所有类名 */
26 | .some-class.class2 { }
27 |
28 | /* 标签名 */
29 | div { }
30 |
31 | /* id */
32 | #someId { }
33 |
34 | /* 由于元素包含attr属性,因此也可以通过这个来指定 */
35 | [attr] { font-size:smaller; }
36 |
37 | /* 以及有特定值的属性 */
38 | [attr='value'] { font-size:smaller; }
39 |
40 | /* 通过属性的值的开头指定 */
41 | [attr^='val'] { font-size:smaller; }
42 |
43 | /* 通过属性的值的结尾来指定 */
44 | [attr$='ue'] { font-size:smaller; }
45 |
46 | /* 通过属性的值的部分来指定 */
47 | [attr~='lu'] { font-size:smaller; }
48 |
49 |
50 | /* 你可以把这些全部结合起来,注意不同部分间不应该有空格,否则会改变语义 */
51 | div.some-class[attr$='ue'] { }
52 |
53 | /* 你也可以通过父元素来指定。*/
54 |
55 | /* 某个元素是另一个元素的直接子元素 */
56 | div.some-parent > .class-name {}
57 |
58 | /* 或者通过该元素的祖先元素 */
59 | div.some-parent .class-name {}
60 |
61 | /* 注意,去掉空格后语义就不同了。
62 | 你能说出哪里不同么? */
63 | div.some-parent.class-name {}
64 |
65 | /* 你可以选择某元素前的相邻元素 */
66 | .i-am-before + .this-element { }
67 |
68 | /* 某元素之前的同级元素(相邻或不相邻) */
69 | .i-am-any-before ~ .this-element {}
70 |
71 | /* 伪类允许你基于页面的行为指定元素(而不是基于页面结构) */
72 |
73 | /* 例如,当鼠标悬停在某个元素上时 */
74 | :hover {}
75 |
76 | /* 已访问过的链接*/
77 | :visited {}
78 |
79 | /* 未访问过的链接*/
80 | :link {}
81 |
82 | /* 当前焦点的input元素 */
83 | :focus {}
84 |
85 |
86 | /* ####################
87 | ## 属性
88 | ####################*/
89 |
90 | 选择器 {
91 |
92 | /* 单位 */
93 | width: 50%; /* 百分比 */
94 | font-size: 2em; /* 当前字体大小的两倍 */
95 | width: 200px; /* 像素 */
96 | font-size: 20pt; /* 点 */
97 | width: 5cm; /* 厘米 */
98 | width: 50mm; /* 毫米 */
99 | width: 5in; /* 英尺 */
100 |
101 | /* 颜色 */
102 | background-color: #F6E; /* 短16位 */
103 | background-color: #F262E2; /* 长16位 */
104 | background-color: tomato; /* 颜色名称 */
105 | background-color: rgb(255, 255, 255); /* rgb */
106 | background-color: rgb(10%, 20%, 50%); /* rgb 百分比 */
107 | background-color: rgba(255, 0, 0, 0.3); /* rgb 加透明度 */
108 |
109 | /* 图片 */
110 | background-image: url(/path-to-image/image.jpg);
111 |
112 | /* 字体 */
113 | font-family: Arial;
114 | font-family: "Courier New"; /* 使用双引号包裹含空格的字体名称 */
115 | font-family: "Courier New", Trebuchet, Arial; /* 如果第一个
116 | 字体没找到,浏览器会使用第二个字体,一次类推 */
117 | }
118 |
119 |
120 |
121 |
122 |
123 |
124 |
127 |
128 |
130 |
131 |
132 |
133 |
134 | /*A*/
135 | p.class1[attr='value']
136 |
137 | /*B*/
138 | p.class1 {}
139 |
140 | /*C*/
141 | p.class2 {}
142 |
143 | /*D*/
144 | p {}
145 |
146 | /*E*/
147 | p { property: value !important; }
148 |
149 |
150 |
151 |
152 |
--------------------------------------------------------------------------------
/learnswift-cn.swift:
--------------------------------------------------------------------------------
1 |
2 | //
3 | // 基础
4 | //
5 |
6 | println("Hello, world")
7 | var myVariable = 42
8 | let myConstant = 3.1415926
9 | let explicitDouble: Double = 70
10 | let label = "some text " + String(myVariable) // Casting
11 | let piText = "Pi = \(myConstant)" // String interpolation
12 | var optionalString: String? = "optional" // Can be nil
13 | optionalString = nil
14 |
15 |
16 | //
17 | // 数组与字典(关联数组)
18 | //
19 |
20 | // 数组
21 | var shoppingList = ["catfish", "water", "lemons"]
22 | shoppingList[1] = "bottle of water"
23 | let emptyArray = String[]()
24 |
25 | // 字典
26 | var occupations = [
27 | "Malcolm": "Captain",
28 | "kaylee": "Mechanic"
29 | ]
30 | occupations["Jayne"] = "Public Relations"
31 | let emptyDictionary = Dictionary()
32 |
33 |
34 | //
35 | // 控制流
36 | //
37 |
38 | // 用于数组的for 循环
39 | let myArray = [1, 1, 2, 3, 5]
40 | for value in myArray {
41 | if value == 1 {
42 | println("One!")
43 | } else {
44 | println("Not one!")
45 | }
46 | }
47 |
48 | // 用于字典的for 循环
49 | for (key, value) in dict {
50 | println("\(key): \(value)")
51 | }
52 |
53 | // 用于区间的for 循环
54 | for i in -1...1 { // [-1, 0, 1]
55 | println(i)
56 | }
57 | // 使用 .. 表示的区间不包含最后一个元素 [-1,0,1)
58 |
59 | // while 循环
60 | var i = 1
61 | while i < 1000 {
62 | i *= 2
63 | }
64 |
65 | // do-while 循环
66 | do {
67 | println("hello")
68 | } while 1 == 2
69 |
70 | // Switch
71 | let vegetable = "red pepper"
72 | switch vegetable {
73 | case "celery":
74 | let vegetableComment = "Add some raisins and make ants on a log."
75 | case "cucumber", "watercress":
76 | let vegetableComment = "That would make a good tea sandwich."
77 | case let x where x.hasSuffix("pepper"):
78 | let vegetableComment = "Is it a spicy \(x)?"
79 | default: // 必须 (为了覆盖所有可能的输入)
80 | let vegetableComment = "Everything tastes good in soup."
81 | }
82 |
83 |
84 | //
85 | // 函数
86 | //
87 |
88 | // 函数是一等类型,这意味着可以在函数中构建函数
89 | // 并且可以被传递
90 |
91 | // 函数
92 | func greet(name: String, day: String) -> String {
93 | return "Hello \(name), today is \(day)."
94 | }
95 | greet("Bob", "Tuesday")
96 |
97 | // 使用多元数组返回多返回值的函数
98 | func getGasPrices() -> (Double, Double, Double) {
99 | return (3.59, 3.69, 3.79)
100 | }
101 |
102 | // 不定参数
103 | func setup(numbers: Int...) {}
104 |
105 | // 传递、返回函数
106 | func makeIncrementer() -> (Int -> Int) {
107 | func addOne(number: Int) -> Int {
108 | return 1 + number
109 | }
110 | return addOne
111 | }
112 | var increment = makeIncrementer()
113 | increment(7)
114 |
115 |
116 | //
117 | // 闭包
118 | //
119 |
120 | // 函数是特殊的闭包({})
121 |
122 | // 闭包示例.
123 | // `->` 分隔参数和返回类型
124 | // `in` 分隔闭包头和闭包体
125 | numbers.map({
126 | (number: Int) -> Int in
127 | let result = 3 * number
128 | return result
129 | })
130 |
131 | // 当类型已知时,可以这样做:
132 | var numbers = [1, 2, 6]
133 | numbers = numbers.map({ number in 3 * number })
134 | print(numbers) // [3, 6, 18]
135 |
136 |
137 | //
138 | // 类
139 | //
140 |
141 | // 类的全部方法和属性都是public 的
142 | // 如果你在一个数据结构中只需储存数据,
143 | // 应使用 `struct`
144 |
145 | // 集成自`Shape` 类的简单的类`Square
146 | class Rect: Shape {
147 | var sideLength: Int = 1
148 |
149 | // Custom getter and setter property
150 | var perimeter: Int {
151 | get {
152 | return 4 * sideLength
153 | }
154 | set {
155 | sideLength = newValue / 4
156 | }
157 | }
158 |
159 | init(sideLength: Int) {
160 | super.init()
161 | self.sideLength = sideLength
162 | }
163 |
164 | func shrink() {
165 | if sideLength > 0 {
166 | --sideLength
167 | }
168 | }
169 |
170 | override func getArea() -> Int {
171 | return sideLength * sideLength
172 | }
173 | }
174 | var mySquare = new Square(sideLength: 5)
175 | print(mySquare.getArea()) // 25
176 | mySquare.shrink()
177 | print(mySquare.sideLength) // 4
178 |
179 | // 如果你不需要自定义getter 和setter,
180 | // 但仍希望在获取或设置一个属性之前或之后运行
181 | // 一些代码,你可以使用`willSet` 和 `didSet`
182 |
183 |
184 | //
185 | // 枚举类型
186 | //
187 |
188 | // 枚举类型可以是某种指定的类型,抑或自成一种类型
189 | // 像类一样,枚举类型可以包含方法
190 |
191 | enum Suit {
192 | case Spades, Hearts, Diamonds, Clubs
193 | func getIcon() -> String {
194 | switch self {
195 | case .Spades: return "♤"
196 | case .Hearts: return "♡"
197 | case .Diamonds: return "♢"
198 | case .Clubs: return "♧"
199 | }
200 | }
201 | }
202 |
203 |
204 | //
205 | // 其它
206 | //
207 |
208 | // `协议(protocol)`: 与Java 的接口(Interface) 类似.
209 | // `扩展(extension)`: 为现有类型添加额外特性
210 | // 泛型: 与Java 相似。使用`where` 关键字指定
211 | // 泛型的要求.
212 |
--------------------------------------------------------------------------------
/learnruby-cn.rb:
--------------------------------------------------------------------------------
1 |
2 | # 这是单行注释
3 |
4 | =begin
5 | 这是多行注释
6 | 没人用这个
7 | 你也不该用
8 | =end
9 |
10 | # 首先,也是最重要的,所有东西都是对象
11 |
12 | # 数字是对象
13 |
14 | 3.class #=> Fixnum
15 |
16 | 3.to_s #=> "3"
17 |
18 |
19 | # 一些基本的算术符号
20 | 1 + 1 #=> 2
21 | 8 - 1 #=> 7
22 | 10 * 2 #=> 20
23 | 35 / 5 #=> 7
24 |
25 | # 算术符号只是语法糖而已
26 | # 实际上是调用对象的方法
27 | 1.+(3) #=> 4
28 | 10.* 5 #=> 50
29 |
30 | # 特殊的值也是对象
31 | nil # 空
32 | true # 真
33 | false # 假
34 |
35 | nil.class #=> NilClass
36 | true.class #=> TrueClass
37 | false.class #=> FalseClass
38 |
39 | # 相等运算符
40 | 1 == 1 #=> true
41 | 2 == 1 #=> false
42 |
43 | # 不等运算符
44 | 1 != 1 #=> false
45 | 2 != 1 #=> true
46 | !true #=> false
47 | !false #=> true
48 |
49 | # 除了false自己,nil是唯一的值为false的对象
50 |
51 | !nil #=> true
52 | !false #=> true
53 | !0 #=> false
54 |
55 | # 更多比较
56 | 1 < 10 #=> true
57 | 1 > 10 #=> false
58 | 2 <= 2 #=> true
59 | 2 >= 2 #=> true
60 |
61 | # 字符串是对象
62 |
63 | 'I am a string'.class #=> String
64 | "I am a string too".class #=> String
65 |
66 | placeholder = "use string interpolation"
67 | "I can #{placeholder} when using double quoted strings"
68 | #=> "I can use string interpolation when using double quoted strings"
69 |
70 |
71 | # 输出值
72 | puts "I'm printing!"
73 |
74 | # 变量
75 | x = 25 #=> 25
76 | x #=> 25
77 |
78 | # 注意赋值语句返回了赋的值
79 | # 这意味着你可以用多重赋值语句
80 |
81 | x = y = 10 #=> 10
82 | x #=> 10
83 | y #=> 10
84 |
85 | # 按照惯例,用 snake_case 作为变量名
86 | snake_case = true
87 |
88 | # 使用具有描述性的运算符
89 | path_to_project_root = '/good/name/'
90 | path = '/bad/name/'
91 |
92 | # 符号(Symbols,也是对象)
93 | # 符号是不可变的,内部用整数类型表示的可重用的值。
94 | # 通常用它代替字符串来有效地表示有意义的值。
95 |
96 |
97 | :pending.class #=> Symbol
98 |
99 | status = :pending
100 |
101 | status == :pending #=> true
102 |
103 | status == 'pending' #=> false
104 |
105 | status == :approved #=> false
106 |
107 | # 数组
108 |
109 | # 这是一个数组
110 | [1, 2, 3, 4, 5] #=> [1, 2, 3, 4, 5]
111 |
112 | # 数组可以包含不同类型的元素
113 |
114 | array = [1, "hello", false] #=> => [1, "hello", false]
115 |
116 | # 数组可以被索引
117 | # 从前面开始
118 | array[0] #=> 1
119 | array[12] #=> nil
120 |
121 | # 像运算符一样,[var]形式的访问
122 | # 也就是一个语法糖
123 | # 实际上是调用对象的[] 方法
124 | array.[] 0 #=> 1
125 | array.[] 12 #=> nil
126 |
127 | # 从尾部开始
128 | array[-1] #=> 5
129 |
130 | # 同时指定开始的位置和结束的位置
131 | array[2, 4] #=> [3, 4, 5]
132 |
133 | # 或者指定一个范围
134 | array[1..3] #=> [2, 3, 4]
135 |
136 | # 像这样往数组增加一个元素
137 | array << 6 #=> [1, 2, 3, 4, 5, 6]
138 |
139 | # 哈希表是Ruby的键值对的基本数据结构
140 | # 哈希表由大括号定义
141 | hash = {'color' => 'green', 'number' => 5}
142 |
143 | hash.keys #=> ['color', 'number']
144 |
145 | # 哈希表可以通过键快速地查询
146 | hash['color'] #=> 'green'
147 | hash['number'] #=> 5
148 |
149 | # 查询一个不存在地键将会返回nil
150 | hash['nothing here'] #=> nil
151 |
152 | # 用 #each 方法来枚举哈希表:
153 | hash.each do |k, v|
154 | puts "#{k} is #{v}"
155 | end
156 |
157 | # 从Ruby 1.9开始, 用符号作为键的时候有特别的记号表示:
158 |
159 | new_hash = { defcon: 3, action: true}
160 |
161 | new_hash.keys #=> [:defcon, :action]
162 |
163 | # 小贴士:数组和哈希表都是可枚举的
164 | # 它们可以共享一些有用的方法,比如each, map, count 等等
165 |
166 | # 控制流
167 |
168 | if true
169 | "if statement"
170 | elsif false
171 | "else if, optional"
172 | else
173 | "else, also optional"
174 | end
175 |
176 | for counter in 1..5
177 | puts "iteration #{counter}"
178 | end
179 | #=> iteration 1
180 | #=> iteration 2
181 | #=> iteration 3
182 | #=> iteration 4
183 | #=> iteration 5
184 |
185 | # 然而
186 | # 没人用for循环
187 | # 用`each`来代替,就像这样
188 |
189 | (1..5).each do |counter|
190 | puts "iteration #{counter}"
191 | end
192 | #=> iteration 1
193 | #=> iteration 2
194 | #=> iteration 3
195 | #=> iteration 4
196 | #=> iteration 5
197 |
198 | counter = 1
199 | while counter <= 5 do
200 | puts "iteration #{counter}"
201 | counter += 1
202 | end
203 | #=> iteration 1
204 | #=> iteration 2
205 | #=> iteration 3
206 | #=> iteration 4
207 | #=> iteration 5
208 |
209 | grade = 'B'
210 |
211 | case grade
212 | when 'A'
213 | puts "Way to go kiddo"
214 | when 'B'
215 | puts "Better luck next time"
216 | when 'C'
217 | puts "You can do better"
218 | when 'D'
219 | puts "Scraping through"
220 | when 'F'
221 | puts "You failed!"
222 | else
223 | puts "Alternative grading system, eh?"
224 | end
225 |
226 | # 函数
227 |
228 | def double(x)
229 | x * 2
230 | end
231 |
232 | # 函数 (以及所有的方法块) 隐式地返回了最后语句的值
233 | double(2) #=> 4
234 |
235 | # 当不存在歧义的时候括号是可有可无的
236 | double 3 #=> 6
237 |
238 | double double 3 #=> 12
239 |
240 | def sum(x,y)
241 | x + y
242 | end
243 |
244 | # 方法的参数通过逗号分隔
245 | sum 3, 4 #=> 7
246 |
247 | sum sum(3,4), 5 #=> 12
248 |
249 | # yield
250 | # 所有的方法都有一个隐式的块参数
251 | # 可以用yield参数调用
252 |
253 | def surround
254 | puts "{"
255 | yield
256 | puts "}"
257 | end
258 |
259 | surround { puts 'hello world' }
260 |
261 | # {
262 | # hello world
263 | # }
264 |
265 |
266 | # 用class关键字定义一个类
267 | class Human
268 |
269 | # 一个类变量,它被这个类地所有实例变量共享
270 | @@species = "H. sapiens"
271 |
272 | # 构造函数
273 | def initialize(name, age=0)
274 | # 将参数name的值赋给实例变量@name
275 | @name = name
276 | # 如果没有给出age, 那么会采用参数列表中地默认地值
277 | @age = age
278 | end
279 |
280 | # 基本的 setter 方法
281 | def name=(name)
282 | @name = name
283 | end
284 |
285 | # 基本地 getter 方法
286 | def name
287 | @name
288 | end
289 |
290 | # 一个类方法以self.开头
291 | # 它可以被类调用,但不能被类的实例调用
292 | def self.say(msg)
293 | puts "#{msg}"
294 | end
295 |
296 | def species
297 | @@species
298 | end
299 |
300 | end
301 |
302 |
303 | # 类的例子
304 | jim = Human.new("Jim Halpert")
305 |
306 | dwight = Human.new("Dwight K. Schrute")
307 |
308 | # 让我们来调用一些方法
309 | jim.species #=> "H. sapiens"
310 | jim.name #=> "Jim Halpert"
311 | jim.name = "Jim Halpert II" #=> "Jim Halpert II"
312 | jim.name #=> "Jim Halpert II"
313 | dwight.species #=> "H. sapiens"
314 | dwight.name #=> "Dwight K. Schrute"
315 |
316 | # 调用对象的方法
317 | Human.say("Hi") #=> "Hi"
318 |
--------------------------------------------------------------------------------
/learngo-cn.go:
--------------------------------------------------------------------------------
1 |
2 | // 单行注释
3 | /* 多行
4 | 注释 */
5 |
6 | // 导入包的子句在每个源文件的开头。
7 | // Main比较特殊,它用来声明可执行文件,而不是一个库。
8 | package main
9 |
10 | // Import语句声明了当前文件引用的包。
11 | import (
12 | "fmt" // Go语言标准库中的包
13 | "net/http" // 一个web服务器包
14 | "strconv" // 字符串转换
15 | )
16 |
17 | // 函数声明:Main是程序执行的入口。
18 | // 不管你喜欢还是不喜欢,反正Go就用了花括号来包住函数体。
19 | func main() {
20 | // 往标准输出打印一行。
21 | // 用包名fmt限制打印函数。
22 | fmt.Println("Hello world!")
23 |
24 | // 调用当前包的另一个函数。
25 | beyondHello()
26 | }
27 |
28 | // 函数可以在括号里加参数。
29 | // 如果没有参数的话,也需要一个空括号。
30 | func beyondHello() {
31 | var x int // 变量声明,变量必须在使用之前声明。
32 | x = 3 // 变量赋值。
33 | // 可以用:=来偷懒,它自动把变量类型、声明和赋值都搞定了。
34 | y := 4
35 | sum, prod := learnMultiple(x, y) // 返回多个变量的函数
36 | fmt.Println("sum:", sum, "prod:", prod) // 简单输出
37 | learnTypes() // 少于y分钟,学的更多!
38 | }
39 |
40 | // 多变量和多返回值的函数
41 | func learnMultiple(x, y int) (sum, prod int) {
42 | return x + y, x * y // 返回两个值
43 | }
44 |
45 | // 内置变量类型和关键词
46 | func learnTypes() {
47 | // 短声明给你所想。
48 | s := "Learn Go!" // String类型
49 |
50 | s2 := `A "raw" string literal
51 | can include line breaks.` // 同样是String类型
52 |
53 | // 非ascii字符。Go使用UTF-8编码。
54 | g := 'Σ' // rune类型,int32的别名,使用UTF-8编码
55 |
56 | f := 3.14195 // float64类型,IEEE-754 64位浮点数
57 | c := 3 + 4i // complex128类型,内部使用两个float64表示
58 |
59 | // Var变量可以直接初始化。
60 | var u uint = 7 // unsigned 无符号变量,但是实现依赖int型变量的长度
61 | var pi float32 = 22. / 7
62 |
63 | // 字符转换
64 | n := byte('\n') // byte是uint8的别名
65 |
66 | // 数组类型编译的时候大小固定。
67 | var a4 [4] int // 有4个int变量的数组,初始为0
68 | a3 := [...]int{3, 1, 5} // 有3个int变量的数组,同时进行了初始化
69 |
70 | // Slice 可以动态的增删。Array和Slice各有千秋,但是使用slice的地方更多些。
71 | s3 := []int{4, 5, 9} // 和a3相比,这里没有省略号
72 | s4 := make([]int, 4) // 分配一个有4个int型变量的slice,全部被初始化为0
73 |
74 | var d2 [][]float64 // 声明而已,什么都没有分配
75 | bs := []byte("a slice") // 类型转换的语法
76 |
77 | p, q := learnMemory() // 声明p,q为int型变量的指针
78 | fmt.Println(*p, *q) // * 取值
79 |
80 | // Map是动态可增长关联数组,和其他语言中的hash或者字典相似。
81 | m := map[string]int{"three": 3, "four": 4}
82 | m["one"] = 1
83 |
84 | // 在Go语言中未使用的变量在编译的时候会报错,而不是warning。
85 | // 下划线 _ 可以使你“使用”一个变量,但是丢弃它的值。
86 | _,_,_,_,_,_,_,_,_ = s2, g, f, u, pi, n, a3, s4, bs
87 | // 输出变量
88 | fmt.Println(s, c, a4, s3, d2, m)
89 |
90 | learnFlowControl() // 回到流程控制
91 | }
92 |
93 | // Go全面支持垃圾回收。Go有指针,但是不支持指针运算。
94 | // 你会因为空指针而犯错,但是不会因为增加指针而犯错。
95 | func learnMemory() (p, q *int) {
96 | // 返回int型变量指针p和q
97 | p = new(int) // 内置函数new分配内存
98 | // 自动将分配的int赋值0,p不再是空的了。
99 | s := make([]int, 20) // 给20个int变量分配一块内存
100 | s[3] = 7 // 赋值
101 | r := -2 // 声明另一个局部变量
102 | return &s[3], &r // & 取地址
103 | }
104 |
105 | func expensiveComputation() int {
106 | return 1e6
107 | }
108 |
109 | func learnFlowControl() {
110 | // If需要花括号,括号就免了
111 | if true {
112 | fmt.Println("told ya")
113 | }
114 | // 用go fmt 命令可以帮你格式化代码,所以不用怕被人吐槽代码风格了,
115 | // 也不用容忍被人的代码风格。
116 | if false {
117 | // pout
118 | } else {
119 | // gloat
120 | }
121 | // 如果太多嵌套的if语句,推荐使用switch
122 | x := 1
123 | switch x {
124 | case 0:
125 | case 1:
126 | // 隐式调用break语句,匹配上一个即停止
127 | case 2:
128 | // 不会运行
129 | }
130 | // 和if一样,for也不用括号
131 | for x := 0; x < 3; x++ { // ++ 自增
132 | fmt.Println("iteration", x)
133 | }
134 | // x在这里还是1。为什么?
135 |
136 | // for 是go里唯一的循环关键字,不过它有很多变种
137 | for { // 死循环
138 | break // 骗你的
139 | continue // 不会运行的
140 | }
141 | // 和for一样,if中的:=先给y赋值,然后再和x作比较。
142 | if y := expensiveComputation(); y > x {
143 | x = y
144 | }
145 | // 闭包函数
146 | xBig := func() bool {
147 | return x > 100 // x是上面声明的变量引用
148 | }
149 | fmt.Println("xBig:", xBig()) // true (上面把y赋给x了)
150 | x /= 1e5 // x变成10
151 | fmt.Println("xBig:", xBig()) // 现在是false
152 |
153 | // 当你需要goto的时候,你会爱死它的!
154 | goto love
155 | love:
156 |
157 | learnInterfaces() // 好东西来了!
158 | }
159 |
160 | // 定义Stringer为一个接口类型,有一个方法String
161 | type Stringer interface {
162 | String() string
163 | }
164 |
165 | // 定义pair为一个结构体,有x和y两个int型变量。
166 | type pair struct {
167 | x, y int
168 | }
169 |
170 | // 定义pair类型的方法,实现Stringer接口。
171 | func (p pair) String() string { // p被叫做“接收器”
172 | // Sprintf是fmt包中的另一个公有函数。
173 | // 用 . 调用p中的元素。
174 | return fmt.Sprintf("(%d, %d)", p.x, p.y)
175 | }
176 |
177 | func learnInterfaces() {
178 | // 花括号用来定义结构体变量,:=在这里将一个结构体变量赋值给p。
179 | p := pair{3, 4}
180 | fmt.Println(p.String()) // 调用pair类型p的String方法
181 | var i Stringer // 声明i为Stringer接口类型
182 | i = p // 有效!因为p实现了Stringer接口(类似java中的塑型)
183 | // 调用i的String方法,输出和上面一样
184 | fmt.Println(i.String())
185 |
186 | // fmt包中的Println函数向对象要它们的string输出,实现了String方法就可以这样使用了。
187 | // (类似java中的序列化)
188 | fmt.Println(p) // 输出和上面一样,自动调用String函数。
189 | fmt.Println(i) // 输出和上面一样。
190 |
191 | learnErrorHandling()
192 | }
193 |
194 | func learnErrorHandling() {
195 | // ", ok"用来判断有没有正常工作
196 | m := map[int]string{3: "three", 4: "four"}
197 | if x, ok := m[1]; !ok { // ok 为false,因为m中没有1
198 | fmt.Println("no one there")
199 | } else {
200 | fmt.Print(x) // 如果x在map中的话,x就是那个值喽。
201 | }
202 | // 错误可不只是ok,它还可以给出关于问题的更多细节。
203 | if _, err := strconv.Atoi("non-int"); err != nil { // _ discards value
204 | // 输出"strconv.ParseInt: parsing "non-int": invalid syntax"
205 | fmt.Println(err)
206 | }
207 | // 待会再说接口吧。同时,
208 | learnConcurrency()
209 | }
210 |
211 | // c是channel类型,一个并发安全的通信对象。
212 | func inc(i int, c chan int) {
213 | c <- i + 1 // <-把右边的发送到左边的channel。
214 | }
215 |
216 | // 我们将用inc函数来并发地增加一些数字。
217 | func learnConcurrency() {
218 | // 用make来声明一个slice,make会分配和初始化slice,map和channel。
219 | c := make(chan int)
220 | // 用go关键字开始三个并发的goroutine,如果机器支持的话,还可能是并行执行。
221 | // 三个都被发送到同一个channel。
222 | go inc(0, c) // go is a statement that starts a new goroutine.
223 | go inc(10, c)
224 | go inc(-805, c)
225 | // 从channel中独处结果并打印。
226 | // 打印出什么东西是不可预知的。
227 | fmt.Println(<-c, <-c, <-c) // channel在右边的时候,<-是读操作。
228 |
229 | cs := make(chan string) // 操作string的channel
230 | cc := make(chan chan string) // 操作channel的channel
231 | go func() { c <- 84 }() // 开始一个goroutine来发送一个新的数字
232 | go func() { cs <- "wordy" }() // 发送给cs
233 | // Select类似于switch,但是每个case包括一个channel操作。
234 | // 它随机选择一个准备好通讯的case。
235 | select {
236 | case i := <-c: // 从channel接收的值可以赋给其他变量
237 | fmt.Println("it's a", i)
238 | case <-cs: // 或者直接丢弃
239 | fmt.Println("it's a string")
240 | case <-cc: // 空的,还没作好通讯的准备
241 | fmt.Println("didn't happen.")
242 | }
243 | // 上面c或者cs的值被取到,其中一个goroutine结束,另外一个一直阻塞。
244 |
245 | learnWebProgramming() // Go很适合web编程,我知道你也想学!
246 | }
247 |
248 | // http包中的一个简单的函数就可以开启web服务器。
249 | func learnWebProgramming() {
250 | // ListenAndServe第一个参数指定了监听端口,第二个参数是一个接口,特定是http.Handler。
251 | err := http.ListenAndServe(":8080", pair{})
252 | fmt.Println(err) // 不要无视错误。
253 | }
254 |
255 | // 使pair实现http.Handler接口的ServeHTTP方法。
256 | func (p pair) ServeHTTP(w http.ResponseWriter, r *http.Request) {
257 | // 使用http.ResponseWriter返回数据
258 | w.Write([]byte("You learned Go in Y minutes!"))
259 | }
260 |
--------------------------------------------------------------------------------
/learnpython-cn.py:
--------------------------------------------------------------------------------
1 |
2 |
3 | # 单行注释
4 | """ 多行字符串可以用
5 | 三个引号包裹,不过这也可以被当做
6 | 多行注释
7 | """
8 |
9 | ####################################################
10 | ## 1. 原始数据类型和操作符
11 | ####################################################
12 |
13 | # 数字类型
14 | 3 # => 3
15 |
16 | # 简单的算数
17 | 1 + 1 # => 2
18 | 8 - 1 # => 7
19 | 10 * 2 # => 20
20 | 35 / 5 # => 7
21 |
22 | # 整数的除法会自动取整
23 | 5 / 2 # => 2
24 |
25 | # 要做精确的除法,我们需要引入浮点数
26 | 2.0 # 浮点数
27 | 11.0 / 4.0 # => 2.75 精确多了
28 |
29 | # 括号具有最高优先级
30 | (1 + 3) * 2 # => 8
31 |
32 | # 布尔值也是基本的数据类型
33 | True
34 | False
35 |
36 | # 用 not 来取非
37 | not True # => False
38 | not False # => True
39 |
40 | # 相等
41 | 1 == 1 # => True
42 | 2 == 1 # => False
43 |
44 | # 不等
45 | 1 != 1 # => False
46 | 2 != 1 # => True
47 |
48 | # 更多的比较操作符
49 | 1 < 10 # => True
50 | 1 > 10 # => False
51 | 2 <= 2 # => True
52 | 2 >= 2 # => True
53 |
54 | # 比较运算可以连起来写!
55 | 1 < 2 < 3 # => True
56 | 2 < 3 < 2 # => False
57 |
58 | # 字符串通过 " 或 ' 括起来
59 | "This is a string."
60 | 'This is also a string.'
61 |
62 | # 字符串通过加号拼接
63 | "Hello " + "world!" # => "Hello world!"
64 |
65 | # 字符串可以被视为字符的列表
66 | "This is a string"[0] # => 'T'
67 |
68 | # % 可以用来格式化字符串
69 | "%s can be %s" % ("strings", "interpolated")
70 |
71 | # 也可以用 format 方法来格式化字符串
72 | # 推荐使用这个方法
73 | "{0} can be {1}".format("strings", "formatted")
74 | # 也可以用变量名代替数字
75 | "{name} wants to eat {food}".format(name="Bob", food="lasagna")
76 |
77 | # None 是对象
78 | None # => None
79 |
80 | # 不要用相等 `==` 符号来和None进行比较
81 | # 要用 `is`
82 | "etc" is None # => False
83 | None is None # => True
84 |
85 | # 'is' 可以用来比较对象的相等性
86 | # 这个操作符在比较原始数据时没多少用,但是比较对象时必不可少
87 |
88 | # None, 0, 和空字符串都被算作 False
89 | # 其他的均为 True
90 | 0 == False # => True
91 | "" == False # => True
92 |
93 |
94 | ####################################################
95 | ## 2. 变量和集合
96 | ####################################################
97 |
98 | # 很方便的输出
99 | print "I'm Python. Nice to meet you!"
100 |
101 |
102 | # 给变量赋值前不需要事先声明
103 | some_var = 5 # 一般建议使用小写字母和下划线组合来做为变量名
104 | some_var # => 5
105 |
106 | # 访问未赋值的变量会抛出异常
107 | # 可以查看控制流程一节来了解如何异常处理
108 | some_other_var # 抛出 NameError
109 |
110 | # if 语句可以作为表达式来使用
111 | "yahoo!" if 3 > 2 else 2 # => "yahoo!"
112 |
113 | # 列表用来保存序列
114 | li = []
115 | # 可以直接初始化列表
116 | other_li = [4, 5, 6]
117 |
118 | # 在列表末尾添加元素
119 | li.append(1) # li 现在是 [1]
120 | li.append(2) # li 现在是 [1, 2]
121 | li.append(4) # li 现在是 [1, 2, 4]
122 | li.append(3) # li 现在是 [1, 2, 4, 3]
123 | # 移除列表末尾元素
124 | li.pop() # => 3 li 现在是 [1, 2, 4]
125 | # 重新加进去
126 | li.append(3) # li is now [1, 2, 4, 3] again.
127 |
128 | # 像其他语言访问数组一样访问列表
129 | li[0] # => 1
130 | # 访问最后一个元素
131 | li[-1] # => 3
132 |
133 | # 越界会抛出异常
134 | li[4] # 抛出越界异常
135 |
136 | # 切片语法需要用到列表的索引访问
137 | # 可以看做数学之中左闭右开区间
138 | li[1:3] # => [2, 4]
139 | # 省略开头的元素
140 | li[2:] # => [4, 3]
141 | # 省略末尾的元素
142 | li[:3] # => [1, 2, 4]
143 |
144 | # 删除特定元素
145 | del li[2] # li 现在是 [1, 2, 3]
146 |
147 | # 合并列表
148 | li + other_li # => [1, 2, 3, 4, 5, 6] - 并不会不改变这两个列表
149 |
150 | # 通过拼接来合并列表
151 | li.extend(other_li) # li 是 [1, 2, 3, 4, 5, 6]
152 |
153 | # 用 in 来返回元素是否在列表中
154 | 1 in li # => True
155 |
156 | # 返回列表长度
157 | len(li) # => 6
158 |
159 |
160 | # 元组类似于列表,但它是不可改变的
161 | tup = (1, 2, 3)
162 | tup[0] # => 1
163 | tup[0] = 3 # 类型错误
164 |
165 | # 对于大多数的列表操作,也适用于元组
166 | len(tup) # => 3
167 | tup + (4, 5, 6) # => (1, 2, 3, 4, 5, 6)
168 | tup[:2] # => (1, 2)
169 | 2 in tup # => True
170 |
171 | # 你可以将元组解包赋给多个变量
172 | a, b, c = (1, 2, 3) # a 是 1,b 是 2,c 是 3
173 | # 如果不加括号,将会被自动视为元组
174 | d, e, f = 4, 5, 6
175 | # 现在我们可以看看交换两个数字是多么容易的事
176 | e, d = d, e # d 是 5,e 是 4
177 |
178 |
179 | # 字典用来储存映射关系
180 | empty_dict = {}
181 | # 字典初始化
182 | filled_dict = {"one": 1, "two": 2, "three": 3}
183 |
184 | # 字典也用中括号访问元素
185 | filled_dict["one"] # => 1
186 |
187 | # 把所有的键保存在列表中
188 | filled_dict.keys() # => ["three", "two", "one"]
189 | # 键的顺序并不是唯一的,得到的不一定是这个顺序
190 |
191 | # 把所有的值保存在列表中
192 | filled_dict.values() # => [3, 2, 1]
193 | # 和键的顺序相同
194 |
195 | # 判断一个键是否存在
196 | "one" in filled_dict # => True
197 | 1 in filled_dict # => False
198 |
199 | # 查询一个不存在的键会抛出 KeyError
200 | filled_dict["four"] # KeyError
201 |
202 | # 用 get 方法来避免 KeyError
203 | filled_dict.get("one") # => 1
204 | filled_dict.get("four") # => None
205 | # get 方法支持在不存在的时候返回一个默认值
206 | filled_dict.get("one", 4) # => 1
207 | filled_dict.get("four", 4) # => 4
208 |
209 | # setdefault 是一个更安全的添加字典元素的方法
210 | filled_dict.setdefault("five", 5) # filled_dict["five"] 的值为 5
211 | filled_dict.setdefault("five", 6) # filled_dict["five"] 的值仍然是 5
212 |
213 |
214 | # 集合储存无顺序的元素
215 | empty_set = set()
216 | # 初始化一个集合
217 | some_set = set([1, 2, 2, 3, 4]) # some_set 现在是 set([1, 2, 3, 4])
218 |
219 | # Python 2.7 之后,大括号可以用来表示集合
220 | filled_set = {1, 2, 2, 3, 4} # => {1 2 3 4}
221 |
222 | # 向集合添加元素
223 | filled_set.add(5) # filled_set 现在是 {1, 2, 3, 4, 5}
224 |
225 | # 用 & 来计算集合的交
226 | other_set = {3, 4, 5, 6}
227 | filled_set & other_set # => {3, 4, 5}
228 |
229 | # 用 | 来计算集合的并
230 | filled_set | other_set # => {1, 2, 3, 4, 5, 6}
231 |
232 | # 用 - 来计算集合的差
233 | {1, 2, 3, 4} - {2, 3, 5} # => {1, 4}
234 |
235 | # 用 in 来判断元素是否存在于集合中
236 | 2 in filled_set # => True
237 | 10 in filled_set # => False
238 |
239 |
240 | ####################################################
241 | ## 3. 控制流程
242 | ####################################################
243 |
244 | # 新建一个变量
245 | some_var = 5
246 |
247 | # 这是个 if 语句,在 python 中缩进是很重要的。
248 | # 下面的代码片段将会输出 "some var is smaller than 10"
249 | if some_var > 10:
250 | print "some_var is totally bigger than 10."
251 | elif some_var < 10: # 这个 elif 语句是不必须的
252 | print "some_var is smaller than 10."
253 | else: # 这个 else 也不是必须的
254 | print "some_var is indeed 10."
255 |
256 |
257 | """
258 | 用for循环遍历列表
259 | 输出:
260 | dog is a mammal
261 | cat is a mammal
262 | mouse is a mammal
263 | """
264 | for animal in ["dog", "cat", "mouse"]:
265 | # 你可以用 % 来格式化字符串
266 | print "%s is a mammal" % animal
267 |
268 | """
269 | `range(number)` 返回从0到给定数字的列表
270 | 输出:
271 | 0
272 | 1
273 | 2
274 | 3
275 | """
276 | for i in range(4):
277 | print i
278 |
279 | """
280 | while 循环
281 | 输出:
282 | 0
283 | 1
284 | 2
285 | 3
286 | """
287 | x = 0
288 | while x < 4:
289 | print x
290 | x += 1 # x = x + 1 的简写
291 |
292 | # 用 try/except 块来处理异常
293 |
294 | # Python 2.6 及以上适用:
295 | try:
296 | # 用 raise 来抛出异常
297 | raise IndexError("This is an index error")
298 | except IndexError as e:
299 | pass # pass 就是什么都不做,不过通常这里会做一些恢复工作
300 |
301 |
302 | ####################################################
303 | ## 4. 函数
304 | ####################################################
305 |
306 | # 用 def 来新建函数
307 | def add(x, y):
308 | print "x is %s and y is %s" % (x, y)
309 | return x + y # 通过 return 来返回值
310 |
311 | # 调用带参数的函数
312 | add(5, 6) # => 输出 "x is 5 and y is 6" 返回 11
313 |
314 | # 通过关键字赋值来调用函数
315 | add(y=6, x=5) # 顺序是无所谓的
316 |
317 | # 我们也可以定义接受多个变量的函数,这些变量是按照顺序排列的
318 | def varargs(*args):
319 | return args
320 |
321 | varargs(1, 2, 3) # => (1,2,3)
322 |
323 |
324 | # 我们也可以定义接受多个变量的函数,这些变量是按照关键字排列的
325 | def keyword_args(**kwargs):
326 | return kwargs
327 |
328 | # 实际效果:
329 | keyword_args(big="foot", loch="ness") # => {"big": "foot", "loch": "ness"}
330 |
331 | # 你也可以同时将一个函数定义成两种形式
332 | def all_the_args(*args, **kwargs):
333 | print args
334 | print kwargs
335 | """
336 | all_the_args(1, 2, a=3, b=4) prints:
337 | (1, 2)
338 | {"a": 3, "b": 4}
339 | """
340 |
341 | # 当调用函数的时候,我们也可以进行相反的操作,把元组和字典展开为参数
342 | args = (1, 2, 3, 4)
343 | kwargs = {"a": 3, "b": 4}
344 | all_the_args(*args) # 等价于 foo(1, 2, 3, 4)
345 | all_the_args(**kwargs) # 等价于 foo(a=3, b=4)
346 | all_the_args(*args, **kwargs) # 等价于 foo(1, 2, 3, 4, a=3, b=4)
347 |
348 | # 函数在 python 中是一等公民
349 | def create_adder(x):
350 | def adder(y):
351 | return x + y
352 | return adder
353 |
354 | add_10 = create_adder(10)
355 | add_10(3) # => 13
356 |
357 | # 匿名函数
358 | (lambda x: x > 2)(3) # => True
359 |
360 | # 内置高阶函数
361 | map(add_10, [1, 2, 3]) # => [11, 12, 13]
362 | filter(lambda x: x > 5, [3, 4, 5, 6, 7]) # => [6, 7]
363 |
364 | # 可以用列表方法来对高阶函数进行更巧妙的引用
365 | [add_10(i) for i in [1, 2, 3]] # => [11, 12, 13]
366 | [x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7]
367 |
368 | ####################################################
369 | ## 5. 类
370 | ####################################################
371 |
372 | # 我们新建的类是从 object 类中继承的
373 | class Human(object):
374 |
375 | # 类属性,由所有类的对象共享
376 | species = "H. sapiens"
377 |
378 | # 基本构造函数
379 | def __init__(self, name):
380 | # 将参数赋给对象成员属性
381 | self.name = name
382 |
383 | # 成员方法,参数要有 self
384 | def say(self, msg):
385 | return "%s: %s" % (self.name, msg)
386 |
387 | # 类方法由所有类的对象共享
388 | # 这类方法在调用时,会把类本身传给第一个参数
389 | @classmethod
390 | def get_species(cls):
391 | return cls.species
392 |
393 | # 静态方法是不需要类和对象的引用就可以调用的方法
394 | @staticmethod
395 | def grunt():
396 | return "*grunt*"
397 |
398 |
399 | # 实例化一个类
400 | i = Human(name="Ian")
401 | print i.say("hi") # 输出 "Ian: hi"
402 |
403 | j = Human("Joel")
404 | print j.say("hello") # 输出 "Joel: hello"
405 |
406 | # 访问类的方法
407 | i.get_species() # => "H. sapiens"
408 |
409 | # 改变共享属性
410 | Human.species = "H. neanderthalensis"
411 | i.get_species() # => "H. neanderthalensis"
412 | j.get_species() # => "H. neanderthalensis"
413 |
414 | # 访问静态变量
415 | Human.grunt() # => "*grunt*"
416 |
417 |
418 | ####################################################
419 | ## 6. 模块
420 | ####################################################
421 |
422 | # 我们可以导入其他模块
423 | import math
424 | print math.sqrt(16) # => 4
425 |
426 | # 我们也可以从一个模块中导入特定的函数
427 | from math import ceil, floor
428 | print ceil(3.7) # => 4.0
429 | print floor(3.7) # => 3.0
430 |
431 | # 从模块中导入所有的函数
432 | # 警告:不推荐使用
433 | from math import *
434 |
435 | # 简写模块名
436 | import math as m
437 | math.sqrt(16) == m.sqrt(16) # => True
438 |
439 | # Python的模块其实只是普通的python文件
440 | # 你也可以创建自己的模块,并且导入它们
441 | # 模块的名字就和文件的名字相同
442 |
443 | # 也可以通过下面的方法查看模块中有什么属性和方法
444 | import math
445 | dir(math)
446 |
447 |
--------------------------------------------------------------------------------
/learnlua-cn.lua:
--------------------------------------------------------------------------------
1 |
2 | -- 单行注释以两个连字符开头
3 |
4 | --[[
5 | 多行注释
6 | --]]
7 |
8 | ----------------------------------------------------
9 | -- 1. 变量和流程控制
10 | ----------------------------------------------------
11 |
12 | num = 42 -- 所有的数字都是双精度浮点型。
13 | -- 别害怕,64位的双精度浮点型数字中有52位用于
14 | -- 保存精确的整型值; 对于52位以内的整型值,
15 | -- 不用担心精度问题。
16 |
17 | s = 'walternate' -- 和Python一样,字符串不可变。
18 | t = "也可以用双引号"
19 | u = [[ 多行的字符串
20 | 以两个方括号
21 | 开始和结尾。]]
22 | t = nil -- 撤销t的定义; Lua 支持垃圾回收。
23 |
24 | -- 块使用do/end之类的关键字标识:
25 | while num < 50 do
26 | num = num + 1 -- 不支持 ++ 或 += 运算符。
27 | end
28 |
29 | -- If语句:
30 | if num > 40 then
31 | print('over 40')
32 | elseif s ~= 'walternate' then -- ~= 表示不等于。
33 | -- 像Python一样,用 == 检查是否相等 ;字符串同样适用。
34 | io.write('not over 40\n') -- 默认标准输出。
35 | else
36 | -- 默认全局变量。
37 | thisIsGlobal = 5 -- 通常使用驼峰。
38 |
39 | -- 如何定义局部变量:
40 | local line = io.read() -- 读取标准输入的下一行。
41 |
42 | -- ..操作符用于连接字符串:
43 | print('Winter is coming, ' .. line)
44 | end
45 |
46 | -- 未定义的变量返回nil。
47 | -- 这不是错误:
48 | foo = anUnknownVariable -- 现在 foo = nil.
49 |
50 | aBoolValue = false
51 |
52 | --只有nil和false为假; 0和 ''均为真!
53 | if not aBoolValue then print('false') end
54 |
55 | -- 'or'和 'and'短路
56 | -- 类似于C/js里的 a?b:c 操作符:
57 | ans = aBoolValue and 'yes' or 'no' --> 'no'
58 |
59 | karlSum = 0
60 | for i = 1, 100 do -- 范围包含两端
61 | karlSum = karlSum + i
62 | end
63 |
64 | -- 使用 "100, 1, -1" 表示递减的范围:
65 | fredSum = 0
66 | for j = 100, 1, -1 do fredSum = fredSum + j end
67 |
68 | -- 通常,范围表达式为begin, end[, step].
69 |
70 | -- 循环的另一种结构:
71 | repeat
72 | print('the way of the future')
73 | num = num - 1
74 | until num == 0
75 |
76 | ----------------------------------------------------
77 | -- 2. 函数。
78 | ----------------------------------------------------
79 |
80 | function fib(n)
81 | if n < 2 then return 1 end
82 | return fib(n - 2) + fib(n - 1)
83 | end
84 |
85 | -- 支持闭包及匿名函数:
86 | function adder(x)
87 | -- 调用adder时,会创建返回的函数,
88 | -- 并且会记住x的值:
89 | return function (y) return x + y end
90 | end
91 | a1 = adder(9)
92 | a2 = adder(36)
93 | print(a1(16)) --> 25
94 | print(a2(64)) --> 100
95 |
96 | -- 返回值、函数调用和赋值都可以
97 | -- 使用长度不匹配的list。
98 | -- 不匹配的接收方会被赋值nil;
99 | -- 不匹配的发送方会被丢弃。
100 |
101 | x, y, z = 1, 2, 3, 4
102 | -- x = 1、y = 2、z = 3, 而 4 会被丢弃。
103 |
104 | function bar(a, b, c)
105 | print(a, b, c)
106 | return 4, 8, 15, 16, 23, 42
107 | end
108 |
109 | x, y = bar('zaphod') --> 打印 "zaphod nil nil"
110 | -- 现在 x = 4, y = 8, 而值15..42被丢弃。
111 |
112 | -- 函数是一等公民,可以是局部的,也可以是全局的。
113 | -- 以下表达式等价:
114 | function f(x) return x * x end
115 | f = function (x) return x * x end
116 |
117 | -- 这些也是等价的:
118 | local function g(x) return math.sin(x) end
119 | local g; g = function (x) return math.sin(x) end
120 | -- 'local g'使得g可以自引用。
121 |
122 | -- 顺便提下,三角函数以弧度为单位。
123 |
124 | -- 用一个字符串参数调用函数,可以省略括号:
125 | print 'hello' --可以工作。
126 |
127 | -- 调用函数时,如果只有一个table参数,
128 | -- 同样可以省略括号(table详情见下):
129 | print {} -- 一样可以工作。
130 |
131 | ----------------------------------------------------
132 | -- 3. Table。
133 | ----------------------------------------------------
134 |
135 | -- Table = Lua唯一的组合数据结构;
136 | -- 它们是关联数组。
137 | -- 类似于PHP的数组或者js的对象,
138 | -- 它们是哈希表或者字典,也可以当列表使用。
139 |
140 | -- 按字典/map的方式使用Table:
141 |
142 | -- Dict字面量默认使用字符串类型的key:
143 | t = {key1 = 'value1', key2 = false}
144 |
145 | -- 字符串key可以使用类似js的点标记:
146 | print(t.key1) -- 打印 'value1'.
147 | t.newKey = {} -- 添加新的键值对。
148 | t.key2 = nil -- 从table删除 key2。
149 |
150 | -- 使用任何非nil的值作为key:
151 | u = {['@!#'] = 'qbert', [{}] = 1729, [6.28] = 'tau'}
152 | print(u[6.28]) -- 打印 "tau"
153 |
154 | -- 数字和字符串的key按值匹配的
155 | -- table按id匹配。
156 | a = u['@!#'] -- 现在 a = 'qbert'.
157 | b = u[{}] -- 我们或许期待的是 1729, 但是得到的是nil:
158 | -- b = nil ,因为没有找到。
159 | -- 之所以没找到,是因为我们用的key与保存数据时用的不是同
160 | -- 一个对象。
161 | -- 所以字符串和数字是移植性更好的key。
162 |
163 | -- 只需要一个table参数的函数调用不需要括号:
164 | function h(x) print(x.key1) end
165 | h{key1 = 'Sonmi~451'} -- 打印'Sonmi~451'.
166 |
167 | for key, val in pairs(u) do -- 遍历Table
168 | print(key, val)
169 | end
170 |
171 | -- _G 是一个特殊的table,用于保存所有的全局变量
172 | print(_G['_G'] == _G) -- 打印'true'.
173 |
174 | -- 按列表/数组的方式使用:
175 |
176 | -- 列表字面量隐式添加整数键:
177 | v = {'value1', 'value2', 1.21, 'gigawatts'}
178 | for i = 1, #v do -- #v 是列表的大小
179 | print(v[i]) -- 索引从 1 开始!! 太疯狂了!
180 | end
181 | -- 'list'并非真正的类型,v 其实是一个table,
182 | -- 只不过它用连续的整数作为key,可以像list那样去使用。
183 |
184 | ----------------------------------------------------
185 | -- 3.1 元表(metatable) 和元方法(metamethod)。
186 | ----------------------------------------------------
187 |
188 | -- table的元表提供了一种机制,支持类似操作符重载的行为。
189 | -- 稍后我们会看到元表如何支持类似js prototype的行为。
190 |
191 | f1 = {a = 1, b = 2} -- 表示一个分数 a/b.
192 | f2 = {a = 2, b = 3}
193 |
194 | -- 这会失败:
195 | -- s = f1 + f2
196 |
197 | metafraction = {}
198 | function metafraction.__add(f1, f2)
199 | sum = {}
200 | sum.b = f1.b * f2.b
201 | sum.a = f1.a * f2.b + f2.a * f1.b
202 | return sum
203 | end
204 |
205 | setmetatable(f1, metafraction)
206 | setmetatable(f2, metafraction)
207 |
208 | s = f1 + f2 -- 调用在f1的元表上的__add(f1, f2) 方法
209 |
210 | -- f1, f2 没有关于元表的key,这点和js的prototype不一样。
211 | -- 因此你必须用getmetatable(f1)获取元表。
212 | -- 元表是一个普通的table,
213 | -- 元表的key是普通的Lua中的key,例如__add。
214 |
215 | -- 但是下面一行代码会失败,因为s没有元表:
216 | -- t = s + s
217 | -- 下面提供的与类相似的模式可以解决这个问题:
218 |
219 | -- 元表的__index 可以重载用于查找的点操作符:
220 | defaultFavs = {animal = 'gru', food = 'donuts'}
221 | myFavs = {food = 'pizza'}
222 | setmetatable(myFavs, {__index = defaultFavs})
223 | eatenBy = myFavs.animal -- 可以工作!感谢元表
224 |
225 | -- 如果在table中直接查找key失败,会使用
226 | -- 元表的__index 递归地重试。
227 |
228 | -- __index的值也可以是function(tbl, key)
229 | -- 这样可以支持自定义查找。
230 |
231 | -- __index、__add等的值,被称为元方法。
232 | -- 这里是一个table元方法的清单:
233 |
234 | -- __add(a, b) for a + b
235 | -- __sub(a, b) for a - b
236 | -- __mul(a, b) for a * b
237 | -- __div(a, b) for a / b
238 | -- __mod(a, b) for a % b
239 | -- __pow(a, b) for a ^ b
240 | -- __unm(a) for -a
241 | -- __concat(a, b) for a .. b
242 | -- __len(a) for #a
243 | -- __eq(a, b) for a == b
244 | -- __lt(a, b) for a < b
245 | -- __le(a, b) for a <= b
246 | -- __index(a, b) for a.b
247 | -- __newindex(a, b, c) for a.b = c
248 | -- __call(a, ...) for a(...)
249 |
250 | ----------------------------------------------------
251 | -- 3.2 与类相似的table和继承。
252 | ----------------------------------------------------
253 |
254 | -- Lua没有内建的类;可以通过不同的方法,利用表和元表
255 | -- 来实现类。
256 |
257 | -- 下面是一个例子,解释在后面:
258 |
259 | Dog = {} -- 1.
260 |
261 | function Dog:new() -- 2.
262 | newObj = {sound = 'woof'} -- 3.
263 | self.__index = self -- 4.
264 | return setmetatable(newObj, self) -- 5.
265 | end
266 |
267 | function Dog:makeSound() -- 6.
268 | print('I say ' .. self.sound)
269 | end
270 |
271 | mrDog = Dog:new() -- 7.
272 | mrDog:makeSound() -- 'I say woof' -- 8.
273 |
274 | -- 1. Dog看上去像一个类;其实它是一个table。
275 | -- 2. 函数tablename:fn(...) 等价于
276 | -- 函数tablename.fn(self, ...)
277 | -- 冒号(:)只是添加了self作为第一个参数。
278 | -- 阅读7 & 8条 了解self变量是如何得到其值的。
279 | -- 3. newObj是类Dog的一个实例。
280 | -- 4. self = 被继承的类。通常self = Dog,不过继承可以改变它。
281 | -- 如果把newObj的元表和__index都设置为self,
282 | -- newObj就可以得到self的函数。
283 | -- 5. 备忘:setmetatable返回其第一个参数。
284 | -- 6. 冒号(:)的作用和第2条一样,不过这里
285 | -- self是一个实例,而不是类
286 | -- 7. 等价于Dog.new(Dog),所以在new()中,self = Dog。
287 | -- 8. 等价于mrDog.makeSound(mrDog); self = mrDog。
288 |
289 | ----------------------------------------------------
290 |
291 | -- 继承的例子:
292 |
293 | LoudDog = Dog:new() -- 1.
294 |
295 | function LoudDog:makeSound()
296 | s = self.sound .. ' ' -- 2.
297 | print(s .. s .. s)
298 | end
299 |
300 | seymour = LoudDog:new() -- 3.
301 | seymour:makeSound() -- 'woof woof woof' -- 4.
302 |
303 | -- 1. LoudDog获得Dog的方法和变量列表。
304 | -- 2. 因为new()的缘故,self拥有了一个'sound' key,参见第3条。
305 | -- 3. 等价于LoudDog.new(LoudDog),转换一下就是
306 | -- Dog.new(LoudDog),这是因为LoudDog没有'new' key,
307 | -- 但是它的元表中有 __index = Dog。
308 | -- 结果: seymour的元表是LoudDog,并且
309 | -- LoudDog.__index = Dog。所以有seymour.key
310 | -- = seymour.key, LoudDog.key, Dog.key
311 | -- 从其中第一个有指定key的table获取。
312 | -- 4. 在LoudDog可以找到'makeSound'的key;
313 | -- 等价于LoudDog.makeSound(seymour)。
314 |
315 | -- 如果有必要,子类也可以有new(),与基类相似:
316 | function LoudDog:new()
317 | newObj = {}
318 | -- 初始化newObj
319 | self.__index = self
320 | return setmetatable(newObj, self)
321 | end
322 |
323 | ----------------------------------------------------
324 | -- 4. 模块
325 | ----------------------------------------------------
326 |
327 |
328 | --[[ 我把这部分给注释了,这样脚本剩下的部分可以运行
329 |
330 | -- 假设文件mod.lua的内容类似这样:
331 | local M = {}
332 |
333 | local function sayMyName()
334 | print('Hrunkner')
335 | end
336 |
337 | function M.sayHello()
338 | print('Why hello there')
339 | sayMyName()
340 | end
341 |
342 | return M
343 |
344 | -- 另一个文件可以使用mod.lua的功能:
345 | local mod = require('mod') -- 运行文件mod.lua.
346 |
347 | -- require是包含模块的标准做法。
348 | -- require等价于: (针对没有被缓存的情况;参见后面的内容)
349 | local mod = (function ()
350 |
351 | end)()
352 | -- mod.lua被包在一个函数体中,因此mod.lua的局部变量
353 | -- 对外不可见。
354 |
355 | -- 下面的代码可以工作,因为在这里mod = mod.lua 中的 M:
356 | mod.sayHello() -- Says hello to Hrunkner.
357 |
358 | -- 这是错误的;sayMyName只在mod.lua中存在:
359 | mod.sayMyName() -- 错误
360 |
361 | -- require返回的值会被缓存,所以一个文件只会被运行一次,
362 | -- 即使它被require了多次。
363 |
364 | -- 假设mod2.lua包含代码"print('Hi!')"。
365 | local a = require('mod2') -- 打印Hi!
366 | local b = require('mod2') -- 不再打印; a=b.
367 |
368 | -- dofile与require类似,但是不缓存:
369 | dofile('mod2') --> Hi!
370 | dofile('mod2') --> Hi! (再次运行,与require不同)
371 |
372 | -- loadfile加载一个lua文件,但是并不运行它。
373 | f = loadfile('mod2') -- Calling f() runs mod2.lua.
374 |
375 | -- loadstring是loadfile的字符串版本。
376 | g = loadstring('print(343)') --返回一个函数。
377 | g() -- 打印343; 在此之前什么也不打印。
378 |
379 | --]]
380 |
--------------------------------------------------------------------------------
/learnr-cn.r:
--------------------------------------------------------------------------------
1 |
2 | # 评论以 # 开始
3 |
4 | # R 语言原生不支持 多行注释
5 | # 但是你可以像这样来多行注释
6 |
7 | # 在窗口里按回车键可以执行一条命令
8 |
9 |
10 | ###################################################################
11 | # 不用懂编程就可以开始动手了
12 | ###################################################################
13 |
14 | data() # 浏览内建的数据集
15 | data(rivers) # 北美主要河流的长度(数据集)
16 | ls() # 在工作空间中查看「河流」是否出现
17 | head(rivers) # 撇一眼数据集
18 | # 735 320 325 392 524 450
19 | length(rivers) # 我们测量了多少条河流?
20 | # 141
21 | summary(rivers)
22 | # Min. 1st Qu. Median Mean 3rd Qu. Max.
23 | # 135.0 310.0 425.0 591.2 680.0 3710.0
24 | stem(rivers) # 茎叶图(一种类似于直方图的展现形式)
25 | #
26 | # The decimal point is 2 digit(s) to the right of the |
27 | #
28 | # 0 | 4
29 | # 2 | 011223334555566667778888899900001111223333344455555666688888999
30 | # 4 | 111222333445566779001233344567
31 | # 6 | 000112233578012234468
32 | # 8 | 045790018
33 | # 10 | 04507
34 | # 12 | 1471
35 | # 14 | 56
36 | # 16 | 7
37 | # 18 | 9
38 | # 20 |
39 | # 22 | 25
40 | # 24 | 3
41 | # 26 |
42 | # 28 |
43 | # 30 |
44 | # 32 |
45 | # 34 |
46 | # 36 | 1
47 |
48 |
49 | stem(log(rivers)) # 查看数据集的方式既不是标准形式,也不是取log后的结果! 看起来,是钟形曲线形式的基本数据集
50 |
51 | # The decimal point is 1 digit(s) to the left of the |
52 | #
53 | # 48 | 1
54 | # 50 |
55 | # 52 | 15578
56 | # 54 | 44571222466689
57 | # 56 | 023334677000124455789
58 | # 58 | 00122366666999933445777
59 | # 60 | 122445567800133459
60 | # 62 | 112666799035
61 | # 64 | 00011334581257889
62 | # 66 | 003683579
63 | # 68 | 0019156
64 | # 70 | 079357
65 | # 72 | 89
66 | # 74 | 84
67 | # 76 | 56
68 | # 78 | 4
69 | # 80 |
70 | # 82 | 2
71 |
72 |
73 | hist(rivers, col="#333333", border="white", breaks=25) # 试试用这些参数画画 (译者注:给 river 做统计频数直方图,包含了这些参数:数据源,颜色,边框,空格)
74 | hist(log(rivers), col="#333333", border="white", breaks=25) #你还可以做更多式样的绘图
75 |
76 | # 还有其他一些简单的数据集可以被用来加载。R 语言包括了大量这种 data()
77 | data(discoveries)
78 | plot(discoveries, col="#333333", lwd=3, xlab="Year", main="Number of important discoveries per year")
79 | # 译者注:参数为(数据源,颜色,线条宽度,X 轴名称,标题)
80 | plot(discoveries, col="#333333", lwd=3, type = "h", xlab="Year", main="Number of important discoveries per year")
81 |
82 |
83 | # 除了按照默认的年份排序,我们还可以排序来发现特征
84 | sort(discoveries)
85 | # [1] 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2
86 | # [26] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3
87 | # [51] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4
88 | # [76] 4 4 4 4 5 5 5 5 5 5 5 6 6 6 6 6 6 7 7 7 7 8 9 10 12
89 |
90 | stem(discoveries, scale=2) # 译者注:茎叶图(数据,放大系数)
91 | #
92 | # The decimal point is at the |
93 | #
94 | # 0 | 000000000
95 | # 1 | 000000000000
96 | # 2 | 00000000000000000000000000
97 | # 3 | 00000000000000000000
98 | # 4 | 000000000000
99 | # 5 | 0000000
100 | # 6 | 000000
101 | # 7 | 0000
102 | # 8 | 0
103 | # 9 | 0
104 | # 10 | 0
105 | # 11 |
106 | # 12 | 0
107 |
108 | max(discoveries)
109 | # 12
110 |
111 | summary(discoveries)
112 | # Min. 1st Qu. Median Mean 3rd Qu. Max.
113 | # 0.0 2.0 3.0 3.1 4.0 12.0
114 |
115 |
116 |
117 |
118 | #基本的统计学操作也不需要任何编程知识
119 |
120 | #随机生成数据
121 | round(runif(7, min=.5, max=6.5))
122 | # 译者注:runif 产生随机数,round 四舍五入
123 | # 1 4 6 1 4 6 4
124 |
125 | # 你输出的结果会和我们给出的不同,除非我们设置了相同的随机种子 random.seed(31337)
126 |
127 |
128 | #从标准高斯函数中随机生成 9 次
129 | rnorm(9)
130 | # [1] 0.07528471 1.03499859 1.34809556 -0.82356087 0.61638975 -1.88757271
131 | # [7] -0.59975593 0.57629164 1.08455362
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 | #########################
142 | # 基础编程
143 | #########################
144 |
145 | # 数值
146 |
147 | #“数值”指的是双精度的浮点数
148 | 5 # 5
149 | class(5) # "numeric"
150 | 5e4 # 50000 # 用科学技术法方便的处理极大值、极小值或者可变的量级
151 | 6.02e23 # 阿伏伽德罗常数#
152 | 1.6e-35 # 布朗克长度
153 |
154 | # 长整数并用 L 结尾
155 | 5L # 5
156 | #输出5L
157 | class(5L) # "integer"
158 |
159 | # 可以自己试一试?用 class() 函数获取更多信息
160 | # 事实上,你可以找一些文件查阅 `xyz` 以及xyz的差别
161 | # `xyz` 用来查看源码实现,?xyz 用来看帮助
162 |
163 | # 算法
164 | 10 + 66 # 76
165 | 53.2 - 4 # 49.2
166 | 2 * 2.0 # 4
167 | 3L / 4 # 0.75
168 | 3 %% 2 # 1
169 |
170 | # 特殊数值类型
171 | class(NaN) # "numeric"
172 | class(Inf) # "numeric"
173 | class(-Inf) # "numeric" # 在以下场景中会用到 integrate( dnorm(x), 3, Inf ) -- 消除 Z 轴数据
174 |
175 | # 但要注意,NaN 并不是唯一的特殊数值类型……
176 | class(NA) # 看上面
177 | class(NULL) # NULL
178 |
179 |
180 | # 简单列表
181 | c(6, 8, 7, 5, 3, 0, 9) # 6 8 7 5 3 0 9
182 | c('alef', 'bet', 'gimmel', 'dalet', 'he')
183 | c('Z', 'o', 'r', 'o') == "Zoro" # FALSE FALSE FALSE FALSE
184 |
185 | # 一些优雅的内置功能
186 | 5:15 # 5 6 7 8 9 10 11 12 13 14 15
187 |
188 | seq(from=0, to=31337, by=1337)
189 | # [1] 0 1337 2674 4011 5348 6685 8022 9359 10696 12033 13370 14707
190 | # [13] 16044 17381 18718 20055 21392 22729 24066 25403 26740 28077 29414 30751
191 |
192 | letters
193 | # [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s"
194 | # [20] "t" "u" "v" "w" "x" "y" "z"
195 |
196 | month.abb # "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec"
197 |
198 |
199 | # Access the n'th element of a list with list.name[n] or sometimes list.name[[n]]
200 | # 使用 list.name[n] 来访问第 n 个列表元素,有时候需要使用 list.name[[n]]
201 | letters[18] # "r"
202 | LETTERS[13] # "M"
203 | month.name[9] # "September"
204 | c(6, 8, 7, 5, 3, 0, 9)[3] # 7
205 |
206 |
207 |
208 | # 字符串
209 |
210 | # 字符串和字符在 R 语言中没有区别
211 | "Horatio" # "Horatio"
212 | class("Horatio") # "character"
213 | substr("Fortuna multis dat nimis, nulli satis.", 9, 15) # "multis "
214 | gsub('u', 'ø', "Fortuna multis dat nimis, nulli satis.") # "Fortøna møltis dat nimis, nølli satis."
215 |
216 |
217 |
218 | # 逻辑值
219 |
220 | # 布尔值
221 | class(TRUE) # "logical"
222 | class(FALSE) # "logical"
223 | # 和我们预想的一样
224 | TRUE == TRUE # TRUE
225 | TRUE == FALSE # FALSE
226 | FALSE != FALSE # FALSE
227 | FALSE != TRUE # TRUE
228 | # 缺失数据(NA)也是逻辑值
229 | class(NA) # "logical"
230 | #定义NA为逻辑型
231 |
232 |
233 |
234 | # 因子
235 | # 因子是为数据分类排序设计的(像是排序小朋友们的年级或性别)
236 | levels(factor(c("female", "male", "male", "female", "NA", "female"))) # "female" "male" "NA"
237 |
238 | factor(c("female", "female", "male", "NA", "female"))
239 | # female female male NA female
240 | # Levels: female male NA
241 |
242 | data(infert) # 自然以及引产导致的不育症
243 | levels(infert$education) # "0-5yrs" "6-11yrs" "12+ yrs"
244 |
245 |
246 |
247 | # 变量
248 |
249 | # 有许多种方式用来赋值
250 | x = 5 # 这样可以
251 | y <- "1" # 更推荐这样
252 | TRUE -> z # 这样可行,但是很怪
253 |
254 | #我们还可以使用强制转型
255 | as.numeric(y) # 1
256 | as.character(x) # "5"
257 |
258 | # 循环
259 |
260 | # for 循环语句
261 | for (i in 1:4) {
262 | print(i)
263 | }
264 |
265 | # while 循环
266 | a <- 10
267 | while (a > 4) {
268 | cat(a, "...", sep = "")
269 | a <- a - 1
270 | }
271 |
272 | # 记住,在 R 语言中 for / while 循环都很慢
273 | # 建议使用 apply()(我们一会介绍)来错做一串数据(比如一列或者一行数据)
274 |
275 | # IF/ELSE
276 |
277 | # 再来看这些优雅的标准
278 | if (4 > 3) {
279 | print("Huzzah! It worked!")
280 | } else {
281 | print("Noooo! This is blatantly illogical!")
282 | }
283 |
284 | # =>
285 | # [1] "Huzzah! It worked!"
286 |
287 | # 函数
288 |
289 | # 定义如下
290 | jiggle <- function(x) {
291 | x + rnorm(x, sd=.1) #add in a bit of (controlled) noise
292 | return(x)
293 | }
294 |
295 | # 和其他 R 语言函数一样调用
296 | jiggle(5) # 5±ε. 使用 set.seed(2716057) 后, jiggle(5)==5.005043
297 |
298 | #########################
299 | # 数据容器:vectors, matrices, data frames, and arrays
300 | #########################
301 |
302 | # 单维度
303 | # 你可以将目前我们学习到的任何类型矢量化,只要它们拥有相同的类型
304 | vec <- c(8, 9, 10, 11)
305 | vec # 8 9 10 11
306 | # 矢量的类型是这一组数据元素的类型
307 | class(vec) # "numeric"
308 | # If you vectorize items of different classes, weird coercions happen
309 | #如果你强制的将不同类型数值矢量化,会出现特殊值
310 | c(TRUE, 4) # 1 4
311 | c("dog", TRUE, 4) # "dog" "TRUE" "4"
312 |
313 | #我们这样来取内部数据,(R 的下标索引顺序 1 开始)
314 | vec[1] # 8
315 | # 我们可以根据条件查找特定数据
316 | which(vec %% 2 == 0) # 1 3
317 | # 抓取矢量中第一个和最后一个字符
318 | head(vec, 1) # 8
319 | tail(vec, 1) # 11
320 | #如果下标溢出或不存会得到 NA
321 | vec[6] # NA
322 | # 你可以使用 length() 获取矢量的长度
323 | length(vec) # 4
324 |
325 | # 你可以直接操作矢量或者矢量的子集
326 | vec * 4 # 16 20 24 28
327 | vec[2:3] * 5 # 25 30
328 | # 这里有许多内置的函数,来表现向量
329 | mean(vec) # 9.5
330 | var(vec) # 1.666667
331 | sd(vec) # 1.290994
332 | max(vec) # 11
333 | min(vec) # 8
334 | sum(vec) # 38
335 |
336 | # 二维(相同元素类型)
337 |
338 | #你可以为同样类型的变量建立矩阵
339 | mat <- matrix(nrow = 3, ncol = 2, c(1,2,3,4,5,6))
340 | mat
341 | # =>
342 | # [,1] [,2]
343 | # [1,] 1 4
344 | # [2,] 2 5
345 | # [3,] 3 6
346 | # 和 vector 不一样的是,一个矩阵的类型真的是 「matrix」,而不是内部元素的类型
347 | class(mat) # => "matrix"
348 | # 访问第一行的字符
349 | mat[1,] # 1 4
350 | # 操作第一行数据
351 | 3 * mat[,1] # 3 6 9
352 | # 访问一个特定数据
353 | mat[3,2] # 6
354 | # 转置整个矩阵(译者注:变成 2 行 3 列)
355 | t(mat)
356 | # =>
357 | # [,1] [,2] [,3]
358 | # [1,] 1 2 3
359 | # [2,] 4 5 6
360 |
361 | # 使用 cbind() 函数把两个矩阵按列合并,形成新的矩阵
362 | mat2 <- cbind(1:4, c("dog", "cat", "bird", "dog"))
363 | mat2
364 | # =>
365 | # [,1] [,2]
366 | # [1,] "1" "dog"
367 | # [2,] "2" "cat"
368 | # [3,] "3" "bird"
369 | # [4,] "4" "dog"
370 | class(mat2) # matrix
371 | # Again, note what happened!
372 | # 注意
373 | # 因为矩阵内部元素必须包含同样的类型
374 | # 所以现在每一个元素都转化成字符串
375 | c(class(mat2[,1]), class(mat2[,2]))
376 |
377 | # 按行合并两个向量,建立新的矩阵
378 | mat3 <- rbind(c(1,2,4,5), c(6,7,0,4))
379 | mat3
380 | # =>
381 | # [,1] [,2] [,3] [,4]
382 | # [1,] 1 2 4 5
383 | # [2,] 6 7 0 4
384 | # 哈哈,数据类型都一样的,没有发生强制转换,生活真美好
385 |
386 | # 二维(不同的元素类型)
387 |
388 | # 利用 data frame 可以将不同类型数据放在一起
389 | dat <- data.frame(c(5,2,1,4), c("dog", "cat", "bird", "dog"))
390 | names(dat) <- c("number", "species") # 给数据列命名
391 | class(dat) # "data.frame"
392 | dat
393 | # =>
394 | # number species
395 | # 1 5 dog
396 | # 2 2 cat
397 | # 3 1 bird
398 | # 4 4 dog
399 | class(dat$number) # "numeric"
400 | class(dat[,2]) # "factor"
401 | # data.frame() 会将字符向量转换为 factor 向量
402 |
403 | # 有很多精妙的方法来获取 data frame 的子数据集
404 | dat$number # 5 2 1 4
405 | dat[,1] # 5 2 1 4
406 | dat[,"number"] # 5 2 1 4
407 |
408 | # 多维(相同元素类型)
409 |
410 | # 使用 arry 创造一个 n 维的表格
411 | # You can make a two-dimensional table (sort of like a matrix)
412 | # 你可以建立一个 2 维表格(有点像矩阵)
413 | array(c(c(1,2,4,5),c(8,9,3,6)), dim=c(2,4))
414 | # =>
415 | # [,1] [,2] [,3] [,4]
416 | # [1,] 1 4 8 3
417 | # [2,] 2 5 9 6
418 | #你也可以利用数组建立一个三维的矩阵
419 | array(c(c(c(2,300,4),c(8,9,0)),c(c(5,60,0),c(66,7,847))), dim=c(3,2,2))
420 | # =>
421 | # , , 1
422 | #
423 | # [,1] [,2]
424 | # [1,] 2 8
425 | # [2,] 300 9
426 | # [3,] 4 0
427 | #
428 | # , , 2
429 | #
430 | # [,1] [,2]
431 | # [1,] 5 66
432 | # [2,] 60 7
433 | # [3,] 0 847
434 |
435 | #列表(多维的,不同类型的)
436 |
437 | # R语言有列表的形式
438 | list1 <- list(time = 1:40)
439 | list1$price = c(rnorm(40,.5*list1$time,4)) # 随机
440 | list1
441 |
442 | # You can get items in the list like so
443 | # 你可以这样获得列表的元素
444 | list1$time
445 | # You can subset list items like vectors
446 | # 你也可以和矢量一样获取他们的子集
447 | list1$price[4]
448 |
449 | #########################
450 | # apply()函数家族
451 | #########################
452 |
453 | # 还记得 mat 么?
454 | mat
455 | # =>
456 | # [,1] [,2]
457 | # [1,] 1 4
458 | # [2,] 2 5
459 | # [3,] 3 6
460 | # Use apply(X, MARGIN, FUN) to apply function FUN to a matrix X
461 | # 使用(X, MARGIN, FUN)将函数 FUN 应用到矩阵 X 的行 (MAR = 1) 或者 列 (MAR = 2)
462 | # That is, R does FUN to each row (or column) of X, much faster than a
463 | # R 在 X 的每一行/列使用 FUN,比循环要快很多
464 | apply(mat, MAR = 2, myFunc)
465 | # =>
466 | # [,1] [,2]
467 | # [1,] 3 15
468 | # [2,] 7 19
469 | # [3,] 11 23
470 | # 还有其他家族函数 ?lapply, ?sapply
471 |
472 | # 不要被吓到,虽然许多人在此都被搞混
473 | # plyr 程序包的作用是用来改进 apply() 函数家族
474 |
475 | install.packages("plyr")
476 | require(plyr)
477 | ?plyr
478 |
479 | #########################
480 | # 载入数据
481 | #########################
482 |
483 | # "pets.csv" 是网上的一个文本
484 | pets <- read.csv("http://learnxinyminutes.com/docs/pets.csv")
485 | pets
486 | head(pets, 2) # 前两行
487 | tail(pets, 1) # 最后一行
488 |
489 | # 以 .csv 格式来保存数据集或者矩阵
490 | write.csv(pets, "pets2.csv") # 保存到新的文件 pets2.csv
491 | # set working directory with setwd(), look it up with getwd()
492 | # 使用 setwd() 改变工作目录,使用 getwd() 查看当前工作目录
493 |
494 | # 尝试使用 ?read.csv 和 ?write.csv 来查看更多信息
495 |
496 | #########################
497 | # 画图
498 | #########################
499 |
500 | # 散点图
501 | plot(list1$time, list1$price, main = "fake data") # 译者注:横轴 list1$time,纵轴 wlist1$price,标题 fake data
502 | # 回归图
503 | linearModel <- lm(price ~ time, data = list1) # 译者注:线性模型,数据集为list1,以价格对时间做相关分析模型
504 | linearModel # 拟合结果
505 | # 将拟合结果展示在图上,颜色设为红色
506 | abline(linearModel, col = "red")
507 | # 也可以获取各种各样漂亮的分析图
508 | plot(linearModel)
509 |
510 | # 直方图
511 | hist(rpois(n = 10000, lambda = 5), col = "thistle") # 译者注:统计频数直方图
512 |
513 | # 柱状图
514 | barplot(c(1,4,5,1,2), names.arg = c("red","blue","purple","green","yellow"))
515 |
516 | # 可以尝试着使用 ggplot2 程序包来美化图片
517 | install.packages("ggplot2")
518 | require(ggplot2)
519 | ?ggplot2
520 |
--------------------------------------------------------------------------------
/learnphp-cn.php:
--------------------------------------------------------------------------------
1 |
2 | 之中
3 |
4 | // 如果你的文件中只有php代码,那么最好省略结束括号标记
5 |
6 | // 这是单行注释的标志
7 |
8 | # 井号也可以,但是//更常见
9 |
10 | /*
11 | 这是多行注释
12 | */
13 |
14 | // 使用 "echo" 或者 "print" 来输出信息到标准输出
15 | print('Hello '); // 输出 "Hello " 并且没有换行符
16 |
17 | // () 对于echo和print是可选的
18 | echo "World\n"; // 输出 "World" 并且换行
19 | // (每个语句必须以分号结尾)
20 |
21 | // 在 Hello World Again!
23 | 12
39 | $int2 = -12; // => -12
40 | $int3 = 012; // => 10 (0开头代表八进制数)
41 | $int4 = 0x0F; // => 15 (0x开头代表十六进制数)
42 |
43 | // 浮点型 (即双精度浮点型)
44 | $float = 1.234;
45 | $float = 1.2e3;
46 | $float = 7E-10;
47 |
48 | // 算数运算
49 | $sum = 1 + 1; // 2
50 | $difference = 2 - 1; // 1
51 | $product = 2 * 2; // 4
52 | $quotient = 2 / 1; // 2
53 |
54 | // 算数运算的简写
55 | $number = 0;
56 | $number += 1; // $number 自增1
57 | echo $number++; // 输出1 (运算后自增)
58 | echo ++$number; // 输出3 (自增后运算)
59 | $number /= $float; // 先除后赋值给 $number
60 |
61 | // 字符串需要被包含在单引号之中
62 | $sgl_quotes = '$String'; // => '$String'
63 |
64 | // 如果需要在字符串中引用变量,就需要使用双引号
65 | $dbl_quotes = "This is a $sgl_quotes."; // => 'This is a $String.'
66 |
67 | // 特殊字符只有在双引号中有用
68 | $escaped = "This contains a \t tab character.";
69 | $unescaped = 'This just contains a slash and a t: \t';
70 |
71 | // 可以把变量包含在一对大括号中
72 | $money = "I have $${number} in the bank.";
73 |
74 | // 自 PHP 5.3 开始, nowdocs 可以被用作多行非计算型字符串
75 | $nowdoc = <<<'END'
76 | Multi line
77 | string
78 | END;
79 |
80 | // 而Heredocs则可以用作多行计算型字符串
81 | $heredoc = << 1, 'Two' => 2, 'Three' => 3);
98 |
99 | // PHP 5.4 中引入了新的语法
100 | $associative = ['One' => 1, 'Two' => 2, 'Three' => 3];
101 |
102 | echo $associative['One']; // 输出 1
103 |
104 | // 声明为列表实际上是给每个值都分配了一个整数键(key)
105 | $array = ['One', 'Two', 'Three'];
106 | echo $array[0]; // => "One"
107 |
108 |
109 | /********************************
110 | * 输出
111 | */
112 |
113 | echo('Hello World!');
114 | // 输出到标准输出
115 | // 此时标准输出就是浏览器中的网页
116 |
117 | print('Hello World!'); // 和echo相同
118 |
119 | // echo和print实际上也属于这个语言本身,所以我们省略括号
120 | echo 'Hello World!';
121 | print 'Hello World!';
122 |
123 | $paragraph = 'paragraph';
124 |
125 | echo 100; // 直接输出标量
126 | echo $paragraph; // 或者输出变量
127 |
128 | // 如果你配置了短标签,或者使用5.4.0及以上的版本
129 | // 你就可以使用简写的echo语法
130 | ?>
131 | = $paragraph ?>
132 | 2
142 | echo $z; // => 2
143 | $y = 0;
144 | echo $x; // => 2
145 | echo $z; // => 0
146 |
147 |
148 | /********************************
149 | * 逻辑
150 | */
151 | $a = 0;
152 | $b = '0';
153 | $c = '1';
154 | $d = '1';
155 |
156 | // 如果assert的参数为假,就会抛出警告
157 |
158 | // 下面的比较都为真,不管它们的类型是否匹配
159 | assert($a == $b); // 相等
160 | assert($c != $a); // 不等
161 | assert($c <> $a); // 另一种不等的表示
162 | assert($a < $c);
163 | assert($c > $b);
164 | assert($a <= $b);
165 | assert($c >= $d);
166 |
167 | // 下面的比较只有在类型相同、值相同的情况下才为真
168 | assert($c === $d);
169 | assert($a !== $d);
170 | assert(1 === '1');
171 | assert(1 !== '1');
172 |
173 | // 变量可以根据其使用来进行类型转换
174 |
175 | $integer = 1;
176 | echo $integer + $integer; // => 2
177 |
178 | $string = '1';
179 | echo $string + $string; // => 2 (字符串在此时被转化为整数)
180 |
181 | $string = 'one';
182 | echo $string + $string; // => 0
183 | // 输出0,因为'one'这个字符串无法被转换为整数
184 |
185 | // 类型转换可以将一个类型视作另一种类型
186 |
187 | $boolean = (boolean) 1; // => true
188 |
189 | $zero = 0;
190 | $boolean = (boolean) $zero; // => false
191 |
192 | // 还有一些专用的函数来进行类型转换
193 | $integer = 5;
194 | $string = strval($integer);
195 |
196 | $var = null; // 空值
197 |
198 |
199 | /********************************
200 | * 控制结构
201 | */
202 |
203 | if (true) {
204 | print 'I get printed';
205 | }
206 |
207 | if (false) {
208 | print 'I don\'t';
209 | } else {
210 | print 'I get printed';
211 | }
212 |
213 | if (false) {
214 | print 'Does not get printed';
215 | } elseif(true) {
216 | print 'Does';
217 | }
218 |
219 | // 三目运算符
220 | print (false ? 'Does not get printed' : 'Does');
221 |
222 | $x = 0;
223 | if ($x === '0') {
224 | print 'Does not print';
225 | } elseif($x == '1') {
226 | print 'Does not print';
227 | } else {
228 | print 'Does print';
229 | }
230 |
231 |
232 |
233 | // 下面的语法常用于模板中:
234 | ?>
235 |
236 |
237 | This is displayed if the test is truthy.
238 |
239 | This is displayed otherwise.
240 |
241 |
242 | 2, 'car' => 4];
280 |
281 | // Foreach 循环可以遍历数组
282 | foreach ($wheels as $wheel_count) {
283 | echo $wheel_count;
284 | } // 输出 "24"
285 |
286 | echo "\n";
287 |
288 | // 也可以同时遍历键和值
289 | foreach ($wheels as $vehicle => $wheel_count) {
290 | echo "A $vehicle has $wheel_count wheels";
291 | }
292 |
293 | echo "\n";
294 |
295 | $i = 0;
296 | while ($i < 5) {
297 | if ($i === 3) {
298 | break; // 退出循环
299 | }
300 | echo $i++;
301 | } // 输出 "012"
302 |
303 | for ($i = 0; $i < 5; $i++) {
304 | if ($i === 3) {
305 | continue; // 跳过此次遍历
306 | }
307 | echo $i;
308 | } // 输出 "0124"
309 |
310 |
311 | /********************************
312 | * 函数
313 | */
314 |
315 | // 通过"function"定义函数:
316 | function my_function () {
317 | return 'Hello';
318 | }
319 |
320 | echo my_function(); // => "Hello"
321 |
322 | // 函数名需要以字母或者下划线开头,
323 | // 后面可以跟着任意的字母、下划线、数字.
324 |
325 | function add ($x, $y = 1) { // $y 是可选参数,默认值为 1
326 | $result = $x + $y;
327 | return $result;
328 | }
329 |
330 | echo add(4); // => 5
331 | echo add(4, 2); // => 6
332 |
333 | // $result 在函数外部不可访问
334 | // print $result; // 抛出警告
335 |
336 | // 从 PHP 5.3 起我们可以定义匿名函数
337 | $inc = function ($x) {
338 | return $x + 1;
339 | };
340 |
341 | echo $inc(2); // => 3
342 |
343 | function foo ($x, $y, $z) {
344 | echo "$x - $y - $z";
345 | }
346 |
347 | // 函数也可以返回一个函数
348 | function bar ($x, $y) {
349 | // 用 'use' 将外部的参数引入到里面
350 | return function ($z) use ($x, $y) {
351 | foo($x, $y, $z);
352 | };
353 | }
354 |
355 | $bar = bar('A', 'B');
356 | $bar('C'); // 输出 "A - B - C"
357 |
358 | // 你也可以通过字符串调用函数
359 | $function_name = 'add';
360 | echo $function_name(1, 2); // => 3
361 | // 在通过程序来决定调用哪个函数时很有用
362 | // 或者,使用 call_user_func(callable $callback [, $parameter [, ... ]]);
363 |
364 | /********************************
365 | * 导入
366 | */
367 |
368 | instanceProp = $instanceProp;
418 | }
419 |
420 | // 方法就是类中定义的函数
421 | public function myMethod()
422 | {
423 | print 'MyClass';
424 | }
425 |
426 | final function youCannotOverrideMe()
427 | {
428 | }
429 |
430 | public static function myStaticMethod()
431 | {
432 | print 'I am static';
433 | }
434 | }
435 |
436 | echo MyClass::MY_CONST; // 输出 'value';
437 | echo MyClass::$staticVar; // 输出 'static';
438 | MyClass::myStaticMethod(); // 输出 'I am static';
439 |
440 | // 通过new来新建实例
441 | $my_class = new MyClass('An instance property');
442 | // 如果不传递参数,那么括号可以省略
443 |
444 | // 用 -> 来访问成员
445 | echo $my_class->property; // => "public"
446 | echo $my_class->instanceProp; // => "An instance property"
447 | $my_class->myMethod(); // => "MyClass"
448 |
449 |
450 | // 使用extends来生成子类
451 | class MyOtherClass extends MyClass
452 | {
453 | function printProtectedProperty()
454 | {
455 | echo $this->prot;
456 | }
457 |
458 | // 方法覆盖
459 | function myMethod()
460 | {
461 | parent::myMethod();
462 | print ' > MyOtherClass';
463 | }
464 | }
465 |
466 | $my_other_class = new MyOtherClass('Instance prop');
467 | $my_other_class->printProtectedProperty(); // => 输出 "protected"
468 | $my_other_class->myMethod(); // 输出 "MyClass > MyOtherClass"
469 |
470 | final class YouCannotExtendMe
471 | {
472 | }
473 |
474 | // 你可以使用“魔法方法”来生成getter和setter方法
475 | class MyMapClass
476 | {
477 | private $property;
478 |
479 | public function __get($key)
480 | {
481 | return $this->$key;
482 | }
483 |
484 | public function __set($key, $value)
485 | {
486 | $this->$key = $value;
487 | }
488 | }
489 |
490 | $x = new MyMapClass();
491 | echo $x->property; // 会使用 __get() 方法
492 | $x->property = 'Something'; // 会使用 __set() 方法
493 |
494 | // 类可以是被定义成抽象类 (使用 abstract 关键字) 或者
495 | // 去实现接口 (使用 implements 关键字).
496 | // 接口需要通过interface关键字来定义
497 |
498 | interface InterfaceOne
499 | {
500 | public function doSomething();
501 | }
502 |
503 | interface InterfaceTwo
504 | {
505 | public function doSomethingElse();
506 | }
507 |
508 | // 接口可以被扩展
509 | interface InterfaceThree extends InterfaceTwo
510 | {
511 | public function doAnotherContract();
512 | }
513 |
514 | abstract class MyAbstractClass implements InterfaceOne
515 | {
516 | public $x = 'doSomething';
517 | }
518 |
519 | class MyConcreteClass extends MyAbstractClass implements InterfaceTwo
520 | {
521 | public function doSomething()
522 | {
523 | echo $x;
524 | }
525 |
526 | public function doSomethingElse()
527 | {
528 | echo 'doSomethingElse';
529 | }
530 | }
531 |
532 |
533 | // 一个类可以实现多个接口
534 | class SomeOtherClass implements InterfaceOne, InterfaceTwo
535 | {
536 | public function doSomething()
537 | {
538 | echo 'doSomething';
539 | }
540 |
541 | public function doSomethingElse()
542 | {
543 | echo 'doSomethingElse';
544 | }
545 | }
546 |
547 |
548 | /********************************
549 | * 特征
550 | */
551 |
552 | // 特征 从 PHP 5.4.0 开始包括,需要用 "trait" 这个关键字声明
553 |
554 | trait MyTrait
555 | {
556 | public function myTraitMethod()
557 | {
558 | print 'I have MyTrait';
559 | }
560 | }
561 |
562 | class MyTraitfulClass
563 | {
564 | use MyTrait;
565 | }
566 |
567 | $cls = new MyTraitfulClass();
568 | $cls->myTraitMethod(); // 输出 "I have MyTrait"
569 |
570 |
571 | /********************************
572 | * 命名空间
573 | */
574 |
575 | // 这部分是独立于这个文件的
576 | // 因为命名空间必须在一个文件的开始处。
577 |
578 | 3
16 |
17 | # 算术没有什么出乎意料的
18 | 1 + 1 # => 2
19 | 8 - 1 # => 7
20 | 10 * 2 # => 20
21 |
22 | # 但是除法例外,会自动转换成浮点数
23 | 35 / 5 # => 7.0
24 | 5 / 3 # => 1.6666666666666667
25 |
26 | # 整数除法的结果都是向下取整
27 | 5 // 3 # => 1
28 | 5.0 // 3.0 # => 1.0 # 浮点数也可以
29 | -5 // 3 # => -2
30 | -5.0 // 3.0 # => -2.0
31 |
32 | # 浮点数的运算结果也是浮点数
33 | 3 * 2.0 # => 6.0
34 |
35 | # 模除
36 | 7 % 3 # => 1
37 |
38 | # x的y次方
39 | 2**4 # => 16
40 |
41 | # 用括号决定优先级
42 | (1 + 3) * 2 # => 8
43 |
44 | # 布尔值
45 | True
46 | False
47 |
48 | # 用not取非
49 | not True # => False
50 | not False # => True
51 |
52 | # 逻辑运算符,注意and和or都是小写
53 | True and False #=> False
54 | False or True #=> True
55 |
56 | # 整数也可以当作布尔值
57 | 0 and 2 #=> 0
58 | -5 or 0 #=> -5
59 | 0 == False #=> True
60 | 2 == True #=> False
61 | 1 == True #=> True
62 |
63 | # 用==判断相等
64 | 1 == 1 # => True
65 | 2 == 1 # => False
66 |
67 | # 用!=判断不等
68 | 1 != 1 # => False
69 | 2 != 1 # => True
70 |
71 | # 比较大小
72 | 1 < 10 # => True
73 | 1 > 10 # => False
74 | 2 <= 2 # => True
75 | 2 >= 2 # => True
76 |
77 | # 大小比较可以连起来!
78 | 1 < 2 < 3 # => True
79 | 2 < 3 < 2 # => False
80 |
81 | # 字符串用单引双引都可以
82 | "这是个字符串"
83 | '这也是个字符串'
84 |
85 | # 用加号连接字符串
86 | "Hello " + "world!" # => "Hello world!"
87 |
88 | # 字符串可以被当作字符列表
89 | "This is a string"[0] # => 'T'
90 |
91 | # 用.format来格式化字符串
92 | "{} can be {}".format("strings", "interpolated")
93 |
94 | # 可以重复参数以节省时间
95 | "{0} be nimble, {0} be quick, {0} jump over the {1}".format("Jack", "candle stick")
96 | #=> "Jack be nimble, Jack be quick, Jack jump over the candle stick"
97 |
98 | # 如果不想数参数,可以用关键字
99 | "{name} wants to eat {food}".format(name="Bob", food="lasagna") #=> "Bob wants to eat lasagna"
100 |
101 | # 如果你的Python3程序也要在Python2.5以下环境运行,也可以用老式的格式化语法
102 | "%s can be %s the %s way" % ("strings", "interpolated", "old")
103 |
104 | # None是一个对象
105 | None # => None
106 |
107 | # 当与None进行比较时不要用 ==,要用is。is是用来比较两个变量是否指向同一个对象。
108 | "etc" is None # => False
109 | None is None # => True
110 |
111 | # None,0,空字符串,空列表,空字典都算是False
112 | # 所有其他值都是True
113 | bool(0) # => False
114 | bool("") # => False
115 | bool([]) #=> False
116 | bool({}) #=> False
117 |
118 |
119 | ####################################################
120 | ## 2. 变量和集合
121 | ####################################################
122 |
123 | # print是内置的打印函数
124 | print("I'm Python. Nice to meet you!")
125 |
126 | # 在给变量赋值前不用提前声明
127 | # 传统的变量命名是小写,用下划线分隔单词
128 | some_var = 5
129 | some_var # => 5
130 |
131 | # 访问未赋值的变量会抛出异常
132 | # 参考流程控制一段来学习异常处理
133 | some_unknown_var # 抛出NameError
134 |
135 | # 用列表(list)储存序列
136 | li = []
137 | # 创建列表时也可以同时赋给元素
138 | other_li = [4, 5, 6]
139 |
140 | # 用append在列表最后追加元素
141 | li.append(1) # li现在是[1]
142 | li.append(2) # li现在是[1, 2]
143 | li.append(4) # li现在是[1, 2, 4]
144 | li.append(3) # li现在是[1, 2, 4, 3]
145 | # 用pop从列表尾部删除
146 | li.pop() # => 3 且li现在是[1, 2, 4]
147 | # 把3再放回去
148 | li.append(3) # li变回[1, 2, 4, 3]
149 |
150 | # 列表存取跟数组一样
151 | li[0] # => 1
152 | # 取出最后一个元素
153 | li[-1] # => 3
154 |
155 | # 越界存取会造成IndexError
156 | li[4] # 抛出IndexError
157 |
158 | # 列表有切割语法
159 | li[1:3] # => [2, 4]
160 | # 取尾
161 | li[2:] # => [4, 3]
162 | # 取头
163 | li[:3] # => [1, 2, 4]
164 | # 隔一个取一个
165 | li[::2] # =>[1, 4]
166 | # 倒排列表
167 | li[::-1] # => [3, 4, 2, 1]
168 | # 可以用三个参数的任何组合来构建切割
169 | # li[始:终:步伐]
170 |
171 | # 用del删除任何一个元素
172 | del li[2] # li is now [1, 2, 3]
173 |
174 | # 列表可以相加
175 | # 注意:li和other_li的值都不变
176 | li + other_li # => [1, 2, 3, 4, 5, 6]
177 |
178 | # 用extend拼接列表
179 | li.extend(other_li) # li现在是[1, 2, 3, 4, 5, 6]
180 |
181 | # 用in测试列表是否包含值
182 | 1 in li # => True
183 |
184 | # 用len取列表长度
185 | len(li) # => 6
186 |
187 |
188 | # 元组是不可改变的序列
189 | tup = (1, 2, 3)
190 | tup[0] # => 1
191 | tup[0] = 3 # 抛出TypeError
192 |
193 | # 列表允许的操作元组大都可以
194 | len(tup) # => 3
195 | tup + (4, 5, 6) # => (1, 2, 3, 4, 5, 6)
196 | tup[:2] # => (1, 2)
197 | 2 in tup # => True
198 |
199 | # 可以把元组合列表解包,赋值给变量
200 | a, b, c = (1, 2, 3) # 现在a是1,b是2,c是3
201 | # 元组周围的括号是可以省略的
202 | d, e, f = 4, 5, 6
203 | # 交换两个变量的值就这么简单
204 | e, d = d, e # 现在d是5,e是4
205 |
206 |
207 | # 用字典表达映射关系
208 | empty_dict = {}
209 | # 初始化的字典
210 | filled_dict = {"one": 1, "two": 2, "three": 3}
211 |
212 | # 用[]取值
213 | filled_dict["one"] # => 1
214 |
215 |
216 | # 用keys获得所有的键。因为keys返回一个可迭代对象,所以在这里把结果包在list里。我们下面会详细介绍可迭代。
217 | # 注意:字典键的顺序是不定的,你得到的结果可能和以下不同。
218 | list(filled_dict.keys()) # => ["three", "two", "one"]
219 |
220 |
221 | # 用values获得所有的值。跟keys一样,要用list包起来,顺序也可能不同。
222 | list(filled_dict.values()) # => [3, 2, 1]
223 |
224 |
225 | # 用in测试一个字典是否包含一个键
226 | "one" in filled_dict # => True
227 | 1 in filled_dict # => False
228 |
229 | # 访问不存在的键会导致KeyError
230 | filled_dict["four"] # KeyError
231 |
232 | # 用get来避免KeyError
233 | filled_dict.get("one") # => 1
234 | filled_dict.get("four") # => None
235 | # 当键不存在的时候get方法可以返回默认值
236 | filled_dict.get("one", 4) # => 1
237 | filled_dict.get("four", 4) # => 4
238 |
239 | # setdefault方法只有当键不存在的时候插入新值
240 | filled_dict.setdefault("five", 5) # filled_dict["five"]设为5
241 | filled_dict.setdefault("five", 6) # filled_dict["five"]还是5
242 |
243 | # 字典赋值
244 | filled_dict.update({"four":4}) #=> {"one": 1, "two": 2, "three": 3, "four": 4}
245 | filled_dict["four"] = 4 # 另一种赋值方法
246 |
247 | # 用del删除
248 | del filled_dict["one"] # 从filled_dict中把one删除
249 |
250 |
251 | # 用set表达集合
252 | empty_set = set()
253 | # 初始化一个集合,语法跟字典相似。
254 | some_set = {1, 1, 2, 2, 3, 4} # some_set现在是{1, 2, 3, 4}
255 |
256 | # 可以把集合赋值于变量
257 | filled_set = some_set
258 |
259 | # 为集合添加元素
260 | filled_set.add(5) # filled_set现在是{1, 2, 3, 4, 5}
261 |
262 | # & 取交集
263 | other_set = {3, 4, 5, 6}
264 | filled_set & other_set # => {3, 4, 5}
265 |
266 | # | 取并集
267 | filled_set | other_set # => {1, 2, 3, 4, 5, 6}
268 |
269 | # - 取补集
270 | {1, 2, 3, 4} - {2, 3, 5} # => {1, 4}
271 |
272 | # in 测试集合是否包含元素
273 | 2 in filled_set # => True
274 | 10 in filled_set # => False
275 |
276 |
277 | ####################################################
278 | ## 3. 流程控制和迭代器
279 | ####################################################
280 |
281 | # 先随便定义一个变量
282 | some_var = 5
283 |
284 | # 这是个if语句。注意缩进在Python里是有意义的
285 | # 印出"some_var比10小"
286 | if some_var > 10:
287 | print("some_var比10大")
288 | elif some_var < 10: # elif句是可选的
289 | print("some_var比10小")
290 | else: # else也是可选的
291 | print("some_var就是10")
292 |
293 |
294 | """
295 | 用for循环语句遍历列表
296 | 打印:
297 | dog is a mammal
298 | cat is a mammal
299 | mouse is a mammal
300 | """
301 | for animal in ["dog", "cat", "mouse"]:
302 | print("{} is a mammal".format(animal))
303 |
304 | """
305 | "range(number)"返回数字列表从0到给的数字
306 | 打印:
307 | 0
308 | 1
309 | 2
310 | 3
311 | """
312 | for i in range(4):
313 | print(i)
314 |
315 | """
316 | while循环直到条件不满足
317 | 打印:
318 | 0
319 | 1
320 | 2
321 | 3
322 | """
323 | x = 0
324 | while x < 4:
325 | print(x)
326 | x += 1 # x = x + 1 的简写
327 |
328 | # 用try/except块处理异常状况
329 | try:
330 | # 用raise抛出异常
331 | raise IndexError("This is an index error")
332 | except IndexError as e:
333 | pass # pass是无操作,但是应该在这里处理错误
334 | except (TypeError, NameError):
335 | pass # 可以同时处理不同类的错误
336 | else: # else语句是可选的,必须在所有的except之后
337 | print("All good!") # 只有当try运行完没有错误的时候这句才会运行
338 |
339 |
340 | # Python提供一个叫做可迭代(iterable)的基本抽象。一个可迭代对象是可以被当作序列
341 | # 的对象。比如说上面range返回的对象就是可迭代的。
342 |
343 | filled_dict = {"one": 1, "two": 2, "three": 3}
344 | our_iterable = filled_dict.keys()
345 | print(our_iterable) # => range(1,10) 是一个实现可迭代接口的对象
346 |
347 | # 可迭代对象可以遍历
348 | for i in our_iterable:
349 | print(i) # 打印 one, two, three
350 |
351 | # 但是不可以随机访问
352 | our_iterable[1] # 抛出TypeError
353 |
354 | # 可迭代对象知道怎么生成迭代器
355 | our_iterator = iter(our_iterable)
356 |
357 | # 迭代器是一个可以记住遍历的位置的对象
358 | # 用__next__可以取得下一个元素
359 | our_iterator.__next__() #=> "one"
360 |
361 | # 再一次调取__next__时会记得位置
362 | our_iterator.__next__() #=> "two"
363 | our_iterator.__next__() #=> "three"
364 |
365 | # 当迭代器所有元素都取出后,会抛出StopIteration
366 | our_iterator.__next__() # 抛出StopIteration
367 |
368 | # 可以用list一次取出迭代器所有的元素
369 | list(filled_dict.keys()) #=> Returns ["one", "two", "three"]
370 |
371 |
372 |
373 | ####################################################
374 | ## 4. 函数
375 | ####################################################
376 |
377 | # 用def定义新函数
378 | def add(x, y):
379 | print("x is {} and y is {}".format(x, y))
380 | return x + y # 用return语句返回
381 |
382 | # 调用函数
383 | add(5, 6) # => 印出"x is 5 and y is 6"并且返回11
384 |
385 | # 也可以用关键字参数来调用函数
386 | add(y=6, x=5) # 关键字参数可以用任何顺序
387 |
388 |
389 | # 我们可以定义一个可变参数函数
390 | def varargs(*args):
391 | return args
392 |
393 | varargs(1, 2, 3) # => (1, 2, 3)
394 |
395 |
396 | # 我们也可以定义一个关键字可变参数函数
397 | def keyword_args(**kwargs):
398 | return kwargs
399 |
400 | # 我们来看看结果是什么:
401 | keyword_args(big="foot", loch="ness") # => {"big": "foot", "loch": "ness"}
402 |
403 |
404 | # 这两种可变参数可以混着用
405 | def all_the_args(*args, **kwargs):
406 | print(args)
407 | print(kwargs)
408 | """
409 | all_the_args(1, 2, a=3, b=4) prints:
410 | (1, 2)
411 | {"a": 3, "b": 4}
412 | """
413 |
414 | # 调用可变参数函数时可以做跟上面相反的,用*展开序列,用**展开字典。
415 | args = (1, 2, 3, 4)
416 | kwargs = {"a": 3, "b": 4}
417 | all_the_args(*args) # 相当于 foo(1, 2, 3, 4)
418 | all_the_args(**kwargs) # 相当于 foo(a=3, b=4)
419 | all_the_args(*args, **kwargs) # 相当于 foo(1, 2, 3, 4, a=3, b=4)
420 |
421 |
422 | # 函数作用域
423 | x = 5
424 |
425 | def setX(num):
426 | # 局部作用域的x和全局域的x是不同的
427 | x = num # => 43
428 | print (x) # => 43
429 |
430 | def setGlobalX(num):
431 | global x
432 | print (x) # => 5
433 | x = num # 现在全局域的x被赋值
434 | print (x) # => 6
435 |
436 | setX(43)
437 | setGlobalX(6)
438 |
439 |
440 | # 函数在Python是一等公民
441 | def create_adder(x):
442 | def adder(y):
443 | return x + y
444 | return adder
445 |
446 | add_10 = create_adder(10)
447 | add_10(3) # => 13
448 |
449 | # 也有匿名函数
450 | (lambda x: x > 2)(3) # => True
451 |
452 | # 内置的高阶函数
453 | map(add_10, [1, 2, 3]) # => [11, 12, 13]
454 | filter(lambda x: x > 5, [3, 4, 5, 6, 7]) # => [6, 7]
455 |
456 | # 用列表推导式可以简化映射和过滤。列表推导式的返回值是另一个列表。
457 | [add_10(i) for i in [1, 2, 3]] # => [11, 12, 13]
458 | [x for x in [3, 4, 5, 6, 7] if x > 5] # => [6, 7]
459 |
460 | ####################################################
461 | ## 5. 类
462 | ####################################################
463 |
464 |
465 | # 定义一个继承object的类
466 | class Human(object):
467 |
468 | # 类属性,被所有此类的实例共用。
469 | species = "H. sapiens"
470 |
471 | # 构造方法,当实例被初始化时被调用。注意名字前后的双下划线,这是表明这个属
472 | # 性或方法对Python有特殊意义,但是允许用户自行定义。你自己取名时不应该用这
473 | # 种格式。
474 | def __init__(self, name):
475 | # Assign the argument to the instance's name attribute
476 | self.name = name
477 |
478 | # 实例方法,第一个参数总是self,就是这个实例对象
479 | def say(self, msg):
480 | return "{name}: {message}".format(name=self.name, message=msg)
481 |
482 | # 类方法,被所有此类的实例共用。第一个参数是这个类对象。
483 | @classmethod
484 | def get_species(cls):
485 | return cls.species
486 |
487 | # 静态方法。调用时没有实例或类的绑定。
488 | @staticmethod
489 | def grunt():
490 | return "*grunt*"
491 |
492 |
493 | # 构造一个实例
494 | i = Human(name="Ian")
495 | print(i.say("hi")) # 印出 "Ian: hi"
496 |
497 | j = Human("Joel")
498 | print(j.say("hello")) # 印出 "Joel: hello"
499 |
500 | # 调用一个类方法
501 | i.get_species() # => "H. sapiens"
502 |
503 | # 改一个共用的类属性
504 | Human.species = "H. neanderthalensis"
505 | i.get_species() # => "H. neanderthalensis"
506 | j.get_species() # => "H. neanderthalensis"
507 |
508 | # 调用静态方法
509 | Human.grunt() # => "*grunt*"
510 |
511 |
512 | ####################################################
513 | ## 6. 模块
514 | ####################################################
515 |
516 | # 用import导入模块
517 | import math
518 | print(math.sqrt(16)) # => 4
519 |
520 | # 也可以从模块中导入个别值
521 | from math import ceil, floor
522 | print(ceil(3.7)) # => 4.0
523 | print(floor(3.7)) # => 3.0
524 |
525 | # 可以导入一个模块中所有值
526 | # 警告:不建议这么做
527 | from math import *
528 |
529 | # 如此缩写模块名字
530 | import math as m
531 | math.sqrt(16) == m.sqrt(16) # => True
532 |
533 | # Python模块其实就是普通的Python文件。你可以自己写,然后导入,
534 | # 模块的名字就是文件的名字。
535 |
536 | # 你可以这样列出一个模块里所有的值
537 | import math
538 | dir(math)
539 |
540 |
541 | ####################################################
542 | ## 7. 高级用法
543 | ####################################################
544 |
545 | # 用生成器(generators)方便地写惰性运算
546 | def double_numbers(iterable):
547 | for i in iterable:
548 | yield i + i
549 |
550 | # 生成器只有在需要时才计算下一个值。它们每一次循环只生成一个值,而不是把所有的
551 | # 值全部算好。这意味着double_numbers不会生成大于15的数字。
552 | #
553 | # range的返回值也是一个生成器,不然一个1到900000000的列表会花很多时间和内存。
554 | #
555 | # 如果你想用一个Python的关键字当作变量名,可以加一个下划线来区分。
556 | range_ = range(1, 900000000)
557 | # 当找到一个 >=30 的结果就会停
558 | for i in double_numbers(range_):
559 | print(i)
560 | if i >= 30:
561 | break
562 |
563 |
564 | # 装饰器(decorators)
565 | # 这个例子中,beg装饰say
566 | # beg会先调用say。如果返回的say_please为真,beg会改变返回的字符串。
567 | from functools import wraps
568 |
569 |
570 | def beg(target_function):
571 | @wraps(target_function)
572 | def wrapper(*args, **kwargs):
573 | msg, say_please = target_function(*args, **kwargs)
574 | if say_please:
575 | return "{} {}".format(msg, "Please! I am poor :(")
576 | return msg
577 |
578 | return wrapper
579 |
580 |
581 | @beg
582 | def say(say_please=False):
583 | msg = "Can you buy me a beer?"
584 | return msg, say_please
585 |
586 |
587 | print(say()) # Can you buy me a beer?
588 | print(say(say_please=True)) # Can you buy me a beer? Please! I am poor :(
589 |
--------------------------------------------------------------------------------
/learnc-cn.c:
--------------------------------------------------------------------------------
1 |
2 | // 单行注释以//开始。(仅适用于C99或更新的版本。)
3 |
4 | /*
5 | 多行注释是这个样子的。(C89也适用。)
6 | */
7 |
8 | // 常数: #define 关键词
9 | #define DAYS_IN_YEAR 365
10 |
11 | // 以枚举的方式定义常数
12 | enum days {SUN = 1, MON, TUE, WED, THU, FRI, SAT};
13 | // MON自动被定义为2,TUE被定义为3,以此类推。
14 |
15 | // 用#include来导入头文件
16 | #include
17 | #include
18 | #include
19 |
20 | // <尖括号>间的文件名是C标准库的头文件。
21 | // 标准库以外的头文件,使用双引号代替尖括号。
22 | #include "my_header.h"
23 |
24 | // 函数的签名可以事先在.h文件中定义,
25 | // 也可以直接在.c文件的头部定义。
26 | void function_1(char c);
27 | void function_2(void);
28 |
29 | // 如果函数出现在main()之后,那么必须在main()之前
30 | // 先声明一个函数原型
31 | int add_two_ints(int x1, int x2); // 函数原型
32 |
33 | // 你的程序的入口是一个返回值为整型的main函数
34 | int main() {
35 |
36 | // 用printf打印到标准输出,可以设定格式,
37 | // %d 代表整数, \n 代表换行
38 | printf("%d\n", 0); // => 打印 0
39 | // 所有的语句都要以分号结束
40 |
41 | ///////////////////////////////////////
42 | // 类型
43 | ///////////////////////////////////////
44 |
45 | // 在使用变量之前我们必须先声明它们。
46 | // 变量在声明时需要指明其类型,而类型能够告诉系统这个变量所占用的空间
47 |
48 | // int型(整型)变量一般占用4个字节
49 | int x_int = 0;
50 |
51 | // short型(短整型)变量一般占用2个字节
52 | short x_short = 0;
53 |
54 | // char型(字符型)变量会占用1个字节
55 | char x_char = 0;
56 | char y_char = 'y'; // 字符变量的字面值需要用单引号包住
57 |
58 | // long型(长整型)一般需要4个字节到8个字节; 而long long型则至少需要8个字节(64位)
59 |
60 | long x_long = 0;
61 | long long x_long_long = 0;
62 |
63 | // float一般是用32位表示的浮点数字
64 | float x_float = 0.0;
65 |
66 | // double一般是用64位表示的浮点数字
67 | double x_double = 0.0;
68 |
69 | // 整数类型也可以有无符号的类型表示。这样这些变量就无法表示负数
70 | // 但是无符号整数所能表示的范围就可以比原来的整数大一些
71 |
72 | unsigned short ux_short;
73 | unsigned int ux_int;
74 | unsigned long long ux_long_long;
75 |
76 | // 单引号内的字符是机器的字符集中的整数。
77 | '0' // => 在ASCII字符集中是48
78 | 'A' // => 在ASCII字符集中是65
79 |
80 | // char类型一定会占用1个字节,但是其他的类型却会因具体机器的不同而各异
81 | // sizeof(T) 可以返回T类型在运行的机器上占用多少个字节
82 | // 这样你的代码就可以在各处正确运行了
83 | // sizeof(obj)返回表达式(变量、字面量等)的尺寸
84 | printf("%zu\n", sizeof(int)); // => 4 (大多数的机器字长为4)
85 |
86 | // 如果`sizeof`的参数是一个表达式,那么这个参数不会被演算(VLA例外,见下)
87 | // 它产生的值是编译期的常数
88 | int a = 1;
89 | // size_t是一个无符号整型,表示对象的尺寸,至少2个字节
90 | size_t size = sizeof(a++); // a++ 不会被演算
91 | printf("sizeof(a++) = %zu where a = %d\n", size, a);
92 | // 打印 "sizeof(a++) = 4 where a = 1" (在32位架构上)
93 |
94 | // 数组必须要被初始化为具体的长度
95 | char my_char_array[20]; // 这个数组占据 1 * 20 = 20 个字节
96 | int my_int_array[20]; // 这个数组占据 4 * 20 = 80 个字节
97 | // (这里我们假设字长为4)
98 |
99 |
100 | // 可以用下面的方法把数组初始化为0:
101 | char my_array[20] = {0};
102 |
103 | // 索引数组和其他语言类似 -- 好吧,其实是其他的语言像C
104 | my_array[0]; // => 0
105 |
106 | // 数组是可变的,其实就是内存的映射!
107 | my_array[1] = 2;
108 | printf("%d\n", my_array[1]); // => 2
109 |
110 | // 在C99 (C11中是可选特性),变长数组(VLA)也可以声明长度。
111 | // 其长度不用是编译期常量。
112 | printf("Enter the array size: "); // 询问用户数组长度
113 | char buf[0x100];
114 | fgets(buf, sizeof buf, stdin);
115 |
116 | // stroul 将字符串解析为无符号整数
117 | size_t size = strtoul(buf, NULL, 10);
118 | int var_length_array[size]; // 声明VLA
119 | printf("sizeof array = %zu\n", sizeof var_length_array);
120 |
121 | // 上述程序可能的输出为:
122 | // > Enter the array size: 10
123 | // > sizeof array = 40
124 |
125 | // 字符串就是以 NUL (0x00) 这个字符结尾的字符数组,
126 | // NUL可以用'\0'来表示.
127 | // (在字符串字面量中我们不必输入这个字符,编译器会自动添加的)
128 | char a_string[20] = "This is a string";
129 | printf("%s\n", a_string); // %s 可以对字符串进行格式化
130 | /*
131 | 也许你会注意到 a_string 实际上只有16个字节长.
132 | 第17个字节是一个空字符(NUL)
133 | 而第18, 19 和 20 个字符的值是未定义。
134 | */
135 |
136 | printf("%d\n", a_string[16]); // => 0
137 | // byte #17值为0(18,19,20同样为0)
138 |
139 | // 单引号间的字符是字符字面量
140 | // 它的类型是`int`,而 *不是* `char`
141 | // (由于历史原因)
142 | int cha = 'a'; // 合法
143 | char chb = 'a'; // 同样合法 (隐式类型转换
144 |
145 | // 多维数组
146 | int multi_array[2][5] = {
147 | {1, 2, 3, 4, 5},
148 | {6, 7, 8, 9, 0}
149 | }
150 | // 获取元素
151 | int array_int = multi_array[0][2]; // => 3
152 |
153 | ///////////////////////////////////////
154 | // 操作符
155 | ///////////////////////////////////////
156 |
157 | // 多个变量声明的简写
158 | int i1 = 1, i2 = 2;
159 | float f1 = 1.0, f2 = 2.0;
160 |
161 | int a, b, c;
162 | a = b = c = 0;
163 |
164 | // 算数运算直截了当
165 | i1 + i2; // => 3
166 | i2 - i1; // => 1
167 | i2 * i1; // => 2
168 | i1 / i2; // => 0 (0.5,但会被化整为 0)
169 |
170 | f1 / f2; // => 0.5, 也许会有很小的误差
171 | // 浮点数和浮点数运算都是近似值
172 |
173 | // 取余运算
174 | 11 % 3; // => 2
175 |
176 | // 你多半会觉得比较操作符很熟悉, 不过C中没有布尔类型
177 | // 而是用整形替代
178 | // (C99中有_Bool或bool。)
179 | // 0为假, 其他均为真. (比较操作符的返回值总是返回0或1)
180 | 3 == 2; // => 0 (false)
181 | 3 != 2; // => 1 (true)
182 | 3 > 2; // => 1
183 | 3 < 2; // => 0
184 | 2 <= 2; // => 1
185 | 2 >= 2; // => 1
186 |
187 | // C不是Python —— 连续比较不合法
188 | int a = 1;
189 | // 错误
190 | int between_0_and_2 = 0 < a < 2;
191 | // 正确
192 | int between_0_and_2 = 0 < a && a < 2;
193 |
194 | // 逻辑运算符适用于整数
195 | !3; // => 0 (非)
196 | !0; // => 1
197 | 1 && 1; // => 1 (且)
198 | 0 && 1; // => 0
199 | 0 || 1; // => 1 (或)
200 | 0 || 0; // => 0
201 |
202 | // 条件表达式 ( ? : )
203 | int a = 5;
204 | int b = 10;
205 | int z;
206 | z = (a > b) ? a : b; // 10 “若a > b返回a,否则返回b。”
207 |
208 | // 增、减
209 | char *s = "iLoveC"
210 | int j = 0;
211 | s[j++]; // "i" 返回s的第j项,然后增加j的值。
212 | j = 0;
213 | s[++j]; // => "L" 增加j的值,然后返回s的第j项。
214 | // j-- 和 --j 同理
215 |
216 | // 位运算
217 | ~0x0F; // => 0xF0 (取反)
218 | 0x0F & 0xF0; // => 0x00 (和)
219 | 0x0F | 0xF0; // => 0xFF (或)
220 | 0x04 ^ 0x0F; // => 0x0B (异或)
221 | 0x01 << 1; // => 0x02 (左移1位)
222 | 0x02 >> 1; // => 0x01 (右移1位)
223 |
224 | // 对有符号整数进行移位操作要小心 —— 以下未定义:
225 | // 有符号整数位移至符号位 int a = 1 << 32
226 | // 左移位一个负数 int a = -1 << 2
227 | // 移位超过或等于该类型数值的长度
228 | // int a = 1 << 32; // 假定int32位
229 |
230 |
231 | ///////////////////////////////////////
232 | // 控制结构
233 | ///////////////////////////////////////
234 |
235 | if (0) {
236 | printf("I am never run\n");
237 | } else if (0) {
238 | printf("I am also never run\n");
239 | } else {
240 | printf("I print\n");
241 | }
242 |
243 | // While循环
244 | int ii = 0;
245 | while (ii < 10) { // 任何非0的值均为真
246 | printf("%d, ", ii++); // ii++ 在取值过后自增
247 | } // => 打印 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
248 |
249 | printf("\n");
250 |
251 | int kk = 0;
252 | do {
253 | printf("%d, ", kk);
254 | } while (++kk < 10); // ++kk 先自增,再被取值
255 | // => 打印 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
256 |
257 | printf("\n");
258 |
259 | // For 循环
260 | int jj;
261 | for (jj=0; jj < 10; jj++) {
262 | printf("%d, ", jj);
263 | } // => 打印 "0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "
264 |
265 | printf("\n");
266 |
267 | // *****注意*****:
268 | // 循环和函数必须有主体部分,如果不需要主体部分:
269 | int i;
270 | for (i = 0; i <= 5; i++) {
271 | ; // 使用分号表达主体(null语句)
272 | }
273 |
274 | // 多重分支:switch()
275 | switch (some_integral_expression) {
276 | case 0: // 标签必须是整数常量表达式
277 | do_stuff();
278 | break; // 如果不使用break,控制结构会继续执行下面的标签
279 | case 1:
280 | do_something_else();
281 | break;
282 | default:
283 | // 假设 `some_integral_expression` 不匹配任何标签
284 | fputs("error!\n", stderr);
285 | exit(-1);
286 | break;
287 | }
288 |
289 | ///////////////////////////////////////
290 | // 类型转换
291 | ///////////////////////////////////////
292 |
293 | // 在C中每个变量都有类型,你可以将变量的类型进行转换
294 | // (有一定限制)
295 |
296 | int x_hex = 0x01; // 可以用16进制字面量赋值
297 |
298 | // 在类型转换时,数字本身的值会被保留下来
299 | printf("%d\n", x_hex); // => 打印 1
300 | printf("%d\n", (short) x_hex); // => 打印 1
301 | printf("%d\n", (char) x_hex); // => 打印 1
302 |
303 | // 类型转换时可能会造成溢出,而且不会抛出警告
304 | printf("%d\n", (char) 257); // => 1 (char的最大值为255,假定char为8位长)
305 |
306 | // 使用提供的CHAR_MAX、SCHAR_MAX和UCHAR_MAX宏可以确定`char`、`signed_char`和`unisigned char`的最大值。
307 |
308 |
309 | // 整数型和浮点型可以互相转换
310 | printf("%f\n", (float)100); // %f 格式化单精度浮点
311 | printf("%lf\n", (double)100); // %lf 格式化双精度浮点
312 | printf("%d\n", (char)100.0);
313 |
314 | ///////////////////////////////////////
315 | // 指针
316 | ///////////////////////////////////////
317 |
318 | // 指针变量是用来储存内存地址的变量
319 | // 指针变量的声明也会告诉它所指向的数据的类型
320 | // 你可以使用得到你的变量的地址,并把它们搞乱,;-)
321 |
322 | int x = 0;
323 | printf("%p\n", &x); // 用 & 来获取变量的地址
324 | // (%p 格式化一个类型为 void *的指针)
325 | // => 打印某个内存地址
326 |
327 | // 指针类型在声明中以*开头
328 | int* px, not_a_pointer; // px是一个指向int型的指针
329 | px = &x; // 把x的地址保存到px中
330 | printf("%p\n", (void *)px); // => 输出内存中的某个地址
331 | printf("%zu, %zu\n", sizeof(px), sizeof(not_a_pointer));
332 | // => 在64位系统上打印“8, 4”。
333 |
334 | // 要得到某个指针指向的内容的值,可以在指针前加一个*来取得(取消引用)
335 | // 注意: 是的,这可能让人困惑,'*'在用来声明一个指针的同时取消引用它。
336 | printf("%d\n", *px); // => 输出 0, 即x的值
337 |
338 | // 你也可以改变指针所指向的值
339 | // 此时你需要取消引用上添加括号,因为++比*的优先级更高
340 | (*px)++; // 把px所指向的值增加1
341 | printf("%d\n", *px); // => 输出 1
342 | printf("%d\n", x); // => 输出 1
343 |
344 | // 数组是分配一系列连续空间的常用方式
345 | int x_array[20];
346 | int xx;
347 | for (xx=0; xx<20; xx++) {
348 | x_array[xx] = 20 - xx;
349 | } // 初始化 x_array 为 20, 19, 18,... 2, 1
350 |
351 | // 声明一个整型的指针,并初始化为指向x_array
352 | int* x_ptr = x_array;
353 | // x_ptr现在指向了数组的第一个元素(即整数20).
354 | // 这是因为数组通常衰减为指向它们的第一个元素的指针。
355 | // 例如,当一个数组被传递给一个函数或者绑定到一个指针时,
356 | //它衰减为(隐式转化为)一个指针。
357 | // 例外: 当数组是`&`操作符的参数:
358 | int arr[10];
359 | int (*ptr_to_arr)[10] = &arr; // &arr的类型不是`int *`!
360 | // 它的类型是指向数组的指针(数组由10个int组成)
361 | // 或者当数组是字符串字面量(初始化字符数组)
362 | char arr[] = "foobarbazquirk";
363 | // 或者当它是`sizeof`或`alignof`操作符的参数时:
364 | int arr[10];
365 | int *ptr = arr; // 等价于 int *ptr = &arr[0];
366 | printf("%zu, %zu\n", sizeof arr, sizeof ptr); // 应该会输出"40, 4"或"40, 8"
367 |
368 | // 指针的增减多少是依据它本身的类型而定的
369 | // (这被称为指针算术)
370 | printf("%d\n", *(x_ptr + 1)); // => 打印 19
371 | printf("%d\n", x_array[1]); // => 打印 19
372 |
373 | // 你也可以通过标准库函数malloc来实现动态分配
374 | // 这个函数接受一个代表容量的参数,参数类型为`size_t`
375 | // 系统一般会从堆区分配指定容量字节大小的空间
376 | // (在一些系统,例如嵌入式系统中这点不一定成立
377 | // C标准对此未置一词。)
378 | int *my_ptr = malloc(sizeof(*my_ptr) * 20);
379 | for (xx=0; xx<20; xx++) {
380 | *(my_ptr + xx) = 20 - xx; // my_ptr[xx] = 20-xx
381 | } // 初始化内存为 20, 19, 18, 17... 2, 1 (类型为int)
382 |
383 | // 对未分配的内存进行取消引用会产生未定义的结果
384 | printf("%d\n", *(my_ptr + 21)); // => 谁知道会输出什么
385 |
386 | // malloc分配的区域需要手动释放
387 | // 否则没人能够再次使用这块内存,直到程序结束为止
388 | free(my_ptr);
389 |
390 | // 字符串通常是字符数组,但是经常用字符指针表示
391 | // (它是指向数组的第一个元素的指针)
392 | // 一个优良的实践是使用`const char *`来引用一个字符串字面量,
393 | // 因为字符串字面量不应当被修改(即"foo"[0] = 'a'犯了大忌)
394 | const char* my_str = "This is my very own string";
395 | printf("%c\n", *my_str); // => 'T'
396 |
397 | // 如果字符串是数组,(多半是用字符串字面量初始化的)
398 | // 情况就不一样了,字符串位于可写的内存中
399 | char foo[] = "foo";
400 | foo[0] = 'a'; // 这是合法的,foo现在包含"aoo"
401 |
402 | function_1();
403 | } // main函数结束
404 |
405 | ///////////////////////////////////////
406 | // 函数
407 | ///////////////////////////////////////
408 |
409 | // 函数声明语法:
410 | // <返回值类型> <函数名称>(<参数>)
411 |
412 | int add_two_ints(int x1, int x2){
413 | return x1 + x2; // 用return来返回一个值
414 | }
415 |
416 | /*
417 | 函数是按值传递的。当调用一个函数的时候,传递给函数的参数
418 | 是原有值的拷贝(数组除外)。你在函数内对参数所进行的操作
419 | 不会改变该参数原有的值。
420 |
421 | 但是你可以通过指针来传递引用,这样函数就可以更改值
422 |
423 | 例子:字符串本身翻转
424 | */
425 |
426 | // 类型为void的函数没有返回值
427 | void str_reverse(char *str_in){
428 | char tmp;
429 | int ii = 0;
430 | size_t len = strlen(str_in); // `strlen()`` 是C标准库函数
431 | for(ii = 0; ii < len / 2; ii++){
432 | tmp = str_in[ii];
433 | str_in[ii] = str_in[len - ii - 1]; // 从倒数第ii个开始
434 | str_in[len - ii - 1] = tmp;
435 | }
436 | }
437 |
438 | /*
439 | char c[] = "This is a test.";
440 | str_reverse(c);
441 | printf("%s\n", c); // => ".tset a si sihT"
442 | */
443 |
444 | // 如果引用函数之外的变量,必须使用extern关键字
445 | int i = 0;
446 | void testFunc() {
447 | extern int i; // 使用外部变量 i
448 | }
449 |
450 | // 使用static确保external变量为源文件私有
451 | static int i = 0; // 其他使用 testFunc()的文件无法访问变量i
452 | void testFunc() {
453 | extern int i;
454 | }
455 | //**你同样可以声明函数为static**
456 |
457 |
458 | ///////////////////////////////////////
459 | // 用户自定义类型和结构
460 | ///////////////////////////////////////
461 |
462 | // Typedefs可以创建类型别名
463 | typedef int my_type;
464 | my_type my_type_var = 0;
465 |
466 | // struct是数据的集合,成员依序分配,按照
467 | // 编写的顺序
468 | struct rectangle {
469 | int width;
470 | int height;
471 | };
472 |
473 | // 一般而言,以下断言不成立:
474 | // sizeof(struct rectangle) == sizeof(int) + sizeof(int)
475 | //这是因为structure成员之间可能存在潜在的间隙(为了对齐)[1]
476 |
477 | void function_1(){
478 |
479 | struct rectangle my_rec;
480 |
481 | // 通过 . 来访问结构中的数据
482 | my_rec.width = 10;
483 | my_rec.height = 20;
484 |
485 | // 你也可以声明指向结构体的指针
486 | struct rectangle *my_rec_ptr = &my_rec;
487 |
488 | // 通过取消引用来改变结构体的成员...
489 | (*my_rec_ptr).width = 30;
490 |
491 | // ... 或者用 -> 操作符作为简写提高可读性
492 | my_rec_ptr->height = 10; // Same as (*my_rec_ptr).height = 10;
493 | }
494 |
495 | // 你也可以用typedef来给一个结构体起一个别名
496 | typedef struct rectangle rect;
497 |
498 | int area(rect r){
499 | return r.width * r.height;
500 | }
501 |
502 | // 如果struct较大,你可以通过指针传递,避免
503 | // 复制整个struct。
504 | int area(const rect *r)
505 | {
506 | return r->width * r->height;
507 | }
508 |
509 | ///////////////////////////////////////
510 | // 函数指针
511 | ///////////////////////////////////////
512 | /*
513 | 在运行时,函数本身也被存放到某块内存区域当中
514 | 函数指针就像其他指针一样(不过是存储一个内存地址) 但却可以被用来直接调用函数,
515 | 并且可以四处传递回调函数
516 | 但是,定义的语法初看令人有些迷惑
517 |
518 | 例子:通过指针调用str_reverse
519 | */
520 | void str_reverse_through_pointer(char *str_in) {
521 | // 定义一个函数指针 f.
522 | void (*f)(char *); // 签名一定要与目标函数相同
523 | f = &str_reverse; // 将函数的地址在运行时赋给指针
524 | (*f)(str_in); // 通过指针调用函数
525 | // f(str_in); // 等价于这种调用方式
526 | }
527 |
528 | /*
529 | 只要函数签名是正确的,任何时候都能将任何函数赋给某个函数指针
530 | 为了可读性和简洁性,函数指针经常和typedef搭配使用:
531 | */
532 |
533 | typedef void (*my_fnp_type)(char *);
534 |
535 | // 实际声明函数指针会这么用:
536 | // ...
537 | // my_fnp_type f;
538 |
539 | // 特殊字符
540 | '\a' // bell
541 | '\n' // 换行
542 | '\t' // tab
543 | '\v' // vertical tab
544 | '\f' // formfeed
545 | '\r' // 回车
546 | '\b' // 退格
547 | '\0' // null,通常置于字符串的最后。
548 | // hello\n\0. 按照惯例,\0用于标记字符串的末尾。
549 | '\\' // 反斜杠
550 | '\?' // 问号
551 | '\'' // 单引号
552 | '\"' // 双引号
553 | '\xhh' // 十六进制数字. 例子: '\xb' = vertical tab
554 | '\ooo' // 八进制数字. 例子: '\013' = vertical tab
555 |
556 | // 打印格式:
557 | "%d" // 整数
558 | "%3d" // 3位以上整数 (右对齐文本)
559 | "%s" // 字符串
560 | "%f" // float
561 | "%ld" // long
562 | "%3.2f" // 左3位以上、右2位以上十进制浮
563 | "%7.4s" // (字符串同样适用)
564 | "%c" // 字母
565 | "%p" // 指针
566 | "%x" // 十六进制
567 | "%o" // 八进制
568 | "%%" // 打印 %
569 |
570 | ///////////////////////////////////////
571 | // 演算优先级
572 | ///////////////////////////////////////
573 | //---------------------------------------------------//
574 | // 操作符 | 组合 //
575 | //---------------------------------------------------//
576 | // () [] -> . | 从左到右 //
577 | // ! ~ ++ -- + = *(type)sizeof | 从右到左 //
578 | // * / % | 从左到右 //
579 | // + - | 从左到右 //
580 | // << >> | 从左到右 //
581 | // < <= > >= | 从左到右 //
582 | // == != | 从左到右 //
583 | // & | 从左到右 //
584 | // ^ | 从左到右 //
585 | // | | 从左到右 //
586 | // && | 从左到右 //
587 | // || | 从左到右 //
588 | // ?: | 从右到左 //
589 | // = += -= *= /= %= &= ^= |= <<= >>= | 从右到左 //
590 | // , | 从左到右 //
591 | //---------------------------------------------------//
592 |
--------------------------------------------------------------------------------
/learncsharp-cn.cs:
--------------------------------------------------------------------------------
1 |
2 | // 单行注释以 // 开始
3 | /*
4 | 多行注释是这样的
5 | */
6 | ///
7 | /// XML文档注释
8 | ///
9 |
10 | // 声明应用用到的命名空间
11 | using System;
12 | using System.Collections.Generic;
13 | using System.Data.Entity;
14 | using System.Dynamic;
15 | using System.Linq;
16 | using System.Linq.Expressions;
17 | using System.Net;
18 | using System.Threading.Tasks;
19 | using System.IO;
20 |
21 | // 定义作用域,将代码组织成包
22 | namespace Learning
23 | {
24 | // 每个 .cs 文件至少需要包含一个和文件名相同的类
25 | // 你可以不这么干,但是这样不好。
26 | public class LearnCSharp
27 | {
28 | // 基本语法 - 如果你以前用过 Java 或 C++ 的话,可以直接跳到后文「有趣的特性」
29 | public static void Syntax()
30 | {
31 | // 使用 Console.WriteLine 打印信息
32 | Console.WriteLine("Hello World");
33 | Console.WriteLine(
34 | "Integer: " + 10 +
35 | " Double: " + 3.14 +
36 | " Boolean: " + true);
37 |
38 | // 使用 Console.Write 打印,不带换行符号
39 | Console.Write("Hello ");
40 | Console.Write("World");
41 |
42 | ///////////////////////////////////////////////////
43 | // 类型和变量
44 | //
45 | // 使用 定义变量
46 | ///////////////////////////////////////////////////
47 |
48 | // Sbyte - 有符号 8-bit 整数
49 | // (-128 <= sbyte <= 127)
50 | sbyte fooSbyte = 100;
51 |
52 | // Byte - 无符号 8-bit 整数
53 | // (0 <= byte <= 255)
54 | byte fooByte = 100;
55 |
56 | // Short - 16-bit 整数
57 | // 有符号 - (-32,768 <= short <= 32,767)
58 | // 无符号 - (0 <= ushort <= 65,535)
59 | short fooShort = 10000;
60 | ushort fooUshort = 10000;
61 |
62 | // Integer - 32-bit 整数
63 | int fooInt = 1; // (-2,147,483,648 <= int <= 2,147,483,647)
64 | uint fooUint = 1; // (0 <= uint <= 4,294,967,295)
65 |
66 | // Long - 64-bit 整数
67 | long fooLong = 100000L; // (-9,223,372,036,854,775,808 <= long <= 9,223,372,036,854,775,807)
68 | ulong fooUlong = 100000L; // (0 <= ulong <= 18,446,744,073,709,551,615)
69 | // 数字默认为 int 或 uint (取决于尺寸)
70 | // 使用 L 标明变量值类型为long 或 ulong
71 |
72 | // Double - 双精度 64-bit IEEE 754 浮点数
73 | double fooDouble = 123.4; // 精度: 15-16 位
74 |
75 | // Float - 单精度 32-bit IEEE 754 浮点数
76 | float fooFloat = 234.5f; // 精度: 7 位
77 | // 使用 f 标明变量值类型为float
78 |
79 | // Decimal - 128-bits 数据类型,比其他浮点类型精度更高
80 | // 适合财务、金融
81 | decimal fooDecimal = 150.3m;
82 |
83 | // 布尔值 - true & false
84 | bool fooBoolean = true; // 或 false
85 |
86 | // Char - 单个 16-bit Unicode 字符
87 | char fooChar = 'A';
88 |
89 | // 字符串 -- 和前面的基本类型不同,字符串不是值,而是引用。
90 | // 这意味着你可以将字符串设为null。
91 | string fooString = "\"escape\" quotes and add \n (new lines) and \t (tabs)";
92 | Console.WriteLine(fooString);
93 |
94 | // 你可以通过索引访问字符串的每个字符:
95 | char charFromString = fooString[1]; // => 'e'
96 | // 字符串不可修改: fooString[1] = 'X' 是行不通的;
97 |
98 | // 根据当前的locale设定比较字符串,大小写不敏感
99 | string.Compare(fooString, "x", StringComparison.CurrentCultureIgnoreCase);
100 |
101 | // 基于sprintf的字符串格式化
102 | string fooFs = string.Format("Check Check, {0} {1}, {0} {1:0.0}", 1, 2);
103 |
104 | // 日期和格式
105 | DateTime fooDate = DateTime.Now;
106 | Console.WriteLine(fooDate.ToString("hh:mm, dd MMM yyyy"));
107 |
108 | // 使用 @ 符号可以创建跨行的字符串。使用 "" 来表示 "
109 | string bazString = @"Here's some stuff
110 | on a new line! ""Wow!"", the masses cried";
111 |
112 | // 使用const或read-only定义常量
113 | // 常量在编译期演算
114 | const int HOURS_I_WORK_PER_WEEK = 9001;
115 |
116 | ///////////////////////////////////////////////////
117 | // 数据结构
118 | ///////////////////////////////////////////////////
119 |
120 | // 数组 - 从0开始计数
121 | // 声明数组时需要确定数组长度
122 | // 声明数组的格式如下:
123 | // [] = new [];
124 | int[] intArray = new int[10];
125 |
126 | // 声明并初始化数组的其他方式:
127 | int[] y = { 9000, 1000, 1337 };
128 |
129 | // 访问数组的元素
130 | Console.WriteLine("intArray @ 0: " + intArray[0]);
131 | // 数组可以修改
132 | intArray[1] = 1;
133 |
134 | // 列表
135 | // 列表比数组更常用,因为列表更灵活。
136 | // 声明列表的格式如下:
137 | // List = new List();
138 | List intList = new List();
139 | List stringList = new List();
140 | List z = new List { 9000, 1000, 1337 }; // i
141 | // <>用于泛型 - 参考下文
142 |
143 | // 列表无默认值
144 | // 访问列表元素时必须首先添加元素
145 | intList.Add(1);
146 | Console.WriteLine("intList @ 0: " + intList[0]);
147 |
148 | // 其他数据结构:
149 | // 堆栈/队列
150 | // 字典 (哈希表的实现)
151 | // 哈希集合
152 | // 只读集合
153 | // 元组 (.Net 4+)
154 |
155 | ///////////////////////////////////////
156 | // 操作符
157 | ///////////////////////////////////////
158 | Console.WriteLine("\n->Operators");
159 |
160 | int i1 = 1, i2 = 2; // 多重声明的简写形式
161 |
162 | // 算术直截了当
163 | Console.WriteLine(i1 + i2 - i1 * 3 / 7); // => 3
164 |
165 | // 取余
166 | Console.WriteLine("11%3 = " + (11 % 3)); // => 2
167 |
168 | // 比较操作符
169 | Console.WriteLine("3 == 2? " + (3 == 2)); // => false
170 | Console.WriteLine("3 != 2? " + (3 != 2)); // => true
171 | Console.WriteLine("3 > 2? " + (3 > 2)); // => true
172 | Console.WriteLine("3 < 2? " + (3 < 2)); // => false
173 | Console.WriteLine("2 <= 2? " + (2 <= 2)); // => true
174 | Console.WriteLine("2 >= 2? " + (2 >= 2)); // => true
175 |
176 | // 位操作符
177 | /*
178 | ~ 取反
179 | << 左移(有符号)
180 | >> 右移(有符号)
181 | & 与
182 | ^ 异或
183 | | 或
184 | */
185 |
186 | // 自增、自减
187 | int i = 0;
188 | Console.WriteLine("\n->Inc/Dec-rementation");
189 | Console.WriteLine(i++); //i = 1. 事后自增
190 | Console.WriteLine(++i); //i = 2. 事先自增
191 | Console.WriteLine(i--); //i = 1. 事后自减
192 | Console.WriteLine(--i); //i = 0. 事先自减
193 |
194 | ///////////////////////////////////////
195 | // 控制结构
196 | ///////////////////////////////////////
197 | Console.WriteLine("\n->Control Structures");
198 |
199 | // 类似C的if语句
200 | int j = 10;
201 | if (j == 10)
202 | {
203 | Console.WriteLine("I get printed");
204 | }
205 | else if (j > 10)
206 | {
207 | Console.WriteLine("I don't");
208 | }
209 | else
210 | {
211 | Console.WriteLine("I also don't");
212 | }
213 |
214 | // 三元表达式
215 | // 简单的 if/else 语句可以写成:
216 | // <条件> ? <真> : <假>
217 | string isTrue = (true) ? "True" : "False";
218 |
219 | // While 循环
220 | int fooWhile = 0;
221 | while (fooWhile < 100)
222 | {
223 | //迭代 100 次, fooWhile 0->99
224 | fooWhile++;
225 | }
226 |
227 | // Do While 循环
228 | int fooDoWhile = 0;
229 | do
230 | {
231 | //迭代 100 次, fooDoWhile 0->99
232 | fooDoWhile++;
233 | } while (fooDoWhile < 100);
234 |
235 | //for 循环结构 => for(<初始条件>; <条件>; <步>)
236 | for (int fooFor = 0; fooFor < 10; fooFor++)
237 | {
238 | //迭代10次, fooFor 0->9
239 | }
240 |
241 | // foreach循环
242 | // foreach 循环结构 => foreach(<迭代器类型> <迭代器> in <可枚举结构>)
243 | // foreach 循环适用于任何实现了 IEnumerable 或 IEnumerable 的对象。
244 | // .Net 框架下的集合类型(数组, 列表, 字典...)
245 | // 都实现了这些接口
246 | // (下面的代码中,ToCharArray()可以删除,因为字符串同样实现了IEnumerable)
247 | foreach (char character in "Hello World".ToCharArray())
248 | {
249 | //迭代字符串中的所有字符
250 | }
251 |
252 | // Switch 语句
253 | // switch 适用于 byte、short、char和int 数据类型。
254 | // 同样适用于可枚举的类型
255 | // 包括字符串类, 以及一些封装了原始值的类:
256 | // Character、Byte、Short和Integer。
257 | int month = 3;
258 | string monthString;
259 | switch (month)
260 | {
261 | case 1:
262 | monthString = "January";
263 | break;
264 | case 2:
265 | monthString = "February";
266 | break;
267 | case 3:
268 | monthString = "March";
269 | break;
270 | // 你可以一次匹配多个case语句
271 | // 但是你在添加case语句后需要使用break
272 | // (否则你需要显式地使用goto case x语句)
273 | case 6:
274 | case 7:
275 | case 8:
276 | monthString = "Summer time!!";
277 | break;
278 | default:
279 | monthString = "Some other month";
280 | break;
281 | }
282 |
283 | ///////////////////////////////////////
284 | // 转换、指定数据类型
285 | ///////////////////////////////////////
286 |
287 | // 转换类型
288 |
289 | // 转换字符串为整数
290 | // 转换失败会抛出异常
291 | int.Parse("123");//返回整数类型的"123"
292 |
293 | // TryParse会尝试转换类型,失败时会返回缺省类型
294 | // 例如 0
295 | int tryInt;
296 | if (int.TryParse("123", out tryInt)) // Funciton is boolean
297 | Console.WriteLine(tryInt); // 123
298 |
299 | // 转换整数为字符串
300 | // Convert类提供了一系列便利转换的方法
301 | Convert.ToString(123);
302 | // or
303 | tryInt.ToString();
304 | }
305 |
306 | ///////////////////////////////////////
307 | // 类
308 | ///////////////////////////////////////
309 | public static void Classes()
310 | {
311 | // 参看文件尾部的对象声明
312 |
313 | // 使用new初始化对象
314 | Bicycle trek = new Bicycle();
315 |
316 | // 调用对象的方法
317 | trek.SpeedUp(3); // 你应该一直使用setter和getter方法
318 | trek.Cadence = 100;
319 |
320 | // 查看对象的信息.
321 | Console.WriteLine("trek info: " + trek.Info());
322 |
323 | // 实例化一个新的Penny Farthing
324 | PennyFarthing funbike = new PennyFarthing(1, 10);
325 | Console.WriteLine("funbike info: " + funbike.Info());
326 |
327 | Console.Read();
328 | } // 结束main方法
329 |
330 | // 终端程序 终端程序必须有一个main方法作为入口
331 | public static void Main(string[] args)
332 | {
333 | OtherInterestingFeatures();
334 | }
335 |
336 | //
337 | // 有趣的特性
338 | //
339 |
340 | // 默认方法签名
341 |
342 | public // 可见性
343 | static // 允许直接调用类,无需先创建实例
344 | int, //返回值
345 | MethodSignatures(
346 | int maxCount, // 第一个变量,类型为整型
347 | int count = 0, // 如果没有传入值,则缺省值为0
348 | int another = 3,
349 | params string[] otherParams // 捕获其他参数
350 | )
351 | {
352 | return -1;
353 | }
354 |
355 | // 方法可以重名,只要签名不一样
356 | public static void MethodSignature(string maxCount)
357 | {
358 | }
359 |
360 | //泛型
361 | // TKey和TValue类由用用户调用函数时指定。
362 | // 以下函数模拟了Python的SetDefault
363 | public static TValue SetDefault(
364 | IDictionary dictionary,
365 | TKey key,
366 | TValue defaultItem)
367 | {
368 | TValue result;
369 | if (!dictionary.TryGetValue(key, out result))
370 | return dictionary[key] = defaultItem;
371 | return result;
372 | }
373 |
374 | // 你可以限定传入值的范围
375 | public static void IterateAndPrint(T toPrint) where T: IEnumerable
376 | {
377 | // 我们可以进行迭代,因为T是可枚举的
378 | foreach (var item in toPrint)
379 | // ittm为整数
380 | Console.WriteLine(item.ToString());
381 | }
382 |
383 | public static void OtherInterestingFeatures()
384 | {
385 | // 可选参数
386 | MethodSignatures(3, 1, 3, "Some", "Extra", "Strings");
387 | MethodSignatures(3, another: 3); // 显式指定参数,忽略可选参数
388 |
389 | // 扩展方法
390 | int i = 3;
391 | i.Print(); // 参见下面的定义
392 |
393 | // 可为null的类型 对数据库交互、返回值很有用
394 | // 任何值类型 (i.e. 不为类) 添加后缀 ? 后会变为可为null的值
395 | // <类型>? <变量名> = <值>
396 | int? nullable = null; // Nullable 的简写形式
397 | Console.WriteLine("Nullable variable: " + nullable);
398 | bool hasValue = nullable.HasValue; // 不为null时返回真
399 | // ?? 是用于指定默认值的语法糖
400 | // 以防变量为null的情况
401 | int notNullable = nullable ?? 0; // 0
402 |
403 | // 变量类型推断 - 你可以让编译器推断变量类型:
404 | var magic = "编译器确定magic是一个字符串,所以仍然是类型安全的";
405 | // magic = 9; // 不工作,因为magic是字符串,而不是整数。
406 |
407 | // 泛型
408 | //
409 | var phonebook = new Dictionary() {
410 | {"Sarah", "212 555 5555"} // 在电话簿中加入新条目
411 | };
412 |
413 | // 调用上面定义为泛型的SETDEFAULT
414 | Console.WriteLine(SetDefault(phonebook, "Shaun", "No Phone")); // 没有电话
415 | // 你不用指定TKey、TValue,因为它们会被隐式地推导出来
416 | Console.WriteLine(SetDefault(phonebook, "Sarah", "No Phone")); // 212 555 5555
417 |
418 | // lambda表达式 - 允许你用一行代码搞定函数
419 | Func square = (x) => x * x; // 最后一项为返回值
420 | Console.WriteLine(square(3)); // 9
421 |
422 | // 可抛弃的资源管理 - 让你很容易地处理未管理的资源
423 | // 大多数访问未管理资源 (文件操作符、设备上下文, etc.)的对象
424 | // 都实现了IDisposable接口。
425 | // using语句会为你清理IDisposable对象。
426 | using (StreamWriter writer = new StreamWriter("log.txt"))
427 | {
428 | writer.WriteLine("这里没有什么可疑的东西");
429 | // 在作用域的结尾,资源会被回收
430 | // (即使有异常抛出,也一样会回收)
431 | }
432 |
433 | // 并行框架
434 | // http://blogs.msdn.com/b/csharpfaq/archive/2010/06/01/parallel-programming-in-net-framework-4-getting-started.aspx
435 | var websites = new string[] {
436 | "http://www.google.com", "http://www.reddit.com",
437 | "http://www.shaunmccarthy.com"
438 | };
439 | var responses = new Dictionary();
440 |
441 | // 为每个请求新开一个线程
442 | // 在运行下一步前合并结果
443 | Parallel.ForEach(websites,
444 | new ParallelOptions() {MaxDegreeOfParallelism = 3}, // max of 3 threads
445 | website =>
446 | {
447 | // Do something that takes a long time on the file
448 | using (var r = WebRequest.Create(new Uri(website)).GetResponse())
449 | {
450 | responses[website] = r.ContentType;
451 | }
452 | });
453 |
454 | // 直到所有的请求完成后才会运行下面的代码
455 | foreach (var key in responses.Keys)
456 | Console.WriteLine("{0}:{1}", key, responses[key]);
457 |
458 | // 动态对象(配合其他语言使用很方便)
459 | dynamic student = new ExpandoObject();
460 | student.FirstName = "First Name"; // 不需要先定义类!
461 |
462 | // 你甚至可以添加方法(接受一个字符串,输出一个字符串)
463 | student.Introduce = new Func(
464 | (introduceTo) => string.Format("Hey {0}, this is {1}", student.FirstName, introduceTo));
465 | Console.WriteLine(student.Introduce("Beth"));
466 |
467 | // IQUERYABLE - 几乎所有的集合都实现了它,
468 | // 带给你 Map / Filter / Reduce 风格的方法
469 | var bikes = new List();
470 | bikes.Sort(); // Sorts the array
471 | bikes.Sort((b1, b2) => b1.Wheels.CompareTo(b2.Wheels)); // 根据车轮数排序
472 | var result = bikes
473 | .Where(b => b.Wheels > 3) // 筛选 - 可以连锁使用 (返回IQueryable)
474 | .Where(b => b.IsBroken && b.HasTassles)
475 | .Select(b => b.ToString()); // Map - 这里我们使用了select,所以结果是IQueryable
476 |
477 | var sum = bikes.Sum(b => b.Wheels); // Reduce - 计算集合中的轮子总数
478 |
479 | // 创建一个包含基于自行车的一些参数生成的隐式对象的列表
480 | var bikeSummaries = bikes.Select(b=>new { Name = b.Name, IsAwesome = !b.IsBroken && b.HasTassles });
481 | // 很难演示,但是编译器在代码编译完成前就能推导出以上对象的类型
482 | foreach (var bikeSummary in bikeSummaries.Where(b => b.IsAwesome))
483 | Console.WriteLine(bikeSummary.Name);
484 |
485 | // ASPARALLEL
486 | // 邪恶的特性 —— 组合了linq和并行操作
487 | var threeWheelers = bikes.AsParallel().Where(b => b.Wheels == 3).Select(b => b.Name);
488 | // 以上代码会并发地运行。会自动新开线程,分别计算结果。
489 | // 适用于多核、大数据量的场景。
490 |
491 | // LINQ - 将IQueryable映射到存储,延缓执行
492 | // 例如 LinqToSql 映射数据库, LinqToXml 映射XML文档
493 | var db = new BikeRespository();
494 |
495 | // 执行被延迟了,这对于查询数据库来说很好
496 | var filter = db.Bikes.Where(b => b.HasTassles); // 不运行查询
497 | if (42 > 6) // 你可以不断地增加筛选,包括有条件的筛选,例如用于“高级搜索”功能
498 | filter = filter.Where(b => b.IsBroken); // 不运行查询
499 |
500 | var query = filter
501 | .OrderBy(b => b.Wheels)
502 | .ThenBy(b => b.Name)
503 | .Select(b => b.Name); // 仍然不运行查询
504 |
505 | // 现在运行查询,运行查询的时候会打开一个读取器,所以你迭代的是一个副本
506 | foreach (string bike in query)
507 | Console.WriteLine(result);
508 |
509 |
510 |
511 | }
512 |
513 | } // 结束LearnCSharp类
514 |
515 | // 你可以在同一个 .cs 文件中包含其他类
516 |
517 | public static class Extensions
518 | {
519 | // 扩展函数
520 | public static void Print(this object obj)
521 | {
522 | Console.WriteLine(obj.ToString());
523 | }
524 | }
525 | // 声明类的语法:
526 | // class <类名>{
527 | // //数据字段, 构造器, 内部函数.
528 | / // 在Java中函数被称为方法。
529 | // }
530 |
531 | public class Bicycle
532 | {
533 | // 自行车的字段、变量
534 | public int Cadence // Public: 任何地方都可以访问
535 | {
536 | get // get - 定义获取属性的方法
537 | {
538 | return _cadence;
539 | }
540 | set // set - 定义设置属性的方法
541 | {
542 | _cadence = value; // value是被传递给setter的值
543 | }
544 | }
545 | private int _cadence;
546 |
547 | protected virtual int Gear // 类和子类可以访问
548 | {
549 | get; // 创建一个自动属性,无需成员字段
550 | set;
551 | }
552 |
553 | internal int Wheels // Internal:在同一程序集内可以访问
554 | {
555 | get;
556 | private set; // 可以给get/set方法添加修饰符
557 | }
558 |
559 | int _speed; // 默认为private: 只可以在这个类内访问,你也可以使用`private`关键词
560 | public string Name { get; set; }
561 |
562 | // enum类型包含一组常量
563 | // 它将名称映射到值(除非特别说明,是一个整型)
564 | // enmu元素的类型可以是byte、sbyte、short、ushort、int、uint、long、ulong。
565 | // enum不能包含相同的值。
566 | public enum BikeBrand
567 | {
568 | AIST,
569 | BMC,
570 | Electra = 42, //你可以显式地赋值
571 | Gitane // 43
572 | }
573 | // 我们在Bicycle类中定义的这个类型,所以它是一个内嵌类型。
574 | // 这个类以外的代码应当使用`Bicycle.Brand`来引用。
575 |
576 | public BikeBrand Brand; // 声明一个enum类型之后,我们可以声明这个类型的字段
577 |
578 | // 静态方法的类型为自身,不属于特定的对象。
579 | // 你无需引用对象就可以访问他们。
580 | // Console.WriteLine("Bicycles created: " + Bicycle.bicyclesCreated);
581 | static public int BicyclesCreated = 0;
582 |
583 | // 只读值在运行时确定
584 | // 它们只能在声明或构造器内被赋值
585 | readonly bool _hasCardsInSpokes = false; // read-only private
586 |
587 | // 构造器是创建类的一种方式
588 | // 下面是一个默认的构造器
589 | public Bicycle()
590 | {
591 | this.Gear = 1; // 你可以使用关键词this访问对象的成员
592 | Cadence = 50; // 不过你并不总是需要它
593 | _speed = 5;
594 | Name = "Bontrager";
595 | Brand = BikeBrand.AIST;
596 | BicyclesCreated++;
597 | }
598 |
599 | // 另一个构造器的例子(包含参数)
600 | public Bicycle(int startCadence, int startSpeed, int startGear,
601 | string name, bool hasCardsInSpokes, BikeBrand brand)
602 | : base() // 首先调用base
603 | {
604 | Gear = startGear;
605 | Cadence = startCadence;
606 | _speed = startSpeed;
607 | Name = name;
608 | _hasCardsInSpokes = hasCardsInSpokes;
609 | Brand = brand;
610 | }
611 |
612 | // 构造器可以连锁使用
613 | public Bicycle(int startCadence, int startSpeed, BikeBrand brand) :
614 | this(startCadence, startSpeed, 0, "big wheels", true, brand)
615 | {
616 | }
617 |
618 | // 函数语法
619 | // <返回值> <函数名称>(<参数>)
620 |
621 | // 类可以为字段实现 getters 和 setters 方法 for their fields
622 | // 或者可以实现属性(C#推荐使用这个)
623 | // 方法的参数可以有默认值
624 | // 在有默认值的情况下,调用方法的时候可以省略相应的参数
625 | public void SpeedUp(int increment = 1)
626 | {
627 | _speed += increment;
628 | }
629 |
630 | public void SlowDown(int decrement = 1)
631 | {
632 | _speed -= decrement;
633 | }
634 |
635 | // 属性可以访问和设置值
636 | // 当只需要访问数据的时候,考虑使用属性。
637 | // 属性可以定义get和set,或者是同时定义两者
638 | private bool _hasTassles; // private variable
639 | public bool HasTassles // public accessor
640 | {
641 | get { return _hasTassles; }
642 | set { _hasTassles = value; }
643 | }
644 |
645 | // 你可以在一行之内定义自动属性
646 | // 这个语法会自动创建后备字段
647 | // 你可以给getter或setter设置访问修饰符
648 | // 以便限制它们的访问
649 | public bool IsBroken { get; private set; }
650 |
651 | // 属性的实现可以是自动的
652 | public int FrameSize
653 | {
654 | get;
655 | // 你可以给get或set指定访问修饰符
656 | // 以下代码意味着只有Bicycle类可以调用Framesize的set
657 | private set;
658 | }
659 |
660 | //显示对象属性的方法
661 | public virtual string Info()
662 | {
663 | return "Gear: " + Gear +
664 | " Cadence: " + Cadence +
665 | " Speed: " + _speed +
666 | " Name: " + Name +
667 | " Cards in Spokes: " + (_hasCardsInSpokes ? "yes" : "no") +
668 | "\n------------------------------\n"
669 | ;
670 | }
671 |
672 | // 方法可以是静态的。通常用于辅助方法。
673 | public static bool DidWeCreateEnoughBycles()
674 | {
675 | // 在静态方法中,你只能引用类的静态成员
676 | return BicyclesCreated > 9000;
677 | } // 如果你的类只需要静态成员,考虑将整个类作为静态类。
678 |
679 |
680 | } // Bicycle类结束
681 |
682 | // PennyFarthing是Bicycle的一个子类
683 | class PennyFarthing : Bicycle
684 | {
685 | // (Penny Farthings是一种前轮很大的自行车。没有齿轮。)
686 |
687 | // 调用父构造器
688 | public PennyFarthing(int startCadence, int startSpeed) :
689 | base(startCadence, startSpeed, 0, "PennyFarthing", true, BikeBrand.Electra)
690 | {
691 | }
692 |
693 | protected override int Gear
694 | {
695 | get
696 | {
697 | return 0;
698 | }
699 | set
700 | {
701 | throw new ArgumentException("你不可能在PennyFarthing上切换齿轮");
702 | }
703 | }
704 |
705 | public override string Info()
706 | {
707 | string result = "PennyFarthing bicycle ";
708 | result += base.ToString(); // 调用父方法
709 | return result;
710 | }
711 | }
712 |
713 | // 接口只包含成员的签名,而没有实现。
714 | interface IJumpable
715 | {
716 | void Jump(int meters); // 所有接口成员是隐式地公开的
717 | }
718 |
719 | interface IBreakable
720 | {
721 | bool Broken { get; } // 接口可以包含属性、方法和事件
722 | }
723 |
724 | // 类只能继承一个类,但是可以实现任意数量的接口
725 | {
726 | int damage = 0;
727 |
728 | public void Jump(int meters)
729 | {
730 | damage += meters;
731 | }
732 |
733 | public bool Broken
734 | {
735 | get
736 | {
737 | return damage > 100;
738 | }
739 | }
740 | }
741 |
742 | ///
743 | /// 连接数据库,一个 LinqToSql的示例。
744 | /// EntityFramework Code First 很棒 (类似 Ruby的 ActiveRecord, 不过是双向的)
745 | /// http://msdn.microsoft.com/en-us/data/jj193542.aspx
746 | ///
747 | public class BikeRespository : DbSet
748 | {
749 | public BikeRespository()
750 | : base()
751 | {
752 | }
753 |
754 | public DbSet Bikes { get; set; }
755 | }
756 | } // 结束 Namespace
757 |
--------------------------------------------------------------------------------