Go基础--基本数据类型

基本类型

一、数值和布尔类型

1.1.int型

  • 分为无符号和有符号的,int8,int16,int32,int64
  • int根据所在的硬件平台决定是int32还是int64
  • rune(文字符号)是int32同义词,表示一个unicode码点,4个字节
  • byte(字节)是uint8的同义词,表示一个字节
  • uniptr是无符号整数,大小不明确,但是可以存放完整的指针
  • 注意:Go里面类型是明确的,例如int和int32是不同的类型
1
2
3
4
The Go Programming Language Specification
Numeric types
uint8 the set of all unsigned 8-bit integers (0 to 255)
byte alias for uint8

1.2.float类型

  • 分为float32和float64
  • 在math包里面有最大值MaxFloat32/64

1.3.复数类型

  • 分为complex64和complex128,二者分别由float32和float64构成

1.4.布尔类型

  • true or false
  • bool类型无法隐式转换成数值???

二、字符串String

  • go的字符串是UTF-8字符的一个序列
    • 当ASCII码时,用一个字节
    • 其他字符根据需要占2-4个字节(JAVA是始终用2个字节)
  • 字符串是一种值类型,且值不可变,即创建某个文本后你无法再次修改这个文本的内容;也可以说,字符串是字节的定长数组。
  • 不可变意味着两个字符串可共用同一段地址空间,因此复制取子串的代价就很小
1
2
3
4
5
6
7
8
9
10
11
s := "hello"
// 获取子串,越界会产生panic
s[0:2] // he

// 字符串复制
t := s
// 并不是给s赋值,而是新创建了一个字符串 "helloa" 赋给s
s += "a"

fmt.Println(s) // helloa
fmt.Println(t) // hello

2.1.字符串字面量

字符串可以用引号或者反引号

  • 使用引号,为解释字符串(字符串字面量),引号内可以有转义字符,包括

    • \n:换行符
    • \r:回车符
    • \t:tab 键
    • \u 或 \U:Unicode 字符
    • \:反斜杠自身
  • 使用反引号,非解释字符串(原生字符串字面量),不转义,适用于正则、JSON等,如

    1
    `This is a raw string \n` //  `\n\` 会被原样输出。

2.2.字符串长度

  • 和 C/C++不一样,Go 中的字符串是根据长度限定,而非特殊字符\0
  • string 类型的零值为长度为零的字符串,即空字符串 ""
  • 一般的比较运算符 ( == 、!=、<、<=、>=、>)通过在内存中按字节比较来实现字符串的对比
  • 可以通过函数 len() 来获取字符串所占的字节长度,例如:len(str)。

字符串的内容(纯字节)可以通过标准索引法来获取,在中括号 [] 内写入索引,索引从 0 开始计数:

  • 字符串 str 的第 1 个字节:str[0]
  • 第 i 个字节:str[i - 1]
  • 最后 1 个字节:str[len(str)-1]

    需要注意的是,这种转换方案只对纯 ASCII 码的字符串有效
    例如 a := “你好”, str[0]并不是你的Unicode值

!!! 获取字符串中某个字节的地址的行为是非法的,例如:&str[i]

例1:数字字符串从后往前数,每3位加一个逗号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func SetComma(s string) string{
sLen := len(s)
if sLen <= 3{
return s
}
return SetComma(s[:sLen-3]) + "," + s[sLen -3:]
}

func main(){
fmt.Println(SetComma("123")) // 123
fmt.Println(SetComma("1234")) // 1,234
fmt.Println(SetComma("123456")) // 123,456
fmt.Println(SetComma("1234567")) // 1,234,567
}

2.3.字符串拼接

在循环中使用加号 + 拼接字符串,这种方式是增量地构建字符串,会导致多次内存分配和复制

1
s := s1 + s2

更好的办法是使用函数 strings.Join()

最高效的是使用字节缓冲(bytes.Buffer)进行拼接(将字符串看作是字节(byte)的切片(slice)来实现对其标准索引法的操作???)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
func intsToString(value []int) string{
var buf bytes.Buffer
buf.WriteByte('[')
for i, v := range value{
if i > 0{
buf.WriteByte(',')
}
buf.WriteString(strconv.Itoa(v))
}
buf.WriteByte(']')
return buf.String()
}

func main(){
fmt.Println(intsToString([]int{1,2,3})) // [1,2,3]
}

2.3.字符串与其他类型的转换

与字符串相关的类型转换一般通过 strconv 包实现

  • 整数转为字符串:
    1
    2
    3
    4
    5
    6
    x: = 123
    // 方式一
    y = fmt.Sprintf("%d", x)

    // 方式二
    z = strconv.Itoa(x)
  • 字符串转为整数:
    1
    2
    x, err = strconv.Atoi("123")
    y, err = strconv.ParseInt("123", 10, 64) // 转为十进制,最长为64位

2.4字符串相关的标准包

作为一种基本数据结构,每种语言都有一些对于字符串的预定义处理函数。Go 中提供了4个重要对字符串操作的标准包

  • bytes
  • strings
  • strconv
  • unicode

strings - 字符串查找

1
2
3
4
5
6
7
strings.HasPrefix(s, prefix string) bool  // 字符串以prefix开头
strings.HasSuffix(s, suffix string) bool // 字符串以suffix结尾
strings.Contains(s, substr string) bool // contains
strings.Index(s, str string) int
strings.LastIndex(s, str string) int
strings.IndexRune(s string, r rune) int // 非 ASCII 编码的字符在父字符串中的位置

strings - 字符串替换

Replace 用于将字符串 str 中的前 n 个字符串 old 替换为字符串 new,并返回一个新的字符串,如果 n = -1 则替换所有字符串 old 为字符串 new:

1
strings.Replace(str, old, new, n) string

三、常量

3.1.常量的定义

  • 常量是一种表达式,其可以保证在编译阶段就计算出表达式的值,并不需要等到运行时
  • 本质上都属于基本类型:布尔、字符串、数字

定义常量使用const关键字,例如:

1
2
// math.Pi更精确的近似
const pi = 3.14159

如果同时声明一组常量,除了第一项以外,其他项在等号右侧的表达式都可以省略

1
2
3
4
5
6
7
const (
a = 1
b
c = 2
d
)
fmt.Println(a, b, c, d) // 1 1 2 2

3.2.常量生成器iota

  • 常量的声明可以使用iota,创建一系列相关的值,无需逐个显示地写出
  • iota从0开始,逐项加1

例1:定义星期

1
2
3
4
5
6
7
type Weekday int
const (
Sunday Weekday = iota // 0
Monday // 1
Tuesday // 2
// ...
)

例2:定义字节单位

1
2
3
4
5
6
7
8
9
10
11
12
const (
// << 为左移运算
B = 1 << (10 * iota) // 1 * 2^0
KiB // 1 * 2^10 = 1024
MiB // 1 * 2^20 = 1024 * 1024
GiB // 1 * 2^30 = 1024 * 1024 * 1024
TiB // 1 * 2^40 = 1024 * 1024 * 1024 * 1024
Pib
Eib
Zib
YiB
)

3.3.无类型常量

许多常量不属于具体的某个类型,编译器将这些类型待定的常量表示成某些值,这些值比基本类型的数字精度更高

常量可以在定义的时候指定类型

1
const a float32 = 0.73700020033992349139414

也可以不指定具体的类型,就称为无类型常量

1
const b = 0.73700020033992349139414

例如3.2.中定义的字节单位,ZiB和YiB已经无法用任何int类型来存储了,但是他们都是合法的常量,并且可以使用以下表达式

1
fmt.Println(YiB / Zib) // 1024

无类型常量可以在被使用的时候,确定类型和精度

1
2
var x float32 = math.Pi
var y float64 = math.Pi

如果一开始给无类型常量确定了类型,精度可能就会丢失,并且需要显示地进行类型转换

1
2
3
const Pi32 float32 = math.Pi
var x float32 = Pi32
var y float64 = float64(Pi32)

Refs