Go基础

go基础

// go镜像地址
https://goproxy.cn,direct

// 占位符
%s 字符串占位
%d 数字占位
%f 浮点数占位
%t 布尔类型
%p 指针
%v 自己寻找数据类型
%T 查看数据类型
%o 八进制
%x 十六进制
%b 二进制
%u rune
%c byte类型
%q 打印出来的值会加引号

变量

一个作用域内标识符只能声明一次

{}来显示声明一个作用域

  • 自定义变量
package main

import "fmt"

var aa = 3					        // 函数外定义变量必须加var
var ss = "kkk"

var (							// 省略写法,不用每个变量都写一个var
	dd = 3
	ee = "kkk"
)

func variableShorter() {				
	a, b, c, d := 3, 4, true, "twg"			// 函数内定义变量使用:=
	b = 5						// 再次对变量名赋值不需要加冒号
	fmt.Println(a, b, c, d)
}

func main() {
	fmt.Println("hello world")
	variableShorter()						
	fmt.Println(aa, ss, ee)
}
  • 内置变量
bool			// 布尔
string			// 字符串
(u)int			// 无符号整数
int			// 有符号整数
(u)int16		// 无符号规定整数长度
uintptr			// 指针
byte			// 字节,8位,unit8别名,存放1位ASCII,如英文
rune			// unit32别名,存放多字节字符,如中文,返回Unicode码点值
float32			// 长度32位
complex64		// 复数类型
complex128		// 复数

// 字符字节说明:
字符串 = 字符 + 字符
字符 = 字节 + 字节
英文字节 = 1字节(使用byte or unit8)
中文字节 = 1 ~ 4字节(rune or int32)
1 字节 = 8 比特位
1字节 = 8unit
4字节 = 32unit = rune

// 编码格式:
Unicode:可以包含世界上任意语言或者字符
UTF-8:是Unicode的一种实现方式,定义了字符串以何种形式存储在内存中,使用1~4为每个字符编码
  • 强制转换
var a,b int = 3,4
var c int = math.Sqrt(a*a + b*b)			//因为sqrt是计算浮点型,但a,b又是int,所以这里计算错误,用如下方式
var c int = int(math.Sqrt(float64(a*a + b*b)))		//计算浮点型就转换为浮点型,定义c为int类型就转为int类型

常量

常量变量名写为大写(大家默认的一种写法)

const filename = "abc.txt",

const数值可作为各种类型使用

不想要后面修改的变量

package main

import (
	"fmt"
	"math"
)

func consts() {
	const filename string = "abc.txt" // 定义一个常量指定为字符串类型
	const a, b = 3, 4                 // 定义一个常量不指定类型
	var c int
	c = int(math.Sqrt(a*a + b*b))     // 以往的计算中Sqrt只能计算浮点型,但现在a,b为常量,也就能被sqrt计算
	fmt.Println(filename, c)	  // abc.txt 5
}

func main() {
	consts()
}

  • 多个常量写法
func consts() {
	const (
		filename string = "abc.txt"
		a, b = 3, 4
	)
}
// 当常量值一致,可以不进行定义
func consts() {
	const (
		C7 int = 1
		C8
         C9
	)
}

作用域

调用的变量向上找变量名对应的值

可以在一个结构体中定义相同变量名

如果变量有定义,但是没有调用,在后续执行会报错

package main

import "fmt"

func main() {
	// 作用域:定义变量和标识符可以使用的范围
	// 在Go中用大括号来定义作用域范围
	// 子语句块可以使用父语句块中的标识符,父不能使用子的

	outer := 1
	{
		fmt.Println(outer)			// 1
		inner2 := 2
		{
			fmt.Println(inner2)		// 2
			fmt.Println(outer)		// 1
			{
				inner3 := 3
				fmt.Println(outer, inner2, inner3)	// 1 2 3
			}
		}
	}
}

数据类型

枚举

const + iota

  • 普通枚举类型
func enums() {
	const (
		cpp = iota // iota为自增赋值,从0开始
		_          // 这里_为占位跳过
		python
		golang
		javascript
	)
	fmt.Println(cpp, python, golang, javascript)
}

func main() {
	enums() // 0 2 3 4
}
  • 自增值枚举类型
func enums() {
	const (
		b = 1 << (10 * iota)
		kb
		mb
		gb
		tb
		pb
	)

	fmt.Println(b, kb, mb, gb, tb, pb)		
}

func main() {
	enums() // 1 1024 1048576 1073741824 1099511627776 1125899906842624
}

布尔

布尔类型表示真假

标识符bool

可选值true/false

零值false

// 范例
func main() {
	var zero bool				// zero 为false
	isBoy := true
	isgirl := false
	fmt.Println(zero, isgirl, isBoy)	// false false true
}

与&&,或||,非!

// && 的运算规则
func main() {
	// 操作
	// 逻辑运算(与&&,或||,非!)
	// aBool && bBool当两个都为True的时候结果为True
	fmt.Println(true && false)		// false
	fmt.Println(true && false)		// false
	fmt.Println(true && false)		// false
	fmt.Println(true && false)		// false
	fmt.Println(true && true)		// true
}

占位符打印

%T 打印类型

%t 占位符为bool类型

func main() {
	// 操作
	// 逻辑运算(与&&,或||,非!)
	// aBool && bBool当两个都为True的时候结果为True
	isBoy := true
	isGirl := false
	fmt.Printf("%T %t %t\n", isBoy, isBoy, isGirl) //bool true false
}

整数与数值运算

func main() {
	// 整数类型
	// 标识符:int/int*/uint*/uintper/byte/rune
	// 字面量:十进制,八进制,十六进制
	var age int = 31
	fmt.Printf("%T %d\n", age, age) // int 31
	fmt.Println(0777)

	// 操作符
	// 计算加减乘除
	fmt.Println(1 + 2)   
	fmt.Println(3 - 10)
	fmt.Println(3 * 9)
	fmt.Println(9 / 2)
	fmt.Println(9 % 2)	        // 1
    
    age++
	fmt.Println(age)		// 32
	age--
	fmt.Println(age)		// 31
    
    // 位运算 二进制的运算 10 => 2
	// & | ^ << >> &^
	// 十进制 => 二进制
	// 7 & 2 => 0111 & 0010 => 0010 => 2
	// 7 | 2 => 0111 & 0010 => 0111 => 7
	// 7 ^ 2 => 0111 & 0010 => 0101 => 7 两者不一样为1
	// 2 << 1 => 0010 << 1 => 0100 => 4 将2左移1位
	// 2 >> 1 => 0010 >> 1 => 0001 => 1 将2右移1位
	// 7 &^ 2 => 0111 &^ 0010 => 0101 => 5 两个都是1变0,0和0是0,1和0是,1和0是1
	fmt.Println(7 & 2) // 2
    
    // 赋值运算(=,+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>=,&^=)
	age = 1
	age += 3         	                  // age = age + 3
	fmt.Println(age) 	                  // 4
	age /= 3
	fmt.Println(age)	                  // 1
    
    // int/uint/byte/rune/int*
	var intA int = 10
	var uintB uint = 3
	fmt.Println(intA + uintB)	        // 报错,不同类型不能计算,需要转换
	fmt.Println(uint(intA) + uintB)		// 将initA转换为uint计算
    
    // fmt.Printf
	// int/unit/int*/uint*
	// byte,rune
	var a byte = 'A'
	var w rune = 'A'
	fmt.Println(a, w)                      // 65 65
	fmt.Printf("%T ", age)                 // int
	fmt.Printf("%T ", a)                   // uint8
	fmt.Printf("%T ", w)                   // int32
	fmt.Println("%T %d %b %o %X\n", a, a, a, a, a)
}

浮点型

func main() {
	// float32,float64
	// 字面量:十进制表示法,科学技术法
	// M E N = M * 10 ^ N
	// 1.9E-1 => 0.19
	var height float64 = 1.68
	fmt.Println(height)
	fmt.Printf("%T %f\n", height, height) // float64 1.680000
	var weight float64 = 13.05e1
	fmt.Println(weight) // 130.5

	// 操作
	// 算数运算(+,-,*,/,++,--)
	fmt.Println(1.1 + 1.2)
}

字符串

func main() {
	// "" => 可解释,也就是可以将\n等结果变为换行
	// `` => 原生字符串,如果是\n结果输出也是\n
	// 特殊字符 \n \f \t \r \b \v \f
	var name string = "KK"
	var desc string = `我来\t自湖南`
	fmt.Println(desc)                       // 我来\t自湖南
	fmt.Println(name)                       // KK

	// 操作
	// 算数运算符:+ (字符串连接)
	fmt.Println("我叫" + "tcy")             // 我叫tcy

	// 赋值
	s := "我叫"
	s += "kk"
	fmt.Println(s)                         // 我叫kk

	// 字符号定义只能为Ascii
	// 索引 0 - n-1 (n 字符串长度)
	desc = "abcdef"
	fmt.Printf("%T %c\n", desc[0], desc[0])           // uint8 a
	// 切片
	fmt.Printf("%T %s\n", desc[0:2], desc[0:2])       // string ab
	// 长度查询
	fmt.Println(len(desc))				  // 6
    
     s := "我爱中华人民共和国"
	fmt.Println(len(s))                              // 27 结果和数字不匹配
	fmt.Println(utf8.RuneCountInString(s))           //9 获取unicode字符数量
}

字符串函数

	fmt.Println(strings.Compare("abc", "bcccccac"))                // 比较两个字符串,不相等为-1
	fmt.Println(strings.Contains("abc", "ac"))                     // false 左边是否包含右边
	fmt.Println(strings.Count("abcdakdjflk", "a"))                 // 右边字符出现次数
	fmt.Println(strings.Fields("abc def \neeee\f"))                // [abc def eeee] 按空白字符分隔(空格,\n,\r,\f,\t)
	fmt.Println(strings.HasPrefix("abcddd", "ab"))                 // true 什么开头
	fmt.Println(strings.HasSuffix("abcddd", "ab"))                 //	false 什么结尾
	fmt.Println(strings.Index("defasdjfj", "fas"))                 // 2 fas出现的索引位置
	fmt.Println(strings.Index("sdfjsldjflk", "bsld"))              // -1 因为不存在
	fmt.Println(strings.LastIndex("abceabcd", "abc"))              // 最后一个abc出现的索引位置
	fmt.Println(strings.Split("ab;cd", ";"))                       // 指定分隔符进行分隔
	fmt.Println(strings.Join([]string{"abc", "def", "deee"}, ";")) // 将切片中的元素以冒号连接
	fmt.Println(strings.Repeat("abc", 3))                          // abcabcabc
	fmt.Println(strings.Replace("abcabcabcab", "ab", "xxx", 1))    // 将第一个匹配到的ab替换成xxx
	fmt.Println(strings.Replace("abcabcabcab", "ab", "xxx", -1))   // 全部替换
	fmt.Println(strings.ToLower("bacAcdkB"))                       // 全部转换为小写
	fmt.Println(strings.ToUpper("ABDFdksjlfdj"))                   // 全部转换为大写
	fmt.Println(strings.TrimSpace("abc bca u\nskdj"))              // 去除空格字符

// 字符串转换
	// 字符串 ==> 其他类型
	// == bool
	v, err := strconv.ParseBool("true") //
	fmt.Println(v, err)                 // true <nil>

	if v, err := strconv.ParseBool("eee"); err == nil {
		fmt.Println(v)
	} else {
		fmt.Println(err)
	}

	// 字符串转换 ==> int类型
	if v, err := strconv.Atoi("1023"); err == nil {
		fmt.Println(v)
	} else {
		fmt.Println(err)
	}

	// 字符串 ==> float
	v, err := strconv.ParseFloat("1.1", 64)
	fmt.Println(v, err) // 1.1 <nil>

	// 其他类型 ==> string
	sd := fmt.Sprintf("%d", 12)
	fmt.Printf("%T %v\n", sd, sd) // string 12

	fmt.Println(strconv.FormatBool(false)) // 字符串类型的false
	fmt.Println(strconv.Itoa(12))          // int类型转换为字符串

指针

  • 取地址操作符&和取值操作符“”是一对互补操作符,&取出地址,“”根据地址取出地址指向的值
    *操作符作为右值时,意义是取指针的值,作为左值时,也就是放在赋值操作符的左边时,表示 a 指针指向的变量。其实归纳起来,
    *操作符的根本意义就是操作指针指向的变量。当操作在右值时,就是取指向变量的值,当操作在左值时,就是将值设置给指向的变量。
func main() {
	A := 2
	B := A
	B = 3
	fmt.Println(A, B)             // 2 3

	// 指针
	var cc *int = &A             // 拿到A变量对应值的内存地址赋值给cc
	c := &A
	fmt.Printf("%T %T\n", cc, c) // *int *int

	fmt.Println(*cc)             // *cc,拿到内存地址对应的值
}

用户输入

func main() {
	// 当定义变量是什么类型,最好就根据指定类型去书写
	var name string
	fmt.Print("请输入你的名字:") // 请输入你的名字:tcy
	fmt.Scan(&name)
	fmt.Println("名字", name)    // 名字 tcy

	var age int
	fmt.Print("请输入你的年龄:")
	fmt.Scan(&age)
	fmt.Println("年龄", age)

	var height float64
	fmt.Print("请输入你的身高: ")
	fmt.Scan(&height)
	fmt.Println("身高", height)
}

if判断

If条件里赋值的变量作用域就在这个if语句里

  • 判断文件是否存在(方式一)
import (
	"fmt"
	"io/ioutil"
)

func main() {
	const filename = "abc.txt"
	contents, err := ioutil.ReadFile(filename)			   // 读取文件
	if err != nil {							   // 如果文件不存在
		fmt.Println(err)
	} else {						           // 反之文件存在
		fmt.Println("%s\n", contents)
	}
}
  • 判断文件是否存在(方式二)
import (
	"fmt"
	"io/ioutil"
)

func main() {
	const filename = "abcd.txt"
	if contents, err := ioutil.ReadFile(filename); err != nil {
		fmt.Println(err)
	} else {
		fmt.Println("%s\n", contents)
	}
}
  • if-else判断
func main() {
	var yes string
	fmt.Print("有卖西瓜的吗:")
	fmt.Scan(&yes)

	fmt.Println("老婆的想法:")
	fmt.Println("十个西瓜")

	if yes == "Y" || yes == "y" {
		fmt.Println("一个西瓜")
	}

	fmt.Println("老公的想法:")
	if yes == "Y" || yes == "y" {
		fmt.Println("一个包子")
	} else {
		fmt.Println("十个包子")
	}
}
  • if - else if - else
func main() {
	var score int
	fmt.Print("请输入你的成绩:")
	fmt.Scan(&score)

	if score >= 90 {
		fmt.Println("A")
	} else if score >= 80 {
		fmt.Println("B")
	} else if score >= 70 {
		fmt.Println("C")
	} else if score >= 60 {
		fmt.Println("D")
	} else {
		fmt.Println("E")
	}
}

switch

switch里的case后面自动加了break

  • switch ==> case
func main() {
	var yes string
	fmt.Print("有卖西瓜的吗:")
	fmt.Scan(&yes)

	switch yes {
	case "y", "Y":
		fmt.Println("买一个西瓜1")
	case "N":
		fmt.Println("啥也不买")
	default:
		fmt.Println("十个包子") // 随便输入什么都输出这个结果
	}
}
  • switch ==> case
func main() {
	var score int
	fmt.Print("请输入你的成绩:")
	fmt.Scan(&score)

	switch {
	case score >= 90:
		fmt.Println("A")
	case score >= 80:
		fmt.Println("B")
	case score >= 70:
		fmt.Println("C")
	case score >= 60:
		fmt.Println("D")
	default:
		fmt.Println("E")
	}
}

for循环

  • 写法一:
func main() {
	// 索引 => 记录已经加到的n
	// 记录结果
	result := 0
	i := 1
	for i <= 100 {
		result += i
		i++
	}
	fmt.Println(result)
}

  • 写法二:
func main() {
	// 索引 => 记录已经加到的n
	// 记录结果
	result := 0
	// 初始化子语句,条件子语句,后置子语句
	for i := 1; i <= 100; i++ {
		result += i
	}
	fmt.Println(result)
}
  • 写法三:
  • for range
func main() {
	desc := "我爱中国"
	for i, ch := range desc {
		fmt.Printf("%d %T %q\n", i, ch, ch)
	}
}
  • for + if + continue + break
func main() {
	fmt.Println("continue: ")
	for i := 0; i < 5; i++ {
		if i == 3 {
			continue
		}
		fmt.Println(i)
	}

	fmt.Println("break: ")
	for i := 0; i < 5; i++ {
		if i == 3 {
			break
		}
		fmt.Println(i)
	}
}

goto

使用场景:当多个循环嵌套,break只能退出本层循环,但goto可以跳转到任意位置。

  • 案例一:
func main() {
	var yes string
	fmt.Print("有卖西瓜的吗? (y/Y) ")
	fmt.Scan(&yes)

	if yes != "y" && yes != "Y" {
		fmt.Println("买十个包子")
		goto END			// 跳转到END
	}
	fmt.Println("买一个西瓜")

END:		                                // 从上面位置直接跳转到END,会忽略打印买一个西瓜
}
  • 案例二:
// 判断大小,当满足条件,跳转到goto指定位置
func main() {
	result := 0
	i := 1

START:
	if i > 100 {
		goto FOREND       // 当i大于100符合if判断,调到FOREND
	}
	result += i
	i++
	goto START		  // 当i小于100,跳到START
FOREND:
	fmt.Println(result)       // 5050
}

数组

相同数据类型,固定长度的序列

数据项为数组的元素,数组长度必须为非负整数的常量,长度也是类型一部分。

声明:

  1. 数组声明需要指定组元素的类型以及存储元素的数量(长度)
  2. 定义完成后,长度不可修改
func main() {
	var nums [10]int				// 定义数组,变量 元素长度,元素类型
	fmt.Printf("%T", nums)
}
  • 数组字面量&简短声明
func main() {
	var nums [10]int                     // 定义数组,变量 元素长度,元素类型

	// 字面量
	nums = [10]int{10, 20, 30}
	fmt.Println(nums)                   // [10 20 30 0 0 0 0 0 0 0]

	nums = [10]int{0: 10, 9: 20}
	fmt.Println(nums)                   // [10 0 0 0 0 0 0 0 0 20]  通过索引给定义的位置赋值

	nums = [...]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
	fmt.Println(nums) 		    // 不定义数组长度,通过值进行推导

	nums02 := [10]int{10, 20, 30}       // 简短声明数组方式
	fmt.Println(nums02)                 // [10 20 30 0 0 0 0 0 0 0]
}
  • 操作
func main() {
	// 操作
	// 判断是否相等
	nums05 := [3]int{1, 3, 4}
	nums06 := [3]int{2, 3, 5}
	fmt.Println(nums05 == nums06)       // false

	// 获取数组长度
	fmt.Println(len(nums05))            // 3

	// 数组元素取值,并且修改数组元素
	fmt.Println(nums05[0], nums05[2])   // 1 4
	nums05[0] = 2
	fmt.Println(nums05)                 // [2 3 4]

	// 遍历数组中的元素
	// 方式一:
	for i := 0; i < len(nums05); i++ {
		fmt.Println(nums05[i])
	}
	// 方式二:
	for index, value := range nums05 {
		fmt.Println(index, ":", value)
	}

	// 切片
	// 数组切片的结果不是属组类型,而是切片
	fmt.Printf("%T", nums05[0:2])           //[]int
    
    // 多维数组
	var marrays [3][2]int
	fmt.Println(marrays)                 // [[0 0] [0 0] [0 0]]
	fmt.Println(marrays[0])              // [0 0]
	fmt.Println(marrays[0][0])           // 0
	marrays[0] = [2]int{1, 3}
	fmt.Println(marrays) 	             // [[1 3] [0 0] [0 0]]

	// 多维数组字面量
	marrays = [3][2]int{{1, 2}, {3, 4}}
	fmt.Println(marrays)                 // [[1 2] [3 4] [0 0]]

}

切片

定义:

  1. 长度可变的数组,数据类型相同的数据项
  2. 三部分组成:指针,长度,容量

声明:

  1. 需要定义组成元素类型,不需要指定存储元素长度
  2. 切片声明后,会被初始化成nil,表示暂不存在的切片
func main() {
	var nums []int
	fmt.Printf("%T", nums)	            // []int
}
  • go操作
func main() {
	var nums []int
	fmt.Printf("%T\n", nums)           // []int

	// 字面量
	nums = []int{1, 2, 3}
	fmt.Println(nums) // [1 2 3]
	nums = []int{1, 2, 3, 4, 5}
	fmt.Println(nums)                   // [1 2 3 4 5]
	fmt.Printf("%#v\n", nums)           // []int{1, 2, 3, 4, 5}

	// 数组切片赋值
	var arrarys [10]int = [10]int{1, 2, 3, 4, 5, 6}
	nums = arrarys[1:10]
	fmt.Println(nums)                   // [2 3 4 5 6 0 0 0 0]
	fmt.Printf("%#v\n", nums)           // []int{2, 3, 4, 5, 6, 0, 0, 0, 0}

	// 切片长度和容量获取
	fmt.Printf("%#v %d %d\n", nums, len(nums), cap(nums)) // []int{2, 3, 4, 5, 6, 0, 0, 0, 0} 9 9

	// make函数
	// 设置存储长度为3,容量不指定
	nums = make([]int, 3)
	fmt.Printf("%#v %d %d\n", nums, len(nums), cap(nums)) // []int{0, 0, 0} 3 3

	// 切片指定长度和容量,存储数据根据长度定,不会将容量塞满
	nums = make([]int, 3, 5)
	fmt.Printf("%#v %d %d\n", nums, len(nums), cap(nums)) // []int{0, 0, 0} 3 5

	// 元素操作(增删改查)
	fmt.Println(nums[0]) // 0
	fmt.Println(nums[1])
	fmt.Println(nums[2])
	nums[0] = 10
	fmt.Println(nums[0]) // 10

	// 新增元素,新增后的结果返回值获取
	// 新增元素之所以需要被返回值接收?
	// 新增元素指针会变
	nums = append(nums, 1)                                // 切片元素最后新增1
	fmt.Printf("%#v %d %d\n", nums, len(nums), cap(nums)) // []int{10, 0, 0, 1} 4 5

	// 遍历切片中的元素
	// 方式一:
	for i := 0; i < len(nums); i++ {
		fmt.Println(i, nums[i])
	}

	// 方式二:
	for index, value := range nums {
		fmt.Println(index, value)
	}

	// 切片操作
	fmt.Printf("%T\n", nums[1:3])
	n := nums[1:3:4]
	fmt.Printf("%T %#v %d %d\n", n, n, len(n), cap(n)) // []int []int{0, 0} 2 3

	// 切片容量副作用
	nums = make([]int, 3, 5)
	nums02 := nums[1:3]
	fmt.Println(nums, nums02)                         // [0 0 0] [0 0]

	nums02[1] = 10
	fmt.Println(nums, nums02)                         // [0 0 10] [0 10] 元素的修改会影响到原

	// 删除
	// copy实现删除机制
	nums04 := []int{1, 2, 3}
	nums05 := []int{10, 20, 30, 40}

	copy(nums05, nums04)
	fmt.Println(nums05) // [1 2 3 40]
	copy(nums04, nums05)
	fmt.Println(nums04) // [1 2 3]
	// 删除索引为0的元素,删除最后一位
	num06 := []int{1, 2, 3, 4, 5}
	fmt.Println(num06[1:])
	fmt.Println(num06[:len(num06)-1])
	// 删除中间的元素
	copy(num06[2:], num06[3:])
	fmt.Println(num06[:len(num06)-1])

	// 堆栈:先进后出
	// 队列:先进先出
	queue := []int{}
	queue = append(queue, 1)
	queue = append(queue, 2)
	queue = append(queue, 3)
	queue = append(queue, 4)
	// 1,2,3,4
	fmt.Println(queue[0])
	queue = queue[1:]
	fmt.Println(queue) // [2 3 4]
	queue = queue[1:]
	fmt.Println(queue) // [3 4]

	// 堆栈
	stack := []int{}
	stack = append(stack, 1)
	stack = append(stack, 2)
	stack = append(stack, 3)

	stack = stack[:len(stack)-1]
	stack = stack[:len(stack)-1]
	fmt.Println(stack) // 1

	// 切片排序
	nums01 := []int{1, 5, 6, 4, 3}
	sort.Ints(nums01)
	fmt.Println(nums01) // [1 3 4 5 6]


}
  • 多维切片
func main() {
	// 多维切片
	// 实现切片元素长度不一致的方式
	points := [][]int{}
	points02 := make([][]int, 0)
	fmt.Printf("%T\n", points02)

	points = append(points, []int{1, 2, 3})
	points = append(points, []int{3, 4, 0})
	points = append(points, []int{3, 4, 0, 2, 4, 5})
	fmt.Println(points)             // [[1 2 3] [3 4 0] [3 4 0 2 4 5]]

	// 多维切片访问
	fmt.Println(points[0][1])       // 2
}

字节切片函数

var bytes01 []byte = []byte{'a', 'b', 'c'}         // 定义字节类型的切片
	fmt.Printf("%T %#v\n", bytes01, bytes01)   // []uint8 []byte{0x61, 0x62, 0x63}

	s := string(bytes01)                       // 将字节切片转换为字符串
	fmt.Printf("%T %v", s, s)                  // string abc

	bs := []byte(s)                            // 将字符串转换为字节切片
	fmt.Printf("%T %v", bs, bs)                // string abc[]uint8 [97 98 99]

	fmt.Println(bytes.Compare([]byte("abc"), []byte("ccc")))         // -1 对比
	fmt.Println(bytes.Index([]byte("abcdefabc"), []byte("dev")))     // -1 寻找索引位置
	fmt.Println(bytes.Contains([]byte("abdsdflkj"), []byte("bbbb"))) // false 是否包含

切片与数组

区别:

  1. 数组是固定长度,切片是可变长长度
  2. 数组创建变量赋值为老变量,会对值拷贝一份新的
  3. 切片创建变量赋值为老变量,不会值拷贝,而是直接引用老变量的值。
	// 数组和切片区别
	// 数组是值类型,新拷贝一份值
	// 切片的新的变量会对老变量值做相同修改
	slice := []int{1, 2, 3}
	slice02 := slice

	slice02[0] = 10
	fmt.Println(slice, slice02)   // [10 2 3] [10 2 3]

	// 数组赋值
	array01 := [3]int{1, 2, 3}
	array02 := array01
	array02[0] = 10
	fmt.Println(array01, array02) // [1 2 3] [10 2 3]

映射

映射是存储一系列无序的key/value,通过key来对value进行查找

映射的key只能为可使用==运算符的值类型(字符串,数字,布尔,数组),value可以为任意类型。

func main() {
	// strint为key类型,int为值类型
	var scores map[string]int              // nil映射
	fmt.Printf("%T %#v\n", scores, scores) // map[string]int map[string]int(nil)
	fmt.Println(scores == nil)	       // true
}
  • 字面量&操作
	// 初始化
	// 字面量
	scores = map[string]int{"汤采玉": 100}
	fmt.Println(scores)                   // map[汤采玉:100]

	// make函数初始化
	scores = make(map[string]int)
	fmt.Println(scores)                   // map[]

	// 操作(增删改查)
	// key
	scores = map[string]int{"汤采玉": 100}
	fmt.Println(scores["汤采玉"])         // 100
	fmt.Println(scores["不存在的key"])    // 当key不存在返回value的0值
	v, ok := scores["汤采玉"]             // 判断key值是否存在
	fmt.Println(v, ok)                   // 存在返回value和true,否则为0和false
	v, ok = scores["汤文广"]              // 因为key不存在
	fmt.Println(v, ok)                   // 0 false
	if ok {
		fmt.Println(v)               // 判断key存在就打印
	}
	fmt.Println(len(scores))

	// if支持初始化,将key返回值写入if中
	if v, ok = scores["汤采玉"]; ok {
		fmt.Println(v)               // 100
	}

	// 修改,key存在即修改,不存在就是添加
	scores["汤采玉"] = 101
	fmt.Println(scores)                  // map[汤采玉:101]
	scores["汤文广"] = 150
	fmt.Println(scores)                  // map[汤文广:150 汤采玉:101]

	// 删除
	delete(scores, "汤文广")
	fmt.Println(scores)                  // map[汤采玉:101]

	for k, v := range scores {
		fmt.Println(k, v)            // 汤采玉 101 遍历,和添加的顺序无关
	}
  • map嵌套 & 小练习
// key为字符串,value也是一个map
	// 名字 = map[字符串]字符串{"地方","联系方式","成绩"}
	var users map[string]map[string]string

	users = map[string]map[string]string{"烟灰": {"地方": "福建", "联系方式": "110", "成绩": "100"}}
	fmt.Println(users)           // map[烟灰:map[地方:福建 成绩:100 联系方式:110]]

	// 统计投票数量练习:
	// 方法一:
	abc := []string{"汤采玉", "汤文广", "汤采玉", "汤采玉", "汤红波", "刘利纯", "汤采玉", "汤文广"}
	sorts := map[string]int{}

	for _, e := range abc {
		v, ok := sorts[e]
		if ok {
			sorts[e] = v + 1
		} else {
			sorts[e] = 1
		}
	}
	fmt.Printf("%#v\n", sorts)

	// 方法二:(代码简化)
	aaa := []string{"汤采玉", "汤文广", "汤采玉", "汤采玉", "汤红波", "刘利纯", "汤采玉", "汤文广"}
	sortx := map[string]int{}

	for _, a := range aaa {
		sortx[a]++
	}
	fmt.Println(sortx)
posted @ 2022-04-28 16:35  元气少女郭德纲!!  阅读(87)  评论(0编辑  收藏  举报