191. go学习2

从下往上看, 可以复制到vscode中通过编辑器查看, 其中model/account.go表示model目录下的account.go文件, model是模块名

stu.go

package main

import "fmt"

type Stud struct {
	Name  string
	Age   int
	Score int
}

func (stu *Stud) ShowInfo() {
	fmt.Printf("学生名=%v 年龄=%v 成绩=%v\n", stu.Name, stu.Age, stu.Score)
}

func (stu *Stud) SetScore(score int) {
	stu.Score = score
}

type Pupil struct {
	Stud // 嵌套了 stud的匿名结构体
}

func (this *Pupil) testing() {
	fmt.Println(this.Name, "正在考试中...")
}

type Graduate struct {
	Stud // 嵌套了 stud的匿名结构体
}

func (this *Graduate) testing() {
	fmt.Println(this.Name, "正在考试中...")
}

model/account.go

package model

import "fmt"

type account struct {
	accountNo string
	pwd       string
	balance   float64
}

func NewAccount(aNo string, pwd string, balance float64) *account {
	err := fmt.Errorf("账号长度需要在6-10之间")
	if 6 > len(aNo) || len(aNo) > 11 {
		panic(err)
	}
	if len(pwd) != 6 {
		fmt.Println("密码长度部队")
		return nil
	}
	if balance < 20 {
		fmt.Println("余额不能小于20")
		return nil
	}
	return &account{
		accountNo: "1234",
		pwd:       pwd,
		balance:   balance,
	}
}

func (this *account) SetAccount(aNo string) {
	if 6 > len(aNo) || len(aNo) > 11 {
		panic("账号长度需要在6-10之间")
	}
	this.accountNo = aNo
}

func (this *account) Deposite(balance float64, pwd string) {
	if balance < 0 {
		fmt.Println("存款不能小于0")
		return
	}
	if pwd != this.pwd {
		fmt.Println("密码错误")
		return
	}
	this.balance += balance
	fmt.Println("存款成功")
}

func (this *account) WithDraw(balance float64, pwd string) {
	if balance < 0 {
		fmt.Println("余额不能小于20")
		return
	}
	if pwd != this.pwd {
		fmt.Println("密码错误")
		return
	}
	if balance > this.balance {
		fmt.Println("余额不足")
		return
	}
	this.balance -= balance
	fmt.Println("取款成功")
}

func (this *account) Query(pwd string) {
	if pwd != this.pwd {
		fmt.Println("密码错误")
		return
	}
	fmt.Printf("账户余额=%f\n", this.balance)
}

main.go

package main

import (
	"day01/example1/model"
	"encoding/json"
	"fmt"
	"math/rand"
	"sort"
	"time"
)

func test1() {
	hen1 := 3.0
	hen2 := 5.0
	hen3 := 1.0
	hen4 := 3.4
	hen5 := 2.0
	hen6 := 50.0

	total := hen1 + hen2 + hen3 + hen4 + hen5 + hen6
	fmt.Printf("avg = %.2f\n", total/6)

	/*
		1) 数组的地址可以通过数组名来获取 &intArr
		2) 数组的第一个元素的地址,就是数组的首地址
		3) 数组的各个元素的地址间隔是依据数组的类型决定,比如 int64 -> 8 int32->4...
		4) 数组的地址是连续的
	*/
	var hen_ [7]float32
	hen_[0] = 3.0
	hen_[1] = 5.0
	hen_[2] = 1.0
	hen_[3] = 3.4
	hen_[4] = 2.0
	hen_[5] = 50.0
	hen_[6] = 30.0
	var total1 float32
	for i := 0; i < len(hen_); i++ {
		total1 += hen_[i]
	}
	fmt.Printf("avg = %.2f\n", total1/6)
	fmt.Printf("hen_的地址=%p hen_[0] 地址=%p hen_[1] 地址=%p hen_[2] 地址=%p\n",
		&hen_, &hen_[0], &hen_[1], &hen_[2])

	// var score [5]float32
	// for i := 0; i < len(score); i++ {
	// 	fmt.Printf("请输入第%d个元素的值\n", i)
	// 	fmt.Scanln(&score[i])
	// }

	// for i := 0; i < len(score); i++ {
	// 	fmt.Printf("score[%d]=%v\n", i, score[i])
	// }

	// 数组初始化方式
	var numArr01 [3]int = [3]int{1, 2, 3}
	fmt.Println("numarr01=", numArr01)

	var numArr02 = [3]int{1, 2, 3}
	fmt.Println("numArr02=", numArr02)

	var numArr03 = [...]int{1, 2, 3}
	fmt.Println("numArr03=", numArr03)

	var numArr04 = [...]int{1: 800, 2: 900, 3: 999}
	fmt.Println("numArr04=", numArr04)

	// 类型推断
	strArr05 := [...]string{0: "mary", 1: "tom", 2: "jack"}
	fmt.Println("strArr05=", strArr05)

	// 数组遍历for...range...
	for index, value := range strArr05 {
		fmt.Printf("i=%v v=%v\n", index, value)
		fmt.Printf("heroes is strArr05[%d]=%v\n", index, value)
	}

	for _, v := range strArr05 {
		fmt.Printf("元素的值=%v\n", v)
	}
}

func test2() {
	// 方式1
	arr := []float32{3.0, 5.0, 1.0, 3.4, 2.0, 50.0}
	slice := arr[1:3]
	fmt.Println(arr)
	fmt.Println("slice 的元素是:", slice)
	fmt.Println("slice 的长度是:", len(slice))
	fmt.Println("slice 的容量是:", cap(slice))

	//方式2
	var slice2 []float32 = make([]float32, 5, 10)
	slice2[1] = 10
	slice2[3] = 20
	slice2[0] = 20
	slice2[2] = 20
	slice2[4] = 20
	// 虽然设置容量为10, 但是超出还是会自动增长
	slice2 = append(slice2, []float32{1, 3, 4, 5, 10, 99}...)

	fmt.Println(slice2)
	fmt.Printf("slice2 的size=%d\n", len(slice2))
	fmt.Printf("slice2 的cap=%d\n", cap(slice2))

	// 元素地址还是连续的, 但是slice2不再是第一个元素的地址
	/*
		切片底层是这样的, 指向的ptr的地址
			type slice struct {
				ptr *[2]int
				len int
				cap int
				}
	*/
	fmt.Printf("slice2的地址=%p slice2[0] 地址=%p slice2[1] 地址=%p slice2[2] 地址=%p\n",
		&slice2, &slice2[0], &slice2[1], &slice2[2])

	// 方式3
	var strSlice []string = []string{"tome", "jerry", "mimi"}
	fmt.Println("strSlice 的元素是:", strSlice)
	fmt.Println("strSlice 的长度是:", len(strSlice))
	fmt.Println("strSlice 的容量是:", cap(strSlice))

	// 切片遍历方式和数组相同for   || for-range
	for i := 0; i < len(strSlice); i++ {
		fmt.Printf("strSlice[%d]=%v\n", i, strSlice[i])
	}
	for i, v := range strSlice {
		fmt.Printf("strSlice[%d]=%v\n", i, v)
	}
}

func test3() {
	/*
		1) 切片初始化时 var slice = arr[startIndex:endIndex]
		说明:从 arr 数组下标为 startIndex,取到 下标为 endIndex 的元素(不含 arr[endIndex])。
		2) 切片初始化时,仍然不能越界。范围在 [0-len(arr)] 之间,但是可以动态增长.
		尚硅谷 Go 语言课程
		更多 Java –大数据 –前端 –python 人工智能 -区块链资料下载,可访问百度:尚硅谷官网 第 207页
		var slice = arr[0:end] 可以简写 var slice = arr[:end]
		var slice = arr[start:len(arr)] 可以简写: var slice = arr[start:]
		var slice = arr[0:len(arr)] 可以简写: var slice = arr[:]
		3) cap 是一个内置函数,用于统计切片的容量,即最大可以存放多少个元素。
		4) 切片定义完后,还不能使用,因为本身是一个空的,需要让其引用到一个数组,或者 make 一
		个空间供切片来使用

	*/

	arr := [...]int{10, 20, 30, 40, 50}
	slice := arr[1:4]
	slice2 := arr[1:2]
	slice2[0] = 100     // 切片slice和slice2指向的是同一个地址, 因此slice2[0]=100,会改变slice的值
	fmt.Println(slice)  // [100 30 40]
	fmt.Println(slice2) // [100]

	slice = append(slice, -2) // 加了一个-2, 但是被slice2覆盖掉了
	for i := 0; i < len(slice); i++ {
		if i < len(slice2) {
			fmt.Printf("slice %p, slice2 %p\n", &slice[i], &slice2[i])
		}
	}
	fmt.Println("11111111111111")
	slice2 = append(slice2, -1)
	for i := 0; i < len(slice); i++ {
		if i < len(slice2) {
			fmt.Printf("slice %p, slice2 %p\n", &slice[i], &slice2[i])
		}
	}
	fmt.Println("22222222222222")

	slice2 = append(slice2, -1)
	for i := 0; i < len(slice); i++ {
		if i < len(slice2) {
			fmt.Printf("slice %p, slice2 %p\n", &slice[i], &slice2[i])
		}
	}
	fmt.Println("22222222222222")
	slice2 = append(slice2, -1)
	for i := 0; i < len(slice); i++ {
		if i < len(slice2) {
			fmt.Printf("slice %p, slice2 %p\n", &slice[i], &slice2[i])
		}
	}
	// 会发现在这个位置之前slice和slice2使用的还是每个元素还是同一个地址, 但是当slice2长度大于slice
	// 之后地址变了slice2被一个数组替换了
	fmt.Println("33333333333333333")
	slice2 = append(slice2, -1)
	for i := 0; i < len(slice2); i++ {
		if i < len(slice) {
			fmt.Printf("slice %p, slice2 %p\n", &slice[i], &slice2[i])
		}
	}
	fmt.Println("4444444444444")
	slice2 = append(slice2, -1)

	for i := 0; i < len(slice2); i++ {
		if i < len(slice) {
			fmt.Printf("slice %p, slice2 %p\n", &slice[i], &slice2[i])
		}
	}

	// 使用切片的时候需要小心
	slice[1] = -88
	slice2[0] = -99     // 切片slice和slice2指向的是同一个地址, 因此slice2[0]=100,会改变slice的值
	fmt.Println(slice)  // [100 -1 -1 -2], 有趣的事情发生了,slice的元素被slice2覆盖掉了
	fmt.Println(slice2) // [-99 -1 -1 -1 -1 -1]

	/*
		切片 append 操作的底层原理分析:
		切片 append 操作的本质就是对数组扩容
		go 底层会创建一下新的数组 newArr(安装扩容后大小)
		将 slice 原来包含的元素拷贝到新的数组 newArr
		slice 重新引用到 newArr
		注意 newArr 是在底层来维护的,程序员不可见.
	*/

	var slice3 []int = []int{1, 2, 3, 4}
	var slice5 = make([]int, 10) // 把10改成1, 会发生什么? slice5=[1]
	copy(slice5, slice3)
	fmt.Println("slice3=", slice3)
	fmt.Println("slice5=", slice5)
}

func test4(arr *[]int) {
	for i := 0; i < len(*arr)-1; i++ {
		for j := 0; j < len(*arr)-i-1; j++ {
			if (*arr)[j] > (*arr)[j+1] {
				(*arr)[j], (*arr)[j+1] = (*arr)[j+1], (*arr)[j]
			}
		}
	}
}

func test5() {
	var arr2 [2][3]int //以这个为例来分析arr2在内存的布局!arr2[1][1]=10
	fmt.Println(arr2)
	fmt.Printf("arr2[0]的地址%p\n", &arr2[0])
	fmt.Printf("arr2[1]的地址%p\n", &arr2[1])
	fmt.Printf("arr2[0][0]的地址%p\n", &arr2[0][0])
	fmt.Printf("arr2[1][0]的地址%p\n", &arr2[1][0])
}

func test6() {
	var a map[string]string
	//
	a = make(map[string]string, 1)
	a["no1"] = "松江"
	a["no2"] = "无用"
	a["no3"] = "武松"
	a["no4"] = "大浪"
	fmt.Println(a, "a的长度=", len(a))

	b := make(map[string]string, 1)
	b["no1"] = "松江"
	b["no2"] = "无用"
	b["no3"] = "武松"
	b["no4"] = "大浪"
	fmt.Println(b, "b的长度=", len(b))

	c := map[string]string{
		"hear1": "松江",
		"hear2": "武松",
		"hear3": "扈三娘",
	}
	fmt.Println(c, "c的长度=", len(c))

	// 复杂数组, 感觉不好用
	var stu map[string]map[string]string
	stu = make(map[string]map[string]string)
	stu["stu1"] = make(map[string]string)
	stu["stu1"]["name"] = "alex"
	stu["stu1"]["age"] = "18"

	stu["stu2"] = make(map[string]string)
	stu["stu2"]["name"] = "tom"
	stu["stu2"]["age"] = "20"

	stu["stu3"] = make(map[string]string)
	stu["stu3"]["name"] = "lisa"
	stu["stu3"]["age"] = "44"
	fmt.Println(stu)
	fmt.Println(stu["stu1"])
	fmt.Println(stu["stu2"]["age"])

	// map["key"] = value //如果 key 还没有,就是增加,如果 key 存在就是修改
	delete(stu, "stu1")
	fmt.Println(stu)
	// 如果我们要删除 map 的所有 key ,没有一个专门的方法一次删除,可以遍历一下 key, 逐个删除
	// 或者 map = make(...),make 一个新的,让原来的成为垃圾,被 gc 回收

	// map 判断key存不存在
	val, ok := stu["stu11"]
	if ok { // 如果存在ok=True, 否则=false
		fmt.Println(val)
	} else {
		fmt.Println("key不存在")
	}

	// 遍历map
	cities := make(map[string]string)
	cities["no1"] = "天津"
	cities["no2"] = "北京"
	cities["no3"] = "上海"

	for k, v := range cities {
		fmt.Printf("key=%s val=%s\n", k, v)
	}
	// 复杂字典遍历
	for k, v := range stu {
		for k2, v2 := range v {
			fmt.Printf("学生: %v, %v=%v\n", k, k2, v2)
		}
	}

}
func test7() {
	var stu []map[string]string
	stu = make([]map[string]string, 2)
	if stu[0] == nil {
		stu[0] = make(map[string]string)
		stu[0]["name"] = "alex"
		stu[0]["age"] = "18"
	}

	if stu[1] == nil {
		stu[1] = make(map[string]string)
		stu[1]["name"] = "tom"
		stu[1]["age"] = "20"
	}

	// 因为make了两个长度, 这个会报错
	// if stu[2] == nil {
	// 	stu[2] = make(map[string]string)
	// 	stu[2]["name"] = "lisa"
	// 	stu[2]["age"] = "44"
	// }

	// 1.定于i一个对象, append进去
	newStu := map[string]string{
		"name": "alex",
		"age":  "22",
	}
	stu = append(stu, newStu)
	fmt.Println(stu)

}

func changeMap(map1 map[int]int) {
	map1[1] = -99
}

type Stu struct {
	name string
	age  int
	city string
}

func test8() {
	map1 := make(map[int]int, 10)
	map1[10] = 100
	map1[1] = 13
	map1[4] = 56
	map1[8] = 90

	fmt.Println(map1)

	var keys []int
	for k, _ := range map1 {
		keys = append(keys, k)
	}
	sort.Ints(keys) // 字典无序, 如果要排序, 需要先对key排序, 之后按照key取值
	fmt.Println(keys)
	for _, k := range keys {
		fmt.Printf("%v=%v\n", k, map1[k])
	}
	/*
		1.map 是引用类型,遵守引用类型传递的机制,在一个函数接收 map,修改后,会直接修改原来的 map
		2.map 的容量达到后,再想 map 增加元素,会自动扩容,并不会发生 panic,也就是说 map 能动
		态的增长 键值对(key-value)
		3.map 的 value 也经常使用 struct 类型,更适合管理复杂的数据(比前面 value 是一个 map 更好),
	*/
	changeMap(map1) // map是引用类型, 传递过去如果被函数修改,会改变里面的值
	fmt.Println(map1)

	students := make(map[string]Stu, 10)
	stu1 := Stu{"tom", 18, "北京"}
	stu2 := Stu{"alex", 18, "上海"}
	stu3 := Stu{"mage", 18, "东京"}
	students["no1"] = stu1
	students["no2"] = stu2
	students["no3"] = stu3
	fmt.Println(students)

	for k, v := range students {
		fmt.Printf("学生编号是%v\n", k)
		fmt.Printf("学生姓名是%v\n", v.name)
		fmt.Printf("学生年龄是%v\n", v.age)
		fmt.Printf("学生城市是%v\n", v.city)
	}
}

func test9() {
	var stu map[string]map[string]string
	stu = make(map[string]map[string]string, 1) // 会自动扩容, 在添加key时
	_, ok := stu["stu1"]                        // 不存在ok返回false, 存在返回true
	if !ok {
		stu["stu1"] = make(map[string]string)
		stu["stu1"]["nickname"] = "alex"
		stu["stu1"]["pwd"] = "123"

		stu["stu2"] = make(map[string]string)
		stu["stu2"]["nickname"] = "mage"
		stu["stu2"]["pwd"] = "999"
	} else {
		stu["stu1"]["pwd"] = "88888"
	}
	stu["stu1"]["pwd"] = "88888"
	fmt.Println(stu)
}

type Cat struct {
	Name  string
	Age   int
	Color string
	Hobby string
}

type Person struct {
	// 结构体可以放很多类型
	Name   string
	Age    int
	Scores [5]float32
	prt    *int
	slice  []int
	map1   map[string]string
}

func test10() {
	var cat1 Cat
	cat1.Name = "小明"
	cat1.Age = 3
	cat1.Color = "黄色"
	cat1.Hobby = "打篮球"

	var cat2 Cat
	cat2.Name = "小花"
	cat2.Age = 100
	cat2.Color = "紫色"
	cat2.Hobby = "睡觉"

	fmt.Println(cat1)
	fmt.Println(cat2)
	fmt.Println(cat1.Name, cat1.Age, cat1.Color, cat1.Hobby)

	var p1 Person
	fmt.Println(p1)
	if p1.prt == nil {
		fmt.Println("ok1")
	}
	if p1.slice == nil {
		fmt.Println("ok2")
	}
	if p1.map1 == nil {
		fmt.Println("ok3")
	}

	p1.slice = make([]int, 10)
	p1.slice[0] = 66

	p1.map1 = make(map[string]string)
	p1.map1["name"] = "alex"

	fmt.Println(p1)

	type Monster struct {
		Name string
		Age  int
	}

	// 初始化对象的几种方式
	var m1 Monster
	m1.Name = "李欣"
	m1.Age = 10

	m2 := Monster{
		Name: "周瑜",
		Age:  99,
	}

	var m3 Monster = Monster{
		Name: "李白",
		Age:  9911,
	}

	var m4 *Monster = &Monster{
		Name: "白起",
		Age:  199,
	}

	(*m4).Name = "嬴政"
	(*m4).Age = 9999

	m4.Name = "女娲"
	m4.Age = 10000000

	var m5 *Monster = new(Monster)
	(*m5).Name = "韩信"
	(*m5).Age = 233

	// go解释器自动转化等价于(*m5)
	m5.Name = "诸葛亮"
	m5.Age = 1232

	fmt.Println("m1=", m1)
	fmt.Println("m2=", m2)
	fmt.Println("m3=", m3)
	fmt.Println("m4=", *m4)
	fmt.Println("m5=", *m5)
}

func test11() {
	type Person struct {
		Name string
		Age  int
	}

	var p1 Person
	p1.Age = 10
	p1.Name = "小明"
	var p2 *Person = &p1

	fmt.Println((*p2).Age)
	fmt.Println(p2.Age)

	p2.Name = "tom~"
	fmt.Printf("p2.Name=%v p1.Name=%v\n", p2.Name, p1.Name)
	fmt.Printf("p2.Name=%v p1.Name=%v\n", (*p2).Name, p1.Name)

	fmt.Printf("p1的地址%p\n", &p1)
	fmt.Printf("p2的地址%p p2的值得地址%p\n", &p2, &(*p2))

	//&(*p2) 的地址== &p1
	// 所以p2其实指向的是一个地址, 而这个地址又指向了另一个地址
}

type Point struct {
	x int
	y int
}
type Rect struct {
	leftUp, rightDown Point
}

type Rect2 struct {
	leftUp, rightDown *Point
}

func test12() {
	// 结构体的所有字段在内存中是连续
	r1 := Rect{Point{x: 1, y: 2}, Point{x: 2, y: 4}}
	// 下面四个地址时连续的
	fmt.Printf("%p %p %p %p\n", &r1.leftUp.x, &r1.leftUp.y, &r1.rightDown.x, &r1.rightDown.y)

	r2 := Rect2{&Point{x: 1, y: 2}, &Point{x: 3, y: 4}}
	// r2有两个指针时连续分布, 但是他们指向的地址不一定连续分布
	fmt.Printf("%p %p\n", &r2.leftUp, &r2.rightDown)
	// 指向的地址, 分配不连续
	fmt.Printf("%p %p\n", r2.leftUp, r2.rightDown)
	fmt.Printf("%p %p\n", &(*(r2.leftUp)), &(*(r2.rightDown)))

}

type A struct {
	Num int
}

type B struct {
	Num int
}

type Student struct {
	Name string
	Age  int
}

type Stu2 Student // 类似于别名

func test13() {
	// 结构体类型转换
	var a A
	var b B
	a = A(b) // 可以转换但是, 要求结构体字段类型一直
	fmt.Println(a, b)

	var stu1 Student
	stu1.Name = "alex"
	stu1.Age = 12
	var stu2 Stu2
	// stu2 = stu1
	stu2 = Stu2(stu1)
	fmt.Println(stu1, stu2)
}

type Monster2 struct {
	Name  string `json:"name"`
	Age   int    `json:"age"`
	Skill string `json:"skill"`
}

func test14() {
	// 结构体tag标签, 序列化
	m1 := Monster2{Name: "alex", Age: 12, Skill: "大豆"}
	jsonStr, err := json.Marshal(m1)
	if err != nil {
		fmt.Println("json dumps failed", err)
		return
	}
	fmt.Println(string(jsonStr))
}

type A1 struct {
	Num int
}

func (this A1) test() {
	fmt.Println(this.Num)
}

type Person1 struct {
	Name string
}

func (this Person1) test() {
	fmt.Println("test() name=", this.Name)
}

func (this *Person1) test1() {
	fmt.Println("test2() name=", this.Name)
	this.Name = "change name"
}

// func (this *Person1) String() string {
// 	return this.Name
// }

func test15() {
	// 结构体方法定义
	var p1 Person1 = Person1{Name: "mage"}
	p1.test() // 方法(函数的另一种形式, 只不过这个函数必须通过对象来调用)
	/*
		1) 在通过一个变量去调用方法时,其调用机制和函数一样
		2) 不一样的地方时,变量调用方法时,该变量本身也会作为一个参数传递到方法(如果变量是值类
		型,则进行值拷贝,如果变量是引用类型,则进行地质拷贝)

		方法的声明(定义)
		func (recevier type) methodName(参数列表) (返回值列表){
		方法体
		return 返回值
		尚硅谷 Go 语言课程
		更多 Java –大数据 –前端 –python 人工智能 -区块链资料下载,可访问百度:尚硅谷官网 第 258页
		}
		1) 参数列表:表示方法输入
		2) recevier type : 表示这个方法和 type 这个类型进行绑定,或者说该方法作用于 type 类型
		3) receiver type : type 可以是结构体,也可以其它的自定义类型
		4) receiver : 就是 type 类型的一个变量(实例),比如 :Person 结构体 的一个变量(实例)
		5) 返回值列表:表示返回的值,可以多个
		6) 方法主体:表示为了实现某一功能代码块
		7) return 语句不是必须的。
	*/
	// 默认结构体为值传递, 可以修改为引用传递
	p2 := &Person1{Name: "hello"}
	p2.test1()
	fmt.Println(p2.Name)
	fmt.Println(p2) // 可以通过String方法控制, 打印p2对象的时的返回
}

type MethodUtils struct {
}

func (this MethodUtils) zhunzhi(a [][]int) {
	m, n := len(a), len(a[0])
	for i := 0; i < m; i++ {
		for j := i + 1; j < n; j++ {
			a[i][j], a[j][i] = a[j][i], a[i][j]
		}
	}
	fmt.Print(a)
}

func test16() {
	// 转置
	a := [][]int{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}
	m1 := MethodUtils{}
	m1.zhunzhi(a)
}

func (this Person1) test2() {
	fmt.Println(this, "test2")
	this.Name = "jack"
	fmt.Println("test02() = ", this.Name)
}

func (this *Person1) test3() {
	fmt.Println(this, "test3")
	this.Name = "mary"
	fmt.Println("test03() = ", this.Name)
}
func test17() {
	//方法和函数区别
	/*
			1) 调用方式不一样
			函数的调用方式: 函数名(实参列表)
			方法的调用方式: 变量.方法名(实参列表)
			2) 对于普通函数,接收者为值类型时,不能将指针类型的数据直接传递,反之亦然
			3) 对于方法(如 struct 的方法),接收者为值类型时,可以直接用指针类型的变量调用方法,反
		过来同样也可以
	*/
	p := Person1{Name: "init"}
	p.test2()
	fmt.Println("p.name=,", p.Name)
	// {init} test2   从打印结果上来看, 传递的时值拷贝
	// test02() =  jack
	// p.name=, init

	(&p).test2() // 形式上传入的时地址, 实际上仍然时值拷贝
	fmt.Println("p.name=,", p.Name)
	// 	{init} test2  从打印结果上来看. 就算你是用&p,传递的时还是值拷贝
	// test02() =  jack
	// p.name=, init

	(&p).test3()
	fmt.Println("p.name=,", p.Name)
	// &{init} test3  从打印结果上来看. 传递时时地址拷贝看见(&你就知道这是个地址)
	// test03() =  mary
	// p.name=, mary

	p.test3() // == (&p).test3(), 形式上时传入值类型, 本质仍然时地址拷贝
	// &{mary} test3  从打印结果上来看,即使你使用了值,传递时时地址拷贝看见(&你就知道这是个地址)
	// test03() =  mary
	// 以上操作都是go内部帮我们做的, 简化我们的操作
}

func test18() {
	// 练习封装性
	ac := model.NewAccount("123456", "666666", 100.0)
	ac.SetAccount("9999999")  // 修改账户
	ac.Deposite(-1, "666666") // 存
	ac.WithDraw(99, "666666") // 取
	ac.Query("666666")        // 插叙余额
	fmt.Println(ac)
}

func test19() {
	// 练习继承性
	pupil := Pupil{}
	pupil.Stud.Name = "tome~"
	pupil.Stud.Age = 8
	pupil.testing()
	pupil.Stud.SetScore(70)
	pupil.Stud.ShowInfo()

	graduate := &Graduate{}
	graduate.Stud.Name = "mary~"
	graduate.Stud.Age = 28
	graduate.testing()
	graduate.Stud.SetScore(90)
	graduate.Stud.ShowInfo()
}

func sum(n1, n2 float32) float32 {
	return 0
}

type E struct {
	Monster2
	int
	a int
}

func test20() {
	var e E
	e.Name = "白骨精"
	e.Age = 12
	e.int = 10
	e.a = 99
	fmt.Println(e)
}

type USB interface {
	Start()
	Stop()
}

type Phone struct {
}

func (this Phone) Start() {
	fmt.Println("手机开机了....")
}

func (this Phone) Stop() {
	fmt.Println("手机关机了....")
}

type Camera struct {
}

func (this Camera) Start() {
	fmt.Println("相机开机了....")
}

func (this Camera) Stop() {
	fmt.Println("相机关机了....")
}

type Computer struct {
}

func (this Computer) Working(usb USB) {
	usb.Start()
	usb.Stop()
}

type AInterface interface {
	Say()
	Hello()
}

type Baby struct {
	Name string
}

func (this Baby) Say() {
	fmt.Println("baby say()")
}
func (this Baby) Hello() {
	fmt.Println("baby say()")
}

type integer int

func (this integer) Say() {
	fmt.Println("baby say()", this)
}

func test21() {
	// 接口介绍, 一个结构体实现了某个接口的所有方法既就是现了接口
	computer := Computer{}
	phone := Phone{}
	Camera := Camera{}

	computer.Working(phone)
	computer.Working(Camera)

	/*
		1) 接口本身不能创建实例,但是可以指向一个实现了该接口的自定义类型的变量(实例)
		2) 接口中所有的方法都没有方法体,即都是没有实现的方法。
		3) 在 Golang 中,一个自定义类型需要将某个接口的所有方法都实现,我们说这个自定义类型实现了该接口。
		4) 一个自定义类型只有实现了某个接口,才能将该自定义类型的实例(变量)赋给接口类型
		5) 只要是自定义数据类型,就可以实现接口,不仅仅是结构体类型。
		6) 一个自定义类型可以实现多个接口
		7) Golang 接口中不能有任何变量
		8)一个接口(比如 A 接口)可以继承多个别的接口(比如 B,C 接口),这时如果要实现 A 接口,也必须将 B,C 接口的方法也全部实现。
		9) interface 类型默认是一个指针(引用类型),如果没有对 interface 初始化就使用,那么会输出 nil
		10) 空接口 interface{} 没有任何方法,所以所有类型都实现了空接口, 即我们可以把任何一个变量 赋给空接口。
	*/
	var baby Baby
	var a AInterface = baby
	a.Say()

	var i integer = 10
	// var i2 AInterface = i // 因为integer未实现AInterface的所有接口,所以不能赋值给接口类型
	i.Say()
}

type BInterface interface {
	Test01()
	Test02()
	Say()
}

type App struct{}

func (this App) Say() {
	fmt.Println("say hi")
}
func (this App) Hello() {
	fmt.Println("say hello")
}

func (this App) Test01() {
	fmt.Println("say Test01")
}
func (this App) Test02() {
	fmt.Println("say Test02")
}

type CInterface interface {
	AInterface
	BInterface
}

func test22() {
	// 多接口实现
	app := App{}
	var a AInterface = app
	var b BInterface = app
	fmt.Println(a, b, "ok")
}

type Hero struct {
	Name string
	Age  int
}

type HeroList []Hero

func (this HeroList) Len() int {
	return len(this)
}

// 实现sort接口的Less方法
func (this HeroList) Less(i, j int) bool {
	return this[i].Age < this[j].Age
}

func (this HeroList) Swap(i, j int) {
	this[i], this[j] = this[j], this[i]
}

func test23() {
	// 系统sort.Sort接口包含几个方法,通过实现Less, 和Swap方法即可实现通过其排序
	rand.Seed(time.Now().UnixMilli())
	var heros HeroList
	for i := 0; i < 10; i++ {
		h1 := Hero{
			Name: fmt.Sprintf("八戒%d", i),
			Age:  rand.Intn(100),
		}
		heros = append(heros, h1)
	}
	fmt.Println("排序前")
	for _, val := range heros {
		fmt.Println(val)
	}
	sort.Sort(heros)
	fmt.Println("排序后")
	for _, val := range heros {
		fmt.Println(val)
	}
}

func main() {
	// test1() // 数组
	// test2() // 切片
	// test3() // 切片使用注意事项
	// arr := []int{4, 1, 2, 5, 9, 8}
	// test4(&arr) // 冒泡排序
	// fmt.Println(arr)
	// test5() // 二位数组
	// test6() //map
	// test7() // map切片
	// test8() // 字典排序
	// test9() // 判断一个key存不存在
	// test10() // 结构体
	// test11() // 结构体地址分析
	// test12() // 结构体字段在内存分布方式
	// test13() // 结构体类型强转
	// test14() // 结构体标签序列化
	// test15() // 结构体方法
	// test16() // 转置二维数组
	// test17() // 方法和函数区别
	// test18() // 封装性课堂练习
	// test19() // 继承性练习
	// fmt.Println("sum=", sum(1, 3)) // defer使用
	// test20() // 匿名字段是基本数据类型
	// test21() // 接口使用
	// test22() // 多接口练习
	test23() // 实现Sort接口的Less和Swap完成排序
}
posted @ 2021-09-24 16:11  楠海  阅读(42)  评论(0)    收藏  举报