说
因为在学习过程中使用工具是vscode,在学习过程中是边学边实践,所以 笔记和心得 都在代码中体现(源码和注释)
下面记录是单纯学了的几个部分,还有几个模块还没有记录,包括goroutine和反射reflect等
const
package main
func main() {
const length int = 100
// fmt.Println(length)
const (
bs = 12923
df = "sjd"
sfh = 'w'
) //类似声明变量的 var(...) 写法
const (
//可以在const()里添加一个关键字iota,每行的iota都会累加 1,第一行的iota的默认值是0
//作枚举使用
//并且:iota只能配合const()一起使用
a = iota // 可以 进行与iota的运算,比如:a=10*iota,则 b = 20,c = 30
b
c
)
// fmt.Println(a, b, c)
//iota默认是0,所以fmt的输出的值为: 0 1 2
const (
aa, bb = iota + 1, iota + 2 //iota = 0
cc, dd //iota 每执行一行const中的代码,iota++
ee, ff //iota = 2
gg, hh = iota * 2, iota * 3 //iota = 3
ii, jj //iota = 4
)
// fmt.Println(aa, bb, cc, dd, ee, ff, gg, hh, ii, jj)
}
func_use
package main
import "fmt"
//貌似目前发现,go语言是不支持函数重载的
func hanshu() int {
//fmt.Print("NIHAOYA")
//fmt.Print("NIHAO")
return 111
}
func hanshu1(kjj int, fd string) int { //注意给进来参的声明:类型在后
//fmt.Print("NIHAOYA")
//fmt.Print("NIHAO")
return 111
}
func hanshu_ret2_nonename() (int, int) { //返回多个返回值,匿名的
return 666, 777
}
func hanshu_ret3_name() (r1 int, r2 int) { //与之相同作用但是不同写法(返回类型相同的) 可以写成:(r1,r2 int)
r1 = 100
r2 = 300
return
}
func main() {
fmt.Println(hanshu()) //函数调用
//fmt.Println(hanshu_ret2_nonename()) //双返回值调用
ret1, ret2 := hanshu_ret2_nonename()
fmt.Println(ret1, ret2)
fmt.Println(hanshu_ret3_name())
}
array
package main
import "fmt"
func printArray(myArr [4]int) { //固定的长度,这里是拷贝的值,而非像 slice 的引用
for i := 0; i < 4; i++ {
fmt.Println(myArr[i])
}
myArr[0] = 99999
}
func main() {
myArray := [4]int{3, 4, 5, 6}
var intarry1 [10]int
for i := 0; i < len(intarry1); i++ {
intarry1[i] = i
fmt.Println(intarry1[i])
}
for index, value := range myArray {
fmt.Println("index = ", index, "value = ", value)
}
fmt.Println("---------------------------------------------------")
printArray(myArray)
printArray(myArray) //这里看看在函数里面更改了值是否是改变的 myArray 的值
//发现确确实实改变不了,从而更证明了 再传固定长度的数组时,他使用的是拷贝的思想;但在slice中是用的引用的思想
/*
printArray(intarry1)
ERROR: cannot use intarry1 (type [10]int) as type [4]int in argument to printArray
传固定长度的函数,无法传数组长度不相匹配的数组,intarry1 是长度为10的数组,所以他会报错
*/
}
defer
package main
import "fmt"
func main() {
//defer 用法关键字
defer fmt.Println("main func ends") //defer非常相似于 c++ 中的析构函数,也就是 函数结束之前触发
//析构作用
//可有多个 defer执行,并且: defer是利用栈的规则,即先压进去后出去
defer fmt.Println("1")
defer fmt.Println("2")
//run后结果就应该为 2 1 main func ends
fmt.Println("start")
fmt.Println("a ...interface{}")
//另外的 defer 还可以用于调用函数: 将函数压栈调用
// 比如:
// defer func1()
// defer func2()
// defer func3()
// 就应该先调用 func3 后 func2 ,最后func3
/*
另外的:
当一个函数有return 的函数时,要知道先执行完return 后再执行defer
如:
func aaa int (){
fmt.Println("10086")
}
func bbb int (){
fmt.Println("12315")
return 0
}
func ggg int (){
defer aaa()
return bbb()
}
执行结果为 : 12315
10086
*/
}
struct
package main
import "fmt"
type car struct {
price int
kind string
grade string
} // 没啥好说的 和c/c++没什么区别,除了命名方式
func changestruct(ff car) { //这边是传递进去了一个拷贝,而不是指针
ff.grade = "iisuturate"
}
func changestruct_pointer(ff *car) { //这边是传递进去了一个指针,而不是拷贝
ff.grade = "iisuturate"
}
func main() {
var osprism car
osprism.grade = "A"
osprism.price = 1230000
osprism.kind = "super car"
fmt.Println(osprism)
changestruct(osprism)
fmt.Println(osprism)
changestruct_pointer(&osprism)
fmt.Println(osprism)
var astr car //类的实例化 astr
astr.grade = "12333321"
}
struct_extends
package main
import "fmt"
type Parentclass struct {
name string
age int
}
func (this *Parentclass) facelike() {
fmt.Println("parentclass_old man face")
}
func (this *Parentclass) printall() {
fmt.Println(this.age, this.name)
}
type sonclass struct {
Parentclass //写上这个就是声明: son这个类继承于 parentclass
likewhat string //新成员变量
}
func (this *sonclass) facelike() {
fmt.Println("sonclass_young man face")
}
func (this *sonclass) changelike() {
this.likewhat = "swimming"
}
func main() {
par1 := Parentclass{
name: "baba",
age: 10,
}
son1 := sonclass{ //注意一下这里:如何实例化子类的对象
Parentclass{
name: "erzi",
age: 2,
}, //逗号别忘了
"basketball", //并且另外这里直接跟着对应的值 --- 对应顺序
}
par1.printall()
son1.printall() //未重写
par1.facelike()
son1.facelike() //子类重写过
//另外的,如果子类不够方便,也可以先定义出来一个对象
//如:
var dd sonclass
dd.name = "dog"
dd.likewhat = "qiuqiu"
dd.age = 4
dd.printall()
}
struct_packed
package main
import "fmt"
type book struct {
page int //page 首字母是小写,所以是私有成员
title string
}
type BoOK struct { //如果类名的首字母大写,表示其他包也能够访问
//如果类内属性的首字母大写,表示该属性是公开的,若是小写,则是只对类内开放
theme string
word int
Report string
}
//封装模式
func (this BoOK) Pinn() { // //如果函数首字母大写,表示该函数是公开的(针对其他包),若是小写,则是只对包内开放
}
func (this book) cha_name() { // 拷贝类型
this.page = 100
this.title = ""
}
func (this *book) cha_name_pointer() { // 指针类型,传进来就是改变原对象的相关属性
this.page = 680
this.title = "只有我才能带领我们走向胜利"
}
func main() {
var moo book
mo := book{
page: 12,
title: "only we can destroy it",
}
mo.cha_name()
moo.cha_name()
fmt.Println(mo.page, mo.title)
fmt.Println(moo.page, moo.title)
mo.cha_name_pointer()
moo.cha_name_pointer()
fmt.Println(mo.page, mo.title)
fmt.Println(moo.page, moo.title)
mo.page = 878
fmt.Println(mo.page)
//总而言之,若包名和类名或者方法名的首字母是大写时,其他包也可访问,若为小写的话,那么只能是在包内访问
}
slice
package main
import "fmt"
func printArray(myArray []int) {
for index, value := range myArray {
fmt.Println(index, value)
}
// slice 非拷贝,是引用
myArray[0] = 888889 //通过 run 的结果可以知道,这里可以对 myArray 的值进行改变,so : 切片不是对数组的拷贝,而是对数组的引用。
}
func printArray_(myArray []int) {
for _, value := range myArray { //与上面的那个原函数作区分,比如说对某个变量不关心的时候,可以用 _ 来代替,代表不需要这个变量
fmt.Println(value)
}
}
func main() {
myArray := []int{133, 285, 34} //动态数组,切片 slice
fmt.Printf("the type of myArray = %T\n", myArray)
printArray(myArray)
printArray_(myArray)
}
slice_use_usual
package main
import "fmt"
func main() {
//-------------------------------------与普通的声明相同的初始化,都默认是 0 ,与c的随机值不同
slice1 := []int{1, 2, 3, 4}
fmt.Println(slice1)
var slice2 []int //类似c++中的 int* slice2 ;
slice2 = make([]int, 4) //等价于 slice2 = new int [4]
//上面也可以直接整合
//比如说:
var slice3 = make([]int, 4) // int *slice3 =new int [3]
//make (数组类型,数组长度)
slice4 := make([]int, 6)
fmt.Println(slice2)
fmt.Println(slice3)
fmt.Println(slice4)
var slice5 []int
if slice5 == nil { // nil = NULL(c++)
fmt.Println("空")
} else {
fmt.Println("非空")
}
//slice 的开辟和追加 ---- 引入容量
slice6 := make([]int, 4, 7) // 这里意思是 slice6 是开辟一个容量为 7 的一个空间,但是先只占用 4 个单位
fmt.Println("the len of slice6 = ", len(slice6), "the cap of slice6 = ", cap(slice6), slice6)
//slice6 的全部信息
//append 追加函数
slice6 = append(slice6, 8989)
fmt.Println(slice6) //[0 0 0 0 8989]
fmt.Println(len(slice6)) // len = 5 容量cap不会变
/*
append 函数在追加时,当容量与长度相同时,即容量已经满的时候,因为slice是一个动态的切片
故有: 系统为 slice 分配一个与之前相同的容量大小,有上面的条件来看,当7个已经全部占满了的时候
系统会再给分配 7 个容量
*/
slice6 = append(slice6, 467, 789)
fmt.Println("the len of slice6 = ", len(slice6), "the cap of slice6 = ", cap(slice6), slice6)
slice6 = append(slice6, 33)
fmt.Println("the len of slice6 = ", len(slice6), "the cap of slice6 = ", cap(slice6), slice6)
//此时,len = 8, cap = 14
/*
切片的截取
*/
SP := make([]int, 0, 4)
SP = append(SP, 67444, 100, 1115500000)
sl1 := SP[0:2] //意义是: 截取到 SP 的 [0,2) 注意闭区间和开区间
fmt.Println(sl1) // 取到的是 下标 0 , 1 的元素 对应的是 [67444 100]
//*****************************************不要忘记了 slice 是指针应用的对象
//如:
jk := make([]int, 0, 4)
jk = append(jk, 55, 66, 77, 88)
jp := jk[:3]
fmt.Println(jp)
fmt.Println(jk)
jk[2] = 0
fmt.Println(jp)
fmt.Println(jk)
jp[2] = 222
fmt.Println(jp)
fmt.Println(jk)
//slice 是指针, 故更改一个,两个输出的结果都会变化
//copy函数,是开辟一个新的空间,复制一个副本
copy1 := make([]int, 5)
copy(copy1, jk)
fmt.Println(copy1)
/*
run 的结果是
[55 66 222 88] // jk
[55 66 222 88 0] // copy1
由此可见,哪怕两个的容量不相同也是可以的 当副本容量大于原件时
副本会把原件原封不动的复制过来,多出来的空间不做处理
*/
copy2 := make([]int, 2)
copy(copy2, jk)
fmt.Println(copy2)
/*
run 的结果是
[55 66 222 88] // jk
[55 66] // copy2
由此可见,哪怕两个的容量不相同也是可以的 当副本容量小于原件时
副本会将自己的空间复制填满,但是少的部分不做处理(填满自己空间就结束)
*/
}
pointer
package main
import "fmt"
func swap1(a int, b int) {
temp := a
a = b
b = temp
}
func swap2_pointer(a *int, b *int) {
temp := *a
*a = *b
*b = temp
}
func main() {
a := 100
b := 200
swap1(a, b)
fmt.Println("a= ", a, "b= ", b)
swap2_pointer(&a, &b)
fmt.Println("a= ", a, "b= ", b)
var e int = 9000
var p *int
p = &e
fmt.Println(p) //得到的是 e 的地址
fmt.Println(&e) //输出 e 的地址
fmt.Println(*p) //得到的是 e 的值
//二级指针:
var pp **int
pp = &p
fmt.Println(**pp) // *pp 对应的 p 的值,再来一级,就是对应 *p 的值
}
map_announce
package main
import "fmt"
//map 就是键值对,一个东西对应着一个值
func main() {
var map1 map[string]string //方式一声明 map 类型
map1 = make(map[string]string, 3)
if map1 == nil {
fmt.Println("空")
} else {
fmt.Println("非空")
}
map1["ni hao"] = "xie xie"
map1["qing wen"] = "nin shuo ?"
fmt.Println(map1)
/*
方式二 声明 map 类型
*/
map2 := make(map[int]string) // := 方式
map2[0] = "ni shi"
map2[1] = "gou ma"
map2[2] = "?"
fmt.Println(map2)
map3 := map[int]int{ // { } 方式,别忘了加上逗号和冒号,这种事不需要make的方式
1: 7,
2: 8,
3: 9,
}
fmt.Println(map3)
}
map_use
package main
import "fmt"
func forprint(mpo map[int]string) { //传进来的类型其实还是指针类
for key, value := range mpo {
fmt.Println(key, value)
}
//尝试改变 键值对
mpo[2] = "你是good"
}
func main() {
mapo := map[int]string{
1: "ii",
2: "oo",
3: "pp",
}
forprint(mapo)
fmt.Println("__________________________")
for key, value := range mapo {
fmt.Println(key, value)
}
//由此可知map传出去到函数还是传递指针,而非拷贝
}
interface
package main
import "fmt"
type compute interface {
add()
}
//具体的类
type cal struct {
kind string
}
type cpu struct {
speed int
many int
}
func (this *cal) add() {
fmt.Println(this.kind)
fmt.Println("the main is cal")
}
func (this *cpu) add() {
fmt.Println(this.many)
fmt.Println(this.speed)
fmt.Println("the main is cpu")
}
func showfunc_interface(inter compute) {
inter.add() // 多态
}
func main() {
// 接口的第一种方式
var inte compute
inte = &cal{"qwer"}
inte.add()
inte = &cpu{5000, 4}
inte.add()
// 接口的第二种方式
// 在函数中直接传个接口参数,
// 多态
fmt.Println("============================")
showfunc_interface(inte)
inte = &cal{"啊啊嘿嘿"}
showfunc_interface(inte)
}
interface_use
package main
import "fmt"
// 万能接口空接口
type innt interface {
ss()
}
type aa struct {
yy string
zz int
}
func (this *aa) ss() { //采用接口时访问不能带 返回类型
fmt.Println("ss=========aa ...interface{}")
}
func testinter(arr interface{}) { //这里传进来的东西(interface()代表的意思是指万能接口,可以使任何数据类型)
fmt.Println(arr)
fmt.Printf("%T\n", arr)
/*
类型断言:
*/
value, kk := arr.(aa) // 如果是括号里的类型,那么 value = as,如果不是的话 value不赋值(还是默认)
// arr的类型是否是 ()中的类型 如果是的话,kk = 1
if kk {
fmt.Println("kk == 1 , is int")
fmt.Println(value)
} else {
fmt.Println("kk == 0 , isn't int")
}
}
func main() {
testinter(3.14)
testinter(3)
//字符
testinter('B')
//字符创传入
testinter("QWWEE")
//结构体传入
var rout aa
rout.zz = 76777554123
rout.yy = "uii"
testinter(rout) // 类型 : main.aa
//接口类传入
var inb innt
inb = &aa{"23223", 134}
testinter(inb) // 类型:*main.aa
}
pair
package main
import "fmt"
type aastr struct {
a int
}
type intaa interface {
funac()
}
type intbb interface {
funac()
}
func (this *aastr) funac() {
fmt.Println("a ...interface{}")
}
func ttpair(as interface{}) {
value, kk := as.(int) /// 核心部分在这
/*
其实他的中心思想是
pair: < type,value >
类型断言
如果是括号里的类型,那么 value = as,如果不是的话 value不赋值(还是默认)
*/
fmt.Println(as)
fmt.Println(value)
fmt.Println(kk)
}
func main() {
var rr aastr
rr.a = 9
rainter := &rr.a
ttpair(*rainter)
fmt.Println("--------------------------------") //---------------------------------------
h := aastr{775}
ttpair(h)
var kk intaa //实例化一个接口 kk
kk = &h //kk = &aastr{}
var ll intbb //实例化一个接口 ll
ll = kk.(*aastr) // 因为pair相同,所以kk和ll可以直接赋值过来
fmt.Println(ll)
ttpair(ll)
ttpair(h)
}