Golang入门第三天

  1. 获取命令行参数
  2. init函数
  3. 局部变量和全局变量
  4. 变量的内存和变量的地址
  5. 指针变量的使用
  6. new函数的使用
  7. 值传递
  8. 引用传递
  9. 随机数的使用
  10. 数组
  11. 切片
  12. map
  13. 结构体
  14. 可见性规则
package main

import (
	. "fmt"
	"math/rand"
	"os"
	"time"
)

// init函数,包被引用时,自动调用的函数,引用包优先当前包
func init() {
	println("main包的init函数")
}

// 获取命令行参数
func demo1() {
	list := os.Args
	for i := range list {
		Printf("list[%d] = %v\n", i, list[i])
	}
}

// 局部变量和全局变量
func demo2() {
	a := 1
	{
		a := 2
		println("内部 a = ", a)
	}
	println("外部 a = ", a)
}

// 变量的内存和变量的地址
func demo3() {
	// 内存1
	a := 1
	// 地址&a
	p := &a
	Printf("a = %v, p = %v\n", a, p)
}

// 指针变量的使用
// 不能操作没有合法指向的指针
func demo4(a *int) (result *int) {
	// 修改地址a中的值
	*a = 666
	result = a
	return
}

// new函数的使用
func demo5() {
	// p是*int
	p := new(int)
	Printf("这里是new函数的使用,p.type = %T, p = %v\n", p, p)
}

// 值传递
func demo6(a int) {
	println("这里是值传递,a = ", a)
}

// 引用传递
func demo7(p *int) {
	println("这里是引用传递,p = ", p)
}

// 随机数的使用
func demo8() {
	// 种子参数一样,生成随机数结果固定
	a := rand.Int()
	// 生成指定范围内的随机数
	b := rand.Intn(100)
	// 按时间生成随机数
	c := rand.Intn(int(time.Now().UnixNano()))
	Printf("生成的随机数为 a = %d,b = %d, c = %d", a, b, c)
}

// 数组和切片
func demo9() {
	// 全量初始化
	array := [5]int{1, 2, 3, 4, 5}
	// 部分初始化
	array1 := [5]int{1, 2}
	// 指定初始化
	array2 := [5]int{2: 2}
	// 二维数组
	array3 := [5][2]int{1: {2, 4}}
	Printf("这里是数组,array = %v,array1 = %v,array2 = %v, array3 = %v\n", array, array1, array2, array3)
	// 数组可以比较和赋值
	Printf("这里是数组赋值比较,array == array1 %v\n", array == array1)
	// 数组做函数参数是值拷贝
	func(arr [5]int) {
		Printf("这里是数组参数传递值拷贝,arr == array %v,&arr == &array %v\n", arr == array, &arr == &array)
	}(array)
	// 数组指针做函数参数
	func(p *[5]int) {
		Printf("这里是数组指针参数传递,p == &array %v, p = %v\n", p == &array, p)
	}(&array)
	// 冒泡排序
	array4 := func() (result [5]int) {
		for i := 0; i < 5; i++ {
			b := rand.Intn(100)
			result[i] = b
		}
		return
	}()
	array5 := func(arr [5]int) (result [5]int) {
		for i := 0; i < 5-1; i++ {
			for j := 0; j < 5-1-i; j++ {
				if arr[j] > arr[j+1] {
					arr[j], arr[j+1] = arr[j+1], arr[j]
				}
			}
		}
		return arr
	}(array4)
	Printf("这里是数组,array4 = %v,排序后,array5 = %v\n", array4, array5)
	// [...]int{} ...代表不确定长度,根据初始化元素数量推测长度
	array6 := [...]int{1}
	Printf("这里是数组,不定长数组array6 = %v,排序后,array6.type = %T\n", array6, array6)

	// 数组切片slice
	// 数组定义后就不可以更改长度,从而提供了数组切片,它通过内部指针和相关属性引用数组片段,以实现变长方案
	// 切片slice并不是真正的动态数组,而是一个引用类型,slice底层总是指向一个数组,声明也可以像数组一样,只是不需要长度
	// array[begin:end:cap],begin起始下标,end结束下标(不包含),cap容量=cap-begin,缺省为原数组长度
	array7 := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
	slice := array7[0:4:5]
	// 缺省cap为原数组长度
	slice2 := array7[5:8]
	// 从第5开始,截取到末尾,容量为数组长度-5
	slice3 := array7[5:]
	// 从0开始,截取到8,容量也为8
	slice4 := array7[:8]
	// 切片的底层都是指向一个数组
	slice5 := slice4[:9]
	Printf("这里是切片,slicer = %v,slicer.type = %T,slicer2 = %v,slicer2.type = %T\n", slice, slice, slice2, slice2)
	Printf("这里是切片,slicer3 = %v,slicer3.type = %T,slicer4 = %v,slicer4.type = %T\n", slice3, slice3, slice4, slice4)
	Printf("这里是切片,slicer5 = %v,slicer5.type = %T\n", slice5, slice5)
	// append,在切片的末尾进行追加
	var slice6 []int = append(slice5, -1, -2, -3)
	Printf("这里是切片,slicer5追加后: slicer6 = %v,slicer6.type = %T\n", slice6, slice6)
	// 切片追加后,如果超出cap,那么将以两倍形式扩容
	// 切片做函数参数,是引用传递,不是值拷贝
	func(s1 []int) {
		oldCap := cap(s1)
		for i := 0; i < 10; i++ {
			if cap(s1) > oldCap {
				Printf("这里是切片,cap(s1) = %v,oldCap = %v\n", cap(s1), oldCap)
				oldCap = cap(s1)
			}
			s1 = append(s1, -1)
		}
	}(array7[:1:1])
}

// map(映射,字典)一个无序的K-V结构
func demo10() {
	// map中的K是唯一的,且必须支持==和!=操作的类型,切片/函数以及包含切片的结构类型,不可作为K,因为存在引用语义,会编译错误
	var map1 map[string]string
	// map 只有 len, 没有cap
	Printf("这里是map,map1 = %v, map1.type = %T, len(map) = %v\n", map1, map1, len(map1))
	// map通过make来进行初始化
	map1 = make(map[string]string)
	// 可指定长度,不足时可自动扩容,扩容机理类似append
	map1 = make(map[string]string, 1)
	map1["a"] = "map-a"
	map1["b"] = "map-b"
	Printf("这里是map,初始化后 map1 = %v, map1.type = %T, len(map) = %v\n", map1, map1, len(map1))
	// 重复赋值即为修改内容
	map1["a"] = "map-a-a"
	Printf("这里是map,修改内容 map1 = %v, map1.type = %T, len(map) = %v\n", map1, map1, len(map1))
	// 删除内容
	delete(map1, "a")
	Printf("这里是map,删除内容 map1 = %v, map1.type = %T, len(map) = %v\n", map1, map1, len(map1))
	// 遍历map
	for k, v := range map1 {
		Printf("这里是map,遍历内容 map1[%v] = %v\n", k, v)
	}
	// 判断元素是否存在map
	key := "a"
	value, result := map1[key]
	if result {
		Printf("这里是map,判断元素Key存在: result = %v, map1[%v] = %v\n", result, key, value)
	} else {
		Printf("这里是map,判断元素Key存在: result = %v\n", result)
	}
	// map做函数参数是引用传递
	func(m1 map[string]string) {
		m1["a"] = "m1-a"
		Printf("这里是map,map做函数参数为引用传递: m1 = %v, map1 = %v\n", m1, map1)
	}(map1)

}

// 结构体
func demo11() {
	// 结构体可被比较与赋值,具有值传递与引用传递
	type Student struct {
		Id   int
		Name string
		Age  int
		Sex  byte
	}
	// 顺序初始化
	var s1 = Student{1, "radish", 20, 'm'}
	Printf("这里是结构体,顺序初始化: s1 = %v, s1.type = %T\n", s1, s1)
	// 指定成员初始化,未初始化赋值为0
	s2 := Student{Id: 1, Name: "radish"}
	Printf("这里是结构体,指定成员初始化: s2 = %v, s2.type = %T\n", s2, s2)
	// 结构体的指针变量初始化
	var p1 *Student
	p1 = &Student{1, "radish", 20, 'm'}
	Printf("这里是结构体,结构体指针变量顺序初始化: p1 = %v, p1.type = %T\n", p1, p1)
	p2 := &Student{Name: "redish"}
	Printf("这里是结构体,结构体指针变量指定成员初始化: p2 = %v, p2.type = %T\n", p2, p2)
	// 操作成员
	s1.Id = 2
	s1.Name = "radish40"
	Printf("这里是结构体,操作成员: s1 = %v, s1.type = %T\n", s1, s1)
	// 通过指针操作成员
	// p1.Id和(*p1).id完全等价,只能使用.运算符
	p1 = new(Student)
	p1.Id = 2
	p1.Name = "radish40"
	Printf("这里是结构体,通过指针操作成员: p1 = %v, p1.type = %T\n", p1, p1)
}

func main() {
	var (
		a = 10
		p = &a
	)
	demo1()
	demo2()
	demo3()
	demo4(p)
	demo5()
	demo6(a)
	demo7(p)
	demo8()
	demo9()
	demo10()
	demo11()
}

posted @ 2023-02-05 02:19  萝卜不会抛异常  阅读(17)  评论(0编辑  收藏  举报