基本数据类型

一、整型

1. 整型介绍

Go 语言中,整型可以分为以下几类:

类型描述
uint8无符号 8位整型 (0 到 255)
uint16无符号 16位整型 (0 到 65535)
uint32无符号 32位整型 (0 到 4294967295)
uint64无符号 64位整型 (0 到 18446744073709551615)
int8有符号 8位整型 (-128 到 127)
int16有符号 16位整型 (-32768 到 32767)
int32有符号 32位整型 (-2147483648 到 2147483647)
int64有符号 64位整型 (-9223372036854775808 到 9223372036854775807)

此外,还有一些特殊整型:

类型描述
uint32位操作系统上就是uint32,64位操作系统上就是uint64
int32位操作系统上就是int32,64位操作系统上就是int64
uintptr无符号整型,用于存放一个指针

int 型是计算最快的一种类型。实际使用中,切片或 map 的元素数量等都可以用int来表示。在涉及到二进制传输、读写文件的结构描述时,为了保持文件的结构不会受到不同编译目标平台字节长度的影响,不要使用intuint

package main

import "fmt"

func main() {
	num1 := 123456
	fmt.Printf("%T\n", num1) // int

	var num int8
	//num = 111111111 // .\main.go:7:6: constant 111111111 overflows int8 赋值长度超过了8位
	fmt.Println(num)

}

查看各类整型类型的表数范围:

package main

import (
	"fmt"
	"unsafe"
	"math"
)

func main() {
	var i8 int8
	var i16 int16
	var i32 int32
	var i64 int64
	var ui8 uint8
	var ui16 uint16
	var ui32 uint32
	var ui64 uint64

	fmt.Printf("%T %dB %v~%v\n", i8, unsafe.Sizeof(i8), math.MinInt8, math.MaxInt8)     // int8 1B -128~127
	fmt.Printf("%T %dB %v~%v\n", i16, unsafe.Sizeof(i16), math.MinInt16, math.MaxInt16) // int16 2B -32768~32767
	fmt.Printf("%T %dB %v~%v\n", i32, unsafe.Sizeof(i32), math.MinInt32, math.MaxInt32) // int32 4B -2147483648~2147483647
	fmt.Printf("%T %dB %v~%v\n", i64, unsafe.Sizeof(i64), math.MinInt64, math.MaxInt64) // int64 8B -9223372036854775808~9223372036854775807

	fmt.Printf("%T %dB %v~%v\n", ui8, unsafe.Sizeof(ui8), 0, math.MaxUint8)            // uint8 1B 0~255
	fmt.Printf("%T %dB %v~%v\n", ui16, unsafe.Sizeof(ui16), 0, math.MaxUint16)         // uint16 2B 0~65535
	fmt.Printf("%T %dB %v~%v\n", ui32, unsafe.Sizeof(ui32), 0, math.MaxUint32)         // uint32 4B 0~4294967295
	fmt.Printf("%T %dB %v~%v\n", ui64, unsafe.Sizeof(ui64), 0, uint64(math.MaxUint64)) // uint64 8B 0~18446744073709551615

	var ui uint
	ui = uint(math.MaxUint64)                                  //再+1会导致overflows错误
	fmt.Printf("%T %dB %v~%v\n", ui, unsafe.Sizeof(ui), 0, ui) // uint 8B 0~18446744073709551615

	var iMax, iMin int
	iMax = int(math.MaxInt64)                                           //再+1会导致overflows错误
	iMin = int(math.MinInt64)                                           //再-1会导致overflows错误
	fmt.Printf("%T %dB %v~%v\n", iMax, unsafe.Sizeof(iMax), iMin, iMax) // int 8B -9223372036854775808~9223372036854775807

}

2. 数字字面量语法

Go1.13 版本之后引入了数字字面量语法,这样便于开发者以二进制、八进制或十六进制浮点数的格式定义数字,还允许我们用 _ 来分隔数字:

package main

import "fmt"

func main() {
	num1 := 123_456
	fmt.Println(num1)  // 123456

	// 定义一个二进制数
	num2 := 0b00101101
	fmt.Println(num2)  // 45 --> 0b00101101用十进制表示是45

	// 定义一个八进制数
	num3 := 0377
	fmt.Println(num3)  // 255 --> 0377用十进制表示是255

	// 定义一个十六进制数
	num4 := 0xff
	fmt.Println(num4)  // 255 --> 0xff用十进制表示是255
}

我们也可以使用 fmt函数来将一个整数以不同进制形式展示:

package main

import "fmt"

func main() {
	a := 10

	fmt.Printf("%b \n", a) // 1010  占位符%b表示二进制
	fmt.Printf("%o \n", a) // 12    占位符%o表示八进制
	fmt.Printf("%d \n", a) // 10    占位符%o表示八进制
	fmt.Printf("%x \n", a) // a     占位符%x表示十六进制小写
	fmt.Printf("%X \n", a) // A     占位符%X表示十六进制大写
}

二、浮点数类型

Go语言支持两种浮点型数:float32float64。这两种浮点型数据格式遵循IEEE 754标准。

类型描述
float32-3.4028234663852886e+38 ~ 3.4028234663852886e+38
float64-1.7976931348623157e+308 ~ 1.7976931348623157e+308
package main

import (
	"fmt"
	"unsafe"
	"math"
)


func main() {
	var f32 float32
	var f64 float64

	fmt.Printf("%T %dB %v~%v\n", f32, unsafe.Sizeof(f32), -math.MaxFloat32, math.MaxFloat32) // float32 4B -3.4028234663852886e+38~3.4028234663852886e+38
	fmt.Printf("%T %dB %v~%v\n", f64, unsafe.Sizeof(f64), -math.MaxFloat64, math.MaxFloat64) // float64 8B -1.7976931348623157e+308~1.7976931348623157e+308

}

打印浮点数时,可以使用fmt包配合动词 %f

package main

import (
	"fmt"
	"math"
)


func main() {
	fmt.Printf("%f\n", math.Pi)   // 3.141593
	fmt.Printf("%.2f\n", math.Pi) // 3.14
}

三、复数类型

复数类型有 complex64complex128 两种类型,complex64 的实部和虚部为32位,complex128 的实部和虚部为64位。

package main

import "fmt"

func main() {
	var c1 complex64
	c1 = 1 + 2i
	var c2 complex128
	c2 = 2 + 3i
	fmt.Println(c1) // (1+2i)
	fmt.Println(c2) // (2+3i)
}

四、布尔类型

Go语言中以bool类型进行声明布尔型数据,布尔型数据只有true(真)false(假)两个值。布尔类型经常用在条件判断语句,循环语句逻辑表达式中,使用布尔类型时需要注意:

  • 布尔类型变量的默认值为false

  • Go 语言中不允许将整型强制转换为布尔型,即不能使用0和非0表示真假。

  • 布尔型无法参与数值运算,也无法与其他类型进行转换。

package main

import "fmt"

func main() {
	// 初始化布尔类似变量
	var b1 bool = true
	var b2 bool = false
	var b3 = true
	var b4 = false

	b5 := true
	b6 := false

	fmt.Printf("b1: %v\n", b1) // b1: true
	fmt.Printf("b2: %v\n", b2) // b2: false
	fmt.Printf("b3: %v\n", b3) // b3: true
	fmt.Printf("b4: %v\n", b4) // b4: false
	fmt.Printf("b5: %v\n", b5) // b5: true
	fmt.Printf("b6: %v\n", b6) // b6: false

	// 布尔值用在条件判断中
	age := 18
	ok := age >= 18
	if ok {
		fmt.Println("你已经成年")
	} else {
		fmt.Println("你还未成年")
	}

	// 布尔值用在循环语句中
	count := 10
	for i := 0; i < count; i++ {
		fmt.Printf("i: %v\n", i)
	}

	// 布尔值用在逻辑表达式中
	age1 := 18
	gender := "男"

	if age1 >= 18 && gender == "男" {
		fmt.Println("你是成年男子")
	}
}

五、字符串类型

Go 语言中的字符串以原生数据类型出现,使用字符串就像使用其他原生数据类型(intboolfloat32float64 等)一样。 Go 语言里的字符串的内部实现使用UTF-8编码。

1. 定义字符串

package main

import "fmt"

func main() {
	// 初始化当行字符串
	str1 := "hello \nworld!"

	// 初始化多行字符串
	str2 := `hello\n
			 world`

	fmt.Println(str1)
	fmt.Println(str2)
}

定义单行字符串使用英文下的双引号包裹,字符串中如果使用到转义字符会生效;定义一个多行字符串使用反引号包裹,但是所有的转义字符均无效,文本将会原样输出。

2. 字符串常用方法

2.1 字符串长度
str1 := "abcdefg"
fmt.Println(len(str1)) // 7
2.2 拼接字符串
  • 方式一,使用加号
name := "cdc"
age := "18"
msg1 := name + " " + age
fmt.Printf("msg1: %v\n", msg1) // cdc 18

msg2 := ""
msg2 += name
msg2 += " "
msg2 += age
fmt.Printf("msg2: %v\n", msg2) // cdc 18

golang 中字符串类型都是不可变的,每次运算都会产生一个新的字符串,所以会产生很多临时的无用的字符串,不仅没有用,还会给 gc 带来额外的负担,所以性能比较差,不推荐该方式。

  • 方式二,使用 fmt.Sprintf() 方法
name := "cdc"
age := "18"
msg := fmt.Sprintf("%s %s", name, age)
fmt.Printf("msg: %v\n", msg)

内部使用 []byte 实现,不像直接运算符这种会产生很多临时的字符串,但是内部的逻辑比较复杂,有很多额外的判断,还用到了 interface,所以性能也不是很好。

  • 方式三,使用 strings.Join() 方法
msg := strings.Join([]string{name, age}, " ")
fmt.Printf("msg: %v\n", msg)

Join 会先根据字符串数组的内容,计算出一个拼接之后的长度,然后申请对应大小的内存,一个一个字符串填入,在已有一个数组的情况下,这种效率会很高,但是本来没有,去构造这个数据的代价也不小。

  • 方式四,使用 buffer.WriteString() 方法
package main

import (
	"bytes"
	"fmt"
)

func main() {
	var buffer bytes.Buffer
	buffer.WriteString("cdc")
	buffer.WriteString(" ")
	buffer.WriteString("18")
	fmt.Printf("msg: %v\n", buffer.String())
}

推荐该方式,可以当成可变字符使用,对内存的增长也有优化。

2.3 字符串分割
str2 := "how do you do"
splitRet := strings.Split(str2, "do")
fmt.Printf("%v -- %T -- %d\n", splitRet, splitRet, len(splitRet)) // [how   you  ] -- []string -- 3
2.4 判断是否包含
str2 := "how do you do"
fmt.Println(strings.Contains(str2, "do")) // true
fmt.Println(strings.Contains(str2, "hehe")) // false
2.5 判断前/后缀
str2 := "how do you do"
fmt.Println(strings.HasPrefix(str2, "how")) // true 判断前缀是否为how
fmt.Println(strings.HasPrefix(str2, "do")) // false
fmt.Println(strings.HasSuffix(str2, "how")) // false 判断后缀是否为how
fmt.Println(strings.HasSuffix(str2, "do")) // true
2.6 字串出现位置
str2 := "how do you do"
fmt.Println(strings.Index(str2, "do"))  // 4
fmt.Println(strings.LastIndex(str2, "do"))  // 11
2.7 字符串切片
// 通过索引切片,范围左闭右开
fmt.Println(str2[:5])  // how d  --> 从开头切到指定索引
fmt.Println(str2[3:6]) //  do --> 从指定开始索引位置切到指定结束索引位置
fmt.Println(str2[2:])  // w do you do --> 从指定索引位置切到字符串最后
fmt.Println(str2[:])   // how do you do --> 从开始切到最后
2.8 格式化输出

Go 语言中输出字符串时可以使用各种占位符来输出不同类型的值:

// 普通占位符
%v		相应值的默认格式。在打印结构体时,“加号”标记(%+v)会添加字段名
%#v		相应值的Go语法表示							
%T		相应值的类型的Go语法表示						
%%		字面上的百分号,并非值的占位符

// 布尔占位符
%t		单词 truefalse

// 整数占位符
%b		二进制表示								
%c		相应Unicode码点所表示的字符					
%d		十进制表示									
%o		八进制表示									
%q		单引号围绕的字符字面值,由Go语法安全地转义		
%x		十六进制表示,字母形式为小写 a-f				
%X		十六进制表示,字母形式为大写 A-F				
%U		Unicode格式:U+1234,等同于 "U+%04X"

// 浮点数和复数的组成部分
%b		无小数部分的,指数为二的幂的科学计数法,与 strconv.FormatFloat的 'b' 转换格式一致。例如 -123456p-78
%e		科学计数法,例如 -1234.456e+78									
%E		科学计数法,例如 -1234.456E+78									
%f		有小数点而无指数,例如 123.456									
%g		根据情况选择 %e 或 %f 以产生更紧凑的(无末尾的0)输出				
%G		根据情况选择 %E 或 %f 以产生更紧凑的(无末尾的0)输出

// 字符串与字节切片
%s		输出字符串表示(string类型或[]byte)					
%q		双引号围绕的字符串,由Go语法安全地转义							
%x		十六进制,小写字母,每字节两个字符								
%X		十六进制,大写字母,每字节两个字符

// 指针
%p		十六进制表示,前缀 0x
package main

import "fmt"

func main() {
	// 普通占位符
	type website struct {
		url string
	}

	web := website{url: "www.chendacheng.com"}

	name := "cdc"

	fmt.Printf("%v\n", name) // cdc
	fmt.Printf("%+v\n", web) // {url:www.chendacheng.com}
	fmt.Printf("%#v\n", web) // main.website{url:"www.chendacheng.com"}
	fmt.Printf("%T\n", name) // string

	// 布尔占位符
	fmt.Printf("%t\n", true) //输出值的 true 或 false

	// 整数占位符
	fmt.Printf("%b\n", 100)  //二进制表示  1100100
	fmt.Printf("%c\n", 1111) //数值对应的 Unicode 编码字符  ї
	fmt.Printf("%d\n", 10)   //十进制表示  10
	fmt.Printf("%o\n", 8)    //八进制表示  10
	fmt.Printf("%q\n", 22)   //转化为十六进制并附上单引号  '\x16'
	fmt.Printf("%x\n", 1223) //十六进制表示,用a-f表示  4c7
	fmt.Printf("%X\n", 1223) //十六进制表示,用A-F表示  4C7
	fmt.Printf("%U\n", 1024) //Unicode表示  U+0400

	fmt.Printf("%s\n", "wqdew")  //直接输出字符串或者[]byte  wqdew
	fmt.Printf("%q\n", "dedede") //双引号括起来的字符串  "dedede"
	fmt.Printf("%x\n", "abczxc") //每个字节用两字节十六进制表示,a-f表示  6162637a7863
	fmt.Printf("%X\n", "asdzxc") //每个字节用两字节十六进制表示,A-F表示  6173647A7863

	// 浮点数和复数的组成部分
	fmt.Printf("%b\n", 12.34)    //无小数部分,两位指数的科学计数法6946802425218990p-49
	fmt.Printf("%e\n", 12.345)   //科学计数法,e表示  1.234500e+01
	fmt.Printf("%E\n", 12.34455) //科学计数法,E表示  1.234455E+01
	fmt.Printf("%f\n", 12.3456)  //有小数部分,无指数部分  12.345600
	fmt.Printf("%g\n", 12.3456)  //根据实际情况采用%e或%f输出  12.3456
	fmt.Printf("%G\n", 12.3456)  //根据实际情况采用%E或%f输出  12.3456

	// 指针占位符
	fmt.Printf("%T\n", &name) //*string 字符串指针
	fmt.Printf("%p\n", &name) //0xc000042270 指针地址
}

六、byte和rune类型

1. 字节类型简介

组成每个字符串的元素叫做字符,可以通过遍历或者单个获取字符串元素获得字符。 字符用英文单引号包裹。

package main

import "fmt"

func main() {
	var a = '华'
	var b = 'a'
	fmt.Printf("a: %v,%c\n", a, a) // a: 21326,华
	fmt.Printf("b: %v,%c\n", b, b) // b: 97,a
}

Go 语言的字符有以下两种:

  • uint8类型,或者叫 byte 型,代表一个ASCII码字符。
  • rune类型,代表一个 UTF-8字符

当需要处理中文、日文或者其他复合字符时,则需要用到rune类型。rune类型实际是一个int32。Go 使用了特殊的 rune 类型来处理 Unicode,让基于 Unicode 的文本处理更为方便,也可以使用 byte 型进行默认字符串处理,性能和扩展性都有照顾。

package main

import "fmt"

func main() {
	s := "hello南京"
	for i := 0; i < len(s); i++ { //byte
		fmt.Printf("%v(%c) ", s[i], s[i])
	}

    fmt.Println()
	
    for _, r := range s { //rune
		fmt.Printf("%v(%c) ", r, r)
	}
}

两种遍历字符串的输出结果如下:

104(h) 101(e) 108(l) 108(l) 111(o) 229(å) 141() 151() 228(ä) 186(º) 172(¬) 
104(h) 101(e) 108(l) 108(l) 111(o) 21335() 20140() 

因为UTF8编码下一个中文汉字由3~4个字节组成,所以我们不能简单的按照字节去遍历一个包含中文的字符串,否则就会出现上面输出中第一行的结果。建议使用for + range 方式遍历字符串。

2. 修改字符串

字符串底层是一个byte数组,且字符串的长度是byte字节的长度,所以字符串类型可以和 []byte 类型相互转换。rune 类型用来表示utf8字符,一个 rune 字符由一个或多个 byte 组成。虽然字符串是不可变的,但是我们可以先将其转换成[]rune[]byte,完成后再转换为string。无论哪种转换,都会重新分配内存,并复制字节数组,即不会修改原始字符串,而是生成一个新的修改过后的字符串。

package main

import "fmt"

func main() {
	s1 := "big"
	// 强制类型转换
	byteS1 := []byte(s1)
	byteS1[0] = 'p'
	fmt.Println(string(byteS1)) // pig

	s2 := "白萝卜"
	runeS2 := []rune(s2)
	runeS2[0] = '红'
	fmt.Println(string(runeS2)) // 红萝卜
}

七、强制类型转换

package main

import "fmt"

func main() {
	num := 12
	numFloat := float32(num)
	fmt.Printf("%T -- %v\n", numFloat, numFloat) // float32 -- 12

	a := 'a'
	aStr := string(a)
	fmt.Printf("%T -- %v\n", aStr, aStr) // string -- a
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值