首页 > 其他分享 >第五章(数据)[上]

第五章(数据)[上]

时间:2023-01-09 00:23:13浏览次数:29  
标签:func int fmt 切片 第五章 数组 main 数据

字符串

  • 字符串是不可变字节(byte)序列
  • 字符串默认值是"",而不是nil
  • 使用反引号"`"定义不做转义处理的原始字符串,支持跨行
          func main() {
          	s := `hello \r\n,
          	line 2`
          	println(s)
                /*
      	hello \r\n,
      	line 2
            */
          }
    
    • 编译器不会解析原始字符串的注释语句,且前置缩进空格也属于字符串内容
  • 字符串使用"+"拼接时,加法操作符必须在上一行结尾
func main() {
    s := "ab" +
	"cd"
    println(s) //abcd

}
  • 允许以索引号访问字节数组,但不能获取元素地址

  • 数组或字符串截取时,从头开始,到指定位置结束(不包含结束索引位置)

    左闭右开区间[)

func main() {
	s := "abcdefg"
	s1 := s[1:3]
	fmt.Printf("%v", s1) //bc
}
  • for遍历字符串时,分byte和rune两种方式
package main

import "fmt"

func main() {
	s := "你好"
	for i := 0; i < len(s); i++ { //byte(int8)
		fmt.Printf("%d:[%c]\n", i, s[i])
	}
	/*
		0:[ä]
		1:[½]
		2:[ ]
		3:[å]
		4:[¥]
		5:[½]
	*/
	for i, v := range s { //rune (int32)
		fmt.Printf("%d:[%c]\n", i, v)
	}
	/*
		0:[你]
		3:[好]
	*/

}

  • 使用append函数,可将string直接追加到[]byte内
func main() {
	var bs []byte
	bs = append(bs, "bcd"...)
	fmt.Println(bs)      //[98 99 100]
	fmt.Printf("%s", bs) //bcd
}
  • []byte转为string
m := map[string]int{
		"abc": 123,
	}
	key := []byte("abc")
	x, ok := m[string(key)]
	println(x, ok) // 123 true
  • 字符串切片转字符串(strings.Join)
func test() string {
	s := make([]string, 1000)
	for i := 0; i < 1000; i++ {
		s[i] = "a"
	}
	return strings.Join(s, "")
}
  • 使用bytes.Buffer拼接字符串(没搞明白这玩意的核心应用是来干啥的???)
func test() string {
	var b bytes.Buffer
	b.Grow(1000)
	for i := 0; i < 1000; i++ {
		b.WriteString("a")
	}
	return b.String()
}
  • 字符串操作通常在堆上分配内存,会对高并发应用造成较大影响,会有大量字符串对象要做垃圾回收。建议使用[]byte缓存池,或在栈上自行拼装等方式zero-garbage

  • 验证utf8-字符串是否合法 utf8.ValidString(string) ,常用来判断中文字符串是否截取正常

  • utf8.RuneCountInString(string) 代替len返回准确的Unicode字符数量

数组

  • 定义数组类型时,数组长度是类型的组成部分,长度必须是非负整数常量表达式
  • 元素类型相同,但长度不同的数组不属于同一类型

func main() {
	var a [4]int              //元素自动初始化为0
	b := [4]int{2, 4}         //未提供初始值的元素自动初始化为0
	c := [4]int{5, 3: 10}     //可指定索引位置初始化
	d := [...]int{1, 2, 3}    //编译器按初始化值数量确定数组长度
	e := [...]int{10, 3: 100} //支持索引初始化,但注意数组长度与此有关
	fmt.Println(a, b, c, d, e)//[0 0 0 0] [2 4 0 0] [5 0 0 10] [1 2 3] [10 0 0 100]
}

  • 定义多维数组时,仅第一维度允许使用"..."来确定数组长度
func main() {
	a := [2][2]int{
		{1, 2},
		{3, 4},
	}
	b := [...][2]int{
		{10, 20},
		{30, 40},
	}
	c := [...][2][2]int{
		{
			{1, 2},
			{3, 4},
		},
		{
			{5, 6},
			{7, 8},
		},
	}
	fmt.Println(a, b, c)
}
  • 内置函数len和cap都返回第一维数组的长度和容量

  • 数组也支持==,!==操作符

  • 指针数组和数组指针(数组的指针)

    • 指针数组是指元素为指针类型的数组
    • 数组指针是获取数组变量的地址
func main() {
	x, y := 100, 200
	a := [...]*int{&x, &y}      //指针数组:元素为指针的数组
	p := &a                     //数组指针,存储数组地址的指针
	fmt.Printf("%T,%v\n", a, a) //[2]*int,[0xc00001c0a8 0xc00001c0c0]

	fmt.Printf("%T,%v\n", p, p)//*[2]*int,&[0xc00001c0a8 0xc00001c0c0]

}
  • 可获取任意元素地址
func main() {
	a := [...]int{1, 2}
	println(&a, &a[0], &a[1]) //0xc000055f60 0xc000055f60 0xc000055f68
}

数组地址和数组第一个元素的地址一样

  • 数组指针可直接用来操作元素
func main() {
	a := [...]int{1, 2}
	p := &a
	p[1] += 10
	println(p[1], a[1]) //12 12
}

可通过unsafe.Pointer转换不同长度的数组指针来实现越界访问

切片

  • 切片有三种创建方式:a-引用数组 b-make函数创建切片对象 c-声明切片类型的变量后使用append函数直接添加元素

  • 切片:底层通过指针引用底层数组,设定相关属性将数据读写操作限定在指定区域内

切片本身是个只读对象,其工作机制类似数组指针的一种包装

  • 基于数组或数组指针创建切片(左闭右开区间[)

    • len 实际元素长度 len=hight-low
    • cap 表示切片所引用数组片段的真实长度 cap=max-low
  • 切片和数组一样使用索引号访问元素内容,但是从引用数组的索引开始并且从0开始

  • 可使用make直接创建切片对象

func main() {
	s1 := make([]int, 3, 5)    // len=3 cap=5
	s2 := make([]int, 3)       //省略cap,和len一样 len=3 cap=3
	s3 := []int{10, 20, 5: 30} //按初始化元素分配底层数组,len=6 cap=6

	fmt.Println(s1, len(s1), cap(s1))
	fmt.Println(s2, len(s2), cap(s2))
	fmt.Println(s3, len(s3), cap(s3))
}
  • 仅定义切片并未初始化时,切片和nil相等。slice不支持比较操作,仅能判断是否为nil
func main() {
	var a []int
	b := []int{}

	println(a == nil, b == nil) //true fase
}
  • 新建切片对象依旧指向底层数组
func main() {
	d := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
	s1 := d[3:7]
	s2 := s1[1:3]//切片重组(reslice)
	for i := range s2 {
		s2[i] += 100
	}

	fmt.Println(d)  //[0 1 2 3 104 105 6 7 8 9]
	fmt.Println(s1) //[3 104 105 6]
	fmt.Println(s2) //[104 105]
}
  • 利用reslice(切片重组)实现栈式数据结构
func main() {
	//栈最大容量5
	stack := make([]int, 0, 5)

	//入栈
	push := func(x int) error {
		//获取栈的长度
		stackLen := len(stack)
		//获取栈的容量
		stackCap := cap(stack)
		//判断如果stack长度大于等于stack容量时,stack is full
		if stackLen >= stackCap {
			return errors.New("stack is full")
		}
		//利用reslice(切片重组) 重组切片 stack长度+1
		stack = stack[:stackLen+1]
		stack[stackLen] = x
		return nil
	}

	//出栈
	pop := func() (int, error) {
		//获取栈的长度
		stackLen := len(stack)
		//判断栈是否为空
		if 0 == stackLen {
			return 0, errors.New("stack is empty")
		}
		//获取最后一个元素
		x := stack[stackLen-1]
		//利用reslice(切片重组) 重组切片
		stack = stack[:stackLen-1]
		return x, nil
	}

	//入栈测试
	for i := 0; i < 7; i++ {
		fmt.Printf("push %d: %v, %v\n", i, push(i), stack)
	}
	//出栈测试
	for i := 0; i < 7; i++ {
		x, err := pop()
		fmt.Printf("pop: %d, %v, %v\n", x, err, stack)
	}
}
  • append:向切片尾部添加数据,返回新的切片对象
func main() {
	s := make([]int, 0, 5)

	s1 := append(s, 10)
	s2 := append(s1, 20, 30) //追加多个故事
	fmt.Println(s, len(s), cap(s))  // [] 0 5
	fmt.Println(s1, len(s1), cap(s1)) // [10] 1 5
	fmt.Println(s2, len(s2), cap(s2))	//[10 20 30] 3 5

}
  • 数组被追加到原底层数组。如超出cap限制,则为新切片对象重新分配数组

    • 是超出切片cap限制,并非是底层数组长度限制
    • 新分配数组长度是原cap的2倍,而非原数组的2倍

      并非总是2倍,对于较大的切片,会尝试扩容1/4,以节约内存

  • 向nil切片追加数据时,会为其分配底层数组内存

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

正因为存在重新分配底层数组的缘故,在某些场合建议预留足够多的空间,避免中途内存分配和数据复制开销

  • copy func copy(dst, src []Type) int

    将元素从来源切片复制到目标切片中,copy返回被复制的元素数量,它会是 len(src) 和 len(dst) 中较小的那个

func main() {
	s := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
	s1 := s[5:8]
	n := copy(s[4:], s1)  //copy函数返回复制元素的数量
	fmt.Println(s, s1, n) //[0 1 2 3 5 6 7 7 8 9] [6 7 7] 3
	s2 := make([]int, 6)
	n = copy(s2, s)    //copy函数返回复制元素的数量
	fmt.Println(n, s2) //6 [0 1 2 3 5 6]
}
  • 从字符串中复制数据到[]byte
func main() {
	b := make([]byte, 3)
	n := copy(b, "abcdef")
	fmt.Println(n, b) // 3 [97 98 99]
}

  • 如果切片长时间引用大数组中很小的片段,那么建议新建独立切片,复制出所需的数据,便于原数组内存可被及时回收

标签:func,int,fmt,切片,第五章,数组,main,数据
From: https://www.cnblogs.com/badake/p/17031744.html

相关文章

  • 数据结构与算法Python版之北大慕课笔记(一)
    数据结构与算法Python版之北大慕课笔记(一)一、“变位词”判断问题1.解法一:逐字检查2.解法二:排序比较3.解法三:计数比较二、线性结构linearstructure1.四个......
  • vue相同路由跳转,数据不刷新问题
    问题的出现    vue-router的切换不同于传统的页面的切换。路由之间的切换,其实就是组件之间的切换,不是真正的页面切换。这也会导致一个问题,就是引用相同组件的时候,会......
  • 图文并茂strapi 4.5.5自定义搭建指南以及数据库字段名接口返回mapping分析
    strapi是什么?基于Nodejs的开源免费CMS框架为什么选择它?基于nodejs,100%JavaScript,上手迅速可轻松创建功能强大且可自定义的API可以使用任何喜欢的数据库先决条件首......
  • 数据分析师都要具备以终为始的思考逻辑
    职场中,需要的是「解决问题」的能力,对于数据分析师同样如此。数据分析解决业务问题有一套“标准化流程”:从明确需求、清洗数据,到分析原因、提出建议。对于这大同小异的过程,有......
  • TypeScript支持的数据类型(一)
    说明TypeScript做为JavaScript的超集,对于JavaScript中的类型完全支持,除了JavaScript中的类型之外,TS自身也提供了一些数据类型。在TS中,数据类型的整体结构如下:最顶级......
  • 数据分析师都要具备以终为始的思考逻辑
    职场中,需要的是「解决问题」的能力,对于数据分析师同样如此。数据分析解决业务问题有一套“标准化流程”:从明确需求、清洗数据,到分析原因、提出建议。对于这大同小异的过程......
  • 如何优雅地校验后端接口数据,不做前端背锅侠
    背景最近新接手了一批项目,还没来得及接新需求,一大堆bug就接踵而至,仔细一看,应该返回数组的字段返回了null,或者没有返回,甚至返回了字符串"null"???这我能忍?我立刻截图发到群......
  • ubuntu20下mysql5.7数据库修改密码
    --找到mysql配置文件修改/etc/mysql/mysql.conf.d/mysqld.cnf#加上下面的可以不要密码登录#skip-grant-tables#skip-networking然后重启mysql服务servicemysqlr......
  • 2.1JS中的数据类型
    ​  1数值型:number整数和浮点数统称为数值。例如85或3.1415926等。2字符串型:String由0个,1个或多个字符组成的序列。在JavaScript中,用双引号或单引号括起来表示,如"......
  • 2.1JS中的数据类型
    ​  1数值型:number整数和浮点数统称为数值。例如85或3.1415926等。2字符串型:String由0个,1个或多个字符组成的序列。在JavaScript中,用双引号或单引号括起来表示,如"......