三.数据类型

本文详细介绍了Go语言中的基本数据类型,包括布尔类型、整数类型(有符号和无符号)、浮点数类型(float32和float64)、字符类型(byte和rune)以及字符串类型。特别强调了类型转换的规则和注意事项,如布尔类型不能直接转换为整数,整数类型间的转换需要显式操作,浮点数比较的不稳定性,以及字符和字符串在UTF-8编码下的处理。同时,提到了unsafe包在计算数据类型大小中的应用。
摘要由CSDN通过智能技术生成

目录

1、布尔类型

2、整数类型

3、浮点数类型

4、字符类型

5、字符串类型

6、类型转换


1、布尔类型

Go语言中的布尔类型与其他语言基本一致,关键字也为bool,可赋值为预定义的true和false

示例代码如下:

var v1 bool

v1 = true

v2 := (1 == 2) // v2也会被推导为bool类型

布尔类型不能接受其他类型的赋值,不支持自动或强制的类型转换。

以下的示例是一些错误的用法,会导致编译错误:

var b bool

b = 1 // 编译错误

b = bool(1) // 编译错误

以下的用法才是正确的:

var b bool

b = (1!=0) // 编译正确

fmt.Println("Result:", b)     // 打印结果为Result: true

var b bool = true

fmt.Println(unsafe.Sizeof(b))         //结果是 1 标明内存尺寸大小

//注意:要在代码开头位置加入 import “unsafe” 包

2、整数类型

整型是所有编程语言里最基础的数据类型。Go语言支持如下所示的这些整型类型。

需要注意的是,int和int32在Go语言里被认为是两种不同的类型,编译器也不会帮你自动做类型转换,

比如以下的例子会有编译错误:

var value2 int32

value1 := 64 // value1将会被自动推导为int类型

value2 = value1 // 编译错误

编译错误类似于:

cannot use value1 (type int) as type int32 in assignment。

使用强制类型转换可以解决这个编译错误:

value2 = int32(value1) // 编译通过

当然,开发者在做强制类型转换时,需要注意数据长度被截短而发生的数据精度损失(比如将浮点数强制转为整数)和值溢出(值超过转换的目标类型的值范围时)问题。

整型的使用细节:

1)golang整数类型分为:有符号和无符号,int和uint的大小和系统有关;

2)golang整型默认申明为int;

3)fmt.Printf("num的数据类型是 %T,占的字节数是 %d", num,

unsafe.Sizeof(num))

4)golang使用整数类型时,遵从保小不保大原则,即在保证程序正常运行的情况下,

尽量使用占用空间小的数据类型;

5)bit:计算机中最小的存储单位,byte:计算机中基本的存储单元;

计算类型的大小:

package main 
import ( 
"fmt" 
"unsafe" 
) 
func main() { 
var a int ; 
fmt.Printf("%T unsafe = %d\n",a,unsafe.Sizeof(a)) 
} 

unsafe.Sizeof() 算基本数据类型可以使用但是算组合数据类型的时候有差别

Go 语言中 unsafe.Sizeof() 函数:

1、对不同长度的字符串,unsafe.Sizeof() 函数的返回值都为 16,这是因为string 类型对应一个结构体,该结构体有两个域,第一个域指向该字符串的指针,第二个域为字符串的长度,每个域占 8 个字节,但是并不包含指针指向的字符串的内容,这就解释了unsafe.Sizeof() 函数对 string 类型的返回值始终是16。

2、对不同长度的数组 unsafe.Sizeof() 函数的返回值随着数组中的元素个数的增加而增加,这是因为unsafe.Sizeof() 函数总是在编译期就进行求值,而不是在运行时,这就意味着,

unsafe.Sizeof() 函数的返回值可以赋值给常量,在编译期求值,意味着可以获得数组所占的内存大小,因为数组总是在编译期就指明自己的容量,并且在以后都是不可变的。

3、对所含元素个数不同的切片,unsafe.Sizeof() 函数的返回值都为 24,这是因为对切片来说,unsafe.Sizeof() 函数返回的值对应的是切片的描述符,而不是切片所指向的内存的大小,因此都是24。

3、浮点数类型

浮点型用于表示包含小数点的数据,比如1.234就是一个浮点型数据。

Go语言中的浮点类型采用IEEE-754标准的表达方式。

float32精度是小数点后7位

float64精度是小数点后15位。

1. 浮点数表示

Go语言定义了两个类型float32和float64,其中float32等价于C语言的float类型,

float64等价于C语言的double类型。

在Go语言里,定义一个浮点数变量的代码如下:

var fvalue1 float32

fvalue1 = 12

fvalue2 := 12.0 // 如果不加小数点,fvalue2会被推导为整型而不是浮点型

对于以上例子中类型被自动推导的fvalue2,需要注意的是其类型将被自动 设为float64,

而不管赋给它的数字是否是用32位长度表示的。因此,对于以上的例子,

下面的赋值将导致编译错误:

fvalue1 = fvalue2

而必须使用这样的强制类型转换:

fvalue1 = float32(fvalue2)

2、浮点数比较

因为浮点数不是一种精确的表达方式,所以像整型那样直接用==来判断

两个浮点数是否相等

是不可行的,这可能会导致不稳定的结果。下面是一种推荐的替代方案:

把decimal移动到那个目录里面

golang中的高精度计算包 github.com/shopspring/decimal

package main 
import ( 
"fmt" 
"github.com/shopspring/decimal" 
) 
func main() { 
v1 := decimal.NewFromFloat(0.00012) 
v2 := decimal.NewFromFloat(0.00011) 
fmt.Println(v1.Equal(v2)) 
} 

执行结果:

false

或者:

package main 
import "fmt" 
import "math" 	//数学库 Abs()求绝对值的函数 Max()求最大值函数
func main() { 
aa:= 2.55 
bb:= 1.23 
//比较float64 大小 用到了库函数 和精度比较 
if math.Max(aa, bb) == aa && math.Abs(aa-bb) > 0.000001 { 
fmt.Println(aa,bb) 
} 
} 

十进制下, float32 有效数字大约有 7 位,

float64 有效数字大约有 15 位,

说明:

1)浮点数在机器中存在的形式:浮点数=符号位+指数位+尾数位(浮点数都是有符号的)

2)尾数部分可能丢失,造成精度损失;

3)浮点型的存储分为三个部分:符号位+指数位+尾数位;

浮点型的使用细节:

1)golang浮点类型有固定的范围和字段长度,不受操作系统的影响;

2)golang默认为float64类别;

3)浮点型常用两种形式表示:

1)十进制:5.12、0.512

2)科学记数法形式:5.1234E2、5.1234E-2

4)通常使用float64,它精度更高;

4、字符类型

在Go语言中支持两个字符类型,

golang没有专门的存储字符类型,如果要存储单个字符,用byte来保存。

另一个是rune,代表单个Unicode字符。

byte字符类型使用 案例如下:

package main 
import ( 
 "fmt" 
) 
func main() { 
 var c1 byte = 'a' 
 fmt.Println(c1) 
} 

当我们直接输出字符c1,,得到的是它的ascII值:97。要用格式化输出:

fmt.Printf("%c",c1)。

而当我们要存储中文时,此时不能够用byte类型了,即ASCII值大于255时,会

显示溢出,我们要用int来存储:

package main 
import ( 
 "fmt" 
) 
func main() { 
 var c1 byte = 'a' 
 var c2 int = '被' 
 fmt.Println(c1) 
 fmt.Printf("c1的值是:%c \n", c1) 
 fmt.Printf("c2的值是:%c,它的ASCii值是:%d", c2, c2) 
} 

执行结果:

97

c1的值是:a

c2的值是:被,它的ASCii值是:34987

字符类型使用细节:(再也不用担忧编码的问题了,所有的编码都是utf-8)

1)字符常量使用单引号括起来的单个字符;

2)go中允许使用转义字符'\'来将其后的字符转变为特殊字符型常量,例如

var c int = '\n';

3)字符使用utf-8编码;

4)go中,字符的本质是一个整数,直接输出时,会输出它对应的UTF-8编码

的值;

5)可以直接给变量赋予某个数字,然后格式化输出%c,会输出该数字对应

的unicode字符;

6)字符类型是可以进行运算的,相当于一个整数,因为它都对应unicode

码;

rune 汉字转换 ==》百度解释:如尼字母(属于北欧古文字体系); 神秘的记号;

有魔力的符号;

//如果我们预期想得到一个字符串的长度,而不是字符串底层占得字节长度,该

怎么办呢???

package main

import (

"fmt"

"unicode/utf8"

)

func main() {

var str = "hello 你好"

//golang中string底层是通过byte数组实现的,直接求len 实际是在按字节长

度计算所以一个汉字占3个字节算了3个长度 fmt.Println("len(str):", len(str))

//以下两种都可以得到str的字符串长度

//golang中的unicode/utf8包提供了用utf-8获取长度的方法

fmt.Println("RuneCountInString:", utf8.RuneCountInString(str))

//通过rune类型处理unicode字符

fmt.Println("rune:", len([]rune(str)))

}

输出:

len(str): 12

RuneCountInString: 8

rune: 8

package main 
import "fmt" 
func main() { 
 s := "abc你好" 
 r := "123你好" 
 fmt.Println("len(s)=", len([]byte(s)), "len(r)=", len([]rune(r))) //len(s)= 9 
len(r)= 5 
 for k, v := range r { 
 fmt.Println("k=", k, "v=", v) 
 } 
 for k, v := range []rune(r) { 
 fmt.Println("k2=", k, "v2=", v) 
 } 
} 

用range遍历包含中文的字符串时,

会发现第一个for中k的值为0,1,2,3,6;第二个for中k的值为0,1,2,3,4;

说明字符串中如果包含中文,range的时候可以识别出来,一个中文占用3个

byte,索引就自动加三; 而rune索引则只会加一。

5、字符串类型

在Go语言中,字符串也是一种基本类型。相比之下, C/C++语言中并不存在原

生的字符串类型,

通常使用字符数组来表示,并以字符指针来传递。

Go语言中字符串的声明和初始化非常简单,举例如下:

var str string // 声明一个字符串变量

str = "Hello world" // 字符串赋值

ch := str[0] // 取字符串的第一个字符

fmt.Printf("The length of \"%s\" is %d \n", str, len(str))

fmt.Printf("The first character of \"%s\" is %c.\n", str, ch)

输出结果为:

The length of "Hello world" is 11

The first character of "Hello world" is H.

字符串的内容可以用类似于数组下标的方式获取,但与数组不同,字符串的内

容不能在初始

化后被修改,比如以下的例子:

str := "Hello world" // 字符串也支持声明时进行初始化的做法

str[0] = 'X' // 编译错误

编译器会报类似如下的错误:

cannot assign to str[0]

1、 字符串操作

平时常用的字符串操作如表所示,更多的字符串操作,请参考标准库strings包。

2、 字符串遍历

Go语言支持两种方式遍历字符串。一种是以字节数组的方式遍历:

str := "Hello,世界"

n := len(str)

for i := 0; i < n; i++ {

ch := str[i] // 依据下标取字符串中的字符,类型为byte

fmt.Println(i, ch)

}

这个例子的输出结果为:

0 72

1 101

2 108

3 108

4 111

5 44

6 32

7 228

8 184

9 150

10 231

11 149

12 140

可以看出,这个字符串长度为13。尽管从直观上来说,这个字符串应该只有9个

字符。

这是因为每个中文字符在UTF-8中占3个字节,而不是1个字节。

另一种是以Unicode字符遍历:

str := "Hello,世界"

for i, ch := range str {

fmt.Println(i, ch)//ch的类型为rune

}

输出结果为:

0 72

1 101

2 108

3 108

4 111

5 44

6 32

7 19990

10 30028

以Unicode字符方式遍历时,

每个字符的类型是rune(早期的Go语言用int类型表示Unicode字符),而不是

byte。

3、字符串的分割

strings.Split 支持单个分隔符

strings.FieldsFunc 支持多个分隔符

返回值:均为切片

func main() {

srcStr1 := "abc:def:k:g"

desStr1 := strings.Split(srcStr1, ":")

fmt.Printf("ret:%s\n", desStr1)

srcStr2 := "a b c,def,k,g"

desStr2 := strings.FieldsFunc(srcStr2, splitFunc)

fmt.Printf("ret:%s\n", desStr2)

}

func splitFunc(r rune) bool {

return r == ' ' || r == ','

}

4、字符串的使用细节:

1)go语言的字符串的字节使用utf-8编码;

2)与python一样,一旦字符串赋值了,就不能被更改;

3)两种表示形式

1)双引号,会识别转义字符;

2)反引号,以字符串的原生形式输出,包括换行和特殊字符,可以实现防

止攻击,输出源代码等

package main

import (

"fmt"

)func main() {

var c = "abc\nabc"

var d = `abc\nabc`

fmt.Println(c)

fmt.Println(d)

}

6、类型转换

go是一种强类型的语言,所以如果在赋值的时候两边类型不一致会报错,

一个类型的值可以被转换成另一种类型的值。由于Go语言不存在隐式类型转

换,

因此所有的类型转换都必须显式的声明:

使用 type (a)这种形式来进行强制类型转换,比如

var a int32 = 10

var b int64 = int64(a)

通过在变量前面添加指定类型,就可以进行强制类型转换

注意,高位转低位的时候,需要注意,会存在精度丢失,比如上述16转8位的时候,就丢失了

var n1 int16 = 130

fmt.Println(int8(n1)) // 变成 -126

其他常用类型转换:

要引入包strconv

string转成int:

int, err := strconv.Atoi(string)

err是错误

int转成string:

string := strconv.Itoa(int)

string转成int64:

int64, err := strconv.ParseInt(string, 10, 64)

string是转换的字符串 10是十进制数字 64为转化int64类型

int64转成string:

string := strconv.FormatInt(int64,10)

int64是要转换的数字变量 10是十进制数字

float转string:

func FormatFloat(f float64, fmt byte, prec, bitSize int) string

f要转换的浮点数 fmt要转换的目标类型.f'表示浮点数.prec小数点后精度个数 bitSize转换前浮点数的类型单位,64表示float64 32.表示float32

比如:

num := 250.56 
str := strconv.FormatFloat(num, 'f', 4,64) 
fmt.Printf("type:%T value:%#v\n", str, str) 

输出:type:string value:"250.5600"

类型转换只能在定义正确的情况下转换成功,

例如从一个取值范围较小的类型转换到一个取值范围较大的类型(将 int16 转换为 int32)。

当从一个取值范围较大的类型转换到取值范围较小的类型时(将 int32 转换为int16 或将 float32 转换为 int),会发生精度丢失(截断)的情况。浮点数在转换为整型时,会将小数部分去掉,只保留整数部分。

err为异常

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值