基本数据类型
一、golang之基本数据类型
- 共有6大基本数据类型
- 整型
- 浮点型
- 复数类型
- 布尔类型
- 字符串类型
- 字符相关的byte和rune类型
二、整型
- 按有无符号分为两类,说白了就是有符号的包含负数、无符号不含
- 如有符号的
int8
类型范围是 (-128 到 127) 的整数,而无符号的uint8
类型范围是(0~255)的整数
1. 有符号(范围是负数、0和正数)
-
int8、int16、int32、int64
,后面的数字表示二进制时的长度 -
其中,
uint8
就是我们熟知的byte
型,int16
对应C语言中的short
型,int64
对应C语言中的long
型。 -
例子:
int8
范围是 (-128 到 127) 的整数,负数比正数多一个
2. 无符号(范围是0和正数)
-
uint8、uint16、uint32、uint64
-
例子:
uint8
范围是 (0 到 255) 的整数
3. 特殊整型
uint
: 32位操作系统上就是uint32
,64位操作系统上就是uint64
int
: 32位操作系统上就是int32
,64位操作系统上就是int64
uintptr
: 无符号整型,用于存放一个指针
- 注意: 在使用
int
和uint
类型时,不能假定它是32位或64位的整型,而是考虑int
和uint
可能在不同平台上的差异。
4. 数字字面量语法(先了解就好)
-
Go1.13版本之后引入了数字字面量语法 , 这样便于开发者以二进制、八进制或十六进制浮点数的格式定义数字 。共四种表示。
-
实例
1. v := 0b00101101, 代表二进制的 101101,相当于十进制的 45 2. v := 0o377,代表八进制的 377,相当于十进制的 255 3. v := 0x1p-2,代表十六进制的 1 除以 2²,也就是 0.25 4. v := 123_456 等于 123456
三、浮点型
-
Go语言支持两种浮点型数:
float32
和float64
-
浮点型和整型的变量直接不能直接相加,需要转换一边的格式成两边相同格式,但是在一个数字表达式中,却可以直接计算
1. 定义浮点型 package main import ( "fmt" ) func main() { a, b := 5.67, 8.97 fmt.Printf("type of a %T b %T\n", a, b) sum := a + b diff := a - b fmt.Println("sum", sum, "diff", diff) no1, no2 := 56, 89 fmt.Println("sum", no1+no2, "diff", no1-no2) } /* 打印结果: type of a float64 b float64 sum 14.64 diff -3.3000000000000007 sum 145 diff -33 */ 2. 浮点型变量和整型变量间的计算 package main import ( "fmt" ) func main() { i := 55 //int j := 67.8 //float64 sum := i + int(j) // 将j转换成int型 fmt.Println(sum) } 3. 数字表达式计算 package main import ( "fmt" ) func main() { var a = 5.9/8 // 可以这样定义 fmt.Printf("a's type %T value %v",a, a) } // 打印结果: a's type float64 value 0.7375
三、复数类型
- 分为
complex64
和complex128
-
complex64:实部和虚部都是 float32 类型的的复数
-
complex128:实部和虚部都是 float64 类型的的复数
-
1. 定义复数
1. 内置函数 complex 用于创建一个包含实部和虚部的复数。complex 函数的语法如下:
complex(x, y) // 表示定义一个实部为x,虚部为y的复数
2. 简短定义
a := 5 + 6i // 表示定义了一个实部为5,虚部为6的复数
2. 实例
package main
import (
"fmt"
)
func main() {
c1 := complex(5, 7)
c2 := 8 + 27i
cadd := c1 + c2
fmt.Println("sum:", cadd)
cmul := c1 * c2
fmt.Println("product:", cmul)
}
/*在上面的程序里,c1 和 c2 是两个复数。c1的实部为 5,虚部为 7。c2 的实部为8,虚部为 27。c1 和 c2 的和赋值给 `cadd` ,
而 c1 和 c2 的乘积赋值给 `cmul`。该程序将输出:*/
sum: (13+34i) product: (-149+191i)
四、布尔类型
-
同其他语言一样,就是两个布尔值
true
和false
-
注意:
- 布尔类型变量的默认值为
false
- 语言中不允许将整型强制转换为布尔型
- 布尔型无法参与数值运算,也无法与其他类型进行转换。
- 布尔类型变量的默认值为
五、字符串类型
-
Go 语言中的字符串是一个字节切片
-
Go 中的字符串是兼容 Unicode 编码的,并且使用 UTF-8 进行编码
-
字符串的值为双引号内的内容
-
关于字符串的其他的操作,见下面的第六点:字符相关的
byte
和rune
类型 -
Go 中的字符串是不可变的。一旦一个字符串被创建,那么它本身将无法被直接修改,但是可以通过其他方法修改
1. 常见的字符串转义符
转义符 | 解释 |
---|---|
\r |
回车符(返回首行) |
\n |
换行符(跳到下一行的同列位置) |
\t |
制表符 |
\' |
单引号 |
\" |
双引号 |
\\ |
反斜杠 |
2. 多行字符串
-
用反引号引住即可
// 单行字符串 s1 := "字符串内容" // 多行字符串 s1 := `第一行 第二行 第三行 `
-
反引号间换行将被作为字符串中的换行,但是所有的转义字符均无效,文本将会原样输出。
3. 字符串常用的方法
(1)字符串长度
-
len
方法返回的结果是字符串的utf8的字节长度,所以在处理当需要处理中文、日文或者其他复合字符时,会出现字符长度和字符串的字符长度不等的情况 -
此时用 [utf8 package] 包中的
func RuneCountInString(s string) (n int)
方法用来获取字符串的长度-
package main import ( "fmt" "unicode/utf8" ) func length(s string) { fmt.Printf("RuneCountInString 函数 求得的长度为 %s is %d\n", s, utf8.RuneCountInString(s)) } func len_get(s string) { fmt.Printf("len 函数 求得的长度为 %s is %d\n", s, len(s)) } func main() { word1 := "Señor" length(word1) len_get(word1) word2 := "Pets" length(word2) len_get(Pets) } /* RuneCountInString 函数 求得的长度为 Señor is 5 len 函数 求得的长度为 Señor is 6 RuneCountInString 函数 求得的长度为 Pets is 4 len 函数 求得的长度为 Pets is 4 */
-
(2)其他字符串常用方法
方法 | 介绍 |
---|---|
len(str) |
len() 返回字符串中字节的数量 |
+或fmt.Sprintf |
拼接字符串 |
strings.Split |
分割 |
strings.contains |
判断是否包含 |
strings.HasPrefix,strings.HasSuffix |
前缀/后缀判断 |
strings.Index(),strings.LastIndex() |
子串出现的位置 |
strings.Join(a[]string, sep string) |
join操作 |
六、字符相关的byte
和 rune
类型
-
Go 语言的字符有两种 :即
byte 和 rune
类型 -
字符串的每个元素就叫做字符。可以通过遍历或单个获取字符串中的字符。
-
字符使用单引号包裹起来
-
实例
a := '中' b := 'x' fmt.Println(a, b) // 20013 120
1. byte
-
byte
型是uint8
类型的别名,代表了ASCII码
的一个字符 -
Go 使用了特殊的 rune 类型来处理 Unicode,让基于 Unicode 的文本处理更为方便,也可以使用 byte 型进行默认字符串处理,性能和扩展性都有照顾
2. rune
-
rune
是 Go 语言的内建类型,它也是 int32 的别称,代表一个UTF-8字符
(注意是字符,一个汉字、一个字母都是一个字符) -
当需要处理中文、日文或者其他复合字符时,则需要用到
rune
类型
3. 总结(byte
和rune
的对比)
-
Go 使用了特殊的 rune 类型来处理 Unicode,让基于 Unicode 的文本处理更为方便,也可以使用 byte 型进行默认字符串处理,性能和扩展性都有照顾
-
实例
// 遍历字符串 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个字节组成,所以我们不能简单的按照字节去遍历一个包含中文的字符串,否则就会出现上面实例中输出中第一行的结果
-
go语言的字符串和python中的字符串类似, 底层都是一个byte数组 ,所以字符串的长度就是其二进制的长度,并且他们可以直接转换成二进制格式即
[]byte
类型。 -
**rune类型用来表示utf8字符,一个rune字符由一个或多个byte组成 **
4. 遍历字符串中的单个字符
-
由于字符串是一个字节切片,所以我们可以获取字符串的每一个字节
-
有两种方法
- 一个是手动转化后遍历(不转化会有bug)
- 一个是用
for range
遍历(推荐)
(1)手动转化后遍历
-
由于go中的字符有
rune
和byte
类型两种,所以,有的字符在打印的时候会出现和我们预期的不符和-
package main import ( "fmt" ) func printBytes(s string) { for i:= 0; i < len(s); i++ { fmt.Printf("%x ", s[i]) // %x 格式限定符用于指定 16 进制编码的byte类型 } } func printChars(s string) { for i:= 0; i < len(s); i++ { fmt.Printf("%c ",s[i]) // %c 格式限定符用于打印字符串的字符 } } func main() { name := "Hello World" printBytes(name) fmt.Printf("\n") printChars(name) fmt.Printf("\n") name = "Señor" printBytes(name) fmt.Printf("\n") printChars(name) } /* 打印结果 48 65 6c 6c 6f 20 57 6f 72 6c 64 H e l l o W o r l d 53 65 c3 b1 6f 72 S e à ± o r 这里的字符 ñ 在打印结果中,变成了 à ± 两个字符,在上一行的16进制编码byte类型中显示 ñ 占用了 c3 b1 两个字节,所以才打印了 à ± 两个字符 。 而我们通常预期的是:字符串中的一个字符应该就打印一个字符,这就造成了实际打印结果和我们的预期对不上 解决方法是使用 rune 类型进行字符串的转换,转换之后再进行字符的遍历,转换的代码如下 */ package main import ( "fmt" ) func printBytes(s string) { for i:= 0; i < len(s); i++ { fmt.Printf("%x ", s[i]) } } func printChars(s string) { runes := []rune(s) // 这里将字符串 s 转化成一个 rune 切片 for i:= 0; i < len(runes); i++ { fmt.Printf("%c ",runes[i]) } } func main() { name := "Hello World" printBytes(name) fmt.Printf("\n") printChars(name) fmt.Printf("\n\n") name = "Señor" printBytes(name) fmt.Printf("\n") printChars(name) } /* 打印结果,符合预期 48 65 6c 6c 6f 20 57 6f 72 6c 64 H e l l o W o r l d 53 65 c3 b1 6f 72 S e ñ o r */
-
(2)for range
遍历
range
内部给我们做了转化,返回的是是当前rune
的字节位置- **rune类型用来表示utf8字符,一个rune字符由一个或多个byte组成(即一个rune字符可以代表多个字节) **
package main
import (
"fmt"
)
func printCharsAndBytes(s string) {
for index, rune_s := range s {
fmt.Printf("%c starts at byte %d\n", rune_s, index)
}
}
func main() {
name := "Señor"
printCharsAndBytes(name)
}
/*
S starts at byte 0
e starts at byte 1
ñ starts at byte 2
o starts at byte 4
r starts at byte 5
o 的索引跳过了3直接变成了4,所以可以推断出 ñ 占了两个字节
*/
5. 修改字符串
-
Go 中的字符串是不可变的。一旦一个字符串被创建,那么它将无法被修改
-
要修改字符串,需要先将其转换成
[]rune
切片或[]byte
切片,完成后再转换为string
。无论哪种转换,都会重新分配内存,并复制字节数组 -
实例
func changeString() { s1 := "big" // 强制类型转换 byteS1 := []byte(s1) byteS1[0] = 'p' fmt.Println(string(byteS1)) // "pig" s2 := "白萝卜" runeS2 := []rune(s2) runeS2[0] = '红' fmt.Println(string(runeS2)) // "红萝卜" }
6. 构造字符串
-
两种构造方式
-
字节切片构造字符串
-
rune
切片构造字符串
-
(1)字节切片构造字符串
// 构造复合字符串 Café
1. 通过16进制字节切片构造
package main
import (
"fmt"
)
func main() {
byteSlice := []byte{0x43, 0x61, 0x66, 0xC3, 0xA9} // 用utf8的16进制的字节切片,转化成字符串
str := string(byteSlice)
fmt.Println(str) // 打印结果:cafe
}
2. 通过10进制字节切片构造
package main
import (
"fmt"
)
func main() {
byteSlice := []byte{67, 97, 102, 195, 169} // 用utf8的10进制的字节切片,转化成字符串
str := string(byteSlice)
fmt.Println(str)
}
两个程序都输出了 字符串 Café
***********由此可见,utf8编码的不同进制数的字节切片对构造字符串无影响***********
(2)rune
切片构造字符串
package main
import (
"fmt"
)
func main() {
runeSlice := []rune{0x0053, 0x0065, 0x00f1, 0x006f, 0x0072}
str := string(runeSlice)
fmt.Println(str)
}
// 在上面的程序中 runeSlice 包含字符串 Señor的 Unicode编码下的 16 进制的 字节串 。这个程序将会输出Señor
七、类型转换
-
Go语言中只有强制类型转换,没有隐式类型转换。该语法只能在两个类型之间支持相互转换的时候使用
-
强制类型转换的基本语法
T(表达式) // T表示要转换的类型 ,表达式包括变量、复杂算子和函数返回值等.
-
强制类型转换实例
1. 例1 func sqrtDemo() { var a, b = 3, 4 var c int // math.Sqrt()接收的参数是float64类型,需要强制转换 c = int(math.Sqrt(float64(a*a + b*b))) fmt.Println(c) } 2. 例2 func main() { i := 10 var j float64 = float64(i) // 若没有显式转换,该语句会报错 fmt.Println("j", j) }