基础类型有哪些?
- 布尔型(bool)
- 数值型
- 有符号整数:int8, int16, int32, int64, int
- 无符号整数:uint8, uint16, uint32, uint64, uint
- 浮点型:float32, float64
- 复合型:complex64, complex128
- 字节型:byte
- rune
- 字符串(string)
布尔类型(bool)
布尔类型表示布尔值,可以为true或false。
package main
import "fmt"
func main() {
a := true
b := false
fmt.Println("a:", a, "b:", b)
c := a && b
fmt.Println("c:", c)
d := a || b
fmt.Println("d:", d)
}
运行结果:
a: true b: false
c: false
d: true
有符号整数
-
int8: 表示8位有符号整数
- 大小: 8位
- 范围: -128至127
-
int16: 表示16位有符号整数
- 大小: 16位
- 范围: -32768至32767
-
int32:表示32位有符号整数
- 大小: 32位
- 范围: -2147483648至2147483647
-
int64: 表示64位有符号整数
- 大小: 64位
- 范围: -9223372036854775808至9223372036854775807
-
int: 表示32或64位整数,具体取决于基础平台。
- 大小:在32位操作系统中为32位,在64位操作系统中为64位。
- 范围:在32位系统中为-2147483648至2147483647,在64位系统中为-9223372036854775808至9223372036854775807
在go中我们可以使用Printf函数%T格式来打印变量的类型,如果要获取变量的大小,则使用unsafe包中的Sizeof函数(返回的是字节数)来获取。例如:
package main
import (
"fmt"
"unsafe"
)
func main() {
var num1 int = 10
num2 := 20
fmt.Println("num1 = ", num1, "num2:", num2)
fmt.Printf("num1的类型: %T, num1的大小: %d", num1, unsafe.Sizeof(num1))
fmt.Println()
fmt.Printf("num2的类型: %T, num2的大小: %d", num2, unsafe.Sizeof(num2))
}
运行结果:
num1 = 10 num2: 20
num1的类型: int, num1的大小: 8
num2的类型: int, num2的大小: 8
为什么int类型的变量大小是8呢? 这是因为int类型的大小与操作系统的位数有关,这里是8个字节,这就代表运行go程序的操作系统是64位的。
无符号整数
-
uint8: 表示8位无符号整数
- 大小: 8位
- 范围: 0至255
-
uint16:表示16位无符号整数
- 大小: 16位
- 范围: 0到65535
-
uint32: 表示32位无符号整数
- 大小: 32位
- 范围: 0至4294967295
-
uint64: 表示64位无符号整数
- 大小: 64位
- 范围: 0至18446744073709551615
-
uint: 表示32或64位无符号整数,具体取决于基础平台。 大小: 32位系统中为32位,64位系统中为64位。 范围:在32位系统中为0到4294967295,在64位系统中为0到18446744073709551615
关于有符号整数与无符号整数的解释
下面我们将以int8 与 uint8为例进行解释
var (
num1 uint8 = 255
num2 int8 = -128
)
以上我们定义了两个变量num1(无符号)和num2(有符号),对于num1我们能很快知道它的二进制数:11111111,而num2所对应的二进制数又是什么呢?
在二进制中表示负数时,一般会把最高位作为符号位来使用。符号位是0表示正数,符号位是1表示负数。
那-128的二进制数是多少呢?答案是:10000000。这个数是怎么得来的呢?在计算机中,二进制的存储都是有的补码,正数的原码、反码和补码相同,负数的原码是最高位为1,反码最高位不变,其余各位取反,补码为其反码+1。
10000000 //128原始值
01111111 //取反 反码
10000000 //加1,即获得补码
浮点类型
- float32: 32位浮点数
- float64: 64位浮点数 示例:
package main
import "fmt"
func main() {
num1, num2 := 5.67, 8.97
fmt.Printf("num1类型:%T num2类型:%T", num1, num2)
fmt.Println()
sum := num1 + num2
diff := num1 - num2
fmt.Println("sum:", sum, "diff:", diff)
}
运行结果:
num1类型:float64 num2类型:float64
sum: 14.64 diff: -3.3000000000000007
复合类型
complex64:具有float32实部和虚部的复数 complex128:具有float64实部和虚部的复数
想要构建实部和虚部的复数是通过内置函数complex完成的。
package main
import (
"fmt"
)
func main() {
complexNumber1 := complex(3, 4)
complexNumber2 := 5 + 6i
sum := complexNumber1 + complexNumber2
fmt.Println("和:", sum)
reduce := complexNumber1 + complexNumber2
fmt.Println("差:", reduce)
product := complexNumber1 * complexNumber1
fmt.Println("积:", product)
divide := complexNumber1 / complexNumber1
fmt.Println("除:", divide)
}
运行结果:
和: (8+10i)
差: (8+10i)
积: (-7+24i)
除: (1+0i)
关于复数运算法则: 假设c1=a+bi,c2=c+di是任意两个复数
- 加法法则:(a+bi)+(c+di)=(a+c)+(b+d)i
- 减法法则:(a+bi)-(c+di)=(a-c)+(b-d)i。
- 乘法法则:(a+bi)(c+di)=(ac-bd)+(bc+ad)i
- 除法法则:满足(c+di)(x+yi)=(a+bi)的复数x+yi(x,y∈R)叫复数a+bi除以复数c+di的商
其他数值类型
- byte: 是uint8的别名,代表了ASCII码的一个字符
- rune: 是int32的别名, 代表一个UTF-8 字符,当需要处理中文、日文或者其他复合字符时,则需要用到rune类型。 示例:
package main
import (
"fmt"
)
func main() {
a := 'a'
A := 65
var str string = "中国"
fmt.Printf("a的ascii码是:%d", int8(a))
fmt.Println()
fmt.Printf("A所对应字符是:%c", A)
fmt.Println()
fmt.Println("str所对应Unicode码是:", []rune(str))
}
运行结果:
a的ascii码是:97
A所对应字符是:A
str所对应Unicode码是: [20013 22269]
ASCII码、Unicode码、UTF-8是什么?
- ASCII码: 一种字符集,使用7 位二进制数(剩下的1位二进制为0)来表示所有的大写和小写字母,数字0 到9、标点符号,以及在美式英语中使用的特殊控制字符。例如:小写a的ASCII是:97,大写A的是:65
- Unicode码: 也是一种字符编码,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。例如:“中国” 在Unicode的编码是:20013和22269。
- UTF-8: 一种编码规则,对Unicode的一种可变长度字符编码。使用1~4字节为每个字符进行编码。一个ASCIl字符只需要一个字节编码,其他语言的字符(包括中日韩文字、东南亚文字、中东文字等)包含了大部分常用字,使用3字节编码。
字符串类型
在go中,字符串是字节的集合。
package main
import (
"fmt"
)
func main() {
var str string = "go基础编程(三)"
strRune := []rune(str)
fmt.Println("str长度:", len(str), " 第一个字符Unicode编码:", str[0])
fmt.Println("strRune长度和strRune第一个字符Unicode编码", len(strRune), strRune[0])
fmt.Println("str第一个和三个字符所对应的Unicode编码:", strRune[0], strRune[2])
fmt.Printf("str第一个和第三个字符: %c, %s", str[0], string(strRune[2]))
fmt.Println()
fmt.Printf("str第一个和第三个字符类型: %T , %T", strRune[0], strRune[2])
}
运行结果:
str长度: 23 第一个字符Unicode编码: 103
strRune长度和strRune第一个字符Unicode编码 9 103
str第一个和三个字符所对应的Unicode编码: 103 22522
str第一个和第三个字符: g, 基
str第一个和第三个字符类型: int32 , int32
类型转换
在go中不存在隐式类型转换,所有的类型转换都必须显式的声明。格式:
valueOfTypeB = typeB(valueOfTypeA)
示例:
package main
import "fmt"
func main() {
f := 3.14
b := 5
sum := int(f) + b
fmt.Println("sum: ", sum)
}
运行结果:
f的类型:float64
sum: 8
上面代码:int(f) 就是将float64转换成int类型。
类型断言
类型断言的作用主要是判断一个变量的类型是什么,其类型断言表达式:
value, ok := interface{}.(type)
- value: 是布尔(bool)类型的,它将代表类型判断的结果,true或false
- ok : 如果是true,那么被判断的值将会被自动转换为[]string类型的值,并赋给变量value,否则value将被赋予type类型的零值。 示例:
package main
import "fmt"
func main() {
// 定义一个interface{}类型变量,并使用float类型值”abc“初始化
var str interface{} = "go 基础编程(三)"
value, ok := str.(int)
fmt.Println(value, ok)
fmt.Println("-------------------")
switch str.(type) {
case int:
fmt.Println("我是int 类型")
case rune:
fmt.Println("我是rune类型")
case string:
fmt.Println("我是字符串类型")
default:
fmt.Println("没有匹配上")
}
}
运行结果:
0 false
-------------------
我是字符串类型
注意:
- 如果使用 .(type) 查询类型的变量不是 interface{} 类型,在编译时就会报错。 示例:
a := 123
a.(string)
运行结果:
invalid type assertion: a.(string) (non-interface type int on left)
- .(type)只能在switch中使用,否则会报错:
var b interface{} = 456
fmt.Println(b.(type))
运行结果:
use of .(type) outside type switch
- .(type)在switch中,要查询类型的变量不是 interface{} 类型,则在编译时会报如下错误:
str := "go 基础编程(三)"
switch str.(type) {
case int:
fmt.Println("我是int 类型")
case rune:
fmt.Println("我是rune类型")
case string:
fmt.Println("我是字符串类型")
default:
fmt.Println("没有匹配上")
}
运行结果:
cannot type switch on non-interface value str (type string)
欢迎关注我的公众号“晓冬编程”,原创技术文章第一时间推送。