字符串
- 字符串并不能修改,下面的+=操作语句只是新生成了一个s字符串,原有的s字符串并没有改变,t的值还是原来的值字符串不可变意味为字符串s及其生成子串s[7:1]都公用的一个内存,这样生成子串就不会分配新的内存,开销非常低廉
s:= "hello"
t:= s
s +="hello";//新生成的一个字符串,并没有改变原有的字符串
fmt.Println(s,t)
fmt.Println(t)
- 字符串的长度,len(s)默认计算的是字节长度,对于中文等汉字,需要使用utf-8计算长度,range将会把字符串默认按照utf8进行隐式转换
k := "hello,世界"
fmt.Println(len(k))
fmt.Println(utf8.RuneCountInString(k))
//使用range统计长度
i:=0
//range将会把字符串默认按照utf8进行隐式转换,所以长度也是正确的
for range k {
i++
}
字符串和字节数组
- 如果我们对一个字符串多次进行增加操作的话,因此字符串底层不可改变性质,我们每次都会从内存中,新生成一个字符串,这样对内存的开销频繁,因此我们可以使用字节数组 字节数组 []byte(s)会重新分配一个数组,将字符串拷贝到,进行增加等修改操作,也只是在原有的slice上面操作,并不会生成新的变量
/**
因为字符串底层的不可改变性质,不适用buffer的话,每次都会分配内存
生成一个新的字符串,所以使用Buffer类型插入可以节约内存
*/
func intTostring(value []int) string {
var buf bytes.Buffer
buf.WriteByte('[')
//循环这个字符串循环写入
for i,v :=range value {
if(i>0) {
buf.WriteByte(',')
}
fmt.Fprintf(&buf,"%d",v)
}
buf.WriteByte(']')
return buf.String()
}
数组的使用
- 数组是具有决定长度,且有零个或者多个相同类型的序列,因为go的数组是固定长度的,因此很少使用,可以使用slice代替,下面看个数组的下例子
func main() {
//创建数组
var a [3]int = [3]int{1,2,3}
f(a)
//值传递
fmt.Println(a) //[1 2 3]
//指针传递
fPoint(&a)
fmt.Println(a) //[2 2 3]
}
func f(a [3]int) [3]int {
a[0] = 2
return a;
}
func fPoint(a *[3]int) [3]int {
a[0] =2
return *a;
}
数组默认是使用的值传递,使用数组指针是高效的,同时允许被调函数修改数组中的元素,但是因为数组的长度是固定的,因此这个函数如果传递[4]int是不可以的,而且对数组进行增加删除也是不行的,因此我们很少使用数组
slice
slice表示对数组的一种引用,slice包含指针,长度,容量,slice的value是指针方式指向了数组,长度表示当前slice的长度,容量表示从slice第一个元素开始到引用数组尾部的长度
fun main() {
var a []int = []int{1,2,3}
f1(s)
fmt.Println(s) //slice指向数组的引用,因此可以改变其值
}
func f1(a []int) []int {
a[1] = 3
return a;
}
/**
实现一个slice简单添加函数
可以看出都是随着append 增加
*/
func appendInt(x []int, y int) []int {
var z []int
zlen := len(x) + 1; //添加一个参数 大小加1
//数组仍然有空间 可以添加数据
//这里要使用slice真实的容量cap而不要使用len
if zlen <= cap(x) {
z = x[:zlen] //对数组增加一个
} else {
//slice的空间不足了,需要进行扩容
zcap := zlen;
//扩充一倍
if zcap <= 2*len(x) {
zcap = 2 * len(x)
}
//生成一个新的slice
z = make([]int, zlen, zcap)
copy(z, x)
}
z[len(x)] = y
return z;
}
//slice并不是纯引用关系,而是行如下面的struct
type sliceInt struct {
ptr *int
cap int
len int
}
map和struct
func main() {
var s = make(map[string]int)
s["age"]=1
s["sex"]=2
fmt.Println(s)
args:= map[string]int {
"name":1,
"age":2,
}
fmt.Println(args)
d,ok :=s["age"];if ok {
fmt.Println(d)
}
s2:= map[string]int {
"name":1,
"age":2,
}
s3:= map[string]int{
"name":1,
"age":2,
}
fmt.Println(s2==s3) //map是不可以比较的
}
//struct
type Person struct {
name string
age int
}
//使用指针的话 传递的效率更快
func (p *Person) study(name string) {
p.name = name
}
//使用值传递不能改变结构体的内容,因此建议使用指针传递
func (p Person) updateAge(age int) {
p.age = age
}
func main() {
var p = Person{
name:"xiaobai",
age:2,
}
//p.study("xiaohei")
//fmt.Println(p)
//p.updateAge(50)
//fmt.Println(p)
//结构体的比较
var p1 = Person{
name:"xiaobai",
age:2,
}
//如果strct所有成员变量都可以比较的话,那么这个struct是可以比较的
fmt.Println(p == p1)
}
json的简单实用
//必须使用大写 可以导出
type Student struct {
Name string `json:"name"`
Score int `json:"score"`
Number int `json:"number"`
DestName int `json:"dest_name"`
}
func main() {
var s= Student{
Name:"xiaobai",
Score:10,
Number:15,
DestName:20,
}
j,err := json.Marshal(s)
fmt.Printf("%s",j)
fmt.Println(err)
var d Student
json.Unmarshal(j,&d)
fmt.Printf(d)
}