运维八一 运维八一
首页
运维杂记
编程浅尝
周积跬步
专栏
生活
关于
收藏
  • 分类
  • 标签
  • 归档
Source (opens new window)

运维八一

运维,运维!
首页
运维杂记
编程浅尝
周积跬步
专栏
生活
关于
收藏
  • 分类
  • 标签
  • 归档
Source (opens new window)
  • Go

    • 前言

    • Go基础知识

    • Go基本语法

    • 实战项目:简单web服务

    • 基本数据类型

      • 内置类型
      • 内置函数
      • 数字 int
        • 3.数字(整型int)
          • 3.1 数值类型
          • 3.1.1 整型
          • 平台无关整型
          • 平台相关整型
          • 整型的溢出问题
          • 字面值与格式化输出
          • 字面值
          • 格式化输出
          • 3.1.2 浮点型
          • 浮点型的二进制表示
          • 字面值与格式化输出
          • 字面值
          • 格式化输出
          • 3.1.3 复数类型
          • 复数类型种类
          • 字面值和格式化输出
          • 字面值
          • 格式化输出
          • 3.1.4 自定义数值类型
          • type关键字
          • 类型别名(Type Alias)
          • 3.2 数字定义
      • 布尔值 bool
      • 字符串 string
      • 数组 array
      • 切片 sice
      • 字典 map
      • 指针
    • 内置运算符

    • 分支和循环

    • 函数 function

    • 结构体 struct

    • 方法 method

    • 实战项目:跟踪函数调用链

    • 接口 interface

    • 并发 concurrency

    • 指针

    • 实战项目:实现轻量级线程池

    • 实战项目:实现TCP服务器

    • go常用包

    • Gin框架

    • go随记

  • Python

  • Shell

  • Java

  • Vue

  • 前端

  • 编程浅尝
  • Go
  • 基本数据类型
lyndon
2022-06-07
目录

数字 int

# 3.数字(整型int)

Go 语言的类型

  1. 基本数据类型
  2. 复合数据类型
  3. 接口类型

日常 Go 编码中使用最多的就是基本数据类型

# 3.1 数值类型

数值类型:整型、浮点型、复数类型

# 3.1.1 整型

**主要用来表示现实世界中整型数量。**比如:人的年龄、班级人数等。

它分为==平台无关整型、平台相关整型==。它们的区别主要就在,这些整数类型在不同 CPU 架构或操作系统下面,它们的长度是否是一致的。

# 平台无关整型

在任何 CPU 架构或任何操作系统下面,长度都是固定不变的。

Go 提供的平台无关整型:

img

关于字节:

字节也叫 Byte,是计算机数据的基本存储单位。

8bit(位)=1Byte(字节) 1024Byte(字节)=1KB 1024KB=1MB 1024MB=1GB 1024GB=1TB 。

在电脑里一个中文字是占两个字节的。

分成两类:==有符号整型(int8-int64)和无符号整型(uint8-uint64)。==

两者的本质差别在于最高二进制位(bit 位)是否被解释为符号位,这点会影响到无符号整型与有符号整型的取值范围。

下图中的这个 8 比特(一个字节)的整型值,当它被解释为无符号整型 uint8 时,和它被解释为有符号整型 int8 时表示的值是不同的:

img

在同样的比特位表示下,当最高比特位被解释为符号位时,它代表一个有符号整型(int8),它表示的值为 -127;当最高比特位不被解释为符号位时,它代表一个无符号整型 (uint8),它表示的值为 129。

Go 采用 2 的补码(Two’s Complement)作为整型的比特位编码方法

因此,我们不能简单地将最高比特位看成负号,把其余比特位表示的值看成负号后面的数值。Go 的补码是通过原码逐位取反后再加 1 得到的,比如,我们以 -127 这个值为例,它的补码转换过程就是这样的:

img

# 平台相关整型

长度会根据运行平台的改变而改变。

Go 语言原生提供了三个平台相关整型,它们是 int、uint 与 uintptr

img

注意:在编写有移植性要求的代码时,千万不要强依赖这些类型的长度。

在目标运行平台上的长度可以通过 unsafe 包提供的 SizeOf 函数来获取,比如在 x86-64 平台上,它们的长度均为 8:

var a, b = int(5), uint(6)
var p uintptr = 0x12345678
fmt.Println("signed integer a's length is", unsafe.Sizeof(a)) // 8
fmt.Println("unsigned integer b's length is", unsafe.Sizeof(b)) // 8
fmt.Println("uintptr's length is", unsafe.Sizeof(p)) // 8
1
2
3
4
5
# 整型的溢出问题

整型溢出:整型参与运算后,结果超出了这个整型的值边界。

出现溢出情况后,对应的整型变量的值依然会落到它的取值范围内,只是结果值与预期不符,导致程序逻辑出错。比如这就是一个无符号整型与一个有符号整型的溢出情况:

var s int8 = 127
s += 1 // 预期128,实际结果-128

var u uint8 = 1
u -= 2 // 预期-1,实际结果255
1
2
3
4
5
# 字面值与格式化输出
# 字面值

Go 语言在设计开始,就继承了 C 语言关于**数值字面值(Number Literal)**的语法形式。

早期 Go 版本支持十进制、八进制、十六进制的数值字面值形式,比如:

a := 53        // 十进制
b := 0700      // 八进制,以"0"为前缀
c1 := 0xaabbcc // 十六进制,以"0x"为前缀
c2 := 0Xddeeff // 十六进制,以"0X"为前缀
1
2
3
4

Go 1.13 版本中,Go 又增加了对二进制字面值的支持和两种八进制字面值的形式,比如:

d1 := 0b10000001 // 二进制,以"0b"为前缀
d2 := 0B10000001 // 二进制,以"0B"为前缀
e1 := 0o700      // 八进制,以"0o"为前缀
e2 := 0O700      // 八进制,以"0O"为前缀
1
2
3
4

为提升字面值的可读性,Go 1.13 版本还支持在字面值中增加数字分隔符“_”,分隔符可以用来将数字分组以提高可读性。

比如每 3 个数字一组,也可以用来分隔前缀与字面值中的第一个数字:

a := 5_3_7   // 十进制: 537
b := 0b_1000_0111  // 二进制位表示为10000111 
c1 := 0_700  // 八进制: 0700
c2 := 0o_700 // 八进制: 0700
d1 := 0x_5c_6d // 十六进制:0x5c6d
1
2
3
4
5

注意:Go 1.13 中增加的二进制字面值以及数字分隔符,只在 go.mod 中的 go version 指示字段为 Go 1.13 以及以后版本的时候,才会生效,否则编译器会报错。

# 格式化输出

通过标准库 fmt 包的格式化输出函数,将一个整型变量输出为不同进制的形式。

比如下面就是将十进制整型值 59,格式化输出为二进制、八进制和十六进制的代码:

var a int8 = 59
fmt.Printf("%b\n", a) //输出二进制:111011
fmt.Printf("%d\n", a) //输出十进制:59
fmt.Printf("%o\n", a) //输出八进制:73
fmt.Printf("%O\n", a) //输出八进制(带0o前缀):0o73
fmt.Printf("%x\n", a) //输出十六进制(小写):3b
fmt.Printf("%X\n", a) //输出十六进制(大写):3B
1
2
3
4
5
6
7

# 3.1.2 浮点型

浮点型的使用场景主要集中在科学数值计算、图形图像处理和仿真、多媒体游戏以及人工智能等领域。

# 浮点型的二进制表示

Go 语言提供了 float32 与 float64 两种浮点类型,它们分别对应的就是 IEEE 754 中的单精度与双精度浮点数值类型。

注意,Go 语言中没有提供 float 类型,Go 提供的浮点类型都是平台无关的。

float32 与 float64 异同点:

相同点:变量的默认值都为 0.0;

不同点:占用的内存空间大小不一样,可以表示的浮点数的范围与精度也不同。

单精度(float32)与双精度(float64)浮点数在阶码和尾数上的不同:

img

将一个十进制形式的浮点值 139.8125,转换为 IEEE 754 规定中的那种单精度二进制表示:

步骤一:把这个浮点数值的整数部分和小数 部分,分别转换为二进制形式(后缀 d 表示十进制数,后缀 b 表示二进制数):

  • 整数部分:139d => 10001011b;
  • 小数部分:0.8125d => 0.1101b(十进制小数转换为二进制可采用“乘 2 取整”的竖式计算)。

这样,原浮点值 139.8125d 进行二进制转换后,就变成 10001011.1101b。

步骤二:移动小数点,直到整数部分仅有一个 1,也就是 10001011.1101b => 1.00010111101b。

我们看到,为了整数部分仅保留一个 1,小数点向左移了 7 位,这样指数就为 7,尾数为 00010111101b。

步骤三:计算阶码。

IEEE754 规定不能将小数点移动而得到的指数,一直填到阶码部分,指数到阶码还需要一个转换过程。对于 float32 的单精度浮点数而言,阶码 = 指数 + 偏移值。偏移值的计算公式为 2^(e-1)-1,其中 e 为阶码部分的 bit 位数,这里为 8,于是单精度浮点数的阶码偏移值就为 2^(8-1)-1 = 127。这样在这个例子中,阶码 = 7 + 127 = 134d = 10000110b。float64 的双精度浮点数的阶码计算也是这样的。

步骤四:将符号位、阶码和尾数填到各自位置,得到最终浮点数的二进制表示。尾数位数不足 23 位,可在后面补 0。

这样,最终浮点数 139.8125d 的二进制表示就为0b_0_10000110_00010111101_000000000000。

步骤5:我们再通过 Go 代码输出浮点数 139.8125d 的二进制表示,和前面我们手工转换的做一下比对,看是否一致。

func main() {
    var f float32 = 139.8125
    bits := math.Float32bits(f)
    fmt.Printf("%b\n", bits)
}
1
2
3
4
5

在这段代码中,我们通过标准库的 math 包,将 float32 转换为整型。在这种转换过程中,float32 的内存表示是不会被改变的。

然后我们再通过前面提过的整型值的格式化输出,将它以二进制形式输出出来。运行这个程序,我们得到下面的结果:

1000011000010111101000000000000
1
# 字面值与格式化输出
# 字面值

分为两类

**一类是直白地用十进制表示的浮点值形式。**这一类,我们通过字面值就可直接确定它的浮点值,比如:

3.1415
.15  // 整数部分如果为0,整数部分可以省略不写
81.80

82. // 小数部分如果为0,小数点后的0可以省略不写
1
2
3
4
5

另一类则是科学计数法形式。采用科学计数法表示的浮点字面值,我们需要通过一定的换算才能确定其浮点值。而且在这里,科学计数法形式又分为十进制形式表示和十六进制形式表示的两种。

十进制科学计数法形式的浮点数字面值,字面值中的 e/E 代表的幂运算的底数为 10:

6674.28e-2 // 6674.28 * 10^(-2) = 66.742800
.12345E+5  // 0.12345 * 10^5 = 12345.000000
1
2

十六进制科学计数法形式的浮点数,字面值中的 p/P 代表的幂运算的底数为 2:

0x2.p10  // 2.0 * 2^10 = 2048.000000
0x1.Fp+0 // 1.9375 * 2^0 = 1.937500
1
2
# 格式化输出

fmt 包提供针对浮点数的格式化输出。

我们最常使用的格式化输出形式是 %f。通过 %f,我们可以输出浮点数最直观的原值形式。

var f float64 = 123.45678
fmt.Printf("%f\n", f) // 123.456780
1
2

也可以将浮点数输出为科学计数法形式,如下面代码:

fmt.Printf("%e\n", f) // 1.234568e+02
fmt.Printf("%x\n", f) // 0x1.edd3be22e5de1p+06
1
2

其中 %e 输出的是十进制的科学计数法形式,而 %x 输出的则是十六进制的科学计数法形式。

# 3.1.3 复数类型

数学课本上将形如 z=a+bi(a、b 均为实数,a 称为实部,b 称为虚部)的数称为复数。Go 中的应用场景更为局限和小众,主要用于专业领域的计算,比如矢量计算等。

# 复数类型种类

Go 提供两种复数类型,它们分别是 complex64 和 complex128。

  • complex64 的实部与虚部都是 float32 类型;
  • complex128 的实部与虚部都是 float64 类型;
  • 如果一个复数没有显示赋予类型,那么它的默认类型为 complex128。
# 字面值和格式化输出
# 字面值

复数字面值的表示有三种方法。

第一种,通过复数字面值直接初始化一个复数类型变量:

var c = 5 + 6i
var d = 0o123 + .12345E+5i // 83+12345i
1
2

第二种,Go 还提供了 complex 函数,方便我们创建一个 complex128 类型值:

var c = complex(5, 6) // 5 + 6i
var d = complex(0o123, .12345E+5) // 83+12345i
1
2

第三种,你还可以通过 Go 提供的预定义的函数 real 和 imag,来获取一个复数的实部与虚部,返回值为一个浮点类型:

var c = complex(5, 6) // 5 + 6i
r := real(c) // 5.000000
i := imag(c) // 6.000000
1
2
3
# 格式化输出

由于 complex 类型的实部与虚部都是浮点类型,所以我们可以直接运用浮点型的格式化输出方法,来输出复数类型。

# 3.1.4 自定义数值类型

# type关键字

通过 type 关键字基于原生数值类型来声明一个新类型。

注意:自定义的数值类型,在和其他类型相互赋值时容易出现一些问题。

建立一个名为 MyInt 的新的数值类型:

type MyInt int32
1

这里,因为 MyInt 类型的底层类型是 int32,所以它的数值性质与 int32 完全相同,但它们仍然是完全不同的两种类型。根据 Go 的类型安全规则,我们无法直接让它们相互赋值,或者是把它们放在同一个运算中直接计算,这样编译器就会报错。

var m int = 5
var n int32 = 6
var a MyInt = m // 错误:在赋值中不能将m(int类型)作为MyInt类型使用
var a MyInt = n // 错误:在赋值中不能将n(int32类型)作为MyInt类型使用
1
2
3
4

要避免这个错误,我们需要借助显式转型,让赋值操作符左右两边的操作数保持类型一致,像下面代码中这样做:

var m int = 5
var n int32 = 6
var a MyInt = MyInt(m) // ok
var a MyInt = MyInt(n) // ok
1
2
3
4
# 类型别名(Type Alias)

通过 Go 提供的类型别名(Type Alias)语法来自定义数值类型。

和使用标准 type 语法的定义不同的是,通过类型别名语法定义的新类型与原类型别无二致,可以完全相互替代。

type MyInt = int32

var n int32 = 6
var a MyInt = n // ok
1
2
3
4

通过类型别名定义的 MyInt 与 int32 完全等价,所以这个时候两种类型就是同一种类型,不再需要显式转型,就可以相互赋值。

# 3.2 数字定义

定义数字类型

package main

import "fmt"

func main() {
   var a int8 = 4
   var b int32 = 4
   var c int64 = 4
   d := 4
   fmt.Printf("a: %T %v \n", a, a)
   fmt.Printf("b: %T %v \n", b, b)
   fmt.Printf("c: %T %v \n", c, c)
   fmt.Printf("d: %T %v \n", d, d)
}

输出:
a: int8 4
b: int32 4
c: int64 4
d: int 4
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

reflect.TypeOf查看数据类型

package main

import (
   "fmt"
   "reflect"
)

func main() {
   c := 18
   fmt.Println(reflect.TypeOf(c))
}

输出:
int
1
2
3
4
5
6
7
8
9
10
11
12
13
14
上次更新: 2022/06/12, 15:48:09
内置函数
布尔值 bool

← 内置函数 布尔值 bool→

最近更新
01
ctr和crictl显示镜像不一致
03-13
02
alpine镜像集成常用数据库客户端
03-13
03
create-cluster
02-26
更多文章>
Theme by Vdoing | Copyright © 2015-2024 op81.com
苏ICP备18041258号-2
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式