go基础编程(三):类型

341 阅读8分钟

基础类型有哪些?

  • 布尔型(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)

欢迎关注我的公众号“晓冬编程”,原创技术文章第一时间推送。