go语言基本操作---三

在这里插入图片描述

变量的内存和变量的地址

指针是一个代表着某个内存地址的值。这个内存地址往往是在内存中存储的另一个变量的值的起始位置。Go语言对指针的支持介于java语言和C/C+语言之间,它即没有想Java语言那样取消了代码对指针的直接操作的能力,也避免了C/C+语言中由于对指针的滥用而造成的安全和可靠性问题。
在这里插入图片描述

package mainimport "fmt"func main() {var a int = 10//每个变量有2层含义,变量的内存,变量的地址fmt.Printf("a = %d\n", a)   //变量的内存  10fmt.Printf("&a = %p\n", &a) //变量的地址  0xc00000a0c8
}

指针变量的基本使用

//保存某个变量的地址,需要指针类型,*int保存int的地址 **int保存*int地址
var a int = 10
var p *int                             //定义只是特殊的声明
p = &a                                 //指针变量指向谁,就把谁的地址赋值给指针变量
fmt.Printf("p = %p, &a = %p\n", p, &a) //p = 0xc00000a0c8, &a = 0xc00000a0c8*p = 666                              //*p操作的不是p的内存是所指向的内存a
fmt.Printf("*p = %d,a = %d\n", *p, a) //*p = 666,a = 666

在这里插入图片描述

不要操作没有合法的指向的内存

var p *intp = nilfmt.Println("p = ", p) //<nil>//*p = 666 //err 因为p没有合法的执行var a intp = &a*p = 666fmt.Println("a = ", a)

new函数的使用

表达式new(T)将创建一个T类型的匿名变量,所做的是T类型的新值分配并清零一块内存空间,然后将这块内存空间的地址作为结果返回,而这个结果就是指向这个新的T类型值的指针值,返回的指针类型为*T。

//a :=10 //整型变量avar p *int
//指向一个合法内存
p = new(int) //p是*int,执行int类型 new为没有名字的内存*p = 666
fmt.Println("*p = ", *p)q :=new(int)
*q = 777

我们只需使用new函数,无需担心其内存的生命周期或怎样将其删除,因为go语言的内存管理系统会帮我们打理一切。

普通变量做函数参数(值传递)

package mainimport "fmt"func swap(a, b int) {a, b = b, afmt.Printf("swap: a = %d, b = %d\n", a, b) // 20 10
}func main() {a, b := 10, 20//通过一个函数交换a和b的内存swap(a, b)                                 //变量本身传递,值传递fmt.Printf("main: a = %d, b = %d\n", a, b) //10 20
}

指针做函数参数(地址传递)

package mainimport "fmt"func swap(p1, p2 *int) {*p1, *p2 = *p2, *p1fmt.Printf("swap: *p1 = %d, *p2 = %d\n", *p1, *p2) // 20 10
}func main() {a, b := 10, 20//通过一个函数交换a和b的内存swap(&a, &b)                               //地址传递fmt.Printf("main: a = %d, b = %d\n", a, b) //20 10
}

数组的基本操作

数组是指一系列同一类型数据的集合。数组中包含的每个数据被称为数组元素,一个数组包含的元素个数被称为数组长度。

package mainimport "fmt"func main() {//定义一个数组[10]int和[5]int是不同类型//[数组],这个数字作为数组元素个数var a [10]intvar b [5]intfmt.Printf("len(a) = %d, len(b) = %d\n", len(a), len(b))// 注意:定义数组是,数组元素个数必须是常量//n := 10//var c [n]int //error non-constant array bound n//操作数组元素,从0开始,到len()-1,不对称元素,这个数字,叫下标//这是下标,可以是变量或常量a[0] = 1i := 1a[i] = 2//赋值,每个元素for i := 0; i < len(a); i++ {a[i] = i + 1}//打印 第一个返回下标,第二个返回元素for i, data := range a {fmt.Printf("a[%d] = %d\n", i, data)}
}

数组初始化

//声明定义同时赋值,叫初始化//1 全部初始化var a [5]int = [5]int{1, 2, 3, 4, 5}fmt.Println("a = ", a) //a =  [1 2 3 4 5]b := [5]int{1, 2, 3, 4, 5}fmt.Println("b = ", b) //b =  [1 2 3 4 5]//部分初始化,没有初始化的元素,自动赋值为0c := [5]int{1, 2, 3}fmt.Println("c = ", c) //c =  [1 2 3 0 0]//指定某个元素初始化d := [5]int{2: 10, 4: 20}fmt.Println("d = ", d) //d =  [0 0 10 0 20]

二维数组的介绍

//有多个[]就是多少维//有多少个[]就用多少个循环var a [3][4]intk := 0for i := 0; i < 3; i++ {for j := 0; j < 4; j++ {k++a[i][j] = kfmt.Printf("a[%d][%d] = %d, ", i, j, a[i][j])}fmt.Printf("\n")}fmt.Println("a = ", a) //a =  [[1 2 3 4] [5 6 7 8] [9 10 11 12]]//有3个元素,每个元素又是一维数组[4]intb := [3][4]int{{1, 2, 3, 4},{5, 6, 7, 8},{9, 10, 11, 12},}fmt.Println("b = ", b) //b =  [[1 2 3 4] [5 6 7 8] [9 10 11 12]]//部分初始化没有初始化的值为0c := [3][4]int{{1, 2, 3},{5, 6, 7, 8},{9, 10},}fmt.Println("c = ", c) //c =  [[1 2 3 0] [5 6 7 8] [9 10 0 0]]//部分初始化没有初始化的值为0d := [3][4]int{{1, 2, 3},{5, 6, 7, 8},}fmt.Println("d = ", d) //d =  [[1 2 3 0] [5 6 7 8] [0 0 0 0]]//部分初始化没有初始化的值为0e := [3][4]int{0: {1, 2, 3, 4}, 1: {5, 6, 7, 8}}fmt.Println("e = ", e) //e =  [[0 0 0 0] [5 6 7 8] [0 0 0 0]]

数组比较和赋值

//支持比较,只支持==或!=,比较每一个元素都一样,2个数组比较,数组类型要一样a := [5]int{1, 2, 3, 4, 5}b := [5]int{1, 2, 3, 4, 5}c := [5]int{1, 2, 3}fmt.Println("a == b ", a == b) //truefmt.Println("a == c ", a == c) //false//同类型的数组可以赋值var d [5]intd = afmt.Println("d = ", d) //d =  [1 2 3 4 5]

随机数的使用

package mainimport ("fmt""math/rand""time"
)func main() {//设置种子,只需要一次//如果种子参数一样,每次运行程序产生的随机数都一样//rand.Seed(666)//for i := 0; i < 5; i++ {//	//产生随机数//	fmt.Println("rand = ", rand.Int())//随机数很大的范围//}//rand.Seed(time.Now().UnixNano()) //以当前系统时间作为种子参数//for i := 0; i < 5; i++ {//	//产生随机数//	fmt.Println("rand = ", rand.Int()) //随机数很大的范围//}rand.Seed(time.Now().UnixNano()) //以当前系统时间作为种子参数for i := 0; i < 5; i++ {//产生随机数fmt.Println("rand = ", rand.Intn(100)) //限制在100内的数}
}

冒泡排序代码实现

rand.Seed(time.Now().UnixNano()) //以当前系统时间作为种子参数var a [10]intfor i := 0; i < len(a); i++ {a[i] = rand.Intn(100) //100以内的随机数fmt.Printf("%d, ", a[i])}fmt.Printf("\n")//冒泡排序 挨着的2个元素比较,升序(大于则交换)for i := 0; i < len(a)-1; i++ {for j := 0; j < len(a)-1-i; j++ {if a[j] > a[j+1] {a[j], a[j+1] = a[j+1], a[j]}}}fmt.Printf("\n排序后:\n")for i := 0; i < len(a); i++ {fmt.Printf("%d, ", a[i])}fmt.Printf("\n")

数组做函数参数是值拷贝

package mainimport "fmt"// 数组做函数参数,他是值传递
// 实参数组的每个元素给形参数组拷贝一份
// 形参数组是实参的复制品,数组越大,拷贝的效率越低
func modify(a [5]int) {a[0] = 666fmt.Println("modify a = ", a)//modify a =  [666 2 3 4 5]
}func main() {a := [5]int{1, 2, 3, 4, 5}modify(a) //数组传递过去fmt.Println("main: a = ", a) //main: a =  [1 2 3 4 5]
}

数组指针做函数参数

package mainimport "fmt"// P指向实参数组a,他是数组指针
// *p代表指针所指向的内存,就是实参a
func modify(p *[5]int) {(*p)[0] = 666fmt.Println("modify a = ", *p)
}func main() {a := [5]int{1, 2, 3, 4, 5}//modify a =  [666 2 3 4 5]//main: a =  [666 2 3 4 5]modify(&a) //地址传递fmt.Println("main: a = ", a)
}

切片

切片并不是数组或数组指针,它通过内部指针和相关属性引用数组片段,以实现边长方案
slice并不是真正意义上的动态数组,而是一个引用类型。slice总是指向一个底层array,slice的声明也可以像array一样,只是不需要长度
在这里插入图片描述

a := []int{1, 2, 3, 4, 5}s := a[0:3:5]                    //左闭右开fmt.Println("s = ", s)           // s = [1,2,3]fmt.Println("len(s) = ", len(s)) //长度 //3 3-0fmt.Println("cap(s) = ", cap(s)) //容量 //5 5-0s1 := a[1:4:5]                    //左闭右开fmt.Println("s = ", s1)           // 从下标1开始,取4-1=3个 s =  [2 3 4]fmt.Println("len(s) = ", len(s1)) //长度 //3 4-1fmt.Println("cap(s) = ", cap(s1)) //容量 //4 5-1

切片和数组区别

//切片和数组的区别
//数组[]里面的长度是固定的一个常量,数组不能修改长度,len和cap永远都是5
a := [5]int{}
fmt.Printf("len = %d, cap = %d\n", len(a), cap(a)) //len = 5, cap = 5//切片,[]里面为空,或者为....切片的长度或容易可以不固定
s := []int{}
fmt.Printf("1: len = %d, cap = %d\n", len(s), cap(s)) //1: len = 0, cap = 0s = append(s, 11)                                          //给切片末尾追加一个成员
fmt.Printf("append: len = %d, cap = %d\n", len(s), cap(s)) //append: len = 1, cap = 1

切片的创建

//自动推导类型 同时初始化
s1 := []int{1, 2, 3, 4}
fmt.Println("s1 = ", s1) //s1 =  [1 2 3 4]//借助make函数 格式make(切片类型,长度,容量)
s2 := make([]int, 5, 10)
fmt.Printf("len = %d, cap = %d\n", len(s2), cap(s2)) //len = 5, cap = 10//没有指定容量,容量和长度一样
s3 := make([]int, 5)
fmt.Printf("len = %d, cap = %d\n", len(s3), cap(s3)) //len = 5, cap = 5

切片截取

在这里插入图片描述

array := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}//[low:high:max] 取下标从low开始的元素,len = high-low,cap=max-lows1 := array[:]                                       //[0:len(array):len(array)] 不指定容量和长度一样fmt.Println("s1 = ", s1)                             //s1 =  [0 1 2 3 4 5 6 7 8 9]fmt.Printf("len = %d, cap = %d\n", len(s1), cap(s1)) //10 10//操作某个元素和数组操作方式一样data := array[0]fmt.Println("data = ", data) //0s2 := array[3:6:7]                                   //a[3] a[4] a[5] len = 3 cap =4fmt.Println("s2 = ", s2)                             //3 4 5fmt.Printf("len = %d, cap = %d\n", len(s2), cap(s2)) //3 4s3 := array[:6]                                      //从0开始,取6个元素,容量是10 容量为数组长度fmt.Println("s3 = ", s3)                             //[0 1 2 3 4 5]fmt.Printf("len = %d, cap = %d\n", len(s3), cap(s3)) // 6 10s4 := array[3:]                                      //从下标为3开始,到结尾fmt.Println("s4 = ", s4)                             //[3 4 5 6 7 8 9]fmt.Printf("len = %d, cap = %d\n", len(s4), cap(s4)) //len = 7, cap = 7

切片和底层数组关系

在这里插入图片描述

a := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}s1 := a[2:5]            //从a[2]开始取三个元素
fmt.Println("s1 =", s1) //[2 3 4]
s1[1] = 666
fmt.Println("s1 =", s1) //s1 = [2 666 4]
fmt.Println("a = ", a)  //a =  [0 1 2 666 4 5 6 7 8 9]s2 := s1[1:7]
fmt.Println("s2 = ", s2) //s2 =  [666,4 5 6 7 8]
s2[2] = 777
fmt.Println("s2 = ", s2) //s2 =  [666 4 777 6 7 8]
fmt.Println("a = ", a)   //a =  [0 1 2 666 4 777 6 7 8 9]

内建函数------append

append函数向切片尾部添加数据,返回新的切片对象,容量不够,会自动扩容

s1 := []int{}
fmt.Printf("len = %d ,cap = %d\n", len(s1), cap(s1)) // 0 0
fmt.Println("s1 = ", s1)                             //[]
//在原切片的末尾添加元素
s1 = append(s1, 1)
s1 = append(s1, 2)
s1 = append(s1, 3)
fmt.Printf("len = %d ,cap = %d\n", len(s1), cap(s1)) // 3 4 容量以两倍的速度增加的
fmt.Println("s1 = ", s1)                             // 1 2 3s2 := []int{1, 2, 3}
fmt.Println("s2 = ", s2) //1 2 3
s2 = append(s2, 5)
s2 = append(s2, 5)
s2 = append(s2, 5)
fmt.Println("s2 = ", s2) //s2 =  [1 2 3 5 5 5]

append扩容特点

一旦超过原底层数组容量,通常以2倍容量重新分配底层数组,并复制原来的数据
//如果超过原来的容量,通常以2倍容量扩容

s := make([]int, 0, 1) //cap 1 len 0
oldCap := cap(s)for i := 0; i < 8; i++ {s = append(s, i)if newCap := cap(s); oldCap < newCap {fmt.Printf("cap: %d ====>%d\n", oldCap, newCap) //cap: 1 ====>2 cap: 2 ====>4 cap: 4 ====>8oldCap = newCap}
}

内建函数copy

srcSlice := []int{1, 2}
dstSlice := []int{6, 6, 6, 6, 6}
copy(dstSlice, srcSlice)
fmt.Println("dst", dstSlice) //dst [1 2 6 6 6]

切片做函数参数

切片为引用传递
package mainimport ("fmt""math/rand""time"
)func InitData(s []int) {rand.Seed(time.Now().UnixNano()) //设置种子for i := 0; i < len(s); i++ {s[i] = rand.Intn(100) //100以内的随机数}
}func BubbleSort(s []int) {n := len(s)for i := 0; i < n-1; i++ {for j := 0; j < n-1-i; j++ {if s[j] > s[j+1] {s[j], s[j+1] = s[j+1], s[j]}}}
}func main() {var n int = 10//创建一个切片,len为ns := make([]int, n)InitData(s)fmt.Println("排序前 s = ", s)BubbleSort(s) //冒泡排序fmt.Println("排序后 s = ", s)
}

猜数字游戏

package mainimport ("fmt""math/rand""time"
)// 创建一个数字
func CreatNum(p *int) {rand.Seed(time.Now().UnixNano())var num intfor {num = rand.Intn(10000)if num >= 1000 {break}}//fmt.Println("num = ", num)*p = num
}// 取出每一位
func GetNum(s []int, num int) {s[0] = num / 1000       //取千位s[1] = num % 1000 / 100 //取百位s[2] = num % 100 / 10   //取十位s[3] = num % 10         //取个位
}// 猜数字逻辑
func OnGame(randSlice []int) {var num intkeySlice := make([]int, 4)for {for {fmt.Printf("请输入一个4位数")fmt.Scan(&num)if 999 < num && num < 10000 {break}fmt.Println("请输入的数不符合要求")}//fmt.Println("num = ", num)GetNum(keySlice, num)//fmt.Println("keySlice = ", keySlice)n := 0for i := 0; i < 4; i++ {if randSlice[i] < keySlice[i] {fmt.Printf("第%d位大了一点\n", i+1)} else if keySlice[i] < randSlice[i] {fmt.Printf("第%d位小了一点\n", i+1)} else {fmt.Printf("第%d位猜对了\n", i+1)n++}}if n == 4 { //4位都猜对了fmt.Println("全部猜对")return}}}func main() {var randNum int //产生随机的数//产生一个4位的随机数CreatNum(&randNum)//fmt.Println("randNum: ", randNum)//切片randSlice := make([]int, 4)//保存这个4位数的每一位GetNum(randSlice, randNum)//fmt.Println("randSlice = ", randSlice)//n1 := 1234 / 1000 //取商//n2 := (1234 % 1000)/100 //取余 结果为234//fmt.Println("n1 = ", n1)//fmt.Println("n2 = ", n2)OnGame(randSlice) //游戏
}

map介绍

Go语言中的map(映射,字典)是一种内置的数据结构,他是一个无序的key-value对的集合。
在一个map里所有的键都是唯一的,而且必须是支持==和!=操作符的类型,切片。函数以及包含切片的结构类型这些类型由于具有引用语句,不能作为映射的键,使用这些类型会造成便于错误
在这里插入图片描述

在这里插入图片描述
map值可以是任意类型,没有限制。map里所有键的数据类型必须是相同的,值也必须如何,但键值的数据类型可以不相同。
注意:map是无序的,我们无法决定它的返回顺序,所以,每次打印结果的顺序有可能不同。

map的基本操作

//map创建
//定义一个变量,类型为map[int]stringvar m1 map[int]string
fmt.Println("m1 = ", m1) //m1 =  map[]//对于map只有len,没有cap
fmt.Println("len = ", len(m1)) //0//可以通过make创建
m2 := make(map[int]string)
fmt.Println("m2 = ", m2)       //m2 = map[]
fmt.Println("len = ", len(m2)) //0//可以通过make创建,可以指定长度,只是指定了容量,但是里面却是一个数据也没有
m3 := make(map[int]string, 10)
m3[1] = "mike"
m3[3] = "c++"
m3[2] = "go"
fmt.Println("m3 = ", m3)       //m3 =  map[1:mike 2:go 3:c++]
fmt.Println("len = ", len(m3)) //3//键值是唯一的
m4 := map[int]string{1: "make",2: "go",3: "c++",//4:"xxxx",
}
fmt.Println("m4 = ", m4) //m4 =  map[1:make 2:go 3:c++]

map赋值

//键值是唯一的
m1 := map[int]string{1: "make",2: "go",3: "c++",//4:"xxxx",
}
//赋值,如果已经存在的key值就是修改内容
fmt.Println("m1 = ", m1) //m1 =  map[1:make 2:go 3:c++]m1[1] = "python"
fmt.Println("m1 = ", m1) //m1 =  map[1:python 2:go 3:c++]
m1[4] = "java"           //追加,nap底层自动扩容,和append类似
fmt.Println("m1 = ", m1) //m1 =  map[1:python 2:go 3:c++ 4:java]

map遍历

//键值是唯一的
m1 := map[int]string{1: "make",2: "go",3: "c++",//4:"xxxx",
}
//1=========>make
//2=========>go
//3=========>c++
//第一个返回值为key,第二个返回值为value,遍历结果是无序的
for key, value := range m1 {fmt.Printf("%d=========>%s\n", key, value)
}//如何判断一个key值是否存在
//第一个返回值为key所对应的value,第二个返回值为key是否存在的条件,存在ok为true
value, ok := m1[1]
if ok == true {fmt.Println("m[1]= ", value) //m[1] make
} else {fmt.Println("key不存在")
}

map删除

//键值是唯一的
m1 := map[int]string{1: "make",2: "go",3: "c++",//4:"xxxx",
}fmt.Println("m1 = ", m1) //m1 =  map[1:make 2:go 3:c++]
delete(m1, 1)            //删除key为1的内容
fmt.Println("m1 = ", m1) //m1 =  map[2:go 3:c++]

map做函数参数

引用传递

package mainimport "fmt"func test1(m map[int]string) {delete(m, 1)
}func main() {//键值是唯一的m1 := map[int]string{1: "make",2: "go",3: "c++",//4:"xxxx",}fmt.Println("m1 = ", m1) //m1 =  map[1:make 2:go 3:c++]test1(m1)fmt.Println("m1 = ", m1) //m1 =  map[2:go 3:c++]
}

结构体普通变量初始化

结构体类型:
有时我们需要将不同的类型的数据组合成一个有机的整体,如:一个学生有学号/姓名/性别等属性,显然单独定义以上变量比较繁琐,数据不便于管理。
在这里插入图片描述
结构体是一种聚合的数据类型,它是由一系列具有相同类型或不同类型的数据构成的数据集合。每个数据称为结构体的成员。

结构体初始化

package mainimport "fmt"//定义一个结构体类型type Student struct {id   intname stringsex  byte //字符类型age  intaddr string
}func main() {//顺序初始化,每个陈冠必须初始化var s1 Student = Student{1, "mike", 'm', 18, "bj"} //s1 =  {1 mike 109 18 bj}fmt.Println("s1 = ", s1)//指定成员初始化,没有初始化的成员自动赋值为零s2 := Student{name: "mike", addr: "bj"}fmt.Println("s2 = ", s2) //s2 =  {0 mike 0 0 bj}
}

结构体指针变量初始化

package mainimport "fmt"//定义一个结构体类型type Student struct {id   intname stringsex  byte //字符类型age  intaddr string
}func main() {//顺序初始化,每个陈冠必须初始化 别忘了&var p1 *Student = &Student{1, "mike", 'm', 18, "bj"}fmt.Println("*p1 = ", *p1) //*p1 =  {1 mike 109 18 bj}fmt.Println("p1 = ", p1)   //p1 =  &{1 mike 109 18 bj}//指定成员初始化,没有初始化的成员自动赋值为零p2 := &Student{name: "mike", addr: "bj"}fmt.Println("*p2 = ", *p2)         //*p2 =  {0 mike 0 0 bj}fmt.Println("p2 = ", p2)           //p2 =  &{0 mike 0 0 bj}fmt.Printf("p2 type is %T\n ", p2) //p2 type is *main.Student
}

结构体成员的使用:普通变量

package mainimport "fmt"//定义一个结构体类型type Student struct {id   intname stringsex  byte //字符类型age  intaddr string
}func main() {//定义一个结构体普通变量var s Student//操作成员需要使用.运算符s.id = 1s.name = "mike"s.sex = 'm' //字符s.age = 18s.addr = "wh"fmt.Println("s = ", s) //s =  {1 mike 109 18 wh}
}

结构体成员的使用:指针变量

package mainimport "fmt"//定义一个结构体类型type Student struct {id   intname stringsex  byte //字符类型age  intaddr string
}func main() {//1 指针有合法指向后,才操作成员// 先定义一个普通结构体变量var s Student//在定义一个指针变量,保存s的地址var p1 *Studentp1 = &s//通过指针操作成员p1.id (*p1).id完全等价,只能使用.运算符p1.id = 1(*p1).name = "mike"p1.sex = 'm'p1.age = 18p1.addr = "bj"fmt.Println("p1 = ", p1)   //p1 =  &{1 mike 109 18 bj}fmt.Println("*p1 = ", *p1) // *p1 = {1 mike 109 18 bj}//2 通过new生气一个结构体p2 := new(Student)p2.id = 1(*p2).name = "mike"p2.sex = 'm'p2.age = 18p2.addr = "bj"fmt.Println("p2 = ", p2)   //p2 =  &{1 mike 109 18 bj}fmt.Println("*p2 = ", *p2) // *p2 = {1 mike 109 18 bj}
}

结构体比较和赋值

如果结构体的全部成员都是可以比较的,那么结构体也是可以可以比较的,那样的话两个结构体将可以使用==或!=运算符进行比较,但不支持>或<

package mainimport "fmt"//定义一个结构体类型type Student struct {id   intname stringsex  byte //字符类型age  intaddr string
}func main() {s1 := Student{1, "mike", 'm', 18, "bj"}s2 := Student{1, "mike", 'm', 18, "bj"}s3 := Student{2, "mike", 'm', 18, "bj"}fmt.Println("s1 == s3", s1 == s3) //falsefmt.Println("s1 == s2", s1 == s2) //true//同类型的2个结构体变量可以相互赋值var tmp Studenttmp = s3fmt.Println("tmp = ", tmp) //tmp =  {2 mike 109 18 bj}
}

结构体做函数参数:值传递

package mainimport "fmt"//定义一个结构体类型type Student struct {id   intname stringsex  byte //字符类型age  intaddr string
}func test01(student Student) {student.id = 2fmt.Println("test01 student = ", student) //test01 student =  {2 mike 109 18 bj}
}
func main() {s := Student{1, "mike", 'm', 18, "bj"}test01(s)                         //值传递,形参无法改实参fmt.Println("main student = ", s) //main student =  {1 mike 109 18 bj}
}

结构体做函数参数:地址传递

package mainimport "fmt"//定义一个结构体类型type Student struct {id   intname stringsex  byte //字符类型age  intaddr string
}func test01(student *Student) {student.id = 2fmt.Println("test01 student = ", *student) //test01 student =  {2 mike 109 18 bj}
}
func main() {s := Student{1, "mike", 'm', 18, "bj"}test01(&s)                        //地址传递(引用传递),形参可以改实参fmt.Println("main student = ", s) //main student =  {2 mike 109 18 bj}
}

go语言可见性规则验证

Go语言对关键字的增加非常吝啬,其中没有private,protected,public这样的关键字.
要使某个符号对其他包(package)可见(即可以访问),需要将符号定义为以大写字母开头.

1):如果使用别的包的函数,结构体类型,结构体成员,函数名,类型名,结构体成员变量名,首字母必须大写,可见。
2):如果首字母是小写,只能在同一个包里面使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/121284.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL - Left Join和Inner Join的效率对比,以及优化

最近在写代码的时候&#xff0c;遇到了需要多表连接的一个问题&#xff0c;初始sql类似于&#xff1a; select * from a left join b on a.id b.aid left join c on c.bid b.id left join d on d.cid c.id 这样的多个left join组合&#xff0c;总觉得这种写法是有问题…

华为Mate 60系列发售,北斗卫星通信技术进一步深入大众消费市场

近日&#xff0c;华为Mate 60系列手机在没有举办发布会的情况下在官方商城突然上架开售&#xff0c;人气火爆。 值得一提的是&#xff0c;华为Mate60 Pro支持卫星通话&#xff0c;无地面网络时&#xff0c;也能拨打和接听卫星电话&#xff0c;还可自由编辑卫星消息。华为 Mate6…

机器人中的数值优化(九)——拟牛顿方法(下)、BB方法

本系列文章主要是我在学习《数值优化》过程中的一些笔记和相关思考&#xff0c;主要的学习资料是深蓝学院的课程《机器人中的数值优化》和高立编著的《数值最优化方法》等&#xff0c;本系列文章篇数较多&#xff0c;不定期更新&#xff0c;上半部分介绍无约束优化&#xff0c;…

【Unity编辑器扩展】 | 编辑器扩展入门基础

前言 【Unity编辑器扩展】 | 编辑器扩展入门基础一、基本概念二、核心知识点 简述三、相关API 总结 前言 当谈到游戏开发工具&#xff0c;Unity编辑器是一个备受赞誉的平台。它为开发者提供了一个强大且灵活的环境&#xff0c;使他们能够创建令人惊叹的游戏和交互式体验。然而…

0829|C++day7 auto、lambda、C++数据类型转换、C++标准模板库(STL)、list、文件操作

一、思维导图 二、【试编程】将实例化类对象写入容器后&#xff0c;写入.txt文本中&#xff0c;再重新定义一个类容器&#xff0c;将.txt中的内容读取出来&#xff0c;输出到终端 封装一个学生的类&#xff0c;定义一个学生这样类的vector容器, 里面存放学生对象&#xff08;至…

字节前端实习的两道算法题,看看强度如何

最长严格递增子序列 题目描述 给你一个整数数组nums&#xff0c;找到其中最长严格递增子序列的长度。 子序列是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是数组 [0,3,1,6,2,2,7…

Hadoop 集群一直处于安全模式,强制退出后出现数据丢失警告。解决方法

文章目录 安全模式相关命令分析集群为什么一直处于安全模式解决方法 安全模式相关命令 # 查看安全模式状态 hdfs dfsadmin -safemode get# 进入安全模式 hdfs dfsadmin -safemode enter# 离开安全模式 hdfs dfsadmin -safemode leave# 强制退出安全模式 hdfs dfsadmin -safemo…

【补充】助力工业物联网,工业大数据之AirFlow安装

【补充】助力工业物联网&#xff0c;工业大数据之AirFlow安装 直接在node1上安装 1、安装Python 安装依赖 yum -y install zlib zlib-devel bzip2 bzip2-devel ncurses ncurses-devel readline readline-devel openssl openssl-devel openssl-static xz lzma xz-devel sqlit…

iOS实时监控与报警器

在现代信息化社会中&#xff0c;即使我们不在电脑前面也能随时获取到最新的数据。而苹果公司提供的iOS推送通知功能为我们带来了一种全新的方式——通过手机接收实时监控和报警信息。 首先让我们了解一下iOS推送通知。它是一个强大且灵活可定制化程度高、适用于各类应用场景&a…

图片转pdf软件有哪些?这几款收藏下来

图片转pdf软件有哪些&#xff1f;图片转PDF的需求很常见。有时候我们需要将一些图片文件合并成一个PDF文件&#xff0c;方便浏览和共享。比如说&#xff0c;你可能需要将一份报告或者简历的图片转换成PDF文件&#xff0c;以便于分享给其他人。此外&#xff0c;将图片转换成PDF文…

elasticsearch的搜索补全提示

当用户在搜索框输入字符时&#xff0c;我们应该提示出与该字符有关的搜索项 拼音分词器 下载 要实现根据字母做补全&#xff0c;就必须对文档按照拼音分词&#xff0c;GitHub上有拼音分词插件 GitHub - medcl/elasticsearch-analysis-pinyin: This Pinyin Analysis plugin…

lv3 嵌入式开发-4 linux shell命令(文件搜索、文件处理、压缩)

目录 1 查看文件相关命令 1.1 常用命令 1.2 硬链接和软链接 2 文件搜索相关命令 2.1 查找文件命令 2.2 查找文件内容命令 2.3 其他相关命令 3 文件处理相关命令 3.1 cut 3.2 sed 过滤 3.3 awk 匹配 4 解压缩相关命令 4.1 解压缩文件的意义 4.2 解压缩相关命令 1 …

社区团购新玩法,生鲜蔬菜配货发货小程序商城

在当前的电商市场中&#xff0c;生鲜市场具有巨大的潜力和发展空间。为了满足消费者的需求&#xff0c;许多生鲜店正在寻找创新的方法来提高销售和客户满意度。其中&#xff0c;制作一个个性且功能强大的生鲜小程序商城是一个非常有效的策略。以下是在乔拓云平台上制作生鲜小程…

maven基础学习

什么是maven 构建 依赖 maven核心概念坐标 在黑窗口使用maven命令生成maven工程 pom.xml 想导入哪个jar包把它的坐标放到dependency里就可以 maven核心概念POM maven核心概念约定的目录结构 执行maven的构建命令 清理操作&#xff0c;clean 编译操作 compile 测试操作 test 打包…

基于Spring Boot的企业门户网站设计与实现(Java+spring boot+MySQL)

获取源码或者论文请私信博主 演示视频&#xff1a; 基于Spring Boot的企业门户网站设计与实现&#xff08;Javaspring bootMySQL&#xff09; 使用技术&#xff1a; 前端&#xff1a;html css javascript jQuery ajax thymeleaf 微信小程序 后端&#xff1a;Java springboot…

BackgroudWork的详细用法,实例

一、什么是BackgroudWorker? 1、简言 backgroudworkd就是一个异步单线程&#xff0c;专门为入门级人员开发的。还可以显示进度条。操作简单实用,属于老技术。 注意&#xff1a;如果调用两次这个线程&#xff0c;将会出错。 2、backgroudwor…

025: vue父子组件中传递方法控制:$emit,$refs,$parent,$children

第025个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使…

Redis 复制(replica)

1. 是什么 1.1 官网地址 https://redis.io/docs/management/replication/ 1.2 一句话 1. 就是主从复制&#xff0c;master以写为主&#xff0c;slave以读为主 2. 当master数据变化的时候&#xff0c;自动将新的数据异步同步到其它slave数据库 2. 能干嘛 1. 读写分离 2. 容灾…

正规黄金代理的三大要素

对于现货黄金投资来说&#xff0c;寻找一个正规的黄金代理是十分重要的问题。在目前的现货黄金投资市场中&#xff0c;现货黄金代理的数量很多&#xff0c;他们都致力于耕耘现货黄金投资市场。当越来越多的专业人士加入到现货黄金投资的市场中当中时&#xff0c;这个市场将会越…

手写Mybatis:第10章-使用策略模式,调用参数处理器

文章目录 一、目标&#xff1a;参数处理器二、设计&#xff1a;参数处理器三、实现&#xff1a;参数处理器3.1 工程结构3.2 参数处理器关系图3.3 入参数校准3.4 参数策略处理器3.4.1 JDBC枚举类型修改3.4.2 类型处理器接口3.4.3 模板模式&#xff1a;类型处理器抽象基类3.4.4 类…