13 基本数据类型之整型

基本数据类型之整型

一 整型介绍

Go语言中提供了不同类型的整型,主要分为有符号和无符号两大类

类型 描述
uint8 无符号 8位整型 (0 到 255),对应go语言的byte类型
uint16 无符号 16位整型 (0 到 65535)
uint32 无符号 32位整型 (0 到 4294967295)
uint64 无符号 64位整型 (0 到 18446744073709551615)
int8 有符号 8位整型 (-128 到 127)
int16 有符号 16位整型 (-32768 到 32767),对应C语言中的short类型
int32 有符号 32位整型 (-2147483648 到 2147483647),对应go语言的rune类型
int64 有符号 64位整型 (-9223372036854775808 到 9223372036854775807),对应C语言中的long类型

此外还有三个特殊的整型,其中int是所有整型里应用最广泛的,也是类型推导的默认类型。

类型 描述
uint 在32位平台下大小与unit32一样, 64位平台下大小与unit64一样
int 在32位平台下大小与int32一样, 64位平台下大小与int64一样
uintptr 无符号整型,没有指定具体的bit大小但是足以容纳指针,所以uintptr通常用于存放一个指针。uintptr类型只有在底层编程是才需要,特别是Go语言和C语言函数库或操作系统接口相交互的地方

二 声明与初始化

声明语法如下,重点关注一下字面量即可

var 变量名 整型类型 = 初始化表达式/字面量

Go1.13版本之后引入了数字字面量语法Number literals syntax,这样便于开发者以二进制、八进制或十六进制浮点数的格式定义数字,例如:

// 无前缀代表十进制
v:=10
// 以0b为前缀的二进制
v := 0b00101101
// 以0o为前缀的八进制
v := 0o711 
// 以0x为前缀的十六进制
v := 0xap-2,代表十六进制的 a 除以 2²,也就是十进制的10/4得 2.5。

// 而且还允许我们用 _ 来分隔数字
v := 123_456 等于 123456。

ps:我们可以借助fmt函数来将一个整数以不同进制形式展示。

x:=57
//x:=0b111001 
//x:=0o71
//x:=0x39

// 输出(不带前缀)
fmt.Printf("%d\n",x) // 57
fmt.Printf("%b\n",x) // 111001
fmt.Printf("%o\n",x) // 71
fmt.Printf("%x\n",x) // 39

// 输出(带前缀)
fmt.Printf("%#d\n",x) // 57
fmt.Printf("%#b\n",x) // 0b111001
fmt.Printf("%#o\n",x) // 071
fmt.Printf("%#x\n",x) // 0x39

// [1]代表取得是第一个操作数,[2]代表取得是第二个操作数
x:=57
y:=33
fmt.Printf("%[1]d   %[1]b   %[1]o  %[1]x,%[2]d   %[2]b   %[2]o  %[2]x ",x,y)

注意点

  • 1、go语言是强类型语言,数据类型有明确的边界,例如:int在32位平台下被解析成了32位,虽然它的宽度与int32一样,但它与int32也是不同的类型,int64同理,在需要将int当作int32类型的地方需要我们自己做显式的类型转换操作/强制转换,反之亦然,
var x int
var y int64
fmt.Println(x + y)  // 报错:mismatched types int and int64
  • 2、len()返回的是一个int类型,实际使用中,切片或 map 的元素数量等都可以用int来表示。
  • 3、在涉及到二进制传输、读写文件的结构描述时,为了保持文件的结构不会受到不同编译目标平台字节长度的影响,不要使用intuint

三 数据类型转换

整型与浮点型为兼容类型,可以相互转换,本节我们主要介绍:整型、浮点型转为—>整型

一:显式转换规则如下:

  • 1.1、无类型的量(无类型的整数、无类型的浮点数)可以转为整型,超出目标类型值域范围就报错

    例1:无类型的整型字面量—>整型,超出目标整型的值域范围就会报错

    int(10)      // ok
    uint8(256)   // 错误,无类型的整型字面量256超过uint8最大存值范围

    例2:无类型的浮点型字面量—>整型,若浮点数需要被截断就会报错,需要截断也就是超出了范围

    int(10.0)    // ok,字面量10.0不需要截断就可以转换为整型
    int(10.3)    // 错误,需要截断就不行
    
    复数转整型也是一个道理
    fmt.Println(int(10+2i))   // 错误,需要截断就不行
  • 1.2、有类型的量(有类型的整数、有类型的浮点数)也可以转为整型,超出目标类型值域范围不报错,但是整数会溢出、浮点数则丢失精度,应该尽量避免

    例1:有类型的整数—>整型,超出值域范围不报错,但是值会溢出

    var x int32 = 256
    fmt.Println(uint8(x))  // 大尺寸转小尺寸,值溢出,输出为0

    例2:有类型的浮点数—>整型,存在需要截断的值不报错,但是会直接丢到小数点后的内容、精度丧失

    var f float64 = 10.9 
    fmt.Println(int(f))   // 10

    强调:我们应该尽量避免溢出或丢失精度!!!
    大多数情况下整型的转换都不要超过目标类型值域,如此,则只改变了类型,并未改变数值,看似没啥用,其实不然,在有些场景下你必须这么做来告诉编译器如何解释这个值,以达到遵循强类型原则的目的,如下

    var x int32
    y := 666 // y将会被自动推导为int类型
    // x = y // 编译错误,因为y是int类型,而x是int32类型,所以无法将y的值赋值给x
    x = int32(y) // 使用强制类型转换可以解决上述错误,此处并没有改变y的值,只是告诉了编译器y的类型为int32,与x的类型保存一致,因此可以赋值
    
    var apples int32 = 1
    var oranges int16 = 2
    //var compote int = apples + oranges  // 编译错误:算术和逻辑运算的二元操作中必须是相同的类型。
    var compote = int(apples) + int(oranges)  // 需要一个显式的转换将一个值从一种类型转化位另一种类型,虽然这偶尔会导致需要很长的表达式,但是它消除了所有和类型相关的问题,而且也使得程序容易理解。
    fmt.Println(compote) // 3

二:隐式转换,只针对无类型的量,底层发生的就是T(x)

var age uint8
age = 256 // 底层隐式执行uint8(256),抛出异常:constant 256 overflows uint8

四 基本操作

4.1 二元运算

整型属于数字,数字之间支持加减乘除等算数运算以及比较运算,但仅限于同类型之间,非同类型经隐式或显式转换成相同类型后也可以,示例如下

(1)算数运算

// 例1:显式转换
var x int64 = 10
var y int32 = 20
fmt.Println(x + y)  // 错误:mismatched types int64 and int32
fmt.Println(x + int64(y))  // 正确

// 例2:隐式转换
var x int64 = 10
fmt.Println(x + 10.3) // 隐式转换int64(10.3),错误:constant 10.3 truncated to integer
fmt.Println(x + 10.0) // 隐式转换int64(10.0),正确,结果为:20

// 例3:显式转换
var x int32 = 1
var y int16 = 2
var z = int(x) + int(y)
fmt.Println(z) // 3

(2)相等性比较

// 同类型ok
var x int64 = 10
var y int64 = 10
fmt.Println(x == y) // true
fmt.Println(x != y) // false

// 不同类型则编译错误
// 再次强调:无论什么类型,宽度或长度都是其重要的组成部分
var i int32 = 10
var j int64 = 20
fmt.Println(i == j)  // 编译错误

// 涉及到无类型的量(无类型的常量或字面量),会隐式转换成相应类型,转换合法就可以进行相等性判断。
var x int64 = 10
fmt.Println(x == 10)  // 可以比较,因为底层:x == int64(10),编译通过
fmt.Println(x == 10.3) // 报错,因为底层:x == int64(10.3),编译错误

(3)比大小

var x int32 = 10
var y int64 = 3

// 显式
fmt.Println(x > y)          // 编译错误
fmt.Println(x > int32(y))   // 编译通过

// 隐式
fmt.Println(x > 3)      // x > int32(3),编译通过
fmt.Println(x > 3.1)    // x > int32(3.1),编译失败

// 隐式:
fmt.Println(10 > 3.1)   // 优先级float>int,所以底层float64(10) > float64(3.1),编译通过

五 在函数参数中传递

值传递

上一篇
下一篇
Copyright © 2022 Egon的技术星球 egonlin.com 版权所有 帮助IT小伙伴学到真正的技术