目录
-
GOROOT:Go的根目录
-
GOPATH:用户工作区,源码必须放这里
-
系统PATH下增加$GOROOT/bin:可以直接执行的命令
-
src源码
-
pkg go install命令 归档文件 .a
-
bin 可执行文件
编译
- 直接执行
go run hello_world.go
- 编译
go build hello_world.go
应用程序入口
- package 必须是main(目录不强制)
- func 必须是main
- 文件名不强制main.go
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
退出
func main 不支持返回值
os.Exit 立即中止,返回状态
命令行参数
func main 不支持传入参数
os.Args获取命令行参数
func main() {
if len(os.Args) > 1{
fmt.Println("Hello ",os.Args[1]) //获取命令行参数
}
os.Exit(-1) //异常退出
}
测试程序
- 源码文件_test结尾,xxx_test.go
- 测试方法Test开头 func TestXX(t *testing.T)
first_test.go
package test
import "testing"
func TestFirst(t *testing.T){
t.Log("test");
}
变量
//全局
var c int
func TestFirst(t *testing.T){
//变量声明
var a int = 1
var b int = 1
//简写
var (
a int = 1
b int = 1
)
//类型推断
a := 1
b := 1
fmt.Println(a)
for i:=0; i<5; i++{
fmt.Println(b)
tmp := a
a = b
b = tmp + a
}
变量交换
a,b = b,a
常量
连续常量
//连续常量
const(
Mon = 1 + iota
Thus
Web
)
//一般常量
const(
GOOGLE = "go"
BAIDU = "bd"
)
//位运算常量
const(
READABLE = 1 << iota //1的二进制 1
WRITEABLE //左移一位 10
EXECABLE //左移一位 100
)
func TestConst(t *testing.T){
t.Log(Mon,Thus,Web)
t.Log(GOOGLE,BAIDU)
t.Log(READABLE,WRITEABLE,EXECABLE)
}
数据类型
bool
string
//标注位数可以忽略平台差别导致的问题
//int uint在32位机器是32位 64位机器是64位
int int8 int16 int32 int64
unit unit8 unit16 uint64 uintptr
byte //uint8的别名
rune //int32别名 unicode编码值
float32 float64
complex64 complex128
类型转换
- 不支持隐式转换(包括原类型和别名类型) type MyInt int64
类型预定义值
- math.MaxInt64
- math.MaxFloat64
- math.MaxUint64
指针类型
- 不支持指针运算
- string是值类型,默认值是空字符串
func TestType(t *testing.T){
var a int = 1
var b int64
b = int64(a) //显式转换
t.Log(b)
}
func TestPtr(t *testing.T){
a := 1
aPtr := &a
t.Log(aPtr) //指针地址 0xc00000a298
t.Logf("%T %T",a,aPtr) // %T格式化符号 (int *int)
}
默认值
- *int ------- nil
- int ------- 0
- float32 ------- 0
- bool ------- false
比较运算
- 数组比较条件(编译错误):
- 相同维
- 相同个数
- 每个元素都相等才是相等
循环
- 只支持for,不需要括号
//一般循环
func TestLoop(t *testing.T){
n := 0
for n <= 5{
t.Log(n)
n++
}
}
//无限循环
func TestRunLoop(t *testing.T){
n := 0
for{
n++
t.Log(n)
}
}
判断
- 不需要括号
- condition结果布尔
- 支持变量赋值
func TestCondition(t *testing.T){
// 变量表达式;条件
if v,err := someFun(2); err == nil{
t.Log("正常",v)
}else{
t.Log("错误",err)
}
}
func someFun(b int) (result int,err error){
err = nil
if b == 1 {
result = b
}else{
err = errors.New("Test Error")
}
return
}
数组
声明
- var a [3]int //声明并初始化为默认零值
- a[0] = 1
- b := [3]int{1, 2, 3} //声明同时初始化
- c := [2][2]int{{1, 2}, {3, 4}} //多维数组初始化
遍历
func TestTravelArray(t *testing.T) {
a := [...]int{1, 2, 3, 4, 5} //不指定元素个数
for idx/*索引*/, elem/*元素*/ := range a {
fmt.Println(idx, elem)
}
}
截取
- a[开始索引(包含), 结束索引(不包含)]
a[1:2] //2
切片
声明
- var s0 []int
- s0 = append(s0, 1)
- s := []int{}
- s1 := []int{1, 2, 3}
- s2 := make([]int, 2, 4)
/*[]type, len, cap
其中len个元素会被初始化为默认零值,未初始化元素不可以访问
*/
-数组 vs 切片:伸缩 比较
map
声明
- m := map[string]int{"one": 1, "two": 2, "three": 3}
- m1 := map[string]int{}
- m1["one"] = 1
- m2 := make(map[string]int, 10 /Initial Capacity/)
元素访问
//m["four"]返回两个值,存在的话第二个是bool的true
if v, ok := m["four"]; ok {
t.Log("four", v)
} else {
t.Log("Not existing")
}
遍历foreach
m := map[string]int{"one": 1, "two": 2, "three": 3}
for k, v := range m {
t.Log(k, v)
}
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](2), m[2](2), m[3](2)) //以2为输入参数
}
set的实现
基本定义
- 元素的唯⼀性
- 基本操作
-
- 添加元素
-
- 判断元素是否存在
-
- 删除元素
-
- 元素个数
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)
}
字符串
- string 是数据类型,不是引⽤或指针类型
- string 是只读的 byte slice, len 函数可以它所包含的 byte 数(其实就是类似字节数组)
- string 的 byte 数组可以存放任何数据(可见字符 不可见字符)
func TestString(t *testing.T) {
var s string
t.Log(s) //初始化为默认零值“”
s = "hello"
t.Log(len(s)) //长度 5
s[1] = '3' //string是不可变的byte slice,这样写 编译错误
s = "\xE4\xBA\xFF" //可以存储任何二进制数据
t.Log(s) //严
t.Log(len(s)) //长度 3
//byte & unicode区别
s = "中"
t.Log(len(s)) //是byte数
c := []rune(s) //能取出字符串里面的unicode(rune切片)
t.Log(len(c)) //长度1
// t.Log("rune size:", unsafe.Sizeof(c[0]))
t.Logf("中 unicode %x", c[0])
t.Logf("中 UTF8 %x", s)
}
func TestStringToRune(t *testing.T) {
s := "*"
for _, c := range s {
t.Logf("%[1]c %[1]d", c) //汉字 编码
}
}
- Unicode 是⼀种字符集(code point 相当于标准)
- UTF8 是 unicode 的存储实现 (转换为字节序列的规则)
字符 | 中 |
---|---|
Unicode | 0x4E2D |
UTF-8 | 0xE4B8AD |
string/[]byte | [0xE4,0xB8,0xAD] |
字符串操作函数
//用逗号分隔成切片
func TestStringFn(t *testing.T) {
s := "A,B,C"
parts := strings.Split(s, ",")
for _, part := range parts {
t.Log(part)
}
//字符串连接
t.Log(strings.Join(parts, "-"))
}
func TestConv(t *testing.T) {
//整数转字符串
s := strconv.Itoa(10)
t.Log("str" + s)
//字符串转整形
if i, err := strconv.Atoi("10"); err == nil {
t.Log(10 + i)
}
}
函数:一等公民
- 可以有多个返回值
- 所有参数都是值传递: slice, map, channel 会有传引⽤的错觉(其实也是传值,因为slice对应的数组,整个数据结构有指针指向同一数组)
- 函数可以作为变量的值
- 函数可以作为参数和返回值
- 多返回值
func returnMultiValues() (int, int) {
return rand.Intn(10), rand.Intn(20)
}
//调用时忽略一个返回值
a, _ := returnMultiValues()
- 装饰器模式(计时函数)
func timeSpent(inner func(op int) int) func(op int) int {
return func(n int) int {
start := time.Now()
ret := inner(n)
fmt.Println("time spent:", time.Since(start).Seconds())
return ret
}
}
func slowFun(op int) int {
time.Sleep(time.Second * 1)
return op
}
//调用
tsSF := timeSpent(slowFun)
t.Log(tsSF(10))
可变参数
//参数会转化成数组
func sum(ops ...int) int {
s := 0
for _, op := range ops {
s += op
}
return s
}
defer 延迟最后执行
- 类似 try .. finally,就上panic的异常中断也会继续执行
func TestDefer(t *testing.T) {
defer func() {
t.Log("Clear resources")
}()
t.Log("Started")
panic("Fatal error”) //defer仍会执⾏
}