内容简介:Go是一个开源的编程语言。Go语言被设计成一门应用于搭载Web服务器,存储集群或类似用途的巨型中央服务器的系统编程语言。目前,Go最新发布版本为1.10.Go语言可以运行在Linux、FreeBSD、Mac OS X和Windows系统上。1. 结构:Go语言的基础组成有以下几个部分:包声明、引入包、函数、变量、语句&表达式、注释。
Go是一个开源的编程语言。Go语言被设计成一门应用于搭载Web服务器,存储集群或类似用途的巨型中央服务器的系统编程语言。目前,Go最新发布版本为1.10.
Go语言可以运行在 Linux 、FreeBSD、Mac OS X和Windows系统上。
1. 结构:Go语言的基础组成有以下几个部分:包声明、引入包、函数、变量、语句&表达式、注释。
(1)、必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main
(2)、注释与C++相同,有单行注释即”//”和多行注释即”/* … */”两种。
(3)、当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出;标识符如果以小写字母开头,则对包外是不可见的,但是它们在整个包的内部是可见并且可用的。
2. 基础语法:
(1)、 Go 标记:Go程序可以由多个标记组成,可以是关键字、标识符、常量、字符串、字符。
(2)、行分隔符:在Go程序中,一行代表一个语句结束。每个语句不需要像C++语言一样以分号”;”结尾,因为这些工作都将由Go编译器自动完成。如果你打算将多个语句写在同一行,它们必须使用”;”为区分,但在实际开发中我们并不鼓励这种做法。
(3)、注释:注释不会被编译,每一个包应该有相关注释。单行注释以”//”开头,多行注释以”/*”开头,以”*/”结尾,与C++相同。
(4)、标识符:用来命名变量、类型等程序实体。一个标识符实际上就是一个或是多个字母(A~Z和a~z)、数字(0~9)、下划线”_”组成的序列,但是第一个字符必须是字母或下划线而不能是数字。标识符不能是Go语言的关键字。
(5)、关键字:25个关键字:break、default、func、interface、select、case、defer、go、map、struct、chan、else、goto、package、switch、const、fallthrough、if、range、type、continue、for、import、return、var。36个预定义标识符:append、bool、type、cap、close、complex、complex64、complex128、uint16、copy、false、float32、float64、image、int、int8、int16、uint32、int32、int64、iota、len、make、new、nil、panic、unit64、print、println、real、recover、string、true、uint、uint8、uintptr。
程序一般由关键字、常量、变量、运算符、类型和函数组成。程序中可能会使用到这些分隔符:()、[]、{}。程序中可能会使用到这些标点符号:.、,、;、:和…。
3. 数据类型:在Go编程语言中,数据类型用于声明函数和变量:布尔型(true、false);数字类型(整型、浮点型、复数);字符串类型(一串固定长度的字符连接起来的字符序列);派生类型(指针类型、数组类型、结构化类型、Channel类型、函数类型、切片类型、接口类型、Map类型)。
4. 变量:声明变量的一般形式是使用var关键字。也可多变量声明。
变量声明方式:(1)、指定变量类型,声明后若不赋值,使用默认值;(2)、根据值自行判定变量类型;(3)、省略var,注意:=左侧的变量不应该是已经声明过的,否则会导致编译错误。
值类型和引用类型:所有像int、float、bool和string这些基本类型都属于值类型,使用这些类型的变量直接指向存在内存中的值。你可以通过&i来获取变量i的内存地址。值类型的变量的值存储在栈中。内存地址会根据机器的不同而有所不同,甚至相同的程序在不同的机器上执行后也会有不同的内存地址。因为每台机器可能有不同的存储器布局,并且位置分配也可能不同。更复杂的数据通常会需要使用多个字,这些数据一般使用引用类型保存。一个引用类型的变量r1存储的是r1的值所在的内存地址(数字),或内存地址中第一个字所在的位置。这个内存地址称之为指针,这个指针实际上也被存在另外的某一个字中。同一个引用类型的指针指向的多个字可以是连续的内存地址中(内存布局是连续的),也可以将这些字分散存放在内存中,每个字都指示了下一个字所在的内存地址。
简短形式,使用:=赋值操作符:我们知道可以在变量的初始化时省略变量的类型而由系统自动推断,声明语句写上var关键字其实是显得多余了,因此我们可以将它们简写为:a:= 5 或b := false,a和b的类型(int和bool)将由编译器自动推断。这是使用变量的首选形式,但是它只能被用在函数体内,而不可以用于全局变量的声明与赋值。
注意事项:(1)、如果在相同的代码块中,我们不可以再次对于相同名称的变量使用初始化声明。(2)、如果你声明了一个局部变量却没有在相同的代码块中使用它,同样会得到编译错误。但是全局变量是允许声明但不使用。同一类型的多个变量可以声明在同一行。
空白标识符_也被用于抛弃值。_实际上是一个只写变量,你不能得到它的值。这样做是因为Go语言中你必须使用所有被声明的变量,但有时你并不需要使用从一个函数得到的所有返回值。
多个变量可以声明在同一行,多个变量也可以在同一行进行赋值,这被称为并行或同时赋值。并行赋值也被用于当一个函数返回多个返回值时。
5. 常量:是一个简单值的标识符,在程序运行时,不会被修改的量。常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。
你可以省略类型说明符,因为编译器可以根据变量的值来推断其类型。也可以在同一行声明多个常量和赋值。常量还可以用作枚举。
常量可以用len()、cap()、unsafe.Sizeof()函数计算表达式的值。常量表达式中,函数必须是内置函数。
iota:特殊常量,可以认为是一个可以被编译器修改的常量。在每一个const关键字出现时,被重置为0,然后再下一个const出现之前,每出现一次iota,其所代表的数字会自动增加1。 iota可以被用作枚举值 。
6. 运算符:用于在程序运行时执行数学或逻辑运算。
Go语言内置的运算符有:算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符、其它运算符。
算术运算符:+、-、*、/、%、++、--
关系运算符:==、!=、>、<、>=、<=
逻辑运算符:&&、||、!
位运算符:&、|、^、<<、>>,对整数在内存中的二进制位进行操作。
赋值运算符:=、+=、-=、*=、/=、%=、<<=、>>=、&=、^=、|=
其它运算符:&(获取变量存储地址)、*(指针变量)
运算符优先级:二元运算符的运算方向均是从左至右。可以使用括号来临时提升某个表达式的整体运算优先级。
7. 条件语句:需要开发者通过指定一个或多个条件,并通过测试条件是否为true来决定是否执行指定语句,并在条件为false的情况下执行另外的语句。
if语句:由布尔表达式后紧跟一个或多个语句组成。if语句后可以使用可选的else语句。你也可以在if或else if语句中嵌入一个或多个if或else if语句。
switch语句:用于基于不同条件执行不同动作,每一个case分支都是唯一的,从上到下逐一检查,直到匹配为止。匹配项后面也不需要再加break。case类型不被局限于常量或整数,但必须是相同的类型。switch语句还可以被用于type--switch来判断某个interface变量中实际存储的变量类型。
select语句:select是Go中的一个控制结构,类似于用于通信的switch语句。每个case必须是一个通信操作,要么是发送要么是接收。select随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。一个默认的子句应该总是可运行的。select语句的语法:(1)、每个case都必须是一个通信;(2)、所有channel表达式都会被求值;(3)、所有被发送的表达式都会被求值;(4)、如果任意某个通信可以进行,它就执行,其它被忽略;(5)、如果有多个case都可以运行,select会随机公平地选出一个执行,其它不会执行。否则,如果有default子句,则执行该语句。如果没有default子句,select将阻塞,直到某个通信可以运行。Go不会重新对channel或值进行求值。
8. 循环语句:for,可以嵌套一个或多个for。循环控制语句可以控制循环体内语句的执行过程,包括break、continue、goto。如果循环中条件语句永远不为false则会进行无限循环。有些类似于 C语言 中的for和while。
break语句:(1)、用于循环语句中跳出循环,并开始执行循环之后的语句;(2)、在switch中在执行一条case后跳出语句的作用。
continue语句:有点像break语句,但是continue不是跳出循环,而是跳过当前循环执行下一次循环语句。
goto语句:可以无条件地转移到过程中指定的行。在结构化程序设计中一般不主张使用goto语句。
9. 函数:是基本的代码块,用于执行一个任务。Go语言最少有个main()函数。函数声明告诉了编译器函数的名称、返回类型和参数。Go语言标准库提供了多种可动用的内置的函数。
函数定义格式:func function_name([parameter list]) [return_types] {函数体}
函数定义解析:(1)、func:函数由func开始声明。(2)、function_name:函数名称,函数名和参数列表一起构成了函数签名。(3)、parameter list:参数列表,参数就像一个占位符,当函数被调用时,你可以将值传递给参数,这个值被称为实际参数。参数列表指定的是参数类型、顺序、及参数个数。参数是可选的,函数也可以不包含参数。(4)、return_types:返回类型,函数返回一列值。(5)、函数体:函数定义的代码集合。
Go函数可以返回多个值。
函数参数:函数如果使用参数,该变量可称为函数的形参。形参就像定义在函数体内的局部变量。调用函数,可以通过两种方式传递参数:值传递和引用传递。默认情况下,Go语言使用的是值传递,即在调用过程中不会影响到实际参数。
值传递:是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递:是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
函数用法:(1)、函数作为值:函数定义后可作为值来使用。(2)、闭包:是匿名函数,可在动态编程中使用。匿名函数是一个”内联”语句或表达式。匿名函数的优越性在于可以直接使用函数内的变量,不必声明。(3)、方法:是一个包含了接受者的函数,接受者可以是命名类型或者结构体类型的一个值或者是一个指针。所有给定类型的方法属于该类型的方法集。
10. 变量作用域:Go语言中变量可以在三个地方声明:局部变量、全局变量、形式参数。
(1)、局部变量:在函数体内声明的变量称之为局部变量,它们的作用域只在函数体内,参数和返回值变量也是局部变量。
(2)、全局变量:在函数体外声明的变量称之为全局变量,全局变量可以在整个包甚至外部包(被导出后)使用。全局变量可以在任何函数中使用。
(3)、形式参数:函数定义中的变量称为形式参数。形式参数会作为函数的局部变量来使用。
Go语言程序中全局变量与局部变量名称可以相同,但是函数内的局部变量会被优先考虑。
11. 数组:是具有相同唯一类型的一组已编号且长度固定的数据项序列,这种类型可以是任意的原始类型如整型、字符串或者自定义类型。数组元素可以通过索引(位置)来读取(或者修改),索引从0开始,第一个元素索引为0,第二个索引为1,以此类推。
声明数组:Go语言数组声明需要指定元素类型及元素个数。数组长度必须是整数且大于0。
初始化数组:初始化数组中{}中的元素个数不能大于[]中的数字。如果忽略[]中的数字不设置数字大小,Go语言会根据元素的个数来设置数组的大小。
访问数组元素:数组元素可以通过索引(位置)来读取。格式为数组名后加中括号,中括号中为索引的值。
多维数组:Go语言支持多维数组。
向函数传递数组:如果你想向函数传递数组参数,你需要在函数定义时,声明形参为数组。
12. 指针:变量是一种方便的占位符,用于引用计算机内存地址。Go语言的取地址符是&,放到一个变量前使用就会返回相应变量的内存地址。一个指针变量指向了一个值的内存地址。
指针使用流程:定义指针变量;为指针变量赋值;访问指针变量中指向地址的值。在指针类型前面加上*号(前缀)来获取指针所指向的内容。
空指针:当一个指针被定义后没有分配到任何变量时,它的值为nil。nil指针也为空指针。nil在概念上和其它语言的null、None、nil、NULL一样,都指代零值或空值。
指针数组:可以定义一个指针数组来存储地址。
指向指针的指针:如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量。访问指向指针的指针变量值需要使用两个*号。
向函数传递指针参数:只需要在函数定义的参数上设置为指针类型即可。通过引用或地址传参,在函数调用时可以改变其值。
13. 结构体:Go语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型。结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。
结构体定义需要使用type和struct语句。struct语句定义一个新的数据类型,结构体中有一个或多个成员。type语句设定了结构体的名称。一旦定义了结构体类型,它就能用于变量的声明。如果要访问结构体成员,需要使用点号(.)操作符。你可以像其它数据类型一样将结构体类型作为参数传递给函数。你可以定义指向结构体的指针类似于其它指针变量。
14. 切片(slice):Go语言切片是对数组的抽象。Go数组的长度不可改变,Go中提供了一种灵活,功能强悍的内置类型切片(“动态数组”)。与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。有些类似于C++中的vector。
你可以声明一个未指定大小的数组来定义切片,切片不需要说明长度,或使用make()函数来创建切片。
切片是可索引的,并且可以用len()方法获取长度。切片提供了计算容量的方法cap()可以测量切片最长可以达到多少。一个空切片在未初始化之前默认为nil,长度为0.可以通过设置下限及上限来设置截取切片。
如果想增加切片的容量,我们必须创建一个新的更大的切片并把原分片的内容都拷贝过来。可使用拷贝切片的copy方法,或向切片追加新元素的append方法。
15. range关键字:Go语言中range关键字用于for循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。在数组和切片中它返回元素的索引值,在集合中返回key-value对的key值。
16. Map(集合):Map是一种无序的键值对的集合。Map最重要的一点是通过key来快速检索数据,key类似于索引,指向数据的值。Map是一种集合,所以我们可以像迭代数组和切片那样迭代它。Map是无序的,我们无法决定它的返回顺序,这是因为Map是使用hash表来实现的。
可以使用内建函数make也可以使用map关键字来定义Map。如果不初始化map,那么就会创建一个nil map。nil map不能用来存放键值对。delete()函数用来删除集合的元素。
17. 递归函数:递归,就是在运行的过程中调用自己。在使用递归时,需要设置退出条件,否则递归将陷入无限循环中。
18. 类型转换:用于将一种数据类型的变量转换为另外一种类型的变量,形式为:type_name(expression)
19. 接口:把所有的具有共性的方法定义在一起,任何其它类型只要实现了这些方法就是实现了这个接口。
20. 错误处理:Go语言通过内置的错误接口提供了非常简单的错误处理机制。
以下是测试代码:
// 变量相关测试代码 package main import "fmt" // 全局变量声明 var c float32 var x = 11 func main() { // 局部变量声明 // 指定变量类型,声明后若不赋值,使用默认值 var available bool available = true fmt.Println(available) // 根据值自动判定变量类型 var a = 1 var b = 2.5 fmt.Println(a, b) c = float32(a) + float32(b) fmt.Printf("c = %f\n", c) // 省略var, 注意 :=左侧的变量不应该是已经声明过的,否则会导致编译错误,这种形式只能被用在函数体中 valid := false _, d := 5, 6 // 空白标识符 fmt.Println(valid, d) // 多变量声明 var enabled, disabled = true, "111" fmt.Println(enabled, disabled) // 获取变量a的内存地址 fmt.Println(&a) // Go语言程序中全局变量与局部变量名称可以相同,但是函数内的局部变量会被优先考虑 var x = -11 fmt.Printf("x = %d\n", x) }
// 常量相关测试代码 package main import "fmt" import "unsafe" // 常量还可以用作枚举 const ( o = "abc" p = len(o) q = unsafe.Sizeof(o) ) // itoa: iota可以被用作枚举值,第一个iota等于0,每当iota在新的一行被使用时,它的值都会自动加1 const ( d = iota e f ) func main() { const a string = "abc" // 显示类型定义 const b = "def" // 隐式类型定义 fmt.Println(a, b) const x, y, z = 1, 0.2, "blog" fmt.Println(x, y, z) fmt.Println(o, p, q) fmt.Println(d, e, f) }
// 运算符相关测试代码 package main import "fmt" func main() { // 算术运算符 var a, b, c = 1, 2, 3 fmt.Printf("a + b = %d\n", a+b) fmt.Printf("a - c = %d\n", a-c) fmt.Printf("a * b = %d\n", a*b) c++ // 注:++和--好像仅有前缀运算符 fmt.Printf("c++ = %d\n", c) b-- fmt.Printf("--b = %d\n", b) // 关系运算符 if a > b { // 注:visual studio code会默认把if (a > b)调整为if a > b fmt.Printf("a > b\n") } else { fmt.Printf("a <= b\n") } // 逻辑运算符 x, y := true, false if x && y { fmt.Printf("true\n") } else { fmt.Printf("false\n") } // 位运算符: 好像仅支持整数 a, b = 1, 3 c = a & b fmt.Printf("c = %d\n", c) fmt.Printf("b << 2: %d\n", b<<2) // 赋值运算符 b <<= 2 fmt.Printf("b = %d\n", b) // 其它运算符:&、* fmt.Printf("b's address: %0x\n", &b) var ptr *int ptr = &a fmt.Printf("pointer: %0x\n", ptr) }
// 条件语句相关测试代码 package main import "fmt" func main() { // if a := 1.2 if a > 0 { fmt.Printf("a > 0, a = %f\n", a) } // if else b := 2.5 if b > 10 { fmt.Printf("b > 10\n") } else { fmt.Printf("b <= 10\n") } fmt.Printf("b = %f\n", b) // if 嵌套 if a > 0 { if b > 0 { fmt.Printf("a > 0, b > 0\n") } } // switch grade := "B" marks := 90 switch marks { case 90: grade = "A" case 80: grade = "B" case 50, 60: grade = "C" default: grade = "D" } fmt.Printf("grade = %s\n", grade) // type switch var x interface{} switch i := x.(type) { case nil: fmt.Printf(" x 的类型: %T\n", i) case int: fmt.Printf("x 是 int 型\n") case float64: fmt.Printf("x 是 float64 型\n") case func(int) float64: fmt.Printf("x 是 func(int) 型\n") case bool, string: fmt.Printf("x 是 bool 或 string 型\n") default: fmt.Printf("未知型\n") } // select var c1, c2, c3 chan int var i1, i2 int select { case i1 = <-c1: fmt.Printf("received ", i1, " from c1\n") case c2 <- i2: fmt.Printf("sent ", i2, " to c2\n") case i3, ok := (<-c3): // same as: i3, ok := <-c3 if ok { fmt.Printf("received ", i3, " from c3\n") } else { fmt.Printf("c3 is closed\n") } default: fmt.Printf("no communication\n") } }
// 循环语句相关测试代码 package main import "fmt" func main() { // for a, b := 0, 15 fmt.Printf("a的值为: ") for a = 0; a < 10; a++ { fmt.Printf(" %d ", a) } fmt.Printf("\n") fmt.Printf("a的值为: ") for a < b { a++ fmt.Printf(" %d ", a) } fmt.Printf("\n") // for嵌套、break var i, j int fmt.Printf("2到100之间的素数包括:") for i = 2; i < 100; i++ { for j = 2; j <= (i / j); j++ { if i%j == 0 { break } } if j > (i / j) { fmt.Printf(" %d ", i) } } fmt.Printf("\n") // continue a = 0 fmt.Printf("a的奇数:") for a < 20 { a++ if a%2 == 0 { continue } fmt.Printf(" %d ", a) } fmt.Printf("\n") // goto a = 0 fmt.Printf("打印a的值:") Loop: for a < 10 { if a == 5 { a++ goto Loop } fmt.Printf(" %d ", a) a++ } fmt.Printf("\n") }
// 函数相关测试代码 package main import ( "fmt" "math" ) // 函数返回两个数的最大值,值传递 func max(num1, num2 int) int { var result int if num1 > num2 { result = num1 } else { result = num2 } return result } // 函数支持返回多个值,值传递 func swap(x, y string) (string, string) { return y, x } // Go函数不支持C++中的函数重载,引用传递 func swap1(x *int, y *int) { var temp int temp = *x *x = *y *y = temp } func getSequence() func() int { i := 0 return func() int { i++ return i } } type Circle struct { radius float64 } func (c Circle) getArea() float64 { // c.radius 即为Circle类型对象中的属性 return 3.14 * c.radius * c.radius } func main() { a, b := 100, 200 var ret = max(a, b) fmt.Printf("a,b最大值为: %d\n", ret) var x, y = "hello", "beijing" fmt.Printf("x: %s, y: %s\n", x, y) m, n := swap(x, y) fmt.Printf("x: %s, y: %s\n", x, y) fmt.Printf("m: %s, n: %s\n", m, n) p, q := -100, 500 fmt.Printf("p: %d, q: %d\n", p, q) swap1(&p, &q) fmt.Printf("p: %d, q: %d\n", p, q) // 函数用法:函数作为值 getSquareRoot := func(x float64) float64 { return math.Sqrt(x) } fmt.Printf("square root: %f\n", getSquareRoot(9)) // 函数用法:闭包 nextNumber := getSequence() // 调用nextNumber函数,i 变量自增 1 并返回 fmt.Println("i的值: %d", nextNumber()) fmt.Println("i的值: %d", nextNumber()) fmt.Println("i的值: %d", nextNumber()) // 创建新的函数nextNumber1,并查看结果 nextNumber1 := getSequence() fmt.Println("i的值: %d", nextNumber1()) fmt.Println("i的值: %d", nextNumber1()) // 函数用法:方法 var c1 Circle c1.radius = 10.00 fmt.Println("Area of Circle(c1) = ", c1.getArea()) }
// 数组相关测试代码 package main import "fmt" func getAverage(arr []int, size int) float32 { var avg, sum float32 for i := 0; i < size; i++ { sum += float32(arr[i]) } avg = sum / float32(size) return avg } func main() { // 一维数组 const num = 10 var n [num]int for i := 0; i < num; i++ { n[i] = i + 100 } for j := 0; j < num; j++ { fmt.Printf("Element[%d] = %d\n", j, n[j]) } // 初始化数组 const num2 = 5 var m = [num2]float32{0., 1., 2., 3., 4.} for i := 0; i < num2; i++ { fmt.Printf("Element[%d] = %f\n", i, m[i]) } // 初始化二维数组并访问 var a = [3][4]int{{0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11}} fmt.Printf("a[2][3]: %d\n", a[2][3]) // 向函数传递数组 var balance = []int{1000, 2, 3, 17, 50} avg := getAverage(balance, 5) fmt.Printf("平均值:%f\n", avg) }
// 指针相关测试代码 package main import "fmt" const MAX int = 3 func swap(x *int, y *int) { var temp int temp = *x *x = *y *y = temp } func main() { // 指针常规操作 var a = 20 var ip *int ip = &a fmt.Printf("a 变量的地址是: %x\n", &a) fmt.Printf("ip 变量储存的指针地址: %x\n", ip) fmt.Printf("*ip 变量的值: %d\n", *ip) var ptr *int fmt.Printf("ptr 的值为 : %x\n", ptr) if ptr == nil { fmt.Printf("ptr为空指针\n") } // 指针数组 b := []int{10, 100, 200} var ptr2 [MAX]*int for i := 0; i < MAX; i++ { ptr2[i] = &b[i] } for i := 0; i < MAX; i++ { fmt.Printf("b[%d] = %d\n", i, *ptr2[i]) } // 指向指针的指针 var pptr **int pptr = &ip fmt.Printf("指向指针的指针变量 **pptr = %d\n", **pptr) // 向函数传递指针参数 x, y := -11, 22 fmt.Printf("x = %d, y = %d\n", x, y) swap(&x, &y) fmt.Printf("x = %d, y = %d\n", x, y) }
// 结构体相关测试代码 package main import "fmt" type Books struct { title string author string subject string book_id int } func main() { // 访问结构体成员 var Book1, Book2 Books Book1 = Books{"Go语言", "www.runoob.com", "Go语言教程", 649507} Book2.title = "Python 教程" Book2.author = "www.runoob.com" Book2.subject = "Python 语言教程" Book2.book_id = 6495700 fmt.Printf("Book 1 title: %s, autor: %s, subject: %s, book_id: %d\n", Book1.title, Book1.author, Book1.subject, Book1.book_id) fmt.Printf("Book 2 title: %s, autor: %s, subject: %s, book_id: %d\n", Book2.title, Book2.author, Book2.subject, Book2.book_id) // 结构体作为函数参数 printBook(Book1) printBook(Book2) // 结构体指针 printBook2(&Book1) printBook2(&Book2) } func printBook(book Books) { fmt.Printf("Book 1 title: %s, autor: %s, subject: %s, book_id: %d\n", book.title, book.author, book.subject, book.book_id) } func printBook2(book *Books) { fmt.Printf("Book 1 title: %s, autor: %s, subject: %s, book_id: %d\n", book.title, book.author, book.subject, book.book_id) }
// 切片(slice)相关测试代码 package main import "fmt" func main() { // 定义切片 //var slice1 []int //slice2 := make([]int, 5) //slice3 := make([]int, 5, 10) // 切片初始化 //slice4 := []int{1, 2, 3} //var arr = [5]float32{0., 1., 2., 3., 4.} //slice5 := arr[:] // len()和cap()函数 var numbers = make([]int, 3, 5) printSlice(numbers) // 空(nil)切片 var number2 []int printSlice(number2) // 切片截取 numbers3 := []int{0, 1, 2, 3, 4, 5, 6, 7, 8} printSlice(numbers3) fmt.Println("numbers3 ==", numbers3) // 打印子切片从索引1(包含) 到索引4(不包含) fmt.Println("numbers3[1:4] ==", numbers3[1:4]) // 默认下限为 fmt.Println("numbers3[:3] ==", numbers3[:3]) // 默认上限为 len(s) fmt.Println("numbers3[4:] ==", numbers3[4:]) // 增加切片的容量 var numbers4 []int printSlice(numbers4) // 允许追加空切片 numbers4 = append(numbers4, 0) printSlice(numbers4) // 向切片添加一个元素 numbers4 = append(numbers4, 1) printSlice(numbers4) // 同时添加多个元素 numbers4 = append(numbers4, 2, 3, 4) printSlice(numbers4) // 创建切片 numbers5是之前切片的两倍容量 numbers5 := make([]int, len(numbers4), (cap(numbers4))*2) printSlice(numbers5) // 拷贝numbers4的内容到numbers5 copy(numbers5, numbers4) printSlice(numbers5) } func printSlice(x []int) { fmt.Printf("len=%d cap=%d slice=%v\n", len(x), cap(x), x) }
// 范围(range)相关测试代码 package main import "fmt" func main() { // 使用range去求一个slice的和,使用数组跟这个很类似 nums := []int{2, 3, 4} sum := 0 for _, num := range nums { sum += num } fmt.Printf("sum: %d\n", sum) // 在数组上使用range将传入index和值两个变量,上面那个例子我们不需要使用该元素的序号,所以我们使用空白符"_"省略 for i, num := range nums { if num == 3 { fmt.Printf("index: %d\n", i) } } // range也可以用在map的键值对上 kvs := map[string]string{"a": "apple", "b": "banana"} for k, v := range kvs { fmt.Printf("%s -> %s\n", k, v) } // range也可以用来枚举Unicode字符串. 第一个参数是字符的索引,第二个是字符(Unicode的值)本身 for i, c := range "go" { fmt.Println(i, c) } }
// Map(集合)相关测试代码 package main import "fmt" func main() { // 创建map var countryCapitalMap map[string]string countryCapitalMap = make(map[string]string) // map插入key-value对,各个国家对应的首都 countryCapitalMap["France"] = "Paris" countryCapitalMap["Italy"] = "Rome" countryCapitalMap["Japan"] = "Tokyo" countryCapitalMap["India"] = "New Delhi" // 使用key输出map值 for country := range countryCapitalMap { fmt.Printf("Capital of %s is %s\n", country, countryCapitalMap[country]) } // 查看元素在集合中是否存在 captial, ok := countryCapitalMap["United States"] // 如果ok是true,则存在,否则不存在 if ok { fmt.Println("Capital of United States is", captial) } else { fmt.Println("Capital of United States is not present") } // 创建map countryCapitalMap2 := map[string]string{"France": "Paris", "Italy": "Rome", "Japan": "Tokyo", "India": "New Delhi"} fmt.Println("原始 map:") for country := range countryCapitalMap2 { fmt.Println("Capital of", country, "is", countryCapitalMap2[country]) } // 删除元素 delete(countryCapitalMap2, "France") fmt.Println("删除元素后 map:") for country := range countryCapitalMap2 { fmt.Println("Capital of", country, "is", countryCapitalMap2[country]) } }
// 递归相关测试代码 package main import "fmt" func Factorial(n uint64) (result uint64) { if n > 0 { result = n * Factorial(n-1) return result } return 1 } func fibonacci(n int) int { if n < 2 { return n } return fibonacci(n-2) + fibonacci(n-1) } func main() { // 阶乘 var i = 15 fmt.Printf("%d 的阶乘是 %d\n", i, Factorial(uint64(i))) // 斐波那契数列 for i = 0; i < 10; i++ { fmt.Printf("%d\t", fibonacci(i)) } fmt.Println() }
// 接口相关测试代码 package main import "fmt" type Phone interface { call() } type NokiaPhone struct { } func (nokiaPhone NokiaPhone) call() { fmt.Println("I am Nokia, I can call you!") } type IPhone struct { } func (iPhone IPhone) call() { fmt.Println("I am iPhone, I can call you!") } func main() { var phone Phone phone = new(NokiaPhone) phone.call() phone = new(IPhone) phone.call() }
// 错误处理相关测试代码 package main import "fmt" type DivideError struct { dividee int divider int } // 实现'error'接口 func (de *DivideError) Error() string { strFormat := ` Cannot proceed, the divider is zero. dividee: %d divider: 0 ` return fmt.Sprintf(strFormat, de.dividee) } func Divide(varDividee int, varDivider int) (result int, errorMsg string) { if varDivider == 0 { dData := DivideError{varDividee, varDivider} errorMsg = dData.Error() return } else { return varDividee / varDivider, "" } } func main() { // 正常情况 if result, errorMsg := Divide(100, 10); errorMsg == "" { fmt.Println("100/10 = ", result) } // 当被除数为零的时候会返回错误信息 if _, errorMsg := Divide(100, 0); errorMsg != "" { fmt.Println("errorMsg is: ", errorMsg) } }
以上内容摘自: runoob.com
GitHub : https://github.com/fengbingchun/Go_Test以上所述就是小编给大家介绍的《Go语言基础介绍》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Dive Into Python 3
Mark Pilgrim / Apress / 2009-11-6 / USD 44.99
Mark Pilgrim's Dive Into Python 3 is a hands-on guide to Python 3 (the latest version of the Python language) and its differences from Python 2. As in the original book, Dive Into Python, each chapter......一起来看看 《Dive Into Python 3》 这本书的介绍吧!
在线进制转换器
各进制数互转换器
html转js在线工具
html转js在线工具