go程序设计笔记(一) 简单,复合类型简单介绍

136 阅读4分钟

字符串

  1. 字符串并不能修改,下面的+=操作语句只是新生成了一个s字符串,原有的s字符串并没有改变,t的值还是原来的值字符串不可变意味为字符串s及其生成子串s[7:1]都公用的一个内存,这样生成子串就不会分配新的内存,开销非常低廉
s:= "hello"
t:= s
s +="hello";//新生成的一个字符串,并没有改变原有的字符串
fmt.Println(s,t)
fmt.Println(t)

  1. 字符串的长度,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++
}

字符串和字节数组

  1. 如果我们对一个字符串多次进行增加操作的话,因此字符串底层不可改变性质,我们每次都会从内存中,新生成一个字符串,这样对内存的开销频繁,因此我们可以使用字节数组 字节数组 []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()
}

数组的使用

  1. 数组是具有决定长度,且有零个或者多个相同类型的序列,因为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)

}