Golang 学习笔记-----基础数据类型

整型

 

一般整型

整型分为以下两个大类: 按长度分为:int8、int16、int32、int64 对应的无符号整型:uint8、uint16、uint32、uint64

其中,uint8就是我们熟知的byte型,int16对应C语言中的short型,int64对应C语言中的long型。

类型 描述
uint8 无符号 8位整型 (0 到 255)
uint16 无符号 16位整型 (0 到 65535)
uint32 无符号 32位整型 (0 到 4294967295)
uint64 无符号 64位整型 (0 到 18446744073709551615)
int8 有符号 8位整型 (-128 到 127)
int16 有符号 16位整型 (-32768 到 32767)
int32 有符号 32位整型 (-2147483648 到 2147483647)
int64 有符号 64位整型 (-9223372036854775808 到 9223372036854775807)

特殊整型

类型 描述
uint 32位操作系统上就是uint32,64位操作系统上就是uint64
int 32位操作系统上就是int32,64位操作系统上就是int64
uintptr 无符号整型,用于存放一个指针

注意: 在使用int和 uint类型时,不能假定它是32位或64位的整型,而是考虑intuint可能在不同平台上的差异。

注意事项 获取对象的长度的内建len()函数返回的长度可以根据不同平台的字节长度进行变化。实际使用中,切片或 map 的元素数量等都可以用int来表示。在涉及到二进制传输、读写文件的结构描述时,为了保持文件的结构不会受到不同编译目标平台字节长度的影响,不要使用int和 uint

浮点型

 Golang 学习笔记-----基础数据类型_第1张图片

复数型

Golang 学习笔记-----基础数据类型_第2张图片

布尔类型

Go语言中以bool类型进行声明布尔型数据,布尔型数据只有true(真)false(假)两个值。

注意:

  1. 布尔类型变量的默认值为false
  2. Go 语言中不允许将整型强制转换为布尔型.
  3. 布尔型无法参与数值运算,也无法与其他类型进行转换。

字符类型 

字符串中的每一个元素叫做“字符”,在遍历或者单个获取字符串元素时可以获得字符。
 

Go语言的字符有以下两种:

一种是 uint8 类型,或者叫 byte 型,代表了 ASCII 码的一个字符。
另一种是 rune 类型,代表一个 UTF-8 字符,当需要处理中文、日文或者其他复合字符时,则需要用到 rune 类型。
rune 类型等价于 int32 类型。


 

byte 类型是 uint8 的别名,对于只占用 1 个字节的传统 ASCII 编码的字符来说,完全没有问题,
例如 var ch byte = 'A',字符使用单引号括起来。
在 ASCII 码表中,A 的值是 65,使用 16 进制表示则为 41,所以下面的写法是等效的:
var ch byte = 65 或 var ch byte = '\x41'      //(\x 总是紧跟着长度为 2 的 16 进制数)
另外一种可能的写法是\后面紧跟着长度为 3 的八进制数,例如 \377。

 


Go语言同样支持 Unicode(UTF-8),因此字符同样称为 Unicode 代码点或者 runes,
并在内存中使用 int32 来表示。
在文档中,一般使用格式 U+hhhh 来表示,其中 h 表示一个 16 进制数。
在书写 Unicode 字符时,需要在 16 进制数之前加上前缀\u或者\U。
因为 Unicode 至少占用 2 个字节,所以我们使用 int16 或者 int 类型来表示。
如果需要使用到 4 字节,则使用\u前缀,如果需要使用到 8 个字节,则使用\U前缀。

var ch int = '\u0041'
var ch2 int = '\u03B2'
var ch3 int = '\U00101234'
fmt.Printf("%d - %d - %d\n", ch, ch2, ch3) // integer
fmt.Printf("%c - %c - %c\n", ch, ch2, ch3) // character
fmt.Printf("%X - %X - %X\n", ch, ch2, ch3) // UTF-8 bytes
fmt.Printf("%U - %U - %U", ch, ch2, ch3) // UTF-8 code point
输出:

65 - 946 - 1053236
A - β - r
41 - 3B2 - 101234
U+0041 - U+03B2 - U+101234

格式化说明符%c用于表示字符,当和字符配合使用时,
%v或%d会输出用于表示该字符的整数,%U输出格式为 U+hhhh 的字符串

 

// 遍历字符串
func traversalString() {
	s := "hello沙河"
	for i := 0; i < len(s); i++ { //byte
		fmt.Printf("%v(%c) ", s[i], s[i])
	}
	fmt.Println()
	for _, r := range s { //rune
		fmt.Printf("%v(%c) ", r, r)
	}
	fmt.Println()
}
输出:

104(h) 101(e) 108(l) 108(l) 111(o) 230(æ) 178(²) 153() 230(æ) 178(²) 179(³) 
104(h) 101(e) 108(l) 108(l) 111(o) 27801(沙) 27827(河) 
因为UTF8编码下一个中文汉字由3~4个字节组成,所以我们不能简单的按照字节去遍历一个包含中文的字符串,
否则就会出现上面输出中第一行的结果。

字符串底层是一个byte数组,所以可以和[]byte类型相互转换。
字符串是不能修改的 字符串是由byte字节组成,所以字符串的长度是byte字节的长度。 
rune类型用来表示utf8字符,一个rune字符由一个或多个byte组成。

 字符串类型

在 Golang 中,字符串是一种基本类型,这一点和 C 语言不同。C 语言没有原生的字符串类型,而是使用字符数组来表示字符串,并以字符指针来传递字符串。Golang 中的字符串是一个不可改变的 UTF-8 字符序列,一个 ASCII 码占用 1个字节,其它字符根据需要占用 2-4 个字节,这一点与其它主流的开发语言( C++、Java、Python)是不同的。这样设计的好处有两个:

  • 减少内存的使用,节约硬盘空间
  • 统一编码格式(UTF-8)有助于减少读取文件时的编码和解码工作

字符串的声明与初始化

声明和初始化字符串非常容易:

s := "hello world"

上面的代码声明了字符串变量 s,其内容为 "hello world"。在 Golang 中字符串的值是不可变的,当创建一个字符串后,无法再次修改这个字符串的内容。所以如果你通过下面的代码修改 s 中的内容就会发生编译错误:

s := "hello nick"

字符串字面量

Golang 支持两种类型的字符串字面量:

  • 解释型字符串
  • 非解释型字符串

所谓的解释型字符串就是用双引号括起来的字符串(""),其中的转义字符会被替换掉,这些转义字符包括:

复制代码

\a    // 响铃     
\b    // 退格
\f    // 换页
\n    // 换行
\r    // 回车
\t    // 制表符
\u    // Unicode 字符
\v    // 垂直制表符
\"    // 双引号
\\    // 反斜杠

复制代码

非解释型字符串是指用反引号( ` 一般在 Esc 键下面,数字键 1 的左边)括起来的字符串。在非解释型字符串中的转义字符不会被解释,并且还支持换行。

看下面的 demo:

复制代码

package main
import "fmt"

func main() {
    s1 := "Hello\nWorld!"
    s2 := `Hello\n
           nick!`
    fmt.Println(s1)
    fmt.Println(s2)
}

复制代码

运行上面的代码,输出如下:

反单引号可以跨行,并且引号内的所有内容都会直接输出,包括转义字符和空格缩进等。而双引号则不能换行,并且会解析转义字符。

字符串的长度

内置函数 len() 可以返回一个字符串中的字节数(注意,不是 rune 字符数目),索引操作 s[i] 可以返回字符串 s 中第 i 个字节的值。

s := "abc你"
fmt.Printf("字符串的字节长度是:%d\n", len(s))
for i := 0; i < len(s); i++ {
    fmt.Println(s[i])
}

字符串的字节长度是:6

97         // a
98         // b
99         // c
228        // 你
189        // 你
160        // 你

最后的三个字节组成了汉字 "你"。

如果要获取字符串中字符的个数,可以先把字符串转换成 []rune 类型,然后用 len() 函数获取字符个数:

s := "abc你"
r := []rune(s)
fmt.Print(len(r))

这次输出的结果为:4。

从字符串中截取内容

可以通过下面的语法截取字符串中的内容:

s := "abcdef"
s1 := s[1:4]

此时 s1 的内容为 "bcd",该语法通过下标索引的方式截取字符串中的内容,特点是 "左含右不含"。也就是说新的子串包含源串索引为 1 的字符,而不包含源串索引为 4 的字符。
如果要从源串的开始处截取可以省略第一个索引:

s2 := s[:4]

s2 的内容为 "abcd"。
如果要从源串的某个位置开始一直截取到末尾,可以省略第二个索引:

s3 := s[2:]

s3 的内容为 "cdef"。

访问越界问题
在通过索引访问字符串或者是截取子串时需要考虑索引越界的问题,如果试图访问超出字符串索引范围的字节将会在运行时导致 panic 异常:

s4 := s[2:10]

Golang 学习笔记-----基础数据类型_第3张图片

连接字符串

使用 + 号可轻松的把字符串连接起来:

s := "hello"
s1 := " "
s2 := "world"
s3 := s + s1 + s2

此时 s3 的内容为 "hello world"。

遍历字符串

由于可以通过下标索引字符串中的字节,所以可以用这种方式遍历字符串:

s := "abc你好"
for i := 0; i < len(s); i++ {
    fmt.Printf("%c", s[i])
}

输出的结果如下:
abc你好
可见在字符串中含有非单字节的字符时这种方法是不正确的。range 函数能解决这个问题:

for _, v := range s {
    fmt.Printf("%c", v)
}

这次输出的结果为:
abc你好

修改字符串

在 Golang 中,不能修改字符串的内容,也就是说不能通过 s[i] 这种方式修改字符串中的字符。要修改字符串的内容,可以先将字符串的内容复制到一个可写的变量中,一般是 []byte 或 []rune 类型的变量,然后再进行修改。
如果要对字符串中的字节进行修改,就转换为 []byte 类型,如果要对字符串中的字符修改,就转换为 []rune 类型,在转换类型的过程中会自动复制数据。

修改字符串中的字节(用 []byte)
对于那些单字节字符来说,可以通过这种方式进行修改:

s := "Hello 世界"
b := []byte(s)    // 转换为 []byte,数据被自动复制
b[5] = ','        // 把空格改为半角逗号
fmt.Printf("%s\n", s)
fmt.Printf("%s\n", b)

输出结果为:
Hello 世界
Hello,世界

修改字符串中的字符(用 []rune)

s := "Hello 世界"
b := []rune(s)    // 转换为 []rune,数据被自动复制
b[6] = '中'
b[7] = '国'
fmt.Println(s)
fmt.Println(string(b))

输出结果为:
Hello 世界
Hello 中国

注意:和 C/C++ 不一样,Golang 语言中的字符串是根据长度限定的,而非特殊的字符 \0。string 类型的 0 值是长度为 0 的字符串,即空字符串 ""。

strings 包

strings 是非常重要的一种基本类型,所需要执行的操作繁多且比较复杂,因此一般的编程语言都会额外封装一些方法用于处理字符串。Golang 语言的标准库中也存在这样一个名称为 strings 的库。下面介绍一些 strings 库的常见用法。

检查是否包含子串
判断一个字符串中是否包含某个子串是经常遇到的一种字符串操作,在 strings 包中,可以使用 Contains() 函数进行判断:

s := "A good tree bears good fruit"
fmt.Printf("%t\n", strings.Contains(s, "tree"))

输出的结果为:true。

如果要检查字符串是不是以某个子串开始的,可以使用 HasPrefix() 函数:

s := "A good tree bears good fruit"
fmt.Printf("%t\n", strings.HasPrefix(s, "A good"))

输出的结果为:true。

如果要检查字符串是不是以某个子串结束的,可以使用 HasSuffix() 函数:

s := "A good tree bears good fruit"
fmt.Printf("%t\n", strings.HasSuffix(s, "good fruit"))

输出的结果为:true。

与 Contains() 函数相比,ContainsAny() 函数能够匹配更广泛的内容,并且可以匹配 Unicode 字符:

复制代码

fmt.Println(strings.Contains("failure", "a & o"))                // false
fmt.Println(strings.Contains("foo", ""))                         // true
fmt.Println(strings.Contains("", ""))                            // true

fmt.Println(strings.ContainsAny("failure", "a & o"))             // true
fmt.Println(strings.ContainsAny("foo", ""))                      // false
fmt.Println(strings.ContainsAny("", ""))                         // false

fmt.Println(strings.ContainsAny("好树结好果", "好树"))             // true

复制代码

获取子串的索引
在 Golang  中,字符串中的字符都有一个索引值,很多时候我们要操作字符串,就必须先获取字符在字符串中的索引值。在 strings 包中 Index 函数可以返回指定字符或字符串的第一个字符的索引值,如果不存在则返回 -1:

fmt.Println(strings.Index("Hi I'm Nick, Hi", "Nick"))                // 7
fmt.Println(strings.Index("Hi I'm Nick, Hi", "Hi"))                  // 0
fmt.Println(strings.Index("Hi I'm Nick, Hi", "abc"))                 // -1
fmt.Println(strings.LastIndex("Hi I'm Nick, Hi", "Hi"))              // 13

LastIndex 函数返回匹配到的最后一个子串的索引值。
如果处理包含多个字节组成的字符的字符串,需要使用 IndexRune 函数来对字符进行定位:

fmt.Println(strings.IndexRune("好树结好果", '树'))     // 3

注意这里返回的是 3,这是 "树" 的第一个字节在字符串中的位置。

替换字符串
替换字符串最常用的方式其实是通过正则匹配去替换的,其灵活度更高。而 Golang 则为比较基础的替换操作提供了 Replace 函数:

fmt.Println(strings.Replace("你好世界", "世界", "地球", 1))

输出的结果为:你好地球
strings.Replate(str, old, new, n) 函数一共有 4 个参数,第一个为源字符串,第二个表示源字符串中需要被替换掉的字符串,第三个是替换的内容,最后一个 n 则表示替换匹配到的前 n 个记录。

大小写转换
操作字符串就免不了大小写转换,ToLower() 函数把字符串转换为小写,ToUpper() 函数把字符串转换为大写:

s := "A good tree bears good fruit"
s1 := "HOW ARE YOU?"
fmt.Printf("%s\n", strings.ToUpper(s))
fmt.Printf("%s\n", strings.ToLower(s1))

输出的结果如下:
A GOOD TREE BEARS GOOD FRUIT
how are you?

修剪
在处理用户的输入时,去掉字符串前后多余的空白字符非常重要,strings 包中提供了 Trem()、TrimLeft() 和 TrimRight() 来实现这个功能:

fmt.Printf("%q\n", strings.Trim(" Golang ", " "))
fmt.Printf("%q\n", strings.TrimLeft(" Golang ", " "))
fmt.Printf("%q\n", strings.TrimRight(" Golang ", " "))

输出的结果如下:
"Golang"
"Golang "
" Golang"

分隔与拼接
Split() 函数按照指定的分隔符分隔字符串并返回一个切片:

fmt.Printf("%q\n", strings.Split("a,b,c", ","))
fmt.Printf("%q\n", strings.Split("a boy a girl a cat", "a "))
fmt.Printf("%q\n", strings.Split("xyz", ""))

输出的结果如下:
["a" "b" "c"]
["" "boy " "girl " "cat"]
["x" "y" "z"]

Join() 函数则会将元素类型为 string 的切片使用分隔符拼接组成一个字符串:

fmt.Printf("%q\n", strings.Join([]string{"boy", "girl", "cat"}, ";"))

输出的结果如下:
"boy;girl;cat"

strconv 包

这个包主要用于字符串与其他类型的转换。这里我们简单的看下如何通过 Itoa() 函数把字符串转换为整型:

num, _ := strconv.Atoi("123")
num += 5
fmt.Printf("%d\n", num)

上面这段代码输出的结果为:128
这说明字符串 "123" 被成功的转换成了十进制整数 123,随后还进行了加法运算。

总结

对于任何一门编程语言来说,字符串的定义和相关操作都是非常基础的内容。从本文我们可以看到,Golang  的字符串类型原生支持 Unicode,操作起来也非常的方便,特别是提供了便利的 strings 包。这让我们能够轻松的了解并使用 Golang 的 string 类型。

 

你可能感兴趣的:(Golang)