每一个变量都有数据类型,Go中的数据类型有:

  • 简单数据类型:int、float、complex、bool和string
  • 数据结构或组合(composite):struct、array、slice、map和channel
  • 接口(interface)

当声明变量的时候,会做默认的赋0初始化。每种数据类型的默认赋0初始化的0值不同,例如int类型的0值为数值0,float的0值为0.0,string类型的0值为空"",bool类型的0值为false,数据结构的0值为nil,struct的0值为字段全部赋0。

其实函数也有类型,不过一般称之为返回类型。例如,下面的函数foo的返回类型是int:

func foo() int {
    ...CODE...
    return INT_TYPE_VALUE
}

函数允许有多个返回值,它们使用逗号分隔,括号包围:

func foo() (int,bool)

Number类型

Integer

3 22 0 1 -3 -22

Go中的Integer有以下几种细分的类型:

  • int8,int16,int32,int64
  • uint8,uint16,uint32,uint64
  • byte
  • rune
  • int,uint
8 16 32 642^8=256

uint中的u表示unsigned,即无符号整数,只保存0和正数。所以uint8能存储256个数的时候,允许的最小值为0,允许的最大值为255。

额外的两种Integer是byte和rune,它们分别等价于uint8(即一个字节大小的正数)、int32。从builtin包中的定义就可以知道:

$ go doc builtin | grep -E "byte|rune"
type byte = uint8
type rune = int32

byte类型后面会详细解释。

还有两种依赖于CPU位数的类型int和uint,它们分别表示一个机器字长。在32位CPU上,一个机器字长为32bit,共4字节,在64位CPU上,一个机器字长为64bit,共8字节。除了int和uint依赖于CPU架构,还有一种uintptr也是依赖于机器字长的。

一般来说,需要使用整型数据的时候,指定int即可,有明确的额外需求时再考虑是否换成其它整数类型。

0770x0x0c1e3 = 1000,6.023e23 = 6.023 x 10^23
a := uint64(5)

byte类型

Go中没有专门提供字符类型char,Go内部的所有字符类型(无论是ASCII字符还是其它多字节字符)都使用整数值保存,所以字符可以存放到byte、int等数据类型变量中。byte类型等价于uint8类型,表示无符号的1字节整数。

'a''我''aA'

例如,ASCII的字母a表示97。下面这种定义方式是允许的:

var a byte = 'A'  // a=65
var b uint8 = 'a' // b=97

注意,字符必须使用单引号,且必须只能是单个字符。所以byte类型经常被称为character类型。

以下也都是允许的:

var a = 'A'
var a uint32 = 'A'
var a int64 = 'A'

所以,Integer类型当存储的是以单引号包围的字符时,它会将字符转换成它二进制值对应的数值。同样适用于unicode字符,它将用来存放各字节对应的二进制的数值:

var a int64 = '我'  // a=25105
var a byte = '我'

可以保存它的unicode字符的代码点:

var a byte = '\u0041'  // a=65,代表的字符A

如果不知道代码点的值,可以将其以int类型保存并输出。

fmt.Printf("%d", '我')  // 25105

如果想将byte值转换为字符,可以使用string()函数做简单的类型转换:

var a = 'A'
println(string(a))     // 输出:A

float和complex

0.0 3.0 -3.12 -3.120

Go中的浮点数类型float有两种:float32和float64。

complex表示复数类型(虚数),有complex64和complex128。

浮点数在计算机系统中非常复杂,对于学习来说,只需将其认为是数学中的一种小数即可。但以下几个注意点需要谨记心中:

1.01-0.99+2.000000e-002==!=(3.2-2.8) == 0.4abs((3.2-2.8)-0.4) < 0.0002

一般来说,在程序中需要使用浮点数的时候都使用float64类型,不仅因为精确,更因为几乎所有包中需要float参数的类型都是float64。

在Go的数学运算中,默认取的是整型数据,如果想要得到浮点数结果,必须至少让运算的一方写成浮点数格式:

var a := 3/2     // a得到截断的整数:a=1
var b := 3/2.0   // b为浮点数b=+1.500000e+000
var c := 3 + 2.0 // c为浮点数

string类型

Go中的string用于保存UTF-8字符序列,它是动态大小的。对于字母和英文字母,它占用一个字节,对于其它unicode字符,按需占用2-4个字节。例如中文字符占用3个字节。

Go中的string类型要使用双引号或反引号包围,它们的区别是:

ab\ncd
func main() {
    println("abc\ndef")
    println(`ABC
    DEF`)
}

上面的结果将输出:

abc
def
ABC
    DEF
'a'

string的底层是byte数组,每个string其实只占用两个机器字长:一个指针和一个长度。只不过这个指针在Go中完全不可见,所以对我们来说,string是一个底层byte数组的值类型而非指针类型。

所以,可以将一个string使用append()或copy()拷贝到一个给定的byte slice中,也可以使用slice的切片功能截取string中的片段。

func main() {
	var a = "Hello Gaoxiaofang"
	println(a[2:3])      // 输出:l

	s1 := make([]byte,30)
	copy(s1,a)          // 将字符串保存到slice中
	println(string(s1)) // 输出"Hello Gaoxiaofang"
}

字符串串接

+
+
str := "Beginning string "+
       "second string"
+"abcd" + 2string(2)strconv
strings

字符串长度

使用len()取字节数量(不是字符数量)。

len("abcde")size(我是中国人)

字符串截取

"abcd"[1]

从字符串取字符的时候,需要注意的是index按字节计算而非按字符计算。两种取数据方式:

"string"[x]
"string"[x:y]

第一种方式将返回第(x+1)个字节对应字符的二进制数值,例如字母将转换为ASCII码,unicode将取对应字节的二进制转换为数值。

第二种方式将返回第(x+1)字节到第y字节中间的字符,Go中采取"左闭右开"的方式,所以所截取部分包括index=x,但不包括index=y。

例如:

func main() {
    println("abcde"[1])          // (1).输出"98"
    println("我是中国人"[1])       // (2).输出"136"
    println("abcde"[0:2])        // (3).输出"ab"
    println("我是中国人"[0:3])     // (4).输出"我"
    println("abcde"[3:4])        // (5).输出"d"
}

分析每一行语句:

  • (1).取第2个字节的二进制值,即字符b对应的值,其ASCII为98
  • (2).取第2个字节的二进制值,因为中文占用3个字节,所以取第一个字符"我"的第二个字节部分,转换为二进制值,为136
  • (3).取第1个字节到第3个字节(不包括)中间的字符,所以输出"ab"
  • (4).取前三个字节对应的字符,所以输出"我"
  • (5).取第4个字节对应的字符,所以输出d

字符串遍历

[]rune(str)
package main

import "fmt"

func main() {
	str := "Hello 你好"
	r := []rune(str)  // 8
	for i := 0; i < len(r); i++ {
		fmt.Printf("%c", r[i])
	}
}

字符串比较

< <= > >= == !=A-Za-z
// 字符串比较
println("a" < "B")  // false

// 数值比较,不是字符串比较
println('a' == 97)  // true

修改字符串

s[1]="c"

要想修改字符串中的字符,必须先将字符串拷贝到一个byte slice中,然后修改指定索引位置的字符,最后将byte slice转换回string类型。

例如,将"gaoxiaofang"改为"maoxiaofang":

s := "gaoxiaofang"
bs := []byte(s)
bs[0] = 'm'     // 必须使用单引号
s = string(bs)
println(s)

注意修改字符的时候,必须使用单引号,因为它是byte类型。

布尔类型(bool)

bool类型的值只有两种:true和false。

&& || !
func main() {
    println(true && true)    // true
    println(true && false)   // false
    println(true || true)    // true
    println(true || false)   // true
    println(!true)           // false
}
==
%t
isSorted()IsFinished()

type关键字:类型别名

可以使用type定义自己的数据类型,例如struct、interface。

还可以使用type定义类型的别名。例如,定义一个int类型的别名INT:

type INT int

这样INT类型的底层数据结构还是int类型。可以将它和int一样使用:

var a INT = 5

type中可以一次性声明多个别名:

type (
    CT int
    IT int32
    DT float32
)

获取数据类型

reflect包的TypeOf(),或者Printf/Sprintf的"%T"。

package main

import (
	"reflect"
	"fmt"
)

type IT int32
func main() {
	var a IT = 322
	var b = 22
	fmt.Println(reflect.TypeOf(a))   // main.IT
	fmt.Println(reflect.TypeOf(b))   // int
	fmt.Println(fmt.Sprintf("%T", a)) // main.IT
}

数据类型的大小

unsafe包的Sizeof()查看变量或常量所属数据类型占用空间的大小。

package main

import (
	"unsafe"
	"fmt"
)

type IT int32
func main() {
	var a IT = 322
	var b = 22
	fmt.Println(unsafe.Sizeof(a)) // 4
	fmt.Println(unsafe.Sizeof(b)) // 8
}

更多关于Go语言的数据类型请查看下面的相关链接

您可能感兴趣的文章: