个人文章分享 - 2013年1月
type: channel
link: https://pub.ofcrab.com/2013/01/
description: 芝兰生于深林，不以无人而不芳；君子修道立德，不谓穷困而改节。
items: Go Structs 中的方法
items: Go Struct中的匿名字段
items: Go 中的 Struct——无类实现面向对象编程
items: Go 中的 for 循环控制结构
items: Go 的 If Else 声明控制结构
items: 构建高效率的 Go 程序 （Effective Go）
items: 如何写 Go 程序
items: Go 的 Hello World程序
items: 通过一行一行的代码写出Go的Hello World程序
items: 安装 Golang 二进制发行包

Go Structs 中的方法
type: item
date: 2013-01-28T22:49:19+00:00
description: 我们知道 Go 中的 Struct 可以像其它语言中的类一样，包含数据，同样的，它也可以通过定义方法来保存属性它自己的行为，将一个方法绑定、关联到一个 Struct 或者任何一个其它的类型中是非常简单的，它就像普通的函数定义一样，唯一的不同是你需要为其指定一个类型（type）。下面这个示例是一个普通的函数定义，它将返回一个类型为 int 的值：func myFunc() int { // code } 上面定义的函数将不接收任何参数，返回一个 int 类型的值，如果我们要将其绑定或者说关联到一个Struct上面的话，只需要做很少的修改即可：type myType struct {} func (m myType) myFunc() int { // code } 让我们现在来扩展一下前面一篇文章《Go 中的 Struct——无类实现面向对象编程》中的那个 Rectangle 示例， 我们为其添加一个名为 Area 的方法，用来计算长方形的面积：package main import "fmt" type Rectangle struct { width, length int } func (r Rectangle) Area() int { return r.width * r.length } func main() { r := Rectangle{4,3} fmt.Println("Rectangle is:", r) fmt.Println("Rectangle area is:", r.Area()) } 输出为：Rectangle is: {4 3} Rectangle area is: 12 许多面向对象的程序开发语言都有一个类似 this 或者 self 的概念，用它来代表并访问当前的实例，Go没有这样的概念，如果要将某一个函数或者方法绑定到一个Struct中，直接将一个Struct的实例作为参数传递给该方法或者函数，在上面的示例中，r 就是这个传递给方法 Area 的 Rectangle实例，它会在每一次调用 r.Area() 方法时，指向 r 自身。同样的，你还可以传递Struct的引用，但是这与直接传递实例没有差别，因为Go会自动为你进行转换：package main import "fmt" type Rectangle struct { length, width int } func (r Rectangle) AreaByValue() int { return r.length * r.width } func (r *Rectangle) AreaByReference() int { return r.length * r.width } func main() { r := Rectangle{4,3} fmt.Println("Rectangle is: ", r) fmt.Println("Rectangle area is: ", r.AreaByValue()) fmt.Println("Rectangle area is: ", r.AreaByReference()) fmt.Println("Rectangle area is: ", (&r).AreaByValue()) fmt.Println("Rectangle area is: ", (&r).AreaByReference()) } 输出为：Rectangle is: {4 3} Rectangle area is: 12 Rectangle area is: 12 Rectangle area is: 12 Rectangle area is: 12 在上面的代码中，我们定义了两人个很相似的方法，一个传递实例，一个传递实例的引用，我们同时又使用了实例分别调用它们，再使用了实例的地址调用它们，可以看到，四种方法的结果都是一样的。下面我们再“绑定”一个名为 Perimeter 的方法来设置长方形的周长：package main import "fmt" type Rectangle struct { width, length int } func (r Rectangle) Area() int { return r.width * r.length } func (r Rectangle) Perimeter() int { return 2 * (r.length + r.width) } func main() { r := Rectangle{4,3} fmt.Println("Rectangle is:", r) fmt.Println("Rectangle area is:", r.Area()) f…

Go Struct中的匿名字段
type: item
date: 2013-01-24T22:48:06+00:00
description: Go 允许你定义含有无变量名的字段的Struct，这些无名称的字段称之为匿名字段，让我们通过一些示例来了解它们到底是什么，以及它们为什么很有用。在下面的示例中，我们定义一个名为 Kitchen 的Struct，它仅仅只包含一个名为 numOfPlates 的 int类型的字段用来保存盘子的个数，我还定义了另一个Struct名为 House ，它包含了一个 Kitchen 的实例，但是我没有为其指定字段名，所以，它是一个匿名字段。package main import "fmt" type Kitchen struct { numOfPlates int } type House struct { Kitchen // 匿名字段 numOfRooms int } func main() { h := House{Kitchen{10}, 3} // 初始化需要使用Struct名 fmt.Println("房屋 h 有", h.numOfRooms, "间房") // numOfRooms 是 House 的一个字段 fmt.Println("房屋 h 有", h.numOfPlates, "个盘子") // numOfPlates 是Kitchen提供的字段，而Kitchen又是House的一个匿名字段，所以这里可以访问到它 fmt.Println("这间房屋的厨房有：", h.Kitchen) // 我们可以通过Struct的名称访问整个匿名Struct的内容 }输出结果为：房屋 h 有 3 间房 房屋 h 有 10 个盘子 这间房屋的厨房有： {10}首先我们需要注意到的事情是，当我们定义了 Kitchen 为House的一个匿名字段之后，我们将可以直接通过Kitchen中的字段名称访问Kitchen中字段的值，这同样也“成了”House的字段，但是如果像在Java这样的语言中，我们做一下对比，它需要像下面这样的去实现同样的功能：public class Kitchen { public int numOfPlates; } public class House { public Kitchen kitchen; } public static void main(String[] args) { House h = new House(); h.kitchen.numOfPlates = 10; // 引用自字段的子字段 }其次我们需要知道，匿名字段的完整的实例数据是可以被访问到的，需要通过它的Struct名称，在本示例中，通过 h.Kitchen 来访问获得，所以，如果你想打印出 Kitchen 中的 Plate 数量的话中，可以这样：fmt.Println(h.Kitchen.numofPlates)最后，要注意到，初始化的时候，匿名字段的Struct名称是不允许省略的，它必须像这样：h := House{Kitchen{10}, 3}*，而下面这样的写法都是错误的：*h := House{{10}, 3} 或者 h := House{10,3}。匿名字段发生命名冲突很有可能两个不同的Struct具有同样名称的字段，而一个Struct又是另一个Struct的匿名字段，这就产生的命名冲突的问题，当这个问题出现的时候，外层的Struct中的字段可以像以前一样直接被访问到，但是其匿名字段就需要通过Struct名称访问了。在下面的示例中，我们的 House 与 Kitchen 同时具有 numOfLamps 字段，但是House是外层的struct，它的 numOfLamps* 字段将隐藏掉Ｋitchen的 *numOfLamps*，如果你还是需要访问Kitchen的numOfLamps值，那么需要通过引用它的Struct名：*h.Kitchen.numOfLamps ：package main import "fmt" type Kitchen struct { numOfLamps int } type House struct { Kitchen numOfLamps int } func main() { h := House{Kitchen{2}, 10} // Kitchen 有2个Lamps，House有10个 fmt.Println("House有", h.numOfLamps, "个Lamps") fmt.Println("Kitchen有", h.Kitchen.numOfLamps, "个Lamps") }输出为：House有 10 个Lamps Kitchen有 2 个Lamps所以从上面可以看到，对于不同层级的相同名称的字段，Go制定了相应的规则，但是对于同一层级的相同名称的字段，则需要我们自己去解决…

Go 中的 Struct——无类实现面向对象编程
type: item
date: 2013-01-20T22:47:03+00:00
description: 星期五, 12/28/2012 - 16:22 — matrixstackGo是非面向对象的，而是面向过程的，但是在当今程序开发的世界里，使用最为广泛的还是面向对象编程，这或许会让你感觉Go作为一个新生的语言最应该有的一面却没有被支持，但是其实它只是用了自己的方法，在本文里，我将介绍在Go里面，如何实现面向对象（Go提供了面向对象所提供的一切，或许提供得更多）。如果你一直都是一个“类”用户，那么转到Go的“面向对象”上来，可能还需要一些观念上的转变，这或许很难，但是一旦你转变过来了，你就会发现，Go的方式有多么的强大了。在了解Go的面向对象之前，一定要在心里面知道：Go是没有类的，这是你进入Go的面向对象世界的第一步，也是最重要的一步；另一个你知道知道的是：Go不是面向对象的，只是他的实现类似于面向对象，我们来看一个简单的示例，它能说明一切：Java代码：class House { public String getHouseName() { // 方法定义在类里面 // 实现 } } Go 代码：type House struct { } func (h House) GetHouseName() string {} //方法被定义在 Struct 外，但是却作用于 House 现在让我们来学习一下如何创建 Struct 以及如何通过它实现“面向对象”，一个 Struct 通过关键字 type 与 struct 定义：type my_struct_name struct { } type Rectangle struct { } type Vehicle struct { } type VehicleCar struct { } 上面的所有定义都是合法的，但是下面这样是不合法的：type Hash# struct { } // 名称不允许包含特殊字符 type 0Struct struct { } // 名称不允许以数字开始 当然了，Struct 还能存储其它数据，所以，在这方面它类似于 Class，可以用来定义真实世界中存在的实体：type mystruct struct { i int j int s string } type Rectangle struct { length, width int //你可以在一行中通过逗号分割的方式创建多个同类型的项目 area float64 } 下面这个示例展示了一个 Struct 的实际应用：package main import "fmt" // 定义 Rectangle 结构 type Rectangle struct { length, width int } func main() { r := Rectangle{} fmt.Println("默认的长方形是：", r) // 打印出默认的 Rectangle 的归零值 } 输出为：默认的长方形是： {0 0} 这里有一个重要的需要注意的事情是：struct中的变量的值都是归零的，也就是说，int 类型的值将为 0，string 类型的值将为空字符串等等，所以，每一个你自己定义的Struct 也都是有一个属于其自己的归堆值的。下面这个示例中，我将展示另一种方式初始化 Struct——在创建它的时候就指定初始值：package main import "fmt" type Rectangle struct { length, width int name string } func main() { r1 := Rectangle{2, 1, "First Rectangle"} fmt.Println("第一个长方形 r1 为：", r1) r2 := Rectangle{width: 3, name: "Second Rectangle", length: 4} fmt.Println("第二个长方形 r2 为：", r2) pr := new (Rectangle) // 获取一个指向一个新的长方形的指针 (*pr).width = 6 // 设置 pr 的宽为 6 pr.length = 8 // 与上面是同样的效果，看这里是没有 -> 符号的 pr.name = "指针长方形" fmt.Println("指针长方形是：", pr) } 输出为：第一个长方形 r1 为： {2 1 First Rectangle} 第二个长方形 r2 为： {4 3 Second Rectangle} 指针长方形是： &{8 6 指针长方形} 这里需要注意的事情是： 你可以只将值按 struct 定义时的顺序赋给它的成员，但是需要放在大括号里面，并且每一个值需要使用逗号分开； 如果你给定值的时候还提供了名称，那么就不受顺序的限制…

Go 中的 for 循环控制结构
type: item
date: 2013-01-18T22:46:02+00:00
description: for 声明是 Go 中唯一的一个循环声明，普通的用法如下：for "initialization statements"; "bool expression that has to evaluate to true"; "statements run prior to every loop except the first" { // Code to be executed if the boolean expression evaluates to true } 翻译过来为：for "初始化声明"; "条件判断，为真是循环才执行"; "除第一外每一次循环都会执行的声明" { // 循环主体 } 上面的三个部分中，任何一个部分都是可以不写的，但是即使不写，那个属于它的结束符的分号却还是必须要写，除非三个声明都没有的时候，所有的分号都可以一并省略，请看下面的示例：package main import "fmt" func main() { // 初始化i为0；每一次循环之后检查i是否小于5；让i加1 for i := 0; i < 5; i++ { fmt.Println("i现在的值为：", i) } } 执行输出结果为：cox@Cox:~/workspace/go/src/gotutorial$ go run forloop1.go i现在的值为： 0 i现在的值为： 1 i现在的值为： 2 i现在的值为： 3 i现在的值为： 4 从上面的结果可以看到，我们在定义 i 的初始值为0之后，在循环主体第一次执行前，i++是没有运行的，所以我们来能取得它的初始值 0。下面这些循环体你都可以在自己的示例中去运行：// 没有判断声明，循环将永远不停的执行 for i := 0; ; i++ { fmt.Println("i现在的值为：", i) } // 因为 i 的值不会变化，而i的初始值小于3，所以，它将永远小于3，那么循环加永远运行 for i := 0; i < 3; { fmt.Println("i现在的值为", i) } // 虽然我们没有在 *for* 中声明初始值以及变量的变量方式，但是我们把初始化移到for循环外面，然后把初始变量的变化声明移动到循环里面也是可以的，下面代码的输出将为： // s的值为： // s的值为： a // s的值为： aa // s的值为： aaa // s的值为： aaaa s := "" for ; s != "aaaaa"; { fmt.Println("s的值为：", s) s = s + "a" } 在 Go 的 for 循环里面，你可以同时初始化多个变量，多个条件判断或者同时更新多个值，请看下面的示例：package main import "fmt" func main() { for i, j, s := 0,5,"a"; i < 3 && j < 100 && s != "aaaaa"; i, j, s = i+1, j+1, s + "a" { fmt.Printf("i=%d, j=%d, s=%sn", i, j, s) } } 输出：i=0, j=5, s=a i=1, j=6, s=aa i=2, j=7, s=aaa 第三次循环之后，虽然 i < 100 与 s != "aaaaa" 都成立，但是 i < 3 已经不成立，所以循终止。break 关键字break 的作用是让循环在它所出现的地方终止，然后执行该循环后面的下一行代码或指令，如下示例：package main import "fmt" func main() { i := 0 for { if i >= 3 { break } fmt.Println("当前i的值为：", i) i++ } fmt.Println("for后的第一个声明") } 输出为：当前i的值为： 0 当前i的值为： 1 当前i的值为： 2 for后的第一个声明 continue 关键字continue 中止当前循环，然后回到循环的起始进行下一步循环，如下示例：package main import "fmt" func main() { for i := 0; i < 11; i++ { if i%2 == 0 { continue //我不输入偶数 } fmt.Println("当前i的值为：", i) } } 输出为：当前i的值为： 1 当前i的值为： 3 当前i的值为： 5 当前i的值为： 7 当前i的值为： 9 range 关键字range 关键字让你可以遍历数据／Map，为了便于理解，你可以把它理解为“每一个XX的索引”，当你使用它对数组或者片段遍历时，每一次返回它们的索引，对于MAP遍历时，每一次返回它的键，如下…

Go 的 If Else 声明控制结构
type: item
date: 2013-01-16T22:45:08+00:00
description: 程序需要根据不同的条件进行不同的处理， 我们程序不可能只按着某一个顺序一路执行下去，比如我们经常会遇到的这样一种情况：如果某一个文件存在，则将新内容更新至已有文件，如果文件不存在，则先创建文件，这个时候我们就可以使用if - else 控制结构了，在Go中，该控制结构如下：if some_boolean_expression { // 如果 some_boolean_expression 为 true，则会执行这里 } else if alternate_boolean_expression { // 如果 some_boolean_expression 为 false 并且 alternate_boolean_expression为 true,则执行这里 } else { // 如果上面的所有判断都为 false ,才能执行这里 } 注意事项 ： 在上面的结构说明，some_boolean_expression 以及 alternate_boolean_expression 的计算结果只能是 true 或者 false 里面的一个，不能为其它的值； 对于判断声明，括号不是必须的，你可以为其添加一个括号，但是这是没必要的； 与其它语言不同的是，Go要求左花括号必须与 if 或者 else 处于同一行内，就会报错，详情看写 GO 程序中一些常见的语法和其它错误。 int 类型的数据不能作为判断声明的结果被 if-else使用。 下面这些是条件判断的比较操作符： == : 等于 != : 不等于 < : 小于 <= : 小于或等于 > : 大于 >= : 大于或等于 && : 和（并且/与） || : 或 下面是一个最很简单的示例：package main import "fmt" func main() { if true { fmt.Println("这里会执行") } if false { fmt.Println("这里不会执行") } } 输出很很简单，就是打印出“这里会执行”这五个字符，下面这个示例则使用了一些判断操作符：package main import "fmt" func main() { a, b := 4, 5 if a < b { fmt.Println("a < b") } else if a > b { fmt.Println("a > b") } else { fmt.Println("a = b") } } 输入结果为 a < b，对于有其它语言编程经验的人来说，下面这些错误可能会经常出现：// 非布尔值 5 if 5 {} // 非布尔值 s var s string if s {} // 非布尔值 e var e os.Error if e {} // if 声明与左大括号不在一行内 if true {} // else 与 右大括号不在一行 if true { } else { }

构建高效率的 Go 程序 （Effective Go）
type: item
date: 2013-01-15T22:43:47+00:00
description: 本文是 「Golang.org」的原文档翻译，出于本人有限的英语水平，如有不当，还请指正。Go 是一个全新的语言，当然，它也从很多以存在多年的优秀语言中吸取了很多优秀的特性，但是因为其自身的特殊性，使得 Go 程序与其它相关的语言所开发的出来的程序有很大的不同，直接将C++或者Java程序翻译为Go程序并不会让你得到一个满意的结果——Java程序永远都只是Java程序，它成不了Go程序。另一方面，从Go的角度去想一个问题，你会得到一个可以成功解决它但是和其它语言完全不一样的方式。换句话说，想写出漂亮的Go程序，你必需要了解它的特性和风格，甚至是已有的约定，比如命名规范、代码格式化结构等，了解这些，可以让你的程序更简单地其它人看懂。本文档给出了一些能让你写出更加干净的符合Go语言习惯的代码，但是建议你在阅读本文之前先阅读一下Language Specification、Tour of Go以及「如何写Go程序(How to Write Go Code)」.示例Go Package Sources 并不只包含了它的核心库，同时它还包含了很多使用该语言写的示例程序，如果你有关于如何使用Go解决问题或者在Go应该如何实现的相关问题，这些示例代码或话会给你答案，它还能告诉你，你应该将自己的想法以怎样的一种方式转换成Go程序。格式化格式化应该是最具有争议但是也是最重要的一个Go语言的特性，每一个开发者可以有属性自己的书写格式，但是所有人都使用同一种格式看起来肯定是最好的，这使得我们不再需要花费太多时间放在了解别人的书写风格上。在Go中，不同于其它语言，它让计算机程序来管理着代码的格式化，gofmt 命令（也可以使用 go fmt)可以读取Go代码文件，并将它们以标准格式对其进行格式化，包括它们的缩进、空格等，请看下面这个示例：type T struct { name string // name of the object value int // its value } gofmt 会将其格式化为：type T struct { name string // name of the object value int // its value } 所有Go标准库中的代码都已经通过gofmt进行了格式化。比如下面这些Go中最常见的会使用到的格式化约定： 缩进：Go使用制表符（Tabs)进行缩进，而不是很多语言中都推荐的空格，gofmt默认会使用制表符进行缩进，你应该仅仅在需要空格的地使用空格。 行长度：Go没有行代度限制，所以，你完全不用担心这个问题，但是如果你感觉某一个行实在是太长了，那你可以将其截断，然后使用一些制表符让它看起来和它原本应该属于的那一行开始于同一个地方。 括号：Go只有很少的一些地方需要括号，结构控制（比如if, for, switch等的条件判断）都是不需要括号的，操作符的优先级层次更短更清晰，所以，x << 1 + y < 6,就可以很明白的知道这是什么了。 注释Go同时对G风格的块注释 /* ......*/ 和 C++风格的行注释 // .....提供支持，行注释是标准的，而块注释一般只建议使用的对包的注释上或者使用在需要禁用（但不是删除）一大段代码的功能上。godoc程序（同时也是文档服务器）会从Go代码中提供包的说明文档，Comments that appear before top-level declarations, with no intervening newlines, are extracted alog with the declaration to serve as explanatory text for the item. The nature and style of these comments determines the quality of the documentation godoc produces.任何一个包都应该包含一个包注释——一个用来说明包功能以及使用方法等信息的块注释，对于被分割为多个文件的包，包注释只需要出现在某中的任何一个文件中即可，godoc会将它作为所有同一个包的说明文档。The package comment should introduce the package and provide information relevant to the package as a whole. It will appear first on the godocpage and should set up the detailed documentation that follows.／＊ Ｐackage regexp implements a simple li…

如何写 Go 程序
type: item
date: 2013-01-14T22:42:49+00:00
description: 本文是 「Golang.org」的原文档翻译，出于本人有限的英语水平，如有不当，还请指正。说明本文档演示了一个最简单的 Go 包的开发过程以及一些 Go 命令行工具的使用，以及Go是如何架构、安装与搜索包的。代码组织GOPATH 以及工作区Go 语言设计的目标之一是让软件开发更简单，得到的结果是 Go命令不使用任何的 Makefiles或者其它的配置文件，取而代之的是直接使用程序的源代码来管理依赖关系及架构条件，这意味着，你程序的源代码与架构脚本总是同步的，因为它们就是同样的东西（注：如果使用 Makefiles之类的东西，那么，你源代码修改了，还需要再去修改Makefiles，而是在Go中，因为没有这些配置文件，所以，你修改源代码，同时直接就修改了这些配置）。你唯一需要做的是设置一个 GOPATH 环境变量，GOPATH 的作用是告诉 Go 从哪里去搜索Go的执行脚本以及将你的Go安装到哪里.$GOPATH 是一个包括很多路径的列表，它的格式与系统的PATH变量格式一样，一个Unix系统中常见的GOPATH像这样的：GOPATH=/home/user/ext:/home/user/mygo （在Windows系统中，将“:”修改为“;”）任何一个被定义至 $GOPATH$ 环境变量中的路径都指定着一个工作区的的位置（比如上例中的 /home/user/ext或者/home/user/mygo），一个工作区包含着Go源代码以及它们所依赖的包对象以及一些可执行的工具，它被规定为需要有下面这三个子目录： src : Go 源代码文件 pkg : 以编译的 Go 包 bin : 可执行命令 src 目录中的子目录都是独立的包，这些包中的所有源代码文件（.go，.co，.h以及.s等）都是子目录包的元素。它构建一个import "widget"的程序时，Go构建工具会搜索 Go 根目录下的 src/pkg/widget 目录——如果没有找到，那么它会接着尝试去寻找同一工作区中的 src/widget 目录。多个工作区可以给我们带来更我铁灵活性与方便，但是在本文档中，我们只涉及单个工作区，下面让我们先创建一个示例工作区，首先创建一个目录，我们用它来存放项目的源代码：cox@CoxStation:~$ mkdir $HOME/example/src -p 下一步，设置 GOPATH 环境变量，你需要同时将 $GOPATH/bin 添加到 PATH 环境变量中，这样一来，你就不需要每次执行这些命令的时候输入完整的绝对路径了。cox@CoxStation:~$ export GOPATH=$HOME/example cox@CoxStation:~$ export PATH=$PATH:$HOME/example/bin 导入路径Go 标准库或者包都可以使用最短的路径名导入，比如 fmt 或者 net/http 等，这是为了程序开发者的方便而设计的，但是对于你自己的项目，你需要认真的设计一个基本的导入路径，这需要考虑它它的可读性同时还需要考虑到它不应该和以有的或者将来会出现的其它的库相冲突。最好的一个办法是总是以你所开发的项目的版本管理工具名称开始，比如，如果你的项目源代码库位置为 example.com 或者 code.google.com/p/example ，那么你应该让你的包路径从该 URL 地址开始，比如：example.com/foo/bar 或者 code.google.com/p/example/foo/bar ，如果你遵循这样的约定，那么 Go 会自动为你检测URL地址所指定的包，同时下载以及以你的导入路径安装至你的工作区中。如果你没有像上面这样的发布路径，那么你至少应该使用一个唯一的前缀，比如 widget 以及 widget/foo/bar ，一个好的规则是使用你的项目名称或者公司名称作为前缀，这一般是不会被别人使用的，比如：example.com。我们下面使用 example.com 作为基本的导入路径：cox@CoxStation:~$ mkdir -p $GOPATH/src/example.com 包名称任何一个 Go 源代码文件的第一个声明都应该是包名：package NAME NAME 就是你的包名称，它也是你导入该包时默认使用的名称（所有处于同一个包中的文件都必须共享同一个包名）。Go 约定包名称是导入路径中的最后一个元素，一个以 crypto/rot12 导入的包的包名应该是 rot13，Go 不要求所有被导入到某一个程序中的包名都具有唯一性，但是要求其完整的导入路径必须是唯一的。在 example 中创建一个新包，名为 newmath:cox@CoxStation:~$ cd $GOPATH/src/e…

Go 的 Hello World程序
type: item
date: 2013-01-11T22:41:52+00:00
description: 什么是Go？来自其网站的介绍：Go 编程语言是一个使得程序员更加有效率的开源项目。Go 是有表 达力、简洁、清晰和有效率的。它的并行机制使其很容易编写多核 和网络应用，而新奇的类型系统允许构建有弹性的模块化程序。Go 编译到机器码非常快速，同时具有便利的垃圾回收和强大的运行 时反射。它是快速的、静态类型编译语言，但是感觉上是动态类型 的，解释型语言。Go 1 是 Go 语言的第一个稳定发布版本。基本上任何一个语言最开始的学习的时候都离不开那个“Hello World！”程序，既然找不到其它的方法，那么，学习Go的时候还是也来一个Hello World吧。package main import "fmt" /* 打印出 Hello World 的各种语言的版本 */ func main() { fmt.Printf("Hello, world; or 你好，世界n") } 在上面的代码段中，首行是必须的，任何 Go 文件都必须以 package 开头，对于需要独立运行的执行文件，则必须是 package main；接着我们导入了 fmt 包，这就是说需要将 "fmt" 包加入 main，不是 main 的其它包都称之为库，其它许多语言中都有着类似的概念，比如Python中的 module。后面跟着的是一行注释。最后面我们定义了一个名为 main() 的函数，当 Go程序在执行的时候，首先调用的函数就是 main.main()，这是从C语言中继承而来的，在这里我们使用关键字 func 定义了这个函数，这个函数不接受任何参数，也不返回任何类型的值，该函数将打印出 “Hello, world; or 你好，世界”字符串，你可以发现，在Go语言中，可以直接使用非ASCII字符，这是因为Go支持任何编码的字符串，你甚至可以使用非ASCII编码的字符作为变量或者函数名称。将上面的代码保存为一个helloworld.go 文件，然后编辑它：go build helloworld.go 这会在当前文件夹中生成一个同名的可执行文件，我现在使用的是Windows 7，所以，这个可执行文件的文件名为 helloworld.exe 。如果不想编译它即执行，可以使用 go run 命令：go run helloworld.go 它会直接运行 helloworld 程序，而不是生成可执行文件后手工去执行。

通过一行一行的代码写出Go的Hello World程序
type: item
date: 2013-01-10T22:40:29+00:00
description: 直接进入正题，在任何一个地方创建一个名为 helloworld.go 的文件，然后立马执行它：cox@Cox:~/workspace/go/src$ touch helloworld.go cox@Cox:~/workspace/go/src$ go run helloworld.go package : helloworld.go:1:1: expected 'package', found 'EOF' 简单吧，看错误信息，你现在应该知道，没有绑定到某一个 package 的文件是不被 Go 认可的，所以，我们都需要加上这么一个，我们在前面的那个 helloworld.go 文件里面加上：package main 之后再来执行：cox@Cox:~/workspace/go/src$ vi helloworld.go cox@Cox:~/workspace/go/src$ go run helloworld.go # command-line-arguments runtime.main: undefined: main.main 恩，Go程序需要从某一个位置开始执行，就像电脑有电源开关一样简单，在 Go 中，程序都是从一个名为 main 的函数开始执行，所以，再加上这个函数：package main func main() {} 再来执行它：cox@Cox:~/workspace/go/src$ vi helloworld.go cox@Cox:~/workspace/go/src$ go run helloworld.go 恩，没报任何错误了，那也就是说我们现在的程序已经正确运行，但是因为 main() 没有做任何事情，所以我们现在什么也看不到，我们现在让它来打印出 “Hello World! 您好！世界。” 这个字符串：package main func main() { Println("Hello World! 您好！世界。") } 又出错了：# command-line-arguments ./helloworld.go:4: undefined: Println Println 未定义，恩，从我们上面的代码中确实看得到，从来没有它，突然就这么一下子就拿来用了，不成，就像你从来没有买过车，一辈子都没见过车，怎么可能走着走着就突然在开车了呢，我们来买一辆车：package main import "fmt" func main() { fmt.Println("Hello World! 您好！世界。") } 再来运行 helloworld.go：cox@Cox:~/workspace/go/src$ go run helloworld.go Hello World! 您好！世界。 成了，这个 fmt 就是我们买来的车，有了车我们才能开车，我们这里用了 fmt 里面的 Println 函数。你学会了吗？ 任何一个 Go 文件都必须被关联到某一个包上 任何一个 Go 程序都必须有一个开始点，就是那个 main 函数 任何一个函数或者变量都必须被定义之后才能使用

安装 Golang 二进制发行包
type: item
date: 2013-01-09T22:39:23+00:00
description: Golang 是一个以类BSD许可发布的程序开发语言，官方提供有两个编译器 gc Go编译器和gccgo编译器，其中gccgo编译器是GNU C 编译器的一部分，而 gc 编译器比较成熟并且它进行了更多的测试，本文所使用的是 gc 编译器安装一个以二进制包发布的 Go 版本。系统需求gc 编译器可以在下面这些操作系统和架构上面运行，请确定您当前的系统满足这些需求，如果你所使用的系统不在当前列表中，那么你就应该试试 gcc 编译器安装，这有可能有适合您的系统。 操作系统名称 系统架构 说明 FreeBSD 7+ amd64,386 Debian GNU/kFreeBSD不被支持 Linux 2.6.23+(glibc) amd64,386,arm CentOS/RHEL 5.x不被支持，还无ARM版本的二进制包 Mac OS X 10.6/10.7 amd64,386 使用XCode的gcc(1) Windows 2000+ amd64,386 使用mingw gcc(2)，cygwin或msys不是必需的 1) 只有你想使用 cgo 时，gcc才是必须的；2) 你仅仅只需要安装命令行工具即可，如果你已经嬢了 Ｘcode 4.3+，那么你可以在组件面板中添加命令行工具下载 Go Tools访问 Go 项目下载页面：http://code.google.com/p/go/downloads/list，选择一个适合你的操作系统或者CPU架构的发行版，官方的发行版有FreeBSD，Linux，Mac OS X(Snow Leopard/Lion)以及Windows系统，同时支持 32位与64位CPU架构，如果没有适合你所使用的操作系统的二进制安装包，你可以需要从源代码安装或者使用gccgo而不是gc。安装 Go ToolsGo的发行布将被安装至 /usr/local/go目录（Windows下为c:Go），但是你是可以修改该安装目录的，使用Go时，你需要指定 GOROOT 环境变量至你使用 Go 的目录，比如，如果你将 Go 安装至你的home目录，那么你需要在 $HOME/.profile文件中添加下面这两行：export GOROOT=$HOME/go export PATH=$PATH:$GOROOT/bin Windows用户请设置环境变量，怎么设置我也不太明白，很少用那个东西……FreeBSD, Linux以及Mac OS X压缩包如果你是从一个老版本的Go进升级，那么你需要在安装之前先删除原先版本：rm -r /usr/local/go 将你获得的压缩包文件解压至 /usr/local：tar -C /usr/local -xvf go1.0.3.linux-amd64.tar.gz 包文件的名称可能和上面我所使用的不一样，因为我们的系统可能不一样，之后你可以将 /usr/local/go/bin目录添加至你的环境变更 PATH 中，比如添加至 /etc/profile或者$HOME/.profile。Mac OS X 包安装工具如果 Mac OS X 的包安装工具的话只需要接照安装工具的流程进行即可，默认会安装至 /usr/local/go 目录中。Windows 下面自己研究测试你的安装要测试你的Go是否已经正确安装的最简单的办法就是写一个Go程序，比如，Hello Golangpackage main import "fmt" func main() { fmt.Printf("Hello, Golang!n") } 然后测试运行：$ go run hello.go Hello, Golang! OK，这表示你安装成功了。