最简单的一个go程序:golang
package main import "fmt" func main() { fmt.Println("Hello, World!") }
Go源程序由几部分构成:数组
package
用于包声明:package main
表示一个可独立执行的程序,** Go应用程序必须包含名为main
的包**,若是无main
包,那么编译器会提示"cannot run non-main package";import
用于导入须要引用的外部包, import "fmt"
告诉 Go 编译器这个程序须要使用 fmt 包;func main()
是程序的主函数,通常来讲都是在启动后第一个执行的函数(若是有init()
函数则会先执行init
函数);public
;protected
;变量分为值类型和引用类型:闭包
Go语言中的变量类型基本涵盖了C语言的基本类型,同时增长指定长度的类型,例如:int八、uint八、int1六、uint1六、int3二、uint32等。ide
Go语言中有多种定义变量的方法,分别介绍:函数
var v_name v_type
,范例:var varInPackage1 int // 本地变量,没有赋初始值 var varInPackage2 int = 10 // 本地变量赋初始值为10 var VarInPackage int = 20 // 全局变量赋初始值为20
var intVar = 10 var stringVar = "String"
:=
进行赋值,这种定义只能位于函数体内,用于建立局部变量,因此必须确保变量没有被定义过:intVar := 10 intVar1, strVar = 20, "StrValue" // 同时定义两个变量 a, _ = 10, 20 // 忽略第二个参数
var ( a int b bool )
go语言中变量的做用域与C语言相同。post
数组的定义:测试
var variable_name [SIZE] variable_type
建立数组格式:ui
var balance1 [10] int32 // 建立一个容量为10的数组 var balance2 = [5]float32{1.0, 2.0, 3.4, 7.0, 5.1} // 建立一个容量为5的数组,而且赋初始值 var balance3 = [...]float32{1.0, 2.1, 3.4, 7.5, 5.0} // 建立一个数组容量由后面定义的数据决定
切片(slice)是对数组一个连续片断的引用(该数组咱们称之为相关数组,一般是匿名的),因此切片是一个引用类型,切记不可用指针指向切片!!指针
和数组不一样的是,切片的长度能够在运行时修改,最小为 0 最大为相关数组的长度:切片是一个 长度可变的数组。code
切片的声明格式:
var identifier []type // 注意方括号为空
切片有几种建立方法:
var slice1 []type = arr1[start:end] // arr1为已经建立的数组或者切片
var x = []int{2, 3, 5, 7, 11} // 建立一个长度为5的切片
slice1 := make([]type, len) // len为切片的初始长度 slice1 := make([]type, len, cap) // cap为切片初始容量
切片能够调整容量,下面的代码用于将sl
的容量增长1:
sl = sl[0:len(sl)+1]
下面的将去掉切片的第一个元素:
sl = sl[1:len(sl)]
Go语言中字符串是常量,不可变。
若是须要修改字符串中的某个数字,则须要将字符串转化成切片后再进行修改。
例如,将字符串 "hello" 转换为 "cello":
s := "hello" c := []byte(s) c[0] = 'c' s2 := string(c) // s2 == "cello"
经过const
关键字建立常量,常量的定义方法与变量相似,差别在于将var
替换为const
,范例:
const a string = "abc" const b = "abc"
下面介绍一个特殊的常量iota
,能够认为这个是在编译前进由编译器修改的常量。
在一个const
组中,首次使用iota
时值为0,每使用一次,iota
自动加一,这种用法通常做为enum
类型使用:
const ( a = iota // 首次调用,因此a=0 b // 不赋任何值时,就是使用与上一个变量相同的方式赋值,因此这个等价于 b = iota,即便不写iota,编译器默认就是自动调用 c // 等价于 c = iota ) const ( a1 = iota // 这是一个新的const组,iota初始值为0,因此a1=0 a2 // 等价于 a2 = iota )
Go语言提供了strings
包,专门处理string
类型的数据。
例如:
strings.Contains()
判断字符串中是否包含特定字符串;strings.Index()
返回特定字符串在指定字符串中的位置;文档能够参考:https://studygolang.com/pkgdoc
Map 是一种无序的键值对的集合,Map 最重要的一点是经过 key 来快速检索数据,key 相似于索引,指向数据的值。
Map 是一种集合,因此咱们能够像迭代数组和切片那样迭代它,可是Map 是无序的,咱们没法决定它的返回顺序,这是由于 Map 是使用 hash 表来实现的。
map声明方式:
var map_variable map[key_data_type]value_data_type
map 是 引用类型 的: 内存用 make 方法来分配,最简单的初始化:
var map1 = make(map[keytype]valuetype) var map1 = make(map[keytype]valuetype, cap) // 指定容量
也能够带初始值方式建立,例如:
mapCreated := map[string]float32{"C0": 16.35, "D0": 18.35}
范例:
var kvs = make(map[string]string) // 建立一个Map kvs["AAA"] = "aaa"; kvs["BBB"] = "bbb"; for k,v := range kvs { // 遍历Map fmt.Printf("\tK=%s, V=%s\n", k, v) } v,ret := kvs["CCC"] // 查找map,第一个返回值是key对应的value,第二个返回值是结果 fmt.Printf("\tfind CCC, ret=%d, v=%s\n", ret, v)
if语句格式与C语言相比,只不过测试表达式不带括号(也能够带括号),其余与C语言相同:
if 测试表达式 { /* 在布尔表达式为 true 时执行 */ } else { /* 在布尔表达式为 false 时执行 */ }
Go的switch
与C的相似,与C的差别在于默认每一个case后面自带break语句,若是不须要break
,则须要经过fallthrough
关键字指明。
范例:
switch marks { case 90: grade = "A" case 80: grade = "B" case 50,60,70 : grade = "C" fallthrough // 表示没有break,至关于接着执行default里面的语句 default: grade = "D" }
if
和switch
还有另一种写法,支持接受一个初始化参数,格式以下:
if initstatement; condition {} switch initstatement; condition {}
例如:
if err := file.Chmod(0664); err != nil
循环控制:
for init; condition; post { } // 与C语言相同 for condition { } // 等同于 while(condition) for { } // 等同于 for(;;)
for
循环的init/post
段不支持经过,
分隔多个表达式,若是您须要初始化多个变量时,能够经过下面的方式:
sum := 0 for i,j := 0,100; i<=j; i++ { sum += i }
循环遍历array、slice、string、map时,能够使用range
关键字进行控制,range
第一个参数返回的是索引,第二个参数返回的是该索引位置的值:
strings := [] string{"string1", "string2", "string last"} for i,s :=range strings { fmt.Printf("\t%d = %s\n", i, s) }
标准函数定义以下:
func function_name([parameter list]) [return_types] { 函数体 }
函数的参数同C语言同样,存在值传递和引用传递,引用传递的方式与C语言的指针格式相同:
func swap(x *int, y *int) { var temp int temp = *x /* 保持 x 地址上的值 */ *x = *y /* 将 y 值赋给 x */ *y = temp /* 将 temp 值赋给 y */ }
而实际上若是进行swap,还有更简单的方式,例以下面是调换a、b两个变量的值:
a, b = b, a
C语言中通常使用函数指针来指向一个函数,Go中能够直接将将函数赋值给变量,该变量就是函数:
// 建立一个函数变量 getSquareRoot getSquareRoot := func(x float64) float64 { return math.Sqrt(x) } fmt.Println(getSquareRoot(9)) /* 使用函数 */
所谓闭包,就是将函数自身使用的数据封装到包中,对外不可见。
参考下面的函数,getSequence
函数返回一个函数,被返回的函数中引用了getSequence
函数的一个局部变量,因此只要被返回的函数存在,那么getSequence
函中的局部变量i就会存在,这个就是至关于将i变量封到了包中,即闭包。
func getSequence() func() int { i:=0 return func() int { i+=1 // 这里能够引用getSequence函数中定义的局部变量 return i } } nextNumber := getSequence() // 建立闭包
Go语言中一个函数能够返回一个或者多个值,多值返回函数范例:
func swap(x, y string) (string, string) { return y, x }
也能够对返回值参数进行命名,这样就能够在函数体中对返回值参数进行赋值,这个赋值就是至关于设置返回值,范例:
func f(x, y int) (sum int, sub int) { sum = x+y sub = x-y return }
关键字defer
容许咱们推迟到函数返回以前执行,若是一个函数存在多个defer
语句,那么按照后进先出的顺序执行,即栈的顺序。
例如,下面的代码指定了2个Defer:
func deferFunc() { fmt.Printf("Hello here is defer funtion\n"); } func testDeferFunc() { fmt.Printf("print 1\n") defer deferFunc() defer func() { // 建立一个匿名函数,并defer执行 fmt.Printf("Hello here is defer function, inner\n") }() fmt.Printf("print 2\n") }
输出结果为:
print 1 print 2 Hello here is defer function, inner Hello here is defer funtion