Go基础教程系列之数据类型详细说明

每一个变量都有数据类型,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

Integer类型是整型数据,例如3 22 0 1 -3 -22等。

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

  • int8,int16,int32,int64
  • uint8,uint16,uint32,uint64
  • byte
  • rune
  • int,uint

其中8 16 32 64表示该数据类型能存储的bit位数。例如int8表示能存储8位数值,所以这个类型占用1字节,也表示最大能存储的整型数共2^8=256个,所以int8类型允许的最大正数为127,允许的最小负数为-128,共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即可,有明确的额外需求时再考虑是否换成其它整数类型。

在整数加上0前缀表示这是8进制,例如077。加上前缀0x表示这是16进制,例如0x0c,使用e符号可以表示这是一个科学计数法,如1e3 = 1000,6.023e23 = 6.023 x 10^23

可以使用TYPE(N)的方式来生成一个数值,例如a := uint64(5)。实际上这是类型转换,将int类型的5转换成int64类型的5。

byte类型

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

Go中的字符都使用单引号包围,例如'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

由于在Go中占用3字节,所以保存到byte中是报错的:

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

float是浮点数(俗称小数),例如0.0 3.0 -3.12 -3.120等。

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

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

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

  • 浮点数是不精确的。例如1.01-0.99从数学运算的角度上得到的值是0.02,但实际上的结果是0.020000000000000018(python运算的结果),在Go中会将其表示为+2.000000e-002。这个结果是一种极限趋近于我们期待值的结果。
  • float32的精度(7个小数位)低于float64(15个小数位),所以float64类型的值比float32类型的值更精确。
  • 因为浮点数不精确,所以尽量不要对两个浮点数数进行等值==和不等值!=比较,例如(3.2-2.8) == 0.4返回Flase。如果非要比较,应该通过它们的减法求绝对值,再与一个足够小(不会影响结果)的值做不等比较,例如abs((3.2-2.8)-0.4) < 0.0002返回True。

一般来说,在程序中需要使用浮点数的时候都使用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表示ab后换行加cd
  • 反引号是强引用,其内任何符号都被强制解释为字面意义,包括字面的换行。也就是所谓的裸字符串。
func main() {
    println("abc\ndef")
    println(`ABC
    DEF`)
}

上面的结果将输出:

abc
def
ABC
    DEF

不能使用单引号包围,单引号包围的表示它的二进制值转换成十进制的数值。例如字母对应的是ASCII码。这个在前面byte类型中介绍过。所以,使用单引号包围的字符实际上是整数数值。例如'a'等价于97。

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"
}

字符串串接

使用加号+连接两段字符串:"Hello" + "World"等价于"HelloWorld"。

可以通过+的方式将多行连接起来。例如:

str := "Beginning string "+
       "second string"

字符串连接+操作符强制认为它两边的都是string类型,所以"abcd" + 2将报错。需要先将int类型的2转换为字符串类型(不能使用string(2)的方式转换,因为这种转换方式不能跨大类型转换,只能使用strconv包中的函数转换)。

另一种更高效的字符串串接方式是使用strings包中的Join()函数,它可以在缓冲中将字符串串接起来。

字符串长度

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

例如len("abcde")返回5,size(我是中国人)返回15。

字符串截取

可以将字符串当作数组,使用索引号取部分字符串(按字节计算),索引号从0开始计算,如"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

字符串遍历

字符串是字符数组,如果字符串中全是ASCII字符,直接遍历即可,但如果包含了多字节字符,则可以[]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的ASCII方式排列。

// 字符串比较
println("a" < "B")  // false

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

修改字符串

字符串是一个不可变对象,所以对字符串s截取后赋值的方式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。

有3种布尔逻辑运算符:&& || !,分别别是逻辑与,逻辑或,取反。

func main() {
    println(true && true)    // true
    println(true && false)   // false
    println(true || true)    // true
    println(true || false)   // true
    println(!true)           // false
}

Go是一门非常严格的怨言,在使用==进行等值比较的时候,要求两边的数据类型必须相同,否则报错。如果两边数据类型是接口类型,则它们必须实现相同的接口函数。如果是常量比较,则两边必须是能够兼容的数据类型。

在printf类的函数的格式中,占位符%t用于代表布尔值。

布尔类型的变量、函数名应该以is或Is的方式开头来表明这是一个布尔类型的东西。例如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语言的数据类型请查看下面的相关链接

(0)

相关推荐

  • 详解Go语言中的数据类型及类型转换

    目录 1.基本数据类型 2.基础数据类型转换 3.基本数据类型转为字符串 4.strconv的使用 5.字符串转为基础类型 1.基本数据类型 数据类型有很多,先研究一下基础的,例如:布尔型.数字类型.字符串类型. 数字类型有uint8.uint16.uint32.uint64.int8.int16.int32.int64(uint和int区别在于uint为无符号整数,即只支持正数,不支持负数形式) 数字浮点型有fload32.float64.complex64.complex126(后面两个均为

  • Go语言七篇入门教程二程序结构与数据类型

    目录 1. 程序结构 1.1 名称 1.2 声明 1.3 注释 1.4 单双引号 1.5 输出 2. 数据类型 2.1 整型 2.2 浮点型 2.3 复数 2.4 布尔型 2.5 字符串 2.6 常量 2.7 数组 2.8 切片 2.9 map 2.10 结构体 2.11 JSON 3. 流程控制 3.1 条件语句 3.2 选择语句 3.3 循环语句 如何学习Go 1. 程序结构 1.1 名称 如果一个实体名称在函数中声明,它只在函数局部有效.如果声明在函数外,它将对包里面的所有源文件可见. 实

  • Golang通脉之数据类型详情

    目录 1.标识符与关键字 1.1 标识符 1.2 关键字 2.变量 2.1 什么是变量 2.2 变量类型 2.3 变量声明 3.常量 3.1 iota 4.基本数据类型 4.1 整型 4.2 浮点型 4.3 复数 4.4 布尔值 4.5 字符串 4.6 byte和rune类型 4.7 类型转换 5.运算符 5.1 算数运算符 5.2 关系运算符 5.3 逻辑运算符 5.4 位运算符 5.5 赋值运算符 5.6 运算符优先级 1.标识符与关键字 在了解数据类型之前,先了解一下go的标识符和关键字

  • Go语言特点及基本数据类型使用详解

    目录 一.Golang 简介 1.Go 语言的特点 2.Golang 的变量作用域 3.Golang 执行流程的两种方式 二.Golang 的基本操作 1.在 Linux 上安装 Golang 语言开发包 2.Golang 变量的基本使用 3.Golang 中整数的类型 4.Golang 基本数据类型的默认值 5.基本数据类型转换为 String 类型 一.Golang 简介 Golang(又称为 Go)是 Google 公司开发出的一种静态强类型.编译型.并发型,并具有垃圾回收功能的编程语言.

  • GO语言基本数据类型总结

    本文实例总结了GO语言基本数据类型.分享给大家供大家参考.具体如下: 1.注释(与C++一样) 行注释://块注释:/* ...*/ 2.标识符 可以这么说,除了数字开头的不允许,符号开头的不允许,关键字不允许,其他的Unicode字符组合都可以."_33"也可以是标识符."我们"也可以是标识符.标识符也区分大小写. (1).以大写字母开头的标识符是公开的.(这个很有意思) (2).其他任何标识符都是私有的. (3).空标识符"_"是一个占位符,

  • Go中map数据类型3点小知识

    1.map数据类型初始化 两种方式:map[string]string{}或make(map[string]string) 2.未初始化的map是nil,它与一个空map基本等价,只是nil的map不允许往里面添加值.(A nil map is equivalent to an empty map except that no elements may be added) 因此,map是nil时,取值是不会报错的(取不到而已),但增加值会报错. 其实,还有一个区别,delete一个nil map

  • Go语言变量与基础数据类型详情

    目录 一.基础介绍 1.Go 的特性 2.Go 的常用命令 3.Hello Word 二.变量 1.定义方式 三.常量 四.基础数据类型 1.数字 2.浮点型(小数,32/64表示小数点后长度多少位) 3.布尔(Bool) 4.字符串 一.基础介绍 Go 是静态(编译型)语言,是区别于解释型语言的弱类型语言(静态:类型固定,强类型:不同类型不允许直接运算) 例如 python 就是动态强类型语言 1.Go 的特性 跨平台的编译型语言,交叉编译 管道(channel),切片(slice),并发(r

  • Go语言基本的语法和内置数据类型初探

    Go令牌 Go程序包括各种令牌和令牌可以是一个关键字,一个标识符,常量,字符串文字或符号.例如,下面的Go语句由六个令牌: 复制代码 代码如下: fmt.Println("Hello, World!") 个体令牌是: 复制代码 代码如下: fmt . Println ( "Hello, World!" ) 行分离器 在Go程序,行的分隔符关键是一个语句终止.也就是说,每一个单独语句不需要特殊的分隔线; 在C编译器转到内部的地方; 作为语句终止符,表示一个逻辑实体的结

  • Go语言数据类型详细介绍

    目录 一.Go 语言两大数据类型 二.基础类型 三.复合类型 指针 四.数组(array) 五.切片(slice) 六.字典/映射(map) 七.通道(channel) 八.结构体(struct) 九.接口(interface) 十.错误(error) 一.Go 语言两大数据类型 Go 语言数据类型包含基础类型和复合类型两大类. 基础类型包括: 布尔类型 bool. 数值类型 int,int8,int16,int32,int64,float32,float64. uint8,uint16,uin

  • Go基础教程系列之数据类型详细说明

    每一个变量都有数据类型,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值

  • Go基础教程系列之Go接口使用详解

    接口用法简介 接口(interface)是一种类型,用来定义行为(方法). type Namer interface { my_method1() my_method2(para) my_method3(para) return_type ... } 但这些行为不会在接口上直接实现,而是需要用户自定义的方法来实现.所以,在上面的Namer接口类型中的方法my_methodN都是没有实际方法体的,仅仅只是在接口Namer中存放这些方法的签名(签名 = 函数名+参数(类型)+返回值(类型)). 当用

  • Go基础教程系列之defer、panic和recover详解

    defer关键字 defer关键字可以让函数或语句延迟到函数语句块的最结尾时,即即将退出函数时执行,即便函数中途报错结束.即便已经panic().即便函数已经return了,也都会执行defer所推迟的对象. 其实defer的本质是,当在某个函数中使用了defer关键字,则创建一个独立的defer栈帧,并将该defer语句压入栈中,同时将其使用的相关变量也拷贝到该栈帧中(显然是按值拷贝的).因为栈是LIFO方式,所以先压栈的后执行.因为是独立的栈帧,所以即使调用者函数已经返回或报错,也一样能在它

  • Java基础教程之理解Annotation详细介绍

    Java基础之理解Annotation 一.概念  Annontation是Java5开始引入的新特征.中文名称一般叫注解.它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类.方法.成员变量等)进行关联. 更通俗的意思是为程序的元素(类.方法.成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且是供指定的工具或框架使用的. Annontation像一种修饰符一样,应用于包.类型.构造方法.方法.成员变量.参数及本地变量的声明语句中.

  • python基础教程之基本数据类型和变量声明介绍

    变量不需要声明 Python的变量不需要声明,你可以直接输入: 复制代码 代码如下: >>>a = 10 那么你的内存里就有了一个变量a, 它的值是10,它的类型是integer (整数). 在此之前你不需要做什么特别的声明,而数据类型是Python自动决定的. 复制代码 代码如下: >>>print a >>>print type(a) 那么会有如下输出: 复制代码 代码如下: 10 <type 'int'> 这里,我们学到一个内置函数t

  • python基础教程之五种数据类型详解

    Python 五种数据类型 在学习一门语言的过程中,首先肯定就是要先接触到它所拥有的数据类型,Python拥有五种主要的数据类型,下面介绍一下我对这五种数据类型的理解和想法. 1.数 在Python中的数主要分为四种:int(整数).float(浮点数).long(长整型)和complex(复数) 主要特别的地方就是float类型的数有一个函数round()可以取整:round(a,b):对float类型的数值a进行操作,小数点后保留b位有效数字,四舍五入,默认为1. complex类型也算是比

  • Go基础教程系列之WaitGroup用法实例详解

    正常情况下,新激活的goroutine(协程)的结束过程是不可控制的,唯一可以保证终止goroutine(协程)的行为是main goroutine(协程)的终止.也就是说,我们并不知道哪个goroutine(协程)什么时候结束. 但很多情况下,我们正需要知道goroutine(协程)是否完成.这需要借助sync包的WaitGroup来实现. WatiGroup是sync包中的一个struct类型,用来收集需要等待执行完成的goroutine(协程).下面是它的定义: type WaitGrou

  • Go基础教程系列之import导入包(远程包)和变量初始化详解

    import导入包 搜索路径 import用于导入包: import ( "fmt" "net/http" "mypkg" ) 编译器会根据上面指定的相对路径去搜索包然后导入,这个相对路径是从GOROOT或GOPATH(workspace)下的src下开始搜索的. 假如go的安装目录为/usr/local/go,也就是说GOROOT=/usr/local/go,而GOPATH环境变量GOPATH=~/mycode:~/mylib,那么要搜索net

  • Go基础教程系列之回调函数和闭包详解

    Go回调函数和闭包 当函数具备以下两种特性的时候,就可以称之为高阶函数(high order functions): 函数可以作为另一个函数的参数(典型用法是回调函数) 函数可以返回另一个函数,即让另一个函数作为这个函数的返回值(典型用法是闭包) 一般来说,附带的还具备一个特性:函数可以作为一个值赋值给变量. f := func(){...} f() 由于Go中函数不能嵌套命名函数,所以函数返回函数的时候,只能返回匿名函数. 先简单介绍下高阶函数,然后介绍闭包. 高阶函数示例 例如,将函数作为另

  • python基础教程项目五之虚拟茶话会

    几乎在学习.使用任何一种编程语言的时候,关于socket的练习从来都不会少,尤其是会写一些局域网的通信的东西.所以书上的这个项目刚好可以练习一下socket编程. 这个练习的整体思路首先有一个聊天的服务器,这个服务器的功能主要是提供客户端socket的连接.存储每个客户端的连接session,处理每个连接发送的消息.解析客户端发送的数据.就这些,至于客户端方面不需要写代码,用系统的telnet工具即可. 我觉得有了上面的分析,剩下的这个程序就没有什么说的了,当然,除了那两个把socket封装的类

随机推荐