目录
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为异常