




免费预览已结束,剩余39页可下载查看
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Go语言入门教程Introduction 简介This document is a tutorial introduction to the basics of the Go programming language, intended for programmers familiar with C or C+. It is not a comprehensive guide to the language; at the moment the document closest to that is the language specification. After youve read this tutorial, you might want to look at Effective Go, which digs deeper into how the language is used. Also, slides from a 3-day course about Go are available: Day 1, Day 2, Day 3.本文是关于Go编程语言的基础教程,主要面向有C/C+基础的读者。本文并不是一个语言的完整指南,关于 Go的具体细节请参考 语言规范 一文。在学习完入门教程后,还可以继续看 Effective Go ,这个文档将涉及到Go语言的更多特性。此外,还有一个Go语言三日教程系列讲座: 第一日, 第二日, 第三日。The presentation here proceeds through a series of modest programs to illustrate key features of the language. All the programs work (at time of writing) and are checked into the repository in the directory /doc/progs/.下面将通过一些小程序来掩饰语言的一些关键特性。所有的演示程序都是可以运行的,程序的代码在安装目录的 /doc/progs/子目录中。Program snippets are annotated with the line number in the original file; for cleanliness, blank lines remain blank.文中的代码篇都都会以代码在源文件中的行号标注。为了清晰起见,我们忽略了源代码文件空白行的行号。Hello, WorldLets start in the usual way:让我们从经典的Hello, World程序开始:代码:全选05 package main07 import fmt fmt / Package implementing formatted I/O.09 func main() 10 fmt.Printf(Hello, world; or ; or 世界n)11 Every Go source file declares, using a package statement, which package its part of. It may also import other packages to use their facilities. This program imports the package fmt to gain access to our old, now capitalized and package-qualified, friend, fmt.Printf.每个Go源文件开头都有一个package声明语句,指明文件所在的包。同时,我们也可以根据具体的需要来导入(import语句)特定的包文件。在这个例子中,我们通过导入“fmt”包来使用我们熟悉的printf函数。不过在Go语言中,Printf函数的开头是大写字母,并且需要fmt包名作为前缀:fmt.Printf。Functions are introduced with the func keyword. The main packages main function is where the program starts running (after any initialization).函数定义要使用“func“关键字。整个程序从main包中的main函数开始执行(在变量和包初始化之后)。String constants can contain Unicode characters, encoded in UTF-8. (In fact, Go source files are defined to be encoded in UTF-8.)常量字符串可以包含Unicode字符,采用UTF-8编码。实际上,所有的Go语言源文件都采用UTF-8编码。The comment convention is the same as in C+:代码注视的方式和C+类似:代码:全选 /* . */ / .Later well have much more to say about printing.稍后,我们还会涉及到打印函数的更多技术。Semicolons 分号You might have noticed that our program has no semicolons. In Go code, the only place you typically see semicolons is separating the clauses of for loops and the like; they are not necessary after every statement.比较细心的读者可能已经发现前面的代码中没有出现分号“;”。在Go语言中,只有在for循环的初始化部分经常用到分号。在代码段的末尾分号都不是必须的。In fact, what happens is that the formal language uses semicolons, much as in C or Java, but they are inserted automatically at the end of every line that looks like the end of a statement. You dont need to type them yourself.你可以想在C或JAVA中那样使用分号。但是很多情况下,分号可以由Go编译起自己添加,用户不需要写全部的分号。For details about how this is done you can see the language specification, but in practice all you need to know is that you never need to put a semicolon at the end of a line. (You can put them in if you want to write multiple statements per line.) As an extra help, you can also leave out a semicolon immediately before a closing brace.关于细节部分,可以查看Go语言说明文档。不过在实际写代码时,只需要记得一行末尾的分号可以省略就可以了(对于一行写多个语句的,可以用分号隔开)。另外一点,在退出某个区域的时候,分号也是可以省略的。This approach makes for clean-looking, semicolon-free code. The one surprise is that its important to put the opening brace of a construct such as an if statement on the same line as the if; if you dont, there are situations that may not compile or may give the wrong result. The language forces the brace style to some extent.极端情况下,甚至可以写出没有任何分号的代码。不过有一个重要的地方,对于if等语句,需要将后面代码段的开始花括弧放在if语句的同一行,如果不这样的话可能出现编译错误。 Go语言强制将开始花括弧放在同一行末尾的风格。Compiling 编译Go is a compiled language. At the moment there are two compilers. Gccgo is a Go compiler that uses the GCC back end. There is also a suite of compilers with different (and odd) names for each architecture: 6g for the 64-bit x86, 8g for the 32-bit x86, and more. These compilers run significantly faster but generate less efficient code than gccgo. At the time of writing (late 2009), they also have a more robust run-time system although gccgo is catching up.Go是一个编译型的语言。目前有两种编译器,其中Gccgo采用GCC作为编译后端。另外还有根据处理器架构命名的编译器:针对64位x86结构为6g,针对32位x86结构的为8g等等。这些go专用的编译器可以产生比gccgo更高效的目标代码,也有更健壮的运行时系统。当然,gccgo 编译器也在快速的完善之中。Heres how to compile and run our program. With 6g, say,下面看看如何编译并运行程序。先是针对64位x86结构的“6g”:代码:全选 $ 6g helloworld.go # compile; object goes into helloworld.6 $ 6l helloworld.6 # link; output goes into 6.out $ 6.out Hello, world; or ; or 世界 $With gccgo it looks a little more traditional.gccgo和传统的gcc编译方法类似:代码:全选 $ gccgo helloworld.go $ a.out Hello, world; or ; or 世界 $EchoNext up, heres a version of the Unix utility echo(1):下面,是Unix系统中echo(1)命令的简化实现:代码:全选05 package main07 import ( 08 os 09 flag / command line option parser 10 )12 var omitNewline = flag.Bool(n, false, dont print final newline)14 const ( 15 Space = 16 Newline = n 17 )19 func main() 20 flag.Parse() / Scans the arg list and sets up flags 21 var s string = 22 for i := 0; i 0 24 s += Space 25 26 s += flag.Arg(i) 27 28 if !*omitNewline 29 s += Newline 30 31 os.Stdout.WriteString(s) 32 This program is small but its doing a number of new things. In the last example, we saw func introduce a function. The keywords var, const, and type (not used yet) also introduce declarations, as does import. Notice that we can group declarations of the same sort into parenthesized lists, one item per line, as on lines 7-10 and 14-17. But its not necessary to do so; we could have said程序虽然很小,但是包含了go语言的更多特性。在前面的例子中,我们演示了用func定义main 函数。其他定义相关的关键字还有var、const和type等。我们还可以像import那样,每次导入一组名字,每个一行(如710和1417行所示)。当然,每个变量分开定义,如:代码:全选 const Space = const Newline = nThis program imports the os package to access its Stdout variable, of type *os.File. The import statement is actually a declaration: in its general form, as used in our hello world program, it names the identifier (fmt) that will be used to access members of the package imported from the file (fmt), found in the current directory or in a standard location. In this program, though, weve dropped the explicit name from the imports; by default, packages are imported using the name defined by the imported package, which by convention is of course the file name itself. Our hello world program could have said just import fmt.程序首先导入os包,因为后面要用到包中的一个*os.File类型的Stdout变量。这里的import语句实际上是一个声明,和我们在“hello world“程序中所使用的,它的名字标识符(fmt)会取代fmt包中所定义的成员,并找到正确的目录和地址。在这个程序中,虽然我们没有在import中使用明确的名称,默认情况下将使用包的名字来import包。在“hello world“程序中,我们只是简单的 import fmt。You can specify your own import names if you want but its only necessary if you need to resolve a naming conflict.如果需要,你可以自己重新定义被import包的名字。但那不是必须的,只在出来包名字冲突的时候会用到。Given os.Stdout we can use its WriteString method to print the string.通过os.Stdout,我们可以用WriteString来输出字符串。Having imported the flag package, line 12 creates a global variable to hold the value of echos -n flag. The variable omitNewline has type *bool, pointer to bool.现在已经导入flag包,并且在12行创建了一个全局变量,用于保存echo的-n命令行参数。变量 omitNewline为一个bool型指针。In main.main, we parse the arguments (line 20) and then create a local string variable we will use to build the output.在main.main中,我们进行了参数解析(20行),并创建了一个局部变量用于保存要输出的内容。The declaration statement has the form变量声明如下:代码:全选 var s string = ;This is the var keyword, followed by the name of the variable, followed by its type, followed by an equals sign and an initial value for the variable.这里有一个var关键字,后面跟着变量名字和变量的数据类型,再后面可以用“”符号来进行赋值。Go tries to be terse, and this declaration could be shortened. Since the string constant is of type string, we dont have to tell the compiler that. We could write这个变量的声明有更简洁的方式,因为根据初始值来判断它的数据类型,没有必要显式写出数据类型。因此也可以像下面代码这样定义变量:代码:全选 var s = ;or we could go even shorter and write the idiom还有更短的写法:代码:全选 s := ;The := operator is used a lot in Go to represent an initializing declaration. Theres one in the for clause on the next line:操作符:=将在Go中大量使用,它可以在声明一个变量同时进行初始化。下面的代码是在for中声明并初始化变量:代码:全选22 for i := 0; i flag.NArg(); i+ The flag package has parsed the arguments and left the non-flag arguments in a list that can be iterated over in the obvious way.flag包会解析命令行参数,并将没有flag的参数保存到一个列表中。可以通过flag的参数列表访问命令行参数。The Go for statement differs from that of C in a number of ways. First, its the only looping construct; there is no while or do. Second, there are no parentheses on the clause, but the braces on the body are mandatory. The same applies to the if and switch statements. Later examples will show some other ways for can be written.Go语言的for语句和C语言中有几个不同的地方:第一,这是Go中唯一的循环语句,Go中没有while或 do语句;第二,for的条件语句并没有用括号包起来,但是循环体却必须要花括弧,这个规则和if和switch 一致。后面我们会看到for的一些例子。The body of the loop builds up the string s by appending (using +=) the flags and separating spaces. After the loop, if the -n flag is not set, the program appends a newline. Finally, it writes the result.在循环体中,通过+=符号向字符串s添加新的参数信息。在循环结束后,根据命令行是否有-n选项,判断末尾是否要添加换行符。最后输出结果。Notice that main.main is a niladic function with no return type. Its defined that way. Falling off the end of main.main means success; if you want to signal an erroneous return, call值得注意的地方是main.main函数并没有返回值(函数被定义为没有返回值的类型)。如果main.main 运行到了末尾,就表示“成功”。如果想返回一个出错信息,可统一用系统调用强制退出:代码:全选 os.Exit(1)The os package contains other essentials for getting started; for instance, os.Args is a slice used by the flag package to access the command-line arguments.os包还包含了其它的一些元素,例如os.Args是flag包的一部分(用来获取命令行输入)。An Interlude about Types 类型简介Go has some familiar types such as int and float, which represent values of the appropriate size for the machine. It also defines explicitly-sized types such as int8, float64, and so on, plus unsigned integer types such as uint, uint32, etc. These are distinct types; even if int and int32 are both 32 bits in size, they are not the same type. There is also a byte synonym for uint8, which is the element type for strings.Go语言中有一些通用的类型,例如int和float,它们不同机器上占用适当空间大小。同时,也包含了许多大小固定的类型,例如int8和float64,还有无符号类型uint和uint32。需要注意的是,int和int32虽然占有同样的内存大小,但是却不是同一种数据类型。不过 byte和uint8却是相同的类型,它们是字符串中字符类型。Speaking of string, thats a built-in type as well. Strings are immutable valuesthey are not just arrays of byte values. Once youve built a string value, you cant change it, although of course you can change a string variable simply by reassigning it. This snippet from strings.go is legal code:说道字符串string,它是一个内建类型。字符串虽然是字符序列,但并不是一个字符数组。当你建立字符串之后,你就不能改变字符串中的元素。不过可以通过指定新字符串来改变它。下面列举strings.go例子说明字符串的用法:代码:全选11 s := hello12 if s1 != e os.Exit(1) 13 s = good bye14 var p *string = &s15 *p = ciaoHowever the following statements are illegal because they would modify a string value:不管如何,下面的用法是禁止的,因为它们试图修改字符串的字符元素的值:代码:全选 s0 = x; (*p)1 = y;In C+ terms, Go strings are a bit like const strings, while pointers to strings are analogous to const string references.Go中的字符串和C+中的const strings概念类似,字符串指针和C+中的const strings 引用类似。Yes, there are pointers. However, Go simplifies their use a little; read on.是的,它们都是是指针,虽然Go中更简化一些。Arrays are declared like this:数组的声明如下:代码:全选 var arrayOfInt 10int;Arrays, like strings, are values, but they are mutable. This differs from C, in which arrayOfInt would be usable as a pointer to int. In Go, since arrays are values, its meaningful (and useful) to talk about pointers to arrays.数组和字符串一样是一个值对象,但是数组是可以修改的。但是不同于C语言,int类型数组 arrayOfInt并不能转化为int指针。因为,在Go语言中数组是一个值对象,它在内部保存 int指针。The size of the array is part of its type; however, one can declare a slice variable, to which one can assign a pointer to any array with the same element type ormuch more commonlya slice expression of the form alow : high, representing the subarray indexed by low through high-1. Slices look a lot like arrays but have no explicit size ( vs. 10) and they reference a segment of an underlying, often anonymous, regular array. Multiple slices can share data if they represent pieces of the same array; multiple arrays can never share data.数组的大小是数组变量的一部分。但是我们可以通过定义一个slice变量,来对数据进行操作。一个slice表示alow : high,它是对数组一部分的引用。Slices虽然看起来和数组类似,但是它并没有自己的内存空间,相反它在底层关引用一段内存。多个Slices如果引用同一个数组可以共享数组,但是多个数组则不可能共享数据。Slices are much more common in Go programs than regular arrays; theyre more flexible, have reference semantics, and are efficient. What they lack is the precise control of storage layout of a regular array; if you want to have a hundred elements of an array stored within your structure, you should use a regular array.在Go中Slices使用的更为普遍,因为它更有弹性,同时也具有效率。但是,Slices缺少对内存的绝对控制。如果你只是想要一个可以存放100个元素,那么你就应该选择数组了。When passing an array to a function, you almost always want to declare the formal parameter to be a slice. When you call the function, take the address of the array and Go will create (efficiently) a slice reference and pass that.当需要传递一个数组给函数时,你应该将函数的参数定义为一个Slice。这样,在调用函数的时候,数组将被自动转换为slice传入。Using slices one can write this function (from sum.go):使用slices可以写出以下函数(来自sum.go):代码:全选09 func sum(a int) int / returns an int10 s := 011 for i := 0; i len(a); i+ 12 s += ai13 14 return s15 and invoke it like this:可以这样调用:代码:全选19 s := sum(&3int1,2,3) / a slice of the array is passed to sumNote how the return type (int) is defined for sum() by stating it after the parameter list. The expression 3int1,2,3a type followed by a brace-bounded expressionis a constructor for a value, in this case an array of 3 ints. Putting an & in front gives us the address of a unique instance of the value. We pass the pointer to sum() by (implicitly) promoting it to a slice.函数的返回值类型在参数列表后定义。表达式3int1,2,3定义一个含有3个int类型元素的数组(并且已经初始化),然后用&来获取数组的地址。我们用数组指针作为参数调用sum(),数组指针被自动转换为slice类型。If you are creating a regular array but want the compiler to count the elements for you, use . as the array size:如果你创建一个初始化的数组,你可以倚赖编译起计算数组的元素数目,只要在数组大小中填写.就可以了:代码:全选 s := sum(&.int1,2,3);In practice, though, unless youre meticulous about storage layout within a data structure, a slice itselfusing empty brackets and no &is all you need:在编码时,除非需要精确控制内存布局;简单的方式是用slice(数组大小为空)作为参数,并且不需要取数组的地址。代码:全选 s := sum(int1,2,3);There are also maps, which you can initialize like this:还有map类型,可以用以下代码初始化:代码:全选 m := mapstringintone:1 , two:2The built-in function len(), which returns number of elements, makes its first appearance in sum. It works on strings, arrays, slices, maps, and channels.用内建的len()函数,可以获取元素的数目,该函数在前面的sum中用到过。len()函数还可以用在strings, arrays, slices, maps, 和 channels 中。By the way, another thing that works on strings, arrays, slices, maps and channels is the range clause on for loops. Instead of writing还有另外range方法可以用到strings, arrays, slices, maps, 和 channels 中,它可以用于for循环的迭代。以下代码代码:全选 for i := 0; i len(a); i+ . to loop over the elements of a slice (or map or .) , we could write也可以写成:代码:全选 for i, v := range a . This assigns i to the index and v to the value of the successive elements of the target of the range. See Effective Go for more examples of its use.这里的i对应元素的索引,v对应元素的值。关于更多的细节可以参考 Effective Go。An Interlude about AllocationMost types in Go are values. If you have an int or a struct or an array, assignment copies the contents of the object. To allocate a new variable, use new(), which returns a pointer to the allocated storage. 在Go语言中,大部分的类型都是变量。如果你有个int或struct(结构体)或 array(数组)的变量,你需要拷贝他们的内容到一个新对象中,并重新分配一个新的变量,就用new(), 它的返回值是一个指向被分配地址空间的指针。代码:全选 type T struct a, b int var t *T = new(T);or the more idiomatic 或者用别的方法代码:全选 t := new(T);Some typesmaps, slices, and channels (see below)have reference semantics. If youre holding a slice or a map and you modify its contents, other variables referencing the same underlying data will see the modification. For these three types you want to use the built-in function make(): 有一些类型,如: maps, slices 和 channels(见下面)有reference semantics(引用语意). 如果你修改了slice 或 map相关的内容,其他引用了这些数据的变量也能看到这个改变。对于这三个类型你得使用另一个内建的函数make()代码:全选 m := make(mapstringint);This statement initializes a new map ready to store entries. If you just declare the map, as in 上面的语句初始化一个新的map并分配了存储空间如果你只想声明一个map,代码如下:代码:全选 var m mapstringint;it creates a nil reference that cannot hold anything. To use the map, you must first initialize the reference using make() or by assignment from an existing map. 它创建了一个nil(空的)引用并且没有分配存储空间。如果你想用这个map, 你必须使用make来初始化引用或者指向一个已经存在的map。Note that new(T) returns type *T while make(T) returns type T. If you (mistakenly) allocate a reference object with new(), you receive a pointer to a nil reference, equivalent to declaring an uninitialized variable and taking its address. 注意: new(T)返回的类型是*T, 而make(T)返回的是T. 如果你(错误的)使用new()分配了一个引用对象,你将会得到一个指向nil引用的指针。这个相当于声明了一个未初始化的变量并取得它的地址.An Interlude about ConstantsAlthough integers come in lots of sizes in Go, integer constants do not. There are no constants like 0LL or 0x0UL. Instead, integer constants are evaluated as large-precision values that can overflow only when they are assigned to an integer variable with too little precision to represent the value. 虽然在Go中整数(integer)占用了大量
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 12横撇教学设计-2025-2026学年小学书法苏少版三年级下册-苏少版
- 27.2.1 第1课时 平行线分线段成比例2024-2025学年九年级下册数学同步说课稿(人教版)
- 4.3 基于物联网的项目开发教学设计-2025-2026学年高中信息技术浙教版2019选修6 开源硬件项目设计-浙教版2019
- 2025年中考数学试题分类汇编:二次函数的性质及应用(13大考点48题) (第1期)原卷版
- 2025年全国中级养老护理员职业技能考试A证题库(含答案)
- 小学升学考试卷及答案
- 蒸馏设备基础知识培训内容课件
- 蒲松龄课件教学课件
- 消防考试网络题目及答案
- 测井工实际操作考试题及答案
- JG/T 231-2018建筑玻璃采光顶技术要求
- JG/T 155-2014电动平开、推拉围墙大门
- 2025消瘦诊治与管理专家共识解读课件
- GB/T 18867-2025电子气体六氟化硫
- (高清版)DG∕TJ 08-15-2020 绿地设计标准 附条文说明
- 小学金融知识小课堂课件
- 病历质量定期检查评估与反馈制度
- 乐天地产(成都)有限公司乐天广场四期项目环评报告
- 初中生叛逆期教育主题班会
- 小学国家领土与主权教育
- 工程造价协议合同
评论
0/150
提交评论