Go笔记(2)数据类型

这篇记录语法。包含数据类型,数组、切片、string、map、map实现set功能、函数。

基本数据类型

基本数据类型

  1. Go 语⾔不允许隐式类型转换,别名和原有类型也不能进⾏隐式类型转换。
  2. 类型的预定义值: math.MaxInt64, math.MaxFloat64, math.MaxUint32
  3. 不⽀持指针运算。
  4. string 是值类型,其默认的初始化值为空字符串。string 是只读的 byte 切片,len(str)=所包含的 byte 数。string 的 byte 数组可以存放任何数据。
  5. 函数可以有多个返回值,所有参数都是值传递(slice/map/channel会有传引用的错觉)
  6. 【解释5】切片本身是一个数据结构,背后对应一个数组,数据结构包含指向数组的指针,在传值的情况下,结构被复制到函数里,通过指针操作具体的值,操作的是同一块空间。
  7. slice 只能和[], nil 比较;map 只能和 nil 比较。可以使用 relect.DeepEqual。

简单语法示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
a := [...]int{1, 2, 3, 4} // 数组初始化
b := [2][2]int{{1,2}, {3,4}} //多维数组

func TestArrayTravel(t *testing.T) {
arr := [...]int{1, 3, 4, 5} // [len]使用...自动识别数组长度
for _, e := range arr3 { // _/idx 表示索引值,_表示并不关心这个值的结果,返回值占位
t.Log(e)
}
// 相同维度的数组可以比较
t.Log(arr[1:len(arr)]==arr[1:]) // true, 返回值均为[3,4,5]
}

func TestSlice(t *testing.T) {
s := []int{} // 切片,容量可伸缩,只能和[], nil比较
s2 := make([]int, 3, 5) //len=3,默认初始化为0
for i := 0; i < 10; i++ {
s = append(s, i) // 用*2的方式创建新的连续存储空间,把值copy过去
t.Log(len(s), cap(s))
}
}

func TestMap(t *testing.T) {
m := map[int]int{}
t.Log(m[1]) // 0,默认初始化为0
m[2] = 0
t.Log(m[2]) // 0
m[3] = 0 // 判断 map 中 key不存在/值为0必须使用 if 语句
if v, ok := m[3]; ok {
t.Logf("Key 3's value is %d", v)
} else {
t.Log("key 3 is not existing.")
}
m2 := map[int]func(op int) int{} // map的值可以是方法
m2[1] = func(op int) int { return op }
m2[2] = func(op int) int { return op*op}
t.Log(m2[1](2), m2[2](2))
}

// go语言没有set(元素唯一性),用map来实现相同的特性。添加元素、判断元素是否存在、删除元素、元素个数
func TestMapForSet(t *testing.T) {
mySet := map[int]bool{}
mySet[1] = true
n := 3
if mySet[n] {
t.Logf("%d is existing", n)
} else {
t.Logf("%d is not existing", n)
}
mySet[3] = true
t.Log(len(mySet))
delete(mySet, 1) // 删除
n = 1
if mySet[n] {
t.Logf("%d is existing", n)
} else {
t.Logf("%d is not existing", n)
}
}

func TestString(t *testing.T) {
var s string
t.Log(s) //初始化为默认零值“”
s = "hello"
t.Log(len(s)) // 5
//s[1] = '3' // string是不可变的byte slice
s = "\xE4\xB8\xA5" // 可以存储任何二进制数据
t.Log(len(s)) // 3
s = "中" // len(s)=3 [0xE4, 0xB8, 0xAD]
c := []rune(s) // 取出unicode,len(c)=1
t.Logf("中 unicode %x", c[0]) // 中 unicode 4e2d
t.Logf("中 UTF8 %x", s) // 中 UTF8 e4b8ad(物理存储)

s := "A,B,C"
parts := strings.Split(s, ",") // 字符串分割
for _, part := range parts {
t.Log(part)
}
t.Log(strings.Join(parts, "-"))

s := strconv.Itoa(10)
t.Log("str" + s) // 整数转字符串
if i, err := strconv.Atoi("10"); err == nil { // 字符串转整数需要用特殊写法
t.Log(10 + i)
}
}

字符串连接-高效

尽量不使用 StringAdd,String 是个不可变对象,每次 add 之后需要生成一个新对象、开辟新的存储空间。
1.10 之前使用bytes.Buffer;1.10 以后可以使用 strings.Builder。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func BenchmarkStringBuilder(b *testing.B) {
var builder strings.Builder
for i := 0; i < numbers; i++ {
builder.WriteString(strconv.Itoa(i))

}
_ = builder.String()
}

func BenchmarkBytesBuf(b *testing.B) {
var buf bytes.Buffer
for i := 0; i < numbers; i++ {
buf.WriteString(strconv.Itoa(i))
}
_ = buf.String()
}

函数

条件判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// if-else
func TestMultiSec(t *testing.T) {
if v, err:=someFunc() ; err==nil { // someFunc本来的返回值v,返回的错误err
} else {}
}
// switch
func TestSwitch(t *testing.T) {
for i := 0; i < 5; i++ {
switch {
case i%2 == 0: // 可以直接使用i的表达式
t.Log("Even") // 不用加break
case i%2 == 1:
t.Log("Odd")
default:
t.Log("unknow")
}
}
}

函数可变参数

1
2
3
4
5
6
7
func Sum(ops ...int) int { 
ret := 0
for _, op := range ops {
ret += op
}
return ret
}

函数式编程,传入一个函数,输出一个函数。
类似于装饰模式,给一个函数套一层,返回依旧是这个函数,作为功能的扩展。

1
2
3
4
5
6
7
8
9
10
func timeSpent(inner func(op int) int) func (op int) int {
return func(n int) int {
start := time.Now()
ret := inner(n)
fmt.PrintIn("time spent:", time.Since(start).Seconds())
return ret
}
}
func slowFun(op int) int { time.Sleep(time.Second * 1) return op} // 表示一个函数的运行
func TestFn(t *testing.T) { tsSF := timeSpent(slowFun) t.Log(tsSF(10))} // 调用装饰函数

package

  1. strconv 包提供了字符串与简单数据类型之间的类型转换功能。可以将简单类型转换为字符串,也可以将字符串转换为其它简单类型。
    字符串转int:Atoi()
    int转字符串:Itoa()
    ParseTP类函数将string转换为TP类型:ParseBool()、ParseFloat()、ParseInt()、ParseUint()。因为string转其它类型可能会失败,所以这些函数都有第二个返回值表示是否转换成功
    FormatTP类函数将其它类型转string:FormatBool()、FormatFloat()、FormatInt()、FormatUint()
    AppendTP类函数用于将TP转换成字符串后 append 到一个 slice 中:AppendBool()、AppendFloat()、AppendInt()、AppendUint()

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!