golang-基础下

切片

切片基本介绍:

  • 切片的英文为slice
  • 切片是数组的一个引用,因此切片是引用传递,在进行值传递需遵守引用传递规则
  • 切片使用和数组类似,遍历,访问切片元素和求切片长度 len(silce) 都一样
  • 切片的长度是可变的,因此切片是一个可以动态变化的数组
  • 切片定义的基本语法:var 变量名 类型 | var a []int
    此时此刻我想吟诗一首:数组有一种初始化数组的方法为:var a = […]int{1,2,3,4} 此种方式等价于 var a […]int | a = {1,2,3,4},能够进行数组长度自动推导,好的我们继续看切片是什么东东

程序示例:

  • 引用数组的切片起始下标为2结束下标为4但不包括4
// 演示切片的使用
package main

import "fmt"

func main(){
	// 定义一个数组
	var a = [...]int{2,3,4,5,6}
	// slice是切片名
	// 引用数组的切片起始下标为2结束下标为4但不包括4
	// a[2:4] 表示slice切片引用到这个数组
	slice := a[2:4]	
	fmt.Println("数组a的值为:",a)
	fmt.Println("slice切片值为: ",slice)
	fmt.Println("slice切片长度为: ",len(slice))
	// cap(切片) 可以用来求切片容量,一般为切片长度的1倍或1.5倍,不固定,
	// 随着切片长度增大,容量会动态增加,不需要关心
	fmt.Println("slice切片容量为: ",cap(slice))
}

在这里插入图片描述
切片在内存中的形式:

  • 切片在内存中的形式是这样的:切片首位元素地址引用自数组元素地址,切片在内存中储存着从数组中引用的元素地址,元素长度,元素容量,同数组取元素,切片也是根据其存储的切片长度通过首位元素地址进行元素取值
    在这里插入图片描述
    在这里插入图片描述

切片的三种定义使用方式:

  • 方式一如上所示,定义一个切片让这个切片去引用已经创建好的数组
  • 方式二:通过make来创建切片,基本语法:var 切片名 []type = make([]type,len,[cap]) 容量可以选填
  • 方式二定义切片容量必须大于等于切片长度
    在这里插入图片描述
  • 方式三:定义一个切片,直接指定具体数组,原理类似 make 语法:var 切片名 []type = []type {元素} 例:var a []int = []int {1,2,3}

方式二程序示例:

// 演示第二种切片使用方式
package main

import "fmt"

func main(){
	var slice []int = make([]int,5,10)
	slice[0] = 10
	fmt.Println(slice)
	fmt.Println("slice的长度为: ",len(slice))
	fmt.Println("slice的容量为: ",cap(slice))
}

在这里插入图片描述
通过make方式创建切片,在内存中的形式如下图所示:
对上面程序总结:

  • 通过make方式创建切片可以指定切片的大小和容量
  • 如果没有给切片的各个元素赋值,就会使用默认值[int,float=>0 string=>"" bool=>false]
  • 通过make方式创建的切片对应的数组由 make 底层维护,对外不可见,即只能通过 slice 去访问各个元素
    在这里插入图片描述

方式三程序示例:

// 演示第三种切片使用方式
package main

import "fmt"

func main(){
	// 方式三
	var slice03 []int = []int {1,2,3}
	fmt.Println(slice03)
	fmt.Println("slice03长度为: ",len(slice03))
	fmt.Println("slice03容量: ",cap(slice03))
}

在这里插入图片描述


方式一和方式二的区别:

  • 方式一是直接引用数组,这个数组是提前定义好的
  • 方式二是通过make创建一个切片,make也会创建一个数组,这个数组没有名字,是由 make 在底层进行维护,对程序员不可见,切片第一个元素指向make创建数组的第一个元素,make创建切片示意图:
    用excle画这个图花了我十几分钟

切片的遍历:
程序示例:

  • 方式一:常规for-i-in进行遍历
  • 方式二:for-range进行遍历
// 演示切片的遍历
package main

import "fmt"

func main(){
	// 使用第三种方式创建一个切片
	var sliceThree []int = []int {1,2,3,4,5}
	// 第一种方式遍历切片
	for i:=0;i<len(sliceThree);i++{
		fmt.Println(sliceThree[i])
	}
	fmt.Println()
	// 第二种方式遍历切片 for-range
	for key,value := range sliceThree{
		fmt.Printf("下标为: %v 值为: %v \n",key,value)
	}
}

在这里插入图片描述


切片注意事项及细节说明:

  • 切片是引用数据类型,进行值传递时遵循引用传递机制
    在这里插入图片描述
    程序示例:

  • 可以通过对数组/引用切片/二层切片元素进行地址打印可以看出来,元素引用自同一个数组
    在这里插入图片描述
    在这里插入图片描述


append内置函数可以对切片进行动态扩容
在这里插入图片描述
切片append操作的底层原理分析:

apend对数组进行扩容原理步骤:1.append过程中go底层会创建一个新的数组,这个数组长度取决于原切片长度及追加元素长度总和,新数组初始元素都置为0,然后将切片引用的数组元素拷贝进新数组,再把追加的元素拷贝进去,完成追加,等于新创建了一个数组,切片将重新引用到这个新数组,老数组将被GC

  • 切片 append 操作的本质就是对数组扩容
  • go底层会创建一个新的数组 newArr(安装扩容后大小)
  • 将 slice 原来包含的元素拷贝到新的数组 newArr
  • slice 重新引用到新创建的数组 newArr
  • newArr 是在底层维护的,对程序员不可见
    在这里插入图片描述

程序示例:

// 使用append可以对切片进行动态追加元素
package main

import "fmt"

func main(){
	var sliceThree []int = []int{1,2,3,4,5}
	// 通过append给切片追加元素
	sliceThree = append(sliceThree,400,500,600)
	fmt.Println(sliceThree)

	// 通过append给切片追加切片(注:必须是切片不能是数组,结尾要加上 ... )
	sliceThree = append(sliceThree,sliceThree...)
	fmt.Println(sliceThree)
}

在这里插入图片描述


切片的拷贝操作:

  • 拷贝双方数据类型必须都为slice
  • sliceTwo和sliceThree的数据空间是相互独立的,拷贝完成后修改双方元素不会互相影响
  • 右边切片元素拷贝到左边切片
  • 拷贝可以动态兼容,不会因为拷贝双方切片元素大小差异报错

程序示例:

// 演示slice的拷贝
package main

import "fmt"

func main(){
	var sliceThree []int = []int{1,2,3,4,5}
	var sliceTwo []int = make([]int,10,20)
	// 将 sliceThree 拷贝到 sliceTwo,注意必须都为 slice 类型
	copy(sliceTwo,sliceThree)
	
	fmt.Println(sliceTwo)
	fmt.Println(sliceThree)
}

在这里插入图片描述


string 和 slice
在这里插入图片描述

  • string底层是一个 byte 数组,这个byte数组实际上也是一个切片,因此string也可以进行切片处理
  • string本身是不可变的,不能通过 str[0]="s" 进行元素修改
  • 如果需要修改字符串元素,可以先把字符串转为byte切片或者rune切片,修改完毕重新转为string类型
  • rune按字符处理,兼容汉字

string修改元素程序示例:

在这里插入图片描述
在这里插入图片描述

以上方法不能修改字符元素为汉字,因为一个汉字四个字节,如果要修改为汉字可以把字符串转为 rune切片
在这里插入图片描述
在这里插入图片描述


string进行切片处理程序示例:

// 演示 string 进行切片处理
package main

import "fmt"

func main(){
	var str string = "helloworld"
	slice := str[3:]
	fmt.Println(slice)
}

在这里插入图片描述


切片练习题:
定义一个函数,传入一个int类型参数则可以求出该参数长度的斐波那契数列,并存入数组中:

// 使用数组存斐波那契数列,uint64用来存最大int数
// 创建一个函数,添加一个参数用来存数列个数,返回一个uint64切片
package main

import "fmt"

func slice(n int)([]uint64){
	sliceTwo := make([]uint64,n,20)
	sliceTwo[0] = 1
	sliceTwo[1] = 1
	for i:=2;i<len(sliceTwo);i++{
		// sliceTwo[0] = 1,sliceTwo[1] = 1
		sliceTwo[i] = sliceTwo[i-1] + sliceTwo[i-2]
	}
	return sliceTwo
}

func main(){
	fmt.Println(slice(10))
}

在这里插入图片描述
在这里插入图片描述


排序和查找(主要针对数组)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
冒泡排序:
在这里插入图片描述
在这里插入图片描述
冒泡排序程序示例:

  • 这里需要注意一下定义一个指针int类型的数组写法(arr *[5]int) [5]元素个数要在前
  • 通过传地址的方式用指针参数进行接收不用进行值拷贝效率比较高
// 验收一下冒泡排序
package main

import "fmt"
// 4.这里定义一个int变量用来接收存放临时数组元素
var tmp int
// 2.定义一个函数,参数定义为一个指针类型数组用来接收main函数地址类型参数
func fb(arr *[5]int){
	fmt.Println("排序前数组:",*arr)
	for i:=0;i<len(*arr);i++{
	// 5.数组进行一轮排序需要 数组长度-1次,这里len(*arr)=5-1=4,四次,从0即位到3,一共四次
		for i:=0;i<len(*arr)-1;i++{
			// 6.1-2,2-3,3-4,4-5挨个判断,若判断双方右边大于左边的数,则把右边的数和左边数交换
			if (*arr)[i] < (*arr)[i+1]{
				// 7.判断为true,把左边的数存入临时变量
				tmp = (*arr)[i]
				// 8.把右边大数赋值给左边小数(*arr)[i]	(*arr)[i+1] = (*arr)[i+1]
				(*arr)[i] = (*arr)[i+1]
				// 9.再把之前存入临时变量的小数赋值给交换前的大数,完成交换
				(*arr)[i+1] = tmp
			}
		}
	}
	fmt.Println("排序后数组: ",*arr)
}

func main(){
	// 1.定义一个数组
	var arr = [...]int{23,645,3,45,64}
	// 3.把这个数组以传地址的方式传入进行排序的函数
	fb(&arr)
}

在这里插入图片描述


查找

在golang中常用的查找方式有两种:

  • 顺序查找
  • 二分查找(该数组的有序的)

顺序查找两种程序示例(推荐第二种):

// 演示golang中的查找
package main

import "fmt"
// 顺序查找第一种方式
func one(){
	var name = [...]string{"金毛","哈士奇","腊肠犬","斑点狗","柯基"}
	var names string
	fmt.Println("请输入你最喜欢的犬种名字:")
	fmt.Scanln(&names)
	for i:=0;i<len(name);i++{
		if names == name[i]{
			fmt.Println("你喜欢的是:",name[i])
			break
		}else{
			fmt.Println("抱歉没有这个选择")
			break
		}
	}
}

// 顺序查找第二种方式
func two(){
	var names string
	var xb int
	var name = [...]string{"拉布拉多","金毛","阿拉斯加","萨摩耶","泰迪"}
	fmt.Println("请输入你喜欢的犬种:")
	fmt.Scanln(&names)
	for i:=0;i<len(name);i++{
		if names == name[i]{
			xb = i
			break
		}
	}
		if xb != 0{
			fmt.Printf("你喜欢的犬种为:%v 对应的下标为 %v",names,xb)
		}
	}
func main(){
	one()
	two()
}

在这里插入图片描述

二分查找程序示例:
在这里插入图片描述
程序示例:

// 二分查找
package main

import "fmt"
var middle int

func fb(arr *[10]int,leftindex int,rightindex int,find int){

	if leftindex>rightindex{
		fmt.Println("找不到")
		return
	}

	middle = (leftindex+rightindex)/2
	fmt.Println("第一次递归",middle)

	if (*arr)[middle]>find{
		fb(arr,leftindex,middle-1,find)
	}else if(*arr)[middle]<find{
		fb(arr,middle+1,rightindex,find)
	}else{
		fmt.Printf("找到了下标为: %v 值为: %v",middle,(*arr)[middle])
	}
}

func main(){
	var tmp int
	arr := [10]int{12,32,34,45,99,122,324,456,767,788}
	fmt.Println("请输入所查找的值: ",arr)
	fmt.Scanln(&tmp)
	fb(&arr,0,9,tmp)
}
  • 从以下的结果可以看出二分查找的规律,递归middle出现几次代表递归了几次
    在这里插入图片描述

多维数组-二维数组

程序示例快速入门:

// 演示二维数组
package main

import "fmt"

func main(){
	var twoarr [5][5]int
	twoarr[1][2] = 1
	for i:=0;i<5;i++{
		for j:=0;j<5;j++{
			fmt.Print(twoarr[i][j]," ")
		}
		fmt.Println()
	}
}

在这里插入图片描述
使用方式1:先声明/定义,再赋值
语法:var 数组名 [大小][大小]类型

二维数组在内存中的布局形式:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


使用方式二:直接初始化

  • 声明:var 数组名 [大小][大小]类型 = [大小][大小]类型 {{初值},{初值}}
  • 赋值(int类型默认为0)
    在这里插入图片描述

程序示例:

// 第二种使用数组方式
package main

import "fmt"

func main(){
	var arrstwo [2][3]int = [2][3]int {{1,2,3},{2,3,4}}
	fmt.Println(arrstwo)
}

在这里插入图片描述

二维数组的使用: 二维数组的遍历
在这里插入图片描述

  • 方式一:双重for循环

程序示例:

// 遍历二维数组
package main

import "fmt"

func main(){
	var arrsTwo = [2][5]int{{1,2,4,5,2},{4,5,6,6,1}}
	for i:=0;i<len(arrsTwo);i++{
		for j:=0;j<len(arrsTwo[i]);j++{
			fmt.Print(arrsTwo[i][j]," ")
		}
		fmt.Println()
	}
}

在这里插入图片描述

  • 方式二:for-range
// 遍历二维数组
package main

import "fmt"

func main(){
	var arrsTwo = [2][5]int{{1,2,4,5,2},{4,5,6,6,1}}
	for index,i := range arrsTwo{
		for indextwo,itwo := range i{
			fmt.Printf("arrTwo[%v][%v] = %v  ",index,indextwo,itwo)
		}
		fmt.Println()
	}
}

在这里插入图片描述

map

map是key-value数据结构,又称为字段或关联数组,类似其他编程语言的集合

基本语法:

var map变量名 map[keytype]valuetype

使用介绍:
golang中的map的key可以是很多种类型,比如bool,数字,string,指针,channel,还可以是只包含前面几种类型的:接口,数组,结构体 通常为 int,string

注意:
slice,map,function不可以,因为这几种没法用 == 来判断

map声明示例:
在这里插入图片描述
注意:
声明是不会分配内存的,初始化需要 make 分配内存后才能赋值使用

示例演示:
在这里插入图片描述
使用说明:
map用前一定要make
map的key是不能重复的,如果重复了则以最后一个key-value为准
map的key-value是无序的
在这里插入图片描述
map的使用方式(推荐第二种):

  • 方式一:先声明再make赋值
    在这里插入图片描述
  • 方式二:声明直接make等价于第一种
    在这里插入图片描述
  • 方式三:声明直接赋值
    在这里插入图片描述

案例演示:

// 演示map使用案例
package main

import "fmt"

func main(){
	a := make(map[string]map[string]string,2)
	a["student"] = make(map[string]string)
	a["student"]["name"] = "小明"
	a["student"]["sex"] = "男"
	a["student"]["address"] = "墨西哥"
	
	a["studenttwo"] = make(map[string]string)
	a["studenttwo"]["name"] = "小花"
	a["studenttwo"]["sex"] = "18"
	a["studenttwo"]["address"] = "国美在线"

	fmt.Println(a["student"])
	fmt.Println(a["studenttwo"])
}

在这里插入图片描述
map的增删改查操作:

  • map的增加和更新:
    如果key没有则增加,如果已有该key则为更新
    在这里插入图片描述
  • map的删除 delete(map名称,"key")
    在这里插入图片描述
    delect(
    在这里插入图片描述

map删除细节说明:

  • 如果要删除map所有的key,可以对map的key进行遍历删除
  • 或者 map = make(…) make一个新的重新分配内存,让原来的key-value成为垃圾被GC
    在这里插入图片描述

map查找:
如果a中存在 age 这个key,则boole返回true,values保存这个key对应的value
在这里插入图片描述

map的遍历
注意:map遍历一定要用for-range进行遍历,因为map映射类型不一定是数字,即使是数字也不一定是连续的数字,使用for-range直接进行元素遍历,for-in进行遍历是通过依次通过元素的位进行取的
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
map的长度

len(map)

map的切片:
基本介绍:
如果切片的基本数据类型为map,我们称为map切片,这样使用则map个数就可以动态变化了

// 练习slice map
package main

import "fmt"

func main(){
	// 声明一个map切片
	var slicemap []map[string]string
	// make这个map切片,make完就可以使用了
	slicemap = make([]map[string]string,2)

	// 切片元素还需要make一下才能使用
	slicemap[0] = make(map[string]string,2)
	slicemap[0]["name"] = "猪八戒"
	slicemap[0]["score"] = "哈士奇"

	slicemap[1] = make(map[string]string,2)
	slicemap[1]["name"] = "孙悟空"
	slicemap[1]["score"] = "牛魔"
	fmt.Println(slicemap)
}

在这里插入图片描述

map排序:
golang的map默认是无序的,每次遍历输出的map元素没有固定位置

排序思路:
注意:key必须是int类型才能进行排序
把map的key存入一个切片进行排序然后进行map根据key取值

sort.Ints可以进行排序
在这里插入图片描述

// 演示map排序
package main

import (
	"fmt"
	"sort"
)
func main(){
	var slice []int
	map2 := make(map[int]string)
	map2[2] = "孙悟空"
	map2[5] = "猪八戒"
	map2[9] = "唐三藏"
	map2[1] = "沙和尚"
	
	// 对map进行遍历把key取出来追加到slice中
	for k,_ := range map2{
		slice = append(slice,k)
	}
	// 将切片排序
	sort.Ints(slice)
	// 对切片进行遍历,然后通过key大小对map进行顺序取值
	for _,v := range slice{
		fmt.Println(map2[v])
	}
}

在这里插入图片描述

map使用细节:

  • map是引用类型,遵守引用类型传递的机制,在一个函数接收map后进行修改会修改引用源map值

    在这里插入图片描述
  • map的容量达到阈值后会自动进行扩容,不会发生panic,也就是说map能动态增长键值对
  • map的value也经常使用 struct (结构体) 类型,更适合管理复杂的数据
  • 如果map的value还是一个map键值对使用时需要make两次

struce作为map的value程序示例:

// 演示map的value为struct类型
package main

import "fmt"

func main(){
	// 声明一个struct
	type stu struct{
		name string
		age int
		address string
	}
	// 声明初始化一个 map,value为刚声明的stu
	student := make(map[string]stu)
	// struct的使用
	stu1 := stu{"小明",18,"邯郸"}
	stu2 := stu{"小王",20,"围魏救赵"}

	// 把结构体值赋值给mapkey作为value
	student["top1"] = stu1
	student["top2"] = stu2

	fmt.Println(student)
	// 这里注意一下mapvalue的属性取值方法value.属性
	for k,v := range student{
		fmt.Println("学生编号为: ",k)
		fmt.Println("学生名字为: ",v.name)
		fmt.Println("学生年龄为: ",v.age)
		fmt.Println("学生地址为: ",v.address)
	}
}

在这里插入图片描述

map习题:

  • 使用 map[string] map[string]string 类型
  • key表示用户名是唯一的
  • 如果某个用户名存在就将其密码修改为 8888,如果不存在就添加这个用户,及密码
package main 

import "fmt"

func fb(maps map[string]map[string]string,id string){
	if maps[id] != nil{
		maps[id]["password"] = "888888"
	}else{
		maps[id] = make(map[string]string)
		maps[id]["username"] = "孙悟空"
		maps[id]["password"] = "888888"
	}
	fmt.Println(maps)
}

func main(){
	maps := make(map[string]map[string]string)
	maps["top1"] = make(map[string]string)
	maps["top1"]["username"] = "牛魔王"
	maps["top1"]["password"] = "123456"
	id := "top2"
	fb(maps,id)
}

在这里插入图片描述
map综合应用实例:
声明一个函数用来接收 map[string]map[string]string 类型的map值,进行判断知否有指定的map类型key有就对密码进行修改,没有则创建

package main

import "fmt"

func fb(map2 map[string]map[string]string,id string){
	if map2[id] != nil{
		map2[id]["password"] = "888888"
	}else {
		// 如果没有这个map则需要make一个
		map2[id] = make(map[string]string)
		map2[id]["password"] = "888888"
	}
	fmt.Println(map2)
}

func main(){
	map2 := make(map[string]map[string]string)
	map2["id"] = make(map[string]string)
	map2["id"]["name"] = "牛魔王"
	map2["id"]["password"] = "123456"
	id := "孙悟空"
	fb(map2,id)
}

在这里插入图片描述

go面向对象

struct的优点:

  • 利于数据管理,不同类型的数据集中管理,方便整洁
  • 使用变量定义,array,slice,map都不能进行统一的不同类型管理
  • struct是值类型,结构体变量地址直接指向结构体

struct:

  • 一个程序就是一个世界,有很多对象(变量)

go语言面向对象编程说明:

  • go语言支持面向对对象编程(OOP)但是和传统的面向对象编程有区别,并不是纯粹的面向对象编程,所以说golang支持面向对象编程特性是比较准确的,golang面向对象编程不够纯粹

  • golang没有类(class),golang使用struct来实现类似class的作用,可以理解为golang是基于struct来实现OOP特性的

  • golang面对对象编程非常简洁,去掉了传统的OOP语言的继承,方法重载,构造函数,析构函数,隐藏和this指针等

  • golang仍然有面向对象的继承,封装,多态的特性,只是实现方式和其他OOP语言不同,比如继承golang没有 extends 关键字,继承是通过匿名字段实现的

  • golang面向对象(OOP)很优雅,OOP本身就是语言类型系统(type system)的一部分,通过接口(interface)进行关联,耦合性低加粗样式也非常灵活,golang中面向接口编程是非常重要的特性

在这里插入图片描述
对上图说明:

  • 将一类事物的特征提取出来(比如猫类),形成一个新的数据类型,就是一个结构体
  • 通过这个结构体,我们可以创建多个变量(实例/对象)
  • 事物可以猫类,也可以Person,Fish或者是某个工具类

在这里插入图片描述
快速入门实例:

// struct结构体
package main

import "fmt"

func main(){
	// 创建一个结构体 Cat
	type Cat struct{
		name string
		age int
		address string
	}
	// 创建一个Cat类型的变量
	// struct是值类型,声明完变量就分配空间
	var Cat1 Cat
	// 给变量赋值
	Cat1.name = "小黄"
	Cat1.age = 10
	Cat1.address = "贝吉塔星球"
	fmt.Println("猫咪的名字叫: ",Cat1.name)
	fmt.Println("猫咪的年龄为: ",Cat1.age)
	fmt.Println("猫咪的地址: ",Cat1.address)
}

在这里插入图片描述

结构体和结构体实例变量的区别和练习:

  • 结构体是自定义的数据类型,代表一类事物
  • 结构体变量(实例)是具体的,实际的,代表一个具体变量

结构体变量在内存中的布局:
在这里插入图片描述
在这里插入图片描述
结构体基本语法:
在这里插入图片描述
实例:

package main

import "fmt"

func main(){
	type Cat struct{
		name string
		age int
		address string
	}
}

字段/属性:

  • 从概念或叫法上看:结构体字段 = 属性 = field (统一叫字段)
  • 字段是结构体的基本组成部分,一般是基本数据类型,array,也可以是引用类型

注意事项和细节说明:

  • 字段声明语法同变量。实例:字段名 字段类型
  • 字段的类型可以为:基本数据类型,数组或引用类型
  • 在创建一个结构体变量后,如果没有给字段赋值,都对应一个默认值。布尔类型默认值为 false,数值为 0,string为 “”,array类型的默认值和他的元素类型相关,比如 score [3]int 则为[0,0,0],Pointer和slice和map都为nil,即还未分配空间
  • slice和map类型要先make才能使用
    在这里插入图片描述在这里插入图片描述
  • 不同结构体变量的字段是独立的,互不影响,一个结构体遍历字段的更改,不影响另外一个,结构体是值类型结构体变量也是值类型,默认使用值拷贝,修改一个结构体变量不会影响别的结构体变量
  • 结构体是值类型
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

创建结构体实例的四种方法:
在这里插入图片描述
方式一:
在这里插入图片描述
方式二注意事项:

  • 声明定义可以直接赋值
    在这里插入图片描述

方式三注意事项:

  • 结构体变量是指针
    (*p3).name = "贝吉塔星球" // 等价于 p3.name = "贝吉塔星球"
    
  • 标准的赋值方式为 (*p3).name = "贝吉塔星球"
    在这里插入图片描述

方式四注意事项:

  • 如果想要通过一个变量修改结构体变量可以通过穿内存地址的方式
  • 结构体变量是指针
  • 因为是指针类型输出时候格式为:*p4
  • 声明定义可以直接赋值
    在这里插入图片描述

struct的内存分配机制:

  • 所有变量值都需要加载到内存中才能允许
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

重要小细节:
在这里插入图片描述
结构体使用注意事项和细节:

  • 结构体中字段元素在内存中都是连续分布的
    这里需要注意一下struct中以struct作为字段类型的使用方式
    在这里插入图片描述
    16进制,满16位进1,间隔几位取决于字段类型长度,int类型8位就间隔8位
    在这里插入图片描述
    在这里插入图片描述

细节二:
struct是用户自主定义的数据类型,和其它struct类型变量进行转换时需要有完全相同的字段(名字,个数和类型)
在这里插入图片描述
在这里插入图片描述

细节三:
struct类型type重新定义(相当于起别名),golang认为是新的数据类型,但是相互可以转换
在这里插入图片描述
序列化struct
使用场景:当客户端像服务端请求参数,则可以将struct序列化为json格式
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

// 演示把struct字段转换为json格式
package main

import (
	"fmt"
	"encoding/json"
)

type Contents struct{
	// `json:username`相当于给字段名打一个tag标签
	Username string `json:"username"`	
	Password string `json:"password"`
}

func main(){
	index := Contents{"admin牛牛牛","123456qwer"}

	js,err := json.Marshal(index)
	if err != nil{
		fmt.Println("struct类型用户信息序列化错误:",err)
	}

	fmt.Println(string(js))
}

在这里插入图片描述

方法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值