golang 数据一   (字符串、数组和数组指针)

从如下几个方面介绍GO语言的数据

1.字符串
2.数组
3.切片
4.字典
5.结构

字符串

Go语言中的字符串是由一组不可变的字节(byte)序列组成从源码文件中看出其本身是一个复合结构

string.go
typestringStructstruct{
strunsafe.Pointer
lenint
}

字符串中的每个字节都是以UTF-8编码存储的Unicode字符字符串的头部指针指向字节数组的开始但是没有NULL或'\0'结尾标志。 表示方式很简单用双引号("")或者反引号(``)它们的区别是

  1. 双引号之间的转义符会被转义而反引号之间的转义符保持不变

  2. 反引号支持跨行编写而双引号则不可以


{
println("hello\tgo")//输出hellogo
println(`hello\tgo`)//输出hello\tgo
}

{
println("hello
go")//syntaxerror:unexpectedsemicolonornewline,expectingcommaor)

println(`hello
go`)//可以编译通过
}
输出
hello
go

在前面类型的章节中描述过字符串的默认值是""而不是nil,比如

varsstring
println(s=="")//true
println(s==nil)//invalidoperation:s==nil(mismatchedtypesstringandnil)

Go字符串支持 "+,+=,==,!=,<,>" 六种运算符

Go字符串允许用索引号访问字节数组(非字符)但不能获取元素的地址比如

{
vara="hello"
println(a[0])//输出104
println(&a[1])//cannottaketheaddressofa[1]
}

Go字符串允许用切片的语法返回子串(起始和结束索引号)比如

vara="0123456"
println(a[:3])//0,1,2
println(a[1:3])//1,2
println(a[3:])//3,4,5,6

日常开发中经常会有遍历字符串的场景比如

{
vara="Go语言"
fori:=0;i<len(a);i++{//以byte方式按字节遍历
fmt.Printf("%d:[%c]\n",i,a[i])
}
fori,v:=rangea{//以rune方式遍历
fmt.Printf("%d:[%c]\n",v)
}
}
输出
0:[G]
1:[o]
2:[è]
3:[ˉ]
4:[-]
5:[è]
6:[¨]
7:[]
0:[G]
1:[o]
2:[语]
5:[言]

在Go语言中字符串的底层使用的是不可以改变的byte数组存的所以在用byte轮询方式时每次得到的只有一个byte而中文字符则是占3个byte的。rune采用计算字符串长度的方式与byte方式不同比如

println(utf8.RuneCountInString(a))//结果为4
println(len(a))//结果为8

所以如果想要获得期待的那种结果的话需要先将字符串a转换为rune切片再使用内置的len函数比如:

{
r:=[]rune(a)
fori:=0;i<len(r);i++{
fmt.Printf("%d:[%c]\n",r[i])
}
}

所以在遍历或处理的字符串的情况下如果其中存在中文尽量使用rune方式处理。

转换

前面讲过不能修改原字符串如果修改的话需要将字符串转换成[]byte或[]rune,然后在转换回来比如

{
vara="hellogo"
a[1]='d'//cannotassigntoa[1]
}
{
vara="hellogo"
bs:=[]byte(a)
...
s2:=string(bs)

rs:=[]rune(a)
...
s3:=string(rs)
}

Go语言支持用"+"运算符进行字符串拼接但是每次拼接都需要重新分配内存如果频繁构造一个很长的字符串则性能影响就会很大比如

functest1()string{
varsstring
fori:=0;i<1000;i++{
s+="a"
}
returns
}

funcBenchmark_test1(b*testing.B){
fori:=0;i<b.N;i++{
test1()
}
}
输出
#goteststr1_b_test.go-bench="test1"-benchmem
Benchmark_test1-2	5000	227539ns/op	530338B/op	999allocs/op

常用的改进方法是预分配足够的内存空间然后使用strings.Join函数该函数会统计出所有参数的长度并一次性完成内存分配操作改进一下上面的代码

functest()string{
s:=make([]string,1000)
fori:=0;i<1000;i++{
s[i]="a"
}
returnstrings.Join(s,"")
}
funcBenchmark_test(b*testing.B){
fori:=0;i<b.N;i++{
test()
}
}
输出
#gotest-vb_test.go-bench="test1"-benchmem
Benchmark_test1-2	200000	10765ns/op	2048B/op	2allocs/op

在日常开发中可以使用fmt.Sprintf函数来格式化和拼接较少的字符串操作比如

{
a:=10010
as:=fmt.Sprintf("%d",a)
fmt.Printf("%T,%v\n",as,as)
}

数组

数组是内置(build-in)类型是一组存放相同类型数据的集合数组的数据类型是由存储的元素类型和数组的长度共同决定的,即使元素类型相同但是长度不同数组也不属于同一类型。数组初始化之后长度是固定无法修改的数组也支持逻辑判断运算符 "==","="定义方式如下

{
vara[10]int
varb[20]int
println(a==b)//invalidoperation:a==b(mismatchedtypes[10]intand[20]int)
}

数组的初始化相对灵活下标索引值从0开始支持按索引位置初始化对于未初始化的数组编译器将给以默认值。

{
vara[4]int//元素初始化为0
b:=[4]int{0,1}//未初始化的元素将被初始化为0
c:=[4]int{0,2:3}//可指定索引位置初始化
d:=[...]int{0,2}//编译器根据初始化值数量来确定数组的长度
e:=[...]int{1,3:3}//支持索引位置初始化但数组长度与其无关

typeuserstruct{
namestring
ageint
}

d:=[...]user{//复合数据类型数组可省略元素初始化类型标签
{"a",1},{"b",2},}
}

定义多维数组时只有数组的第一维度允许使用 "..."

{
x:=[2]int{2,2}
a:=[2][2]int{{1,{2,2}}
b:=[...][2]int{{2,3},{3,3}}
c:=[...][2][2]int{{{2,2}},{{3,{4,4}}}
}

计算数组长度时无论使用内置的len还是cap返回的都是第一维度的长度比如

{
fmt.Println(x,len(x),cap(x))
fmt.Println(a,len(a),cap(x))
fmt.Println(b,len(b),cap(x))
fmt.Println(c,len(c),cap(x))
}
输出
[22]22
[[12][22]]22
[[23][22][33]]32
[[[23][22]][[33][44]]]22

数组指针&指针数组

数组除了可以存放具体类型的数据也可以存放指针比如

{
x,y:=10,20
a:=[...]*int{&x,&y}//指针数组
p:=&a//数组的指针
}

数组复制

Go语言数组是值(非引用)类型所以在赋值和参数传递过程中都会复制整个数组数据比如:

functest(x[2]int){
fmt.Printf("x:=%p,&x,x)
}

funcmain(){
a:=[2]int{1,2}
test(a)//传参过程中完全复制
varb[2]int
b=a//赋值过程中完全复制
fmt.Printf("a:=%p,&a,a)
fmt.Printf("b:=%p,&b,b)
}
输出
x:=0xc42000a330,[12]
a:=0xc42000a320,[12]
b:=0xc42000a370,[12]


借鉴: 雨痕<GO学习笔记>

讨论学习: 675020908

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


简介 WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket让客户端和服务端之间的数据交换变得非常简单,且允许服务器主动向客户端推送数据,并且之后客户端和服务端所有的通信都依靠这个专用协议进行。 在websocket出现之前,一些网站为了实现消息的推送,采用最多的技术是A
使用gin框架编写服务端应用,配置路由接收websocket请求并处理。同时实现一个websocket命令行客户端用于与服务端通信。
## 前言 linux自带的crontab默认情况下只能精确到分钟,没法执行秒级任务。当然,也不是不行,比如: ```shell * * * * * for i in $(seq 1 11);do echo hello &gt;&gt; /home/heruos/tmp.txt;sleep 5;do
前言 代码参考自《Building Distributed Application in Gin》 需求:设计一个食谱相关的API,数据存放到切片中。 设计模型和API 模型 type Recipe struct { // 菜品名 Name string `json:&quot;name&quot;
前言 通过钉钉群机器人的webhook,实现消息推送。 本文代码仅示例markdown格式的消息。 示例代码 注意修改钉钉机器人的webhook package main import ( &quot;bytes&quot; &quot;encoding/json&quot; &quot;fmt&q
golang-jwt是go语言中用来生成和解析jwt的一个第三方库,早先版本也叫jwt-go。本文中使用目前最新的v5版本。
## 前言 假设gRPC服务端的主机名为`qw.er.com`,需要为gRPC服务端和客户端之间的通信配置tls双向认证加密。 ## 生成证书 1. 生成ca根证书。生成过程会要求填写密码、CN、ON、OU等信息,记住密码。 ```shell openssl req -x509 -newkey rs
前言 在go语言中,因为字符串只能被访问,不能被修改,所以进行字符串拼接的时候,golang都需要进行内存拷贝,造成一定的性能消耗。 方式1:操作符 + 特点:简单,可读性良好。每次拼接都会产生内存拷贝,性能一般。仅适用于字符串类型的变量。 示例代码: str1 := &quot;hello &qu
前言 正常情况下,主协程一旦退出,其子协程也会全部中止并退出。为了阻塞主协程,可以使用time.Sleep(),也可以使用WaitGroup。 用法说明 // 导入sync import &quot;sync&quot; // 定义一个sync.WaitGroup var wg sync.WaitG
前言 方便在内网环境中获取服务器本机IP,省了在脚本中过滤ip或ifconfig的结果。 如果内网中有nginx的话,通过nginx获取本机IP也很方便,可参考 借助nginx自动获取本机IP 示例代码 package main import ( &quot;fmt&quot; &quot;net&
简介 logrus是一个第三方日志库,性能虽不如zap和zerolog,但方便易用灵活。logrus完全兼容标准的log库,还支持文本、JSON两种日志输出格式。 特点 相较于标准库,logrus有更细致的日志级别,从高到低分别是:trace &gt; debug &gt; info &gt; wa
基于Gin框架编写的Web API,实现简单的CRUD功能,数据存放在MongoDB,并设置Redis缓存。
## 简介 借助 `github.com/hpcloud/tail` ,可以实时追踪文件变更,达到类似shell命令`tail -f`的效果。 ## 示例代码 以下示例代码用于实时读取nginx的`access.log`日志文件,读取到后输出到控制台。如果nginx日志做了json格式化,还可以解析
前言 go在操作MySQL时,可以使用ORM(比如gorm、xorm),也可以使用原生sql。本文以使用sqlx为例,简单记录步骤。 go version: 1.16 安装相关库 # mysql驱动 go get github.com/go-sql-driver/mysql # 基于MySQL驱动的
前言 某次在客户内网传输数据的时候,防火墙拦截了SSH的数据包,导致没法使用scp命令传输文件,tcp协议和http协议也只放开了指定端口,因此想了个用http传输的“曲线救国”方案。 假设要从192.168.1.23传输到192.168.2.34,因防火墙限制,只能从1.23访问2.34,不能从2
前言 go version: 1.18 本文主要包含JSON、Form、Uri、XML的数据解析与绑定。 JSON数据解析与绑定 go代码 package main import ( &quot;net/http&quot; &quot;github.com/gin-gonic/gin&quot;
## 前言 假设一个场景,服务端部署在内网,客户端需要通过暴露在公网的nginx与服务端进行通信。为了避免在公网进行 http 明文通信造成的信息泄露,nginx与客户端之间的通信应当使用 https 协议,并且nginx也要验证客户端的身份,也就是mTLS双向加密认证通信。 这条通信链路有三个角色
使用gin框架编写web程序作为alertmanager的webhook receiver,解析数据并发送到钉钉
前言 多阶段封装docker镜像,使用scratch镜像,尽量减小镜像包的体积。 封装用于编译的go镜像 Dockerfile FROM golang:1.20.1 AS builder WORKDIR /apps COPY . /apps/ ENV CGO_ENABLED=0 ENV GOOS=l
前言 标准库strconv提供了字符串类型与其他常用数据类型之间的转换。 strconv.FormatX()用于X类型转字符串,如strconv.FormatFloat()用于浮点型转字符串。 strconv.ParseX()用于字符串转X类型,如strconv.ParseFloat()用于字符串转