一等公民 Golang
2011 年 1 月 2 日
下载安装Go语言
https://golang.org/doc/install
安装IDE
Atom: https://atom.io
+ package:go-plus
若没有设置环境变量使用
Unix上默认为 $HOME/go
Windows上默认为 %USERPROFILE%/go
Mac 上 GOPATH 通过修改~/.bash_profile来设置
package main //包 ,表明代码所在的模块(包) /* //只有25个关键字 1.必须是main 包:package main 2.必须是main 方法:func main() 3. 文件名不一定是main.go */ /* 退出返回值 与其他主要编程语言的差异 Go中main 函数不支持任何返回值 通过os.Exit来返回状态 */ import "fmt" //引入代码依赖 //功能实现 func main() { fmt.Print("hello world") os.Exit(0) }
直接运行 使用 go run hello.go
编译生成二进制 go build hello.go
package main /* 获取命令行参数 与其他主要编程语言的差异 main 函数不支持传入参数 func main(arg []string) 不支持 X 在程序中通过os.Args获取命令行参数 */ import ( "fmt" "os" ) func main() { fmt.Println(os.Args) if len(os.Args)>1 { fmt.Println("hello world cmd: ",os.Args[1]) } fmt.Print("hello world") os.Exit(0) }
编写测试程序
//源码文件以 _test结尾:xxx_test.go //测试方法名以Test开头:func TestXXX(t *testing.T){ ... } 大写是包外可以访问 package try_test import "testing" func TestFirstTry(t *testing.T){ t.Log("My First try!") }
package fib import ( "fmt" "testing" ) //全局变量声明 //var a int func TestFibList(t *testing.T) { //a = 1 //全局变量赋值 //定义变量方法一 //var a int = 1 //var b int = 1 //定义变量方法二 //var( // a int = 1 // b int = 1 //) // 自动推断变量类型 a := 1 b := 1 fmt.Print(a) for i :=0; i<5; i++ { // fmt.Print(" ", b) t.Log(" ", b) tmp := a a = b b = tmp + a } fmt.Println() } func TestSwap(t *testing.T) { a := 1 b := 2 // tmp := a // a = b // b = tmp // 对多个变量赋值 a, b = b, a t.Log(a, b) }
// 常量定义 // 与其他主要编程语言的差异 // 快速设置连续值 package constant_test import "testing" const ( Monday = iota +1 Tuesday Wednesday Thursday Friday Saturday Sunday ) const ( Open = 1 << iota Close ) func TestConstantTry(t *testing.T) { t.Log(Monday, Tuesday) } func TestConstantTryBin(t *testing.T) { a := 7 //0111 t.Log( a&Open == Open, a&Close == Close) }
// 基本数据类型 bool string int int8 int16 int32 int64 uint uint8 uint16 uint32 uint64 uintptr byte //alias for uint8 rune //alias for int32,represents a Unicode code point float32 float64 complex64 complex128 // 类型转换 // 与其他主要编程语言的差异 // 1.Go语言不允许隐式类型转换 // 2.别名和原有类型也不能进行隐式类型转换
package type_test import "testing" type MyInt int64 // 声明一个int64 的别名MyInt func TestImplicit(t *testing.T) { var a int = 1 var b int64 b = int64(a) //显示转换 // b = a //Err 不能隐式转换 var c MyInt //c = b //Err 同类型的别名也不能隐式转换 严格 c = MyInt(b) t.Log(a, b, c) }
//类型的预定义值 1.math.MaxInt64 2.math.MaxFloat64 3.math.MaxUint32 //指针类型 与其他主要编程语言的差异 1.不支持指针运算 2.string是值类型,其默认的初始化值为空字符串,而不是nil
package type_test import ( "testing" ) type MyInt int64 // 声明一个int64 的别名MyInt func TestImplicit(t *testing.T) { var a int = 1 var b int64 b = int64(a) //显示转换 // b = a //Err 不能隐式转换 var c MyInt //c = b //Err 同类型的别名也不能隐式转换 严格 c = MyInt(b) t.Log(a, b, c) } func TestPoint(t *testing.T) { a :=1 aPtr := &a // aPtr = aPtr + 1 //Err 不支持运算 t.Log(a, aPtr) t.Logf(" %T %T", a, aPtr) } func TestString(t *testing.T) { var s string //string是值类型默认是空字符串 t.Log("*" + s +"*") t.Log(len(s)) if s == ""{ t.Log("字符串是空") } }
- 算术运算符
运算符 | 描述 | 示例 |
---|---|---|
+ | 相加 | A := 10 B := 10 ==> A + B 输出结果 20 |
– | 相减 | A – B 输出结果 0 |
* | 相乘 | A * B 输出结果 100 |
/ | 相除 | B / A 输出结果 1 |
% | 求余 | B % A 输出结果 0 |
++ | 自增 | A++ 输出结果 11 |
— | 自减 | A– 输出结果 9 |
Go语言没有前置的 ++, –;(++a) Err
-
比较运算符
运算符 描述 示例 == 检查两个值是否相等,如果相等返回True,否则返回False !> 检查两个值是否不相等,如果不相等返回True ,否则返回False > 检查左边值是否大于右边值,如果是返回True,否则返回False < 检查左边值是否小于右边值,如果是返回True 否则返回False >= 检查左边值是否大于等于右边值,如果是返回True 否则返回False <= 检查左边值是否小于等于右边值,如果是返回True 否则返回False -
用 == 比较数组
- 相同维数且含有相同个数元素的数组才可以比较
- 每个元素都相同才相等
- 逻辑运算符 ( && 、 || 、!)
-
位运算符 (&、 | 、^ 、<>)
位运算符 与其他主要编程语言的差异 &^ 按位清零 1 &^ 0 -- 1 1 &^ 1 -- 0 0 &^ 1 -- 0 0 &^ 0 -- 0
package operator_test import ( "fmt" "testing" ) func TestCompareArray(t *testing.T) { a := [...]int{1,2,3,4} b := [...]int{1,2,3,4} //c := [...]int{1,2,3,4,5} // t.Log(a == b) //t.Log(c) //t.Log( a == c) } /* 循环 Go 语言仅支持循环关键字 for for j :=7; j <=9; j++ */ func TestForLoop(t *testing.T) { for j := 0; j <= 10; j++ { t.Log("执行第" ,j , "次") } } /* while 条件循环 while (n < 5) */ func TestWhileLoop(t *testing.T){ n := 0 for n < 5 { n++ fmt.Println(n) } } /* while 条件循环 while (true) */ func TestForLoop(t *testing.T){ //n := 0 //for { // n++ // fmt.Print("死循环") //} }
if 条件
与其他主要编程语言差异
1.condition表达式结果必须为bool 布尔值
2.支持变量赋值
if var declaration; condition{
//code
}
switch 条件
1.条件表达式不限制为常量或者整数
2.单个case中,可以出现多个结果选项,使用逗号分隔
3.与C语言等规则相反,Go语言不需要用break 来明确退出一个case;
4.可以不设定switch之后的条件表达式,在这种情况下,整个switch结构与多个if else 的逻辑作用等同
switch os := runtime.GOOS;os{
case “xxx”:
default:
}
func TestSwitchMultiCase(t *testing.T) { for i :=0; i <5; i++ { switch i { case 0, 2: t.Log("Even") case 1,3: t.Log("Odd") default: t.Log("it is not 0-3") } } } func TestSwitchCaseCondition(t *testing.T) { for i :=0; i <5; i++ { switch { case i%2 == 0: t.Log("Even") case i%2 == 1: t.Log("Odd") default: t.Log("不会走这个分支") } } }
package slice_test import "testing" func TestSliceInit(t *testing.T) { var s0 []int t.Log(len(s0), cap(s0)) s0 = append(s0, 1) t.Log(len(s0), cap(s0)) //方式二 s1 := []int{1, 2, 3, 4} t.Log(len(s1), cap(s1)) //方式三 //[]type ,len,cap 其中len 个元素会被初始化为默认零值,未初始化元素不可以访问 s2 := make([]int, 3, 5) t.Log(len(s2), cap(s2)) s2 = append(s2, 1) t.Log(s2[0], s2[1],s2[2] ,s2[3]) } /** 切片共享存储结构 */ func TestSliceGrowing(t *testing.T) { s := []int{} for i := 0; i < 10; i++ { s = append(s, i) t.Log(len(s),cap(s)) } } func TestSliceShareMemory(t *testing.T) { year := []string{"Jan", "Feb", "Mar", "Apr", "May","Jun", "Jul","Aug","Sep","Oct","Nov","Dec"} Q2 := year[3:6] t.Log(Q2, len(Q2),cap(Q2)) summer := year[5 :8] t.Log(summer,len(summer), cap(summer)) summer[0] = "UnKnow" t.Log(Q2) t.Log(year) } /* 数组 vs 切片 1.容量是否可伸缩 2.是否可以进行比较 结论: 数组不可伸缩 ,可比较 切片可伸缩,不可比较 */
package string_test import ( "testing" "unsafe" ) /* 字符串 与其他主要编程语言的差异 1.string 是数据类型,不是引用或指针类型 2. string是只读 byte slice ,len 函数是它所包含的byte数 3.string的byte数组可以存放任何数据 */ func TestString(t *testing.T){ var s string t.Log(s) //初始化默认零值"" s = "hello" t.Log(len(s)) //s[1] = "3" //string是不可变byte slice s ="\347\216\213" //可以存储任何二进制数据 t.Log(s) s = "中China" t.Log(len(s)) // byte数 c :=[]rune(s) t.Log("rune size:",unsafe.Sizeof(c[0])) t.Logf("中 Unicode %x", c[0]) t.Logf("中 UTF %x",s) }
package map_and_factory_test import ( "testing" ) /* Map 与工厂模式 Map的value 可以是一个方法 与Go的 Dock type接口方式一起,可以方便的实现单一方法对象的工厂模式 */ func TestMapWithFunValue(t *testing.T) { m := map[int]func(op int)int{} m[1] = func(op int) int { return op } m[2] = func(op int) int { return op * op } m[3] = func(op int) int { return op * op * op } t.Log(m[1](1), m[2](2), m[3](2)) } /* 实现 Set Go 的内置集合中没有Set的实现 ,可以map[type]bool 1.元素的唯一性 2.基本操作 1)添加元素 2)判断元素是否存在 3)删除元素 4)元素个数 */ func TestMapForSet(t *testing.T) { mySet := map[int]bool{} mySet[1] = true n := 3 if mySet[n] { t.Logf("%d is existing", n) } else { t.Logf(" %d is not existing", n) } t.Log(len(mySet)) delete(mySet,1) t.Log(len(mySet)) n = 1 if mySet[n] { t.Logf("%d is existing", n) } else { t.Logf(" %d is not existing", n) } }
package string_test import ( "strconv" "strings" "testing" ) func TestStringFn(t *testing.T) { t.Log("test") s :="A, B, C" parts := strings.Split(s, ",") for _, part := range parts{ t.Log(part) } t.Log(strings.Join(parts, "-")) } func TestStringToNum(t *testing.T) { s :=strconv.Itoa(10) t.Log("str " + s) if i, err :=strconv.Atoi("10");err == nil { t.Log(10 + i) } }
package string_test import ( "testing" "unsafe" ) /* 字符串 与其他主要编程语言的差异 1.string 是数据类型,不是引用或指针类型 2. string是只读 byte slice ,len 函数是它所包含的byte数 3.string的byte数组可以存放任何数据 */ func TestString(t *testing.T){ var s string t.Log(s) //初始化默认零值"" s = "hello" t.Log(len(s)) //s[1] = "3" //string是不可变byte slice s = "\347\216\213"//可以存储任何二进制数据 t.Log(s) s = "中" t.Log(len(s)) // byte数 c :=[]rune(s) t.Log("rune size:",unsafe.Sizeof(c[0])) t.Logf("中 Unicode %x", c[0]) t.Logf("中 UTF %x",s) } /* strings 包 https://golang.org/pkg/strings/ strconv 包 https://golang.org/pkg/strconv/ */ func TestStringToRune(t *testing.T) { s := "中华人民共和国" for _, c := range s { t.Logf(" %[1]c %[1]d",c) } }