Fixed something wrong.

This commit is contained in:
Oling Cat
2012-09-22 16:00:26 +08:00
parent a39d2cf8fe
commit 65aa4e36d2
4 changed files with 276 additions and 276 deletions

2
2.2.md
View File

@@ -395,7 +395,7 @@ slice有一些简便的操作
// map有两个返回值第二个返回值如果不存在key那么ok为false如果存在ok为true // map有两个返回值第二个返回值如果不存在key那么ok为false如果存在ok为true
csharpRating, ok := rating["C#"] csharpRating, ok := rating["C#"]
if ok { if ok {
fmt.Println("C# is in the map and its rating is ", csharp_rating) fmt.Println("C# is in the map and its rating is ", csharpRating)
} else { } else {
fmt.Println("We have no rating associated with C# in the map") fmt.Println("We have no rating associated with C# in the map")
} }

100
2.3.md
View File

@@ -1,9 +1,9 @@
#2.3 流程和函数 #2.3 流程和函数
这小节我们要介绍Go里面的流程控制以及函数操作 这小节我们要介绍Go里面的流程控制以及函数操作
##流程控制 ##流程控制
流程控制是最伟大的发明了,因为有了它,你可以通过很简单的描述来表达很复杂的事情 流程控制在编程语言中是最伟大的发明了,因为有了它,你可以通过很简单的描述来表达很复杂的事情
###if ###if
if语法也许是所有语言里面最常见的一种语法了,它的语法概括起来就是:`如果满足条件就做某事,否则做另一件事` `if`也许是所有语言最常见的了,它的语法概括起来就是:`如果满足条件就做某事,否则做另一件事`
Go里面`if`条件语法中不需要括号,如下代码所示 Go里面`if`条件语法中不需要括号,如下代码所示
@@ -15,7 +15,7 @@ Go里面`if`条件语法中不需要括号,如下代码所示
Go的`if`还有一个强大的地方就是条件里面允许声明一个变量,这个变量的作用域只能在该条件中,出了这个条件就不起作用了,如下所示 Go的`if`还有一个强大的地方就是条件里面允许声明一个变量,这个变量的作用域只能在该条件中,出了这个条件就不起作用了,如下所示
// 计算获取值x,然后根据x返回的大小判断是否大于10. // 计算获取值x,然后根据x返回的大小判断是否大于10
if x := computedValue(); x > 10 { if x := computedValue(); x > 10 {
fmt.Println("x is greater than 10") fmt.Println("x is greater than 10")
} else { } else {
@@ -25,7 +25,7 @@ Go的`if`还有一个强大的地方就是条件里面允许声明一个变量
//这个地方如果这样调用就编译出错了因为x是条件里面的变量 //这个地方如果这样调用就编译出错了因为x是条件里面的变量
fmt.Println(x) fmt.Println(x)
多个条件的时候如下所示 多个条件的时候如下所示
if integer == 3 { if integer == 3 {
fmt.Println("The integer is equal to 3") fmt.Println("The integer is equal to 3")
@@ -50,15 +50,15 @@ Go有`goto`语句——请明智地使用它。用`goto`跳转到一定是当前
标签名是大小写敏感的。 标签名是大小写敏感的。
###for ###for
Go里面最强大的一个控制逻辑就是`for`,它即可以用来循环读取数据,又可以当作`while`来控制逻辑,还能迭代操作。它的语法如下 Go里面最强大的一个控制逻辑就是`for`,它即可以用来循环读取数据,又可以当作`while`来控制逻辑,还能迭代操作。它的语法如下
for expression1; expression2; expression3 { for expression1; expression2; expression3 {
... //...
} }
`expression1``expression2``expression3`都是表达式,其中`expression1``expression3`是变量声明或者函数调用返回值之类的,`expression2`是条件判断,`expression1`在循环开始之前调用,`expression3`在每轮循环结束之时调用。 `expression1``expression2``expression3`都是表达式,其中`expression1``expression3`是变量声明或者函数调用返回值之类的,`expression2`是条件判断,`expression1`在循环开始之前调用,`expression3`在每轮循环结束之时调用。
一个例子比上面讲那么多更有用,那么我们看看下面的例子吧 一个例子比上面讲那么多更有用,那么我们看看下面的例子吧
package main package main
import "fmt" import "fmt"
@@ -70,9 +70,9 @@ Go里面最强大的一个控制逻辑就是`for`,它即可以用来循环读
} }
fmt.Println("sum is equal to ", sum) fmt.Println("sum is equal to ", sum)
} }
//输出sum is equal to 45 // 输出sum is equal to 45
有些时候有多个需要操作的赋值操作由于Go里面没有`,`操作,那么可以使用平行赋值`i, j = i+1, j-1` 有些时候需要进行多个赋值操作由于Go里面没有`,`操作,那么可以使用平行赋值`i, j = i+1, j-1`
有些时候如果我们忽略`expression1``expression3` 有些时候如果我们忽略`expression1``expression3`
@@ -82,23 +82,23 @@ Go里面最强大的一个控制逻辑就是`for`,它即可以用来循环读
sum += sum sum += sum
} }
其中`;`也可以省略,那么就变成如下的代码了,是不是似曾相识对,这就是`while`的功能 其中`;`也可以省略,那么就变成如下的代码了,是不是似曾相识对,这就是`while`的功能
sum := 1 sum := 1
for sum < 1000 { for sum < 1000 {
sum += sum sum += sum
} }
在循环里面有两个关键操作`break``continue` ,`break`操作是跳出当前循环,`continue`是跳本次循环当嵌套过深的时候,`break`可以配合标签使用,即跳标签所指定的循环,详细参考如下例子 在循环里面有两个关键操作`break``continue` ,`break`操作是跳出当前循环,`continue`是跳本次循环当嵌套过深的时候,`break`可以配合标签使用,即跳转至标签所指定的位置,详细参考如下例子
for index := 10; index>0; index-- { for index := 10; index>0; index-- {
if index == 5{ if index == 5{
break或者continue break // 或者continue
} }
fmt.Println(index) fmt.Println(index)
} }
//break打印出来10、9、8、7、6 // break打印出来10、9、8、7、6
//continue打印出来10、9、8、7、6、4、3、2、1 // continue打印出来10、9、8、7、6、4、3、2、1
`break``continue`还可以跟着标号,用来跳到多重循环中的外层循环 `break``continue`还可以跟着标号,用来跳到多重循环中的外层循环
@@ -109,11 +109,11 @@ Go里面最强大的一个控制逻辑就是`for`,它即可以用来循环读
fmt.Println("map's val:",v) fmt.Println("map's val:",v)
} }
其中还可以使用`_`扔掉不需要的返回值 其中还可以使用`_`丢弃不需要的返回值
###switch ###switch
有些时候你需要写很多的`if/else`来实现一些逻辑处理,这个时候代码看上去就很丑很冗长,而且也不易于以后的维护,这个时候`switch`就能很好的解决这个问题它的语法如下 有些时候你需要写很多的`if-else`来实现一些逻辑处理,这个时候代码看上去就很丑很冗长,而且也不易于以后的维护,这个时候`switch`就能很好的解决这个问题它的语法如下
switch sExpr { switch sExpr {
case expr1: case expr1:
@@ -126,7 +126,7 @@ Go里面最强大的一个控制逻辑就是`for`,它即可以用来循环读
other code other code
} }
`sExpr``expr1``expr2``expr3`的类型必须一致。Go的`switch`非常灵活表达式不必是常量或整数,执行的过程从上至下,直到找到匹配项而如果`switch`没有表达式,它会匹配`true` `sExpr``expr1``expr2``expr3`的类型必须一致。Go的`switch`非常灵活表达式不必是常量或整数,执行的过程从上至下,直到找到匹配项而如果`switch`没有表达式,它会匹配`true`
i := 10 i := 10
switch i { switch i {
@@ -144,23 +144,23 @@ Go里面最强大的一个控制逻辑就是`for`,它即可以用来循环读
integer := 6 integer := 6
switch integer { switch integer {
case 4: case 4:
fmt.Println("The integer was <= 4") fmt.Println("The integer was <= 4")
fallthrough fallthrough
case 5: case 5:
fmt.Println("The integer was <= 5") fmt.Println("The integer was <= 5")
fallthrough fallthrough
case 6: case 6:
fmt.Println("The integer was <= 6") fmt.Println("The integer was <= 6")
fallthrough fallthrough
case 7: case 7:
fmt.Println("The integer was <= 7") fmt.Println("The integer was <= 7")
fallthrough fallthrough
case 8: case 8:
fmt.Println("The integer was <= 8") fmt.Println("The integer was <= 8")
fallthrough fallthrough
default: default:
fmt.Println("default case") fmt.Println("default case")
} }
上面的程序将输出 上面的程序将输出
@@ -172,7 +172,7 @@ Go里面最强大的一个控制逻辑就是`for`,它即可以用来循环读
##函数 ##函数
函数是Go里面的核心设计它通过关键字`func`来声明,它的格式如下 函数是Go里面的核心设计它通过关键字`func`来声明,它的格式如下
func funcName(input1 type1, input2 type2) (output1 type1, output2 type2) { func funcName(input1 type1, input2 type2) (output1 type1, output2 type2) {
//这里是处理逻辑代码 //这里是处理逻辑代码
@@ -194,7 +194,7 @@ Go里面最强大的一个控制逻辑就是`for`,它即可以用来循环读
package main package main
import "fmt" import "fmt"
//返回a、b中最大值. // 返回a、b中最大值.
func max(a, b int) int { func max(a, b int) int {
if a > b { if a > b {
return a return a
@@ -212,7 +212,7 @@ Go里面最强大的一个控制逻辑就是`for`,它即可以用来循环读
fmt.Printf("max(%d, %d) = %d\n", x, y, max_xy) fmt.Printf("max(%d, %d) = %d\n", x, y, max_xy)
fmt.Printf("max(%d, %d) = %d\n", x, z, max_xz) fmt.Printf("max(%d, %d) = %d\n", x, z, max_xz)
fmt.Printf("max(%d, %d) = %d\n", y, z, max(y,z)) //just call it here fmt.Printf("max(%d, %d) = %d\n", y, z, max(y,z)) // 也可在这直接调用它
} }
上面这个里面我们可以看到`max`函数有两个参数,它们的类型都是`int`那么第一个变量的类型可以省略默认为离它最近的类型同理多于2个同类型的变量或者返回值。同时我们注意到它的返回值就是一个类型这个就是省略写法。 上面这个里面我们可以看到`max`函数有两个参数,它们的类型都是`int`那么第一个变量的类型可以省略默认为离它最近的类型同理多于2个同类型的变量或者返回值。同时我们注意到它的返回值就是一个类型这个就是省略写法。
@@ -240,7 +240,7 @@ Go语言和C相比更先进的地方其中一点就是能够返回多个
fmt.Printf("%d * %d = %d\n", x, y, xTIMESy) fmt.Printf("%d * %d = %d\n", x, y, xTIMESy)
} }
上面的例子我们可以看到直接返回了两个参数,当然我们也可以命名返回参数的变量,这个例子里面只是用了两个类型,我们也可以改成如下这样的定义,然后返回的时候不用带上变量名,因为直接在函数里面初始化了。但是当你的函数如果是导出的(首字母大写),官方建议,不要命名返回值名称,因为这样会造成生成的文档不易读。 上面的例子我们可以看到直接返回了两个参数,当然我们也可以命名返回参数的变量,这个例子里面只是用了两个类型,我们也可以改成如下这样的定义,然后返回的时候不用带上变量名,因为直接在函数里面初始化了。但如果你的函数是导出的(首字母大写),官方建议,不要命名返回值,因为这样会造成生成的文档不易读。
func SumAndProduct(A, B int) (add int, Multiplied int) { func SumAndProduct(A, B int) (add int, Multiplied int) {
add = A+B add = A+B
@@ -275,17 +275,17 @@ Go函数支持变参。接受变参的函数是有着不定数量的参数的。
func main() { func main() {
x := 3 x := 3
fmt.Println("x = ", x) // 应该输出 "x = 3" fmt.Println("x = ", x) // 应该输出 "x = 3"
x1 := add1(x) //调用add1(x) x1 := add1(x) //调用add1(x)
fmt.Println("x+1 = ", x1) // 应该输出"x+1 = 4" fmt.Println("x+1 = ", x1) // 应该输出"x+1 = 4"
fmt.Println("x = ", x) // 应该输出"x = 3" fmt.Println("x = ", x) // 应该输出"x = 3"
} }
看到了吗?虽然我们调用了`add1`函数,并且在`add1`中执行`a=a+1`操作,但是上面例子中`x`变量的值没有发生变化 看到了吗?虽然我们调用了`add1`函数,并且在`add1`中执行`a=a+1`操作,但是上面例子中`x`变量的值没有发生变化
理由很简单:因为当我们调用`add1`的时候,`add1`接收的参数其实是`x`的copy而不是`x`本身 理由很简单:因为当我们调用`add1`的时候,`add1`接收的参数其实是`x`的copy而不是`x`本身
那你也许会问了,如果真的需要传这个`x`本身,该怎么办呢? 那你也许会问了,如果真的需要传这个`x`本身,该怎么办呢?
@@ -303,12 +303,12 @@ Go函数支持变参。接受变参的函数是有着不定数量的参数的。
func main() { func main() {
x := 3 x := 3
fmt.Println("x = ", x) // 应该输出 "x = 3" fmt.Println("x = ", x) // 应该输出 "x = 3"
x1 := add1(&x) // 调用 add1(&x) 传x的地址 x1 := add1(&x) // 调用 add1(&x) 传x的地址
fmt.Println("x+1 = ", x1) // 应该输出 "x+1 = 4" fmt.Println("x+1 = ", x1) // 应该输出 "x+1 = 4"
fmt.Println("x = ", x) // 应该输出 "x = 4" fmt.Println("x = ", x) // 应该输出 "x = 4"
} }
这样,我们就达到了修改`x`的目的。那么到底传指针有什么好处呢? 这样,我们就达到了修改`x`的目的。那么到底传指针有什么好处呢?
@@ -368,7 +368,7 @@ Go里面有一个不错的设计就是回调函数有点类似面向对象
package main package main
import "fmt" import "fmt"
type testInt func(int) bool //声明了一个函数类型 type testInt func(int) bool // 声明了一个函数类型
func isOdd(integer int) bool { func isOdd(integer int) bool {
if integer%2 == 0 { if integer%2 == 0 {
@@ -384,8 +384,8 @@ Go里面有一个不错的设计就是回调函数有点类似面向对象
return false return false
} }
//声明的函数类型在这个地方当做了一个参数 // 声明的函数类型在这个地方当做了一个参数
func filter(slice []int, f test_int) []int { func filter(slice []int, f testInt) []int {
var result []int var result []int
for _, value := range slice { for _, value := range slice {
if f(value) { if f(value) {
@@ -398,9 +398,9 @@ Go里面有一个不错的设计就是回调函数有点类似面向对象
func main(){ func main(){
slice := []int {1, 2, 3, 4, 5, 7} slice := []int {1, 2, 3, 4, 5, 7}
fmt.Println("slice = ", slice) fmt.Println("slice = ", slice)
odd := filter(slice, isOdd) //函数当做值来传递了 odd := filter(slice, isOdd) // 函数当做值来传递了
fmt.Println("Odd elements of slice are: ", odd) fmt.Println("Odd elements of slice are: ", odd)
even := filter(slice, isEven)//函数当做值来传递了 even := filter(slice, isEven) // 函数当做值来传递了
fmt.Println("Even elements of slice are: ", even) fmt.Println("Even elements of slice are: ", even)
} }

178
2.4.md
View File

@@ -6,23 +6,23 @@ Go语言中也和C或者其他语言一样我们可以声明新的类型
name string name string
age int age int
} }
看到了吗?明一个struct如此简单上面的类型包含有两个字段 看到了吗?明一个struct如此简单上面的类型包含有两个字段
- 一个string类型的字段name用来保存用户名称这个属性 - 一个string类型的字段name用来保存用户名称这个属性
- 一个int类型的字段age,用来保存用户年龄这个属性 - 一个int类型的字段age,用来保存用户年龄这个属性
如何使用struct呢请看下面的代码 如何使用struct呢请看下面的代码
type person struct { type person struct {
name string name string
age int age int
} }
var P person // P现在就是person类型的变量了 var P person // P现在就是person类型的变量了
P.name = "Astaxie" //赋值"Astaxie"给P的name属性. P.name = "Astaxie" // 赋值"Astaxie"给P的name属性.
P.age = 25 //赋值"25"给变量P的age属性 P.age = 25 // 赋值"25"给变量P的age属性
fmt.Printf("The person's name is %s", P.name) // 访问P的name属性. fmt.Printf("The person's name is %s", P.name) // 访问P的name属性.
除了上面这种P的明使用之外,还有两种明使用方式 除了上面这种P的明使用之外,还有两种明使用方式
- 1.按照顺序提供初始化值 - 1.按照顺序提供初始化值
@@ -37,45 +37,45 @@ Go语言中也和C或者其他语言一样我们可以声明新的类型
package main package main
import "fmt" import "fmt"
//明一个新的类型 //明一个新的类型
type person struct { type person struct {
name string name string
age int age int
} }
// 比较两个人的年龄,返回年龄大的那个人,并且返回年龄差 // 比较两个人的年龄,返回年龄大的那个人,并且返回年龄差
// struct也是传值的 // struct也是传值的
func Older(p1, p2 person) (person, int) { func Older(p1, p2 person) (person, int) {
if p1.age>p2.age { //比较p1和p2这两个人的年龄 if p1.age>p2.age { // 比较p1和p2这两个人的年龄
return p1, p1.age-p2.age return p1, p1.age-p2.age
} }
return p2, p2.age-p1.age return p2, p2.age-p1.age
} }
func main() { func main() {
var tom person var tom person
//赋值初始化 // 赋值初始化
tom.name, tom.age = "Tom", 18 tom.name, tom.age = "Tom", 18
//两个字段都写清楚的初始化 // 两个字段都写清楚的初始化
bob := person{age:25, name:"Bob"} bob := person{age:25, name:"Bob"}
//按照struct定义顺序初始化值 // 按照struct定义顺序初始化值
paul := person{"Paul", 43} paul := person{"Paul", 43}
tb_Older, tb_diff := Older(tom, bob) tb_Older, tb_diff := Older(tom, bob)
tp_Older, tp_diff := Older(tom, paul) tp_Older, tp_diff := Older(tom, paul)
bp_Older, bp_diff := Older(bob, paul) bp_Older, bp_diff := Older(bob, paul)
fmt.Printf("Of %s and %s, %s is older by %d years\n", fmt.Printf("Of %s and %s, %s is older by %d years\n",
tom.name, bob.name, tb_Older.name, tb_diff) tom.name, bob.name, tb_Older.name, tb_diff)
fmt.Printf("Of %s and %s, %s is older by %d years\n", fmt.Printf("Of %s and %s, %s is older by %d years\n",
tom.name, paul.name, tp_Older.name, tp_diff) tom.name, paul.name, tp_Older.name, tp_diff)
fmt.Printf("Of %s and %s, %s is older by %d years\n", fmt.Printf("Of %s and %s, %s is older by %d years\n",
bob.name, paul.name, bp_Older.name, bp_diff) bob.name, paul.name, bp_Older.name, bp_diff)
} }
###struct的匿名字段 ###struct的匿名字段
@@ -89,37 +89,37 @@ Go语言中也和C或者其他语言一样我们可以声明新的类型
import "fmt" import "fmt"
type Human struct { type Human struct {
name string name string
age int age int
weight int weight int
} }
type Student struct { type Student struct {
Human //匿名字段那么默认Student就包含了Human的所有字段 Human // 匿名字段那么默认Student就包含了Human的所有字段
speciality string speciality string
} }
func main() { func main() {
//我们初始化一个学生 // 我们初始化一个学生
mark := Student{Human{"Mark", 25, 120}, "Computer Science"} mark := Student{Human{"Mark", 25, 120}, "Computer Science"}
//我们访问相应的字段 // 我们访问相应的字段
fmt.Println("His name is ", mark.name) fmt.Println("His name is ", mark.name)
fmt.Println("His age is ", mark.age) fmt.Println("His age is ", mark.age)
fmt.Println("His weight is ", mark.weight) fmt.Println("His weight is ", mark.weight)
fmt.Println("His speciality is ", mark.speciality) fmt.Println("His speciality is ", mark.speciality)
//修改对应的备注信息 // 修改对应的备注信息
mark.speciality = "AI" mark.speciality = "AI"
fmt.Println("Mark changed his speciality") fmt.Println("Mark changed his speciality")
fmt.Println("His speciality is ", mark.speciality) fmt.Println("His speciality is ", mark.speciality)
//修改他的年龄信息 // 修改他的年龄信息
fmt.Println("Mark become old") fmt.Println("Mark become old")
mark.age = 46 mark.age = 46
fmt.Println("His age is", mark.age) fmt.Println("His age is", mark.age)
//修改他的体重信息 // 修改他的体重信息
fmt.Println("Mark is not an athlet anymore") fmt.Println("Mark is not an athlet anymore")
mark.weight += 60 mark.weight += 60
fmt.Println("His weight is", mark.weight) fmt.Println("His weight is", mark.weight)
} }
我们看到Student访问属性age和name的时候就像访问自己所有用的字段一样匿名字段就是这样能够实现字段的继承。是不是很酷啊还有比这个更酷的呢那就是student还能访问Human这个字段作为字段名。请看下面的代码是不是更酷了。 我们看到Student访问属性age和name的时候就像访问自己所有用的字段一样匿名字段就是这样能够实现字段的继承。是不是很酷啊还有比这个更酷的呢那就是student还能访问Human这个字段作为字段名。请看下面的代码是不是更酷了。
@@ -135,38 +135,38 @@ Go语言中也和C或者其他语言一样我们可以声明新的类型
type Skills []string type Skills []string
type Human struct { type Human struct {
name string name string
age int age int
weight int weight int
} }
type Student struct { type Student struct {
Human //匿名字段struct Human // 匿名字段struct
Skills //匿名字段自定义的类型string slice Skills // 匿名字段自定义的类型string slice
int //内置类型作为匿名字段 int // 内置类型作为匿名字段
speciality string speciality string
} }
func main() { func main() {
//初始化学生Jane // 初始化学生Jane
jane := Student{Human:Human{"Jane", 35, 100}, speciality:"Biology"} jane := Student{Human:Human{"Jane", 35, 100}, speciality:"Biology"}
//现在我们来访问相应的字段 // 现在我们来访问相应的字段
fmt.Println("Her name is ", jane.name) fmt.Println("Her name is ", jane.name)
fmt.Println("Her age is ", jane.age) fmt.Println("Her age is ", jane.age)
fmt.Println("Her weight is ", jane.weight) fmt.Println("Her weight is ", jane.weight)
fmt.Println("Her speciality is ", jane.speciality) fmt.Println("Her speciality is ", jane.speciality)
//我们来修改他的skill技能字段 // 我们来修改他的skill技能字段
jane.Skills = []string{"anatomy"} jane.Skills = []string{"anatomy"}
fmt.Println("Her skills are ", jane.Skills) fmt.Println("Her skills are ", jane.Skills)
fmt.Println("She acquired two new ones ") fmt.Println("She acquired two new ones ")
jane.Skills = append(jane.Skills, "physics", "golang") jane.Skills = append(jane.Skills, "physics", "golang")
fmt.Println("Her skills now are ", jane.Skills) fmt.Println("Her skills now are ", jane.Skills)
//修改匿名内置类型字段 // 修改匿名内置类型字段
jane.int = 3 jane.int = 3
fmt.Println("Her preferred number is", jane.int) fmt.Println("Her preferred number is", jane.int)
} }
从上面例子我们看出来struct不仅仅能够将struct作为匿名字段、自定义类型、内置类型都可以作为匿名字段而且可以在相应的字段上面进行函数操作(如例子中的append) 从上面例子我们看出来struct不仅仅能够将struct作为匿名字段、自定义类型、内置类型都可以作为匿名字段而且可以在相应的字段上面进行函数操作如例子中的append
这里有一个问题如果human里面有一个字段叫做phone而student也有一个字段叫做phone那么该怎么办呢 这里有一个问题如果human里面有一个字段叫做phone而student也有一个字段叫做phone那么该怎么办呢
@@ -178,22 +178,22 @@ Go里面很简单的解决了这个问题最外层的优先访问也就是
import "fmt" import "fmt"
type Human struct { type Human struct {
name string name string
age int age int
phone string //Human类型拥有的字段 phone string // Human类型拥有的字段
} }
type Employee struct { type Employee struct {
Human //匿名字段Human Human // 匿名字段Human
speciality string speciality string
phone string //雇员的phone字段 phone string // 雇员的phone字段
} }
func main() { func main() {
Bob := Employee{Human{"Bob", 34, "777-444-XXXX"}, "Designer", "333-222"} Bob := Employee{Human{"Bob", 34, "777-444-XXXX"}, "Designer", "333-222"}
fmt.Println("Bob's work phone is:", Bob.phone) fmt.Println("Bob's work phone is:", Bob.phone)
//如果我们要访问Human的phone字段 // 如果我们要访问Human的phone字段
fmt.Println("Bob's personal phone is:", Bob.Human.phone) fmt.Println("Bob's personal phone is:", Bob.Human.phone)
} }

272
2.5.md
View File

@@ -6,23 +6,23 @@
package main package main
import "fmt" import "fmt"
type Rectangle struct { type Rectangle struct {
width, height float64 width, height float64
}
func area(r Rectangle) float64 {
return r.width*r.height
}
func main() {
r1 := Rectangle{12, 2}
r2 := Rectangle{9, 4}
fmt.Println("Area of r1 is: ", area(r1))
fmt.Println("Area of r2 is: ", area(r2))
} }
这个代码是可以计算出来长方形的面积但是area不是作为Rectangle的一个方法(类似面向对象里面的方法)实现的, 而是Rectangle的对象(r1,r2)作为函数的一个参数传入,然后计算获取的。 func area(r Rectangle) float64 {
return r.width*r.height
}
func main() {
r1 := Rectangle{12, 2}
r2 := Rectangle{9, 4}
fmt.Println("Area of r1 is: ", area(r1))
fmt.Println("Area of r2 is: ", area(r2))
}
这个代码是可以计算出来长方形的面积但是area不是作为Rectangle的一个方法类似面向对象里面的方法实现的而是Rectangle的对象r1,r2作为函数的一个参数传入然后计算获取的。
这样实现有什么问题,当然没有问题咯,但是当你代码里面增加一个圆形、正方形、多边形等的时候,然后你又想计算他们的面积的时候怎么办啊?那就增加新的函数咯,但是函数名你就必须要跟着换了,你就要把函数名变成`area_rectangle, area_circle, area_triangle...` 这样实现有什么问题,当然没有问题咯,但是当你代码里面增加一个圆形、正方形、多边形等的时候,然后你又想计算他们的面积的时候怎么办啊?那就增加新的函数咯,但是函数名你就必须要跟着换了,你就要把函数名变成`area_rectangle, area_circle, area_triangle...`
@@ -34,9 +34,9 @@
>“A method is a function with an implicit first argument, called a receiver.“ >“A method is a function with an implicit first argument, called a receiver.“
method的语法如下 method的语法如下
func (ReceiverType r) func_name (parameters) (results) func (ReceiverType r) funcName(parameters) (results)
下面我们用最开始的例子用method来实现 下面我们用最开始的例子用method来实现
@@ -45,36 +45,36 @@ method的语法如下
"fmt" "fmt"
"math" "math"
) )
type Rectangle struct { type Rectangle struct {
width, height float64 width, height float64
} }
type Circle struct { type Circle struct {
radius float64 radius float64
} }
func (r Rectangle) area() float64 { func (r Rectangle) area() float64 {
return r.width*r.height return r.width*r.height
} }
func (c Circle) area() float64 { func (c Circle) area() float64 {
return c.radius * c.radius * math.Pi return c.radius * c.radius * math.Pi
} }
func main() { func main() {
r1 := Rectangle{12, 2} r1 := Rectangle{12, 2}
r2 := Rectangle{9, 4} r2 := Rectangle{9, 4}
c1 := Circle{10} c1 := Circle{10}
c2 := Circle{25} c2 := Circle{25}
fmt.Println("Area of r1 is: ", r1.area()) fmt.Println("Area of r1 is: ", r1.area())
fmt.Println("Area of r2 is: ", r2.area()) fmt.Println("Area of r2 is: ", r2.area())
fmt.Println("Area of c1 is: ", c1.area()) fmt.Println("Area of c1 is: ", c1.area())
fmt.Println("Area of c2 is: ", c2.area()) fmt.Println("Area of c2 is: ", c2.area())
} }
在使用method的时候重要注意几点 在使用method的时候重要注意几点
- 虽然method的名字一模一样但是如果接收者不一样那么method就不一样 - 虽然method的名字一模一样但是如果接收者不一样那么method就不一样
@@ -83,8 +83,8 @@ method的语法如下
那是不是method只能作用在struct上面呢当然不是咯他可以定义在任何你自定义的类型、内置类型、struct等各种类型上面。这里你是不是有点迷糊了什么叫自定义类型自定义类型不就是struct嘛不是这样的哦struct只是自定义类型里面一种比较特殊的类型而已还有其他自定义类型申明可以通过如下这样的申明来实现。 那是不是method只能作用在struct上面呢当然不是咯他可以定义在任何你自定义的类型、内置类型、struct等各种类型上面。这里你是不是有点迷糊了什么叫自定义类型自定义类型不就是struct嘛不是这样的哦struct只是自定义类型里面一种比较特殊的类型而已还有其他自定义类型申明可以通过如下这样的申明来实现。
type type_name type_literal type typeName typeLiteral
请看下面这个申明自定义类型的代码 请看下面这个申明自定义类型的代码
type ages int type ages int
@@ -94,12 +94,12 @@ method的语法如下
type months map[string]int type months map[string]int
m := months { m := months {
"January":31, "January":31,
"February":28, "February":28,
... ...
"December":31, "December":31,
} }
看到了吗?简单的很吧,这样你就可以在自己的代码里面定义有意义的类型了,实际上只是一个定义了一个别名,有点类似于c中的typedef例如上面ages替代了int 看到了吗?简单的很吧,这样你就可以在自己的代码里面定义有意义的类型了,实际上只是一个定义了一个别名,有点类似于c中的typedef例如上面ages替代了int
好了,让我们回到`method` 好了,让我们回到`method`
@@ -110,75 +110,75 @@ method的语法如下
import "fmt" import "fmt"
const( const(
WHITE = iota WHITE = iota
BLACK BLACK
BLUE BLUE
RED RED
YELLOW YELLOW
) )
type Color byte type Color byte
type Box struct { type Box struct {
width, height, depth float64 width, height, depth float64
color Color color Color
} }
type BoxList []Box //a slice of boxes type BoxList []Box //a slice of boxes
func (b Box) Volume() float64 { func (b Box) Volume() float64 {
return b.width * b.height * b.depth return b.width * b.height * b.depth
} }
func (b *Box) SetColor(c Color) { func (b *Box) SetColor(c Color) {
b.color = c b.color = c
} }
func (bl BoxList) BiggestsColor() Color { func (bl BoxList) BiggestsColor() Color {
v := 0.00 v := 0.00
k := Color(WHITE) k := Color(WHITE)
for _, b := range bl { for _, b := range bl {
if b.Volume() > v { if b.Volume() > v {
v = b.Volume() v = b.Volume()
k = b.color k = b.color
} }
} }
return k return k
} }
func (bl BoxList) PaintItBlack() { func (bl BoxList) PaintItBlack() {
for i, _ := range bl { for i, _ := range bl {
bl[i].SetColor(BLACK) bl[i].SetColor(BLACK)
} }
} }
func (c Color) String() string { func (c Color) String() string {
strings := []string {"WHITE", "BLACK", "BLUE", "RED", "YELLOW"} strings := []string {"WHITE", "BLACK", "BLUE", "RED", "YELLOW"}
return strings[c] return strings[c]
} }
func main() { func main() {
boxes := BoxList { boxes := BoxList {
Box{4, 4, 4, RED}, Box{4, 4, 4, RED},
Box{10, 10, 1, YELLOW}, Box{10, 10, 1, YELLOW},
Box{1, 1, 20, BLACK}, Box{1, 1, 20, BLACK},
Box{10, 10, 1, BLUE}, Box{10, 10, 1, BLUE},
Box{10, 30, 1, WHITE}, Box{10, 30, 1, WHITE},
Box{20, 20, 20, YELLOW}, Box{20, 20, 20, YELLOW},
} }
fmt.Printf("We have %d boxes in our set\n", len(boxes)) fmt.Printf("We have %d boxes in our set\n", len(boxes))
fmt.Println("The volume of the first one is", boxes[0].Volume(), "cm³") fmt.Println("The volume of the first one is", boxes[0].Volume(), "cm³")
fmt.Println("The color of the last one is",boxes[len(boxes)-1].color.String()) fmt.Println("The color of the last one is",boxes[len(boxes)-1].color.String())
fmt.Println("The biggest one is", boxes.BiggestsColor().String()) fmt.Println("The biggest one is", boxes.BiggestsColor().String())
fmt.Println("Let's paint them all black") fmt.Println("Let's paint them all black")
boxes.PaintItBlack() boxes.PaintItBlack()
fmt.Println("The color of the second one is", boxes[1].color.String()) fmt.Println("The color of the second one is", boxes[1].color.String())
fmt.Println("Obviously, now, the biggest one is", boxes.BiggestsColor().String()) fmt.Println("Obviously, now, the biggest one is", boxes.BiggestsColor().String())
} }
上面这个例子我们通过const定义了一些常量然后定义了一些自定义类型 上面这个例子我们通过const定义了一些常量然后定义了一些自定义类型
- Color作为byte的别名 - Color作为byte的别名
@@ -223,34 +223,34 @@ method的语法如下
package main package main
import "fmt" import "fmt"
type Human struct { type Human struct {
name string name string
age int age int
phone string phone string
} }
type Student struct { type Student struct {
Human //匿名字段 Human //匿名字段
school string school string
} }
type Employee struct { type Employee struct {
Human //匿名字段 Human //匿名字段
company string company string
} }
//在human上面定义了一个method //在human上面定义了一个method
func (h *Human) SayHi() { func (h *Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone) fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
} }
func main() { func main() {
mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"} mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"} sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
mark.SayHi() mark.SayHi()
sam.SayHi() sam.SayHi()
} }
###method重载 ###method重载
@@ -258,49 +258,49 @@ method的语法如下
package main package main
import "fmt" import "fmt"
type Human struct { type Human struct {
name string name string
age int age int
phone string phone string
} }
type Student struct { type Student struct {
Human //匿名字段 Human //匿名字段
school string school string
} }
type Employee struct { type Employee struct {
Human //匿名字段 Human //匿名字段
company string company string
} }
//Human定义method //Human定义method
func (h *Human) SayHi() { func (h *Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone) fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
} }
//Employee的method重载Human的method //Employee的method重载Human的method
func (e *Employee) SayHi() { func (e *Employee) SayHi() {
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name, fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
e.company, e.phone) //Yes you can split into 2 lines here. e.company, e.phone) //Yes you can split into 2 lines here.
} }
func main() { func main() {
mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"} mark := Student{Human{"Mark", 25, "222-222-YYYY"}, "MIT"}
sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"} sam := Employee{Human{"Sam", 45, "111-888-XXXX"}, "Golang Inc"}
mark.SayHi() mark.SayHi()
sam.SayHi() sam.SayHi()
} }
上面的代码设计的是如此的美妙让人不自觉的为Go的设计惊叹 上面的代码设计的是如此的美妙让人不自觉的为Go的设计惊叹
通过这些内容我们可以设计出基本的面向对象的程序了但是Go里面的面向对象是如此的简单没有任何的私有、共有关键字通过大小写来实现(大写开头的为共有,小写开头的为私有),方法也同样适用这个原则。 通过这些内容我们可以设计出基本的面向对象的程序了但是Go里面的面向对象是如此的简单没有任何的私有、共有关键字通过大小写来实现(大写开头的为共有,小写开头的为私有),方法也同样适用这个原则。
## links ## links
* [目录](<preface.md>) * [目录](<preface.md>)
* 上一章: [struct类型](<2.4.md>) * 上一章: [struct类型](<2.4.md>)
* 下一节: [interface](<2.6.md>) * 下一节: [interface](<2.6.md>)
## LastModified ## LastModified
* $Id$ * $Id$