go 语言入门02

1. 函数

  1. 基本类型和数组都是值传递, 可以通过指针来达到引用传递的目的
  2. 函数本是也是一种数据类型, 可以赋值给一个变量, 通过该变量可以实现对函数的调用
  3. 函数可以作为另一个函数的形参, 高阶函数
func b(fun func(int, int) int, ...){...}
  1. 自定义数据类型: type 自定义数据类型 原数据类型
type myInt int
type myFun func(..)(..)
  1. 返回值命名
sum, sub := cal(3, 2)

func cal(n1 int, n2 int)(sum int, sub int){
	sum = n1 + n2
	sub = n1 - n2
	return
}
  1. 使用 _ 忽略返回值
sum, _ := cal(3, 2)
  1. 可变长参数, 且只能放到形参列表最后
func sum(args... int)( sum int) {
	for i := 0; i < len(args); i++ {
		sum += args[i]
	}
	return
}

// args 是切片, 通过args[index]可以访问各参数    

2. init 函数

每个源文件都可以包函一个 init 函数, 该函数会在 main 函数之前执行

3. go源文件加载顺序

  1. 被引入文件的全局变量定义
  2. 被引入文件的init函数
  3. 当前文件的全局变量
  4. 当前文件的init 函数
  5. 当前文件的main 函数

4. 匿名函数

如果某个函数只希望执行一次, 那么可以使用匿名函数, 匿名函数也可以实现多次调用

使用方式:

  1. 在定义匿名函数时直接调用, 只能调用一次
	res := func (n1 int, n2 int) int{
		return n1 + n2
	}(1, 2)
	fmt.Println(res)    
  1. 赋给一个变量, 再通过这个变量来调用函数
	sum := func (n1 int, n2 int) int{
		return n1 + n2
	}

	fmt.Println(sum(2, 3))
	fmt.Println(sum(2, 4))
  1. 全局匿名函数, 变量首字母要大写

5. 闭包

一个函数与其相关引用环境组合而成的一个整体

简单而言,闭包与普通函数的区别就在于它有了自己的上下文环境;

其实 java 对象的方法就是一种闭包

func addUpper() func(int) int{
	n := 10
	return func(i int) int{
		n += i
		return n
	}
}

func main(){
	f := addUpper()
	fmt.Println(f(1)); //11
	fmt.Println(f(2)); //13
	fmt.Println(f(3)); //16
}

6. defer

函数执行完毕后, 及时释放资源

当执行到 defer 语句时, 暂时将其压入 defer 栈中; 当程序执行完毕, 再从 defer 栈中以先进后出的原则进行执行

当 defer 语句入栈时, 会将相关的值进行拷贝同时入栈

func test(){
	file := openfile(文件名)
	defer file.close
}

7. 函数参数传递

无论值传递还是引用传递, 其本质都是值的副本传递, 不同的是:

值传递时, 是将值进行拷贝然后传递(基本类型的 int系列, float 系列, bool, string, 数组, 结构体)

引用传递, 是将地址进行拷然后传递(指针, 切片, map, 管道, interface)

8. 字符串系统函数

  1. len(str) //输出 str 占用的字节数, 如: “北京” 的 len 为 6
  2. []rune(str) //将含有中文的字符串处理成切片
  3. n, err := strconv.Atoi("") //将字符串转成整数, 如果转换成功: err == nil
  4. str := strconv.Itoa(整数) //将整数转成字符串
  5. bytes := []byte(" ") //将字符串转成切片
  6. str := string([]byte{整数…}) //将byte切片转string
  7. str := strconv.FormatInt(10进制数, 进制数[2, 8, 16]) //将10进制数转其它进制数
  8. strings.Contains(“源串”, “模式串”) //源串中是否包含模式串
  9. strings.Count(“源串”, “模式串”) //源串中有几个模式串
  10. string.EqualFold("", “”) //不区分大小写比较两个字符串是否相同
  11. strings.Index(“源串”, “模式串”) //返回模式串在源串中第一次出现的下标; 没有的话返回 -1
  12. strings.LastIndex(“源串”, “模式串”) //返回模式串在源串中最后一次出现的下标; 没有的话返回 -1
  13. strings.Replace(“源串”, “aim”, “res”, n) //将源串中的"aim", 换成"res", n次; n为-1时表示全部换掉
  14. strings.Split(“源串”, “aim”) //将源串以"aim"拆分成字符串数组
  15. strings.ToLower(" “) // 转小写 ToUpper(” ") 转大写
  16. strings.TrimSpace(" ")//去掉两边的空格
  17. string.Trim(“源串”, “模式”) //去掉源串两边的模式串 TrimLeft() TrimRight()
  18. strings.HasPrefix(“源串”, “模式串”) //是否以指定的字符串开头
  19. strings.HasSuffix(“源串”, “模式串”) //是否以指定的字符串结尾

9. 时间

  1. 需要导入 time 包
  2. 获取当前时间: now := time.now()
  3. 获取年 year:=now.Year() 月 month := now.Month(); int(month) …
  4. 格式化时间
	1. fmt.Printf("%d-%d-%d %d:%d:%d", now.Year(), now.Month()....)
	2. str := Sprintf("%d-%d-%d %d:%d:%d", now.Year(), now.Month()....)
	3. now.Format("2006/01/02 15:04:05") //数字固定只能这样写
	4. now.Format("2006/01/02")  //数字固定只能这样写
	5. now.Format("15:04:05")  //数字固定只能这样写
  1. 时间常量
	1. 5 纳秒: 5*time.Namosecond
	2. 5 毫秒: 5*time.Millisecond
	....
  1. 休眠: time.Sleep(通过时间常来取得的时间)
  2. time 的 Unix 和 UnixNano 分别返回到目前的 秒数 和 纳秒数

10. 内置函数

  1. len() 用来求变量所点字节长度
  2. new() 主要给值类型分配内存, 返回的是指针
  3. make(), 主要给引用类型分配内存

11. 错误处理

  1. go 中没有 try-catch; 使用 defer, panic, recover 来处理错误
  2. 抛出一个 panic 的异常, 然后在 defer 中通过 recover 捕获这个异常, 然后正常处理
func testErr(){
	defer func(){
		err := recover()
		if err != nil{
			fmt.Println(err)
		}
	}()

	a, b := 1, 0
	c := a/b
	fmt.Println(c)
}
  1. 自定义错误
    1. errors.New(“错误说明”), 返回一个 error 类型的值, 表示一个错误
    2. panic 内置函数, 接收一个 interface{}类型的值, 可以接收 error 类型的变量, 输出错误信息并退出程序
func testCustomErr(){
	err := customErr("init.conf1")
	if  err != nil {
		panic(err)
	}
	fmt.Println("其它代码......")
}

func customErr(fileName string)(err error){
	if fileName == "init.conf" {
		fmt.Println("读取配置文件")
		return nil
	}else{
		return errors.New("不能读取配置文件")
	}
}

12. 数组

  1. 定义数组:
	1. var arr [3]int
	2. var arr [3]int = [3]int {1, 2, 3}
	3. var arr = [3]int {1, 2, 3}
	4. var arr = [...]int{1, 2, 3}
	5. var arr = [3]string{0:"tom", 1:"jack"}
  1. go的数组属于值类型, 默认情况下是值传递, 数组间不会相互影响; 如果想修改原数据中的值, 可以通过指针的方式来传递数组
  2. 数组遍历
    1. 普通 for 循环
    2. for-range
func testForRange(){

	arr := [...]string{"111", "222", "333"}
	for index, value := range arr {
		// 1. index 是数组下标
		// 2. value 是该下标的值
		// 3. range 是关键字
		// 4. arr 是数组变量名
		fmt.Println(index, value)
	}

}

13. 切片

  1. 切片是长度可以变化的数组

  2. 切片是数组的一个引用, 传递时遵守引用传递

  3. 定义: var 切片名 []类型; 如: var arr []int

  4. 切片内存结构

    1. 第一个元素所在的内存地址
    2. len
    3. cap
  5. 使用方式

    1. 定义一个切片, 然后让它引用一个已创建好的数组, 如:slice := arr[1:3], slice := arr[:]// 全取
func testSlice(){
	arr := [...]string{"111", "222", "333"}
	//包含下标为1,2两个元素
	slice := arr[1:3]
	fmt.Println("slice = ", slice)
	fmt.Println("sliece len = ", len(slice))
	fmt.Println("slice cap = ", cap(slice))
}
2. 通过 make 来创建
var 切片名 []type = make([]type, len, [cap])	
3. 通过直接定义并赋值
var slice []type = []type{}
  1. 切片遍历和数组一样
  2. 内置函数 append(slice, elems…type) 将元素追加到切片的尾部, 若 cap 不够用会分配一个新的基本数组, 返回新切片的引用
func testMakeSlice(){
	slice := make([]int, 2, 2)
	slice[0], slice[1] = 1, 2
	fmt.Println(&slice[0])
	
	slice = append(slice, 3)
	fmt.Println(&slice[0])
} 

//切片追加一个切片
slice = append(slice, slice...)
  1. string 和 slice
func testStringSlice(){

	str := "hello 世界"
	bytes := []byte(str)
	bytes[5] = '-'
	fmt.Println(str)
	fmt.Println(string(bytes))
	
	//处理含有中文的字符串
	bytes2 := []rune(str)
	fmt.Println(len(bytes2)) //8
	bytes2[6] = '中'
	bytes2[7] = '国'
	fmt.Println(string(bytes2))
}

14. map

  1. map 声明: var 变量名 map[key类型]value类型
  2. 声明是不会分配内存的, 初始化需要 make, 分配内存后才能赋值和使用
func testMap(){
	// 定义1
	var map1 map[string]string 
	map1 = make(map[string]string, 2)
	map1["111"] = "111"
	map1["222"] = "222"
	map1["333"] = "333"

	// 定义2
	var map2 = make(map[string]string, 2)
	map2["111"] = "111"
	map2["222"] = "222"
	map2["333"] = "333"

	// 定义3
	var map3 = map[string]string{
		"111":"1111",
	}
	map3["222"] = "222"

	fmt.Println(map1)
	fmt.Println(map2)
	fmt.Println(map3)
}
  1. map的遍历
func testMapForRange(){
	userMap := map[string]string{
		"01": "宋江",
		"02": "卢俊义",
		"03": "吴用",
	}

	for key, value := range userMap {
		fmt.Printf("key = %v\tvalue = %v\n", key, value)
	}

}
  1. map 的排序
	1. 先将 map 的 key 放入到切片中
	2. 对切片排序: sort.Ints(slice)
	3. 遍历切片, 然后按照 key 来输出 map 值
  1. map 是引用类型
  2. map 在容量达到最大后,继续添加元素, map会自动扩容

你可能感兴趣的:(go 语言入门02)