基本数据类型篇

本篇介绍

本篇主要就是介绍下go中的基本类型,看看和我们平时就见得有什么不一样。具体就是基本类型中多了表示unicode的rune,复数的complex,然后string操作那块介绍了下unicode的来源。最后就是类似于枚举的常量产生器iota。这篇还好,不难理解。

整数类型

go提供的整数类型比较多,int8,int16,int32,int64,也有对应的无符号形式uint8,uint16.uint32,uint64.当然也有int,uint,但是int,uint究竟是int64,还是int32,这取决于编译器,这块我们不能自己做假设。当然也多了两个类型rune和uintptr,rune用来表示Unicode编码,比如var i rune = '我'. 类似于char,不过char只能表示ASCII码,rune对应的是Unicode码,范围更广。uintptr是用来表示指针值,上层开发应用不多。

运算符这块区别不大,不再介绍。在看打印这块发现有一个小技巧,是go中新增的。

package main

import (

"fmt"

)

func main() {

var i int = 17

fmt.Printf("%d, %#[1]o, %#[1]X\n",i)

}

fox@fox:~/Documents/Go/chapter3/day1$ ./inter

17, 021, 0X11

这样需要将一个变量以多种形式打印时,可以借助于索引。这样的话就不需要把一个变量写多次了。#的作用就是将格式也打印出来,8进制的0,16进制的0X。

浮点类型

go提供了两种浮点类型,float32和float64,打印的时候除了使用%f外,还支持了%g(全部打印小数点后尾数),%e(用科学计数法打印)。在go里面多了+Inf,-Inf,NaN,也就是正无穷,负无穷,不是一个数字。正无穷和负无穷比较好理解,不是一个数字就是指一些非法的计算,比如零除以零,求-1的平方根。NaN和任何对象比较都是false,包括他自己。

复数类型

go中支持复数,这样在go中就可以直接进行复数的操作了。在go中提供了两种精度的复数,可以猜出来,就是complex64,complex128,为什么?因为go中的浮点数就只有两种啊,float32,float64. 如何构造一个复数?有两种方法,我们通过下面的代码看一下:

package main

import (

"fmt"

)

func main() {

var a complex128 = complex(1,3)

b := 1 + 3i

fmt.Println(a, b, a==b, real(a), imag(a))

}

fox@fox:~/Documents/Go/chapter3/day1$ ./inter

(1+3i) (1+3i) true 1 3

也就是复数可以像其他基本类型一样进行比较,加减乘除等基本操作,内置的real,imag分别是获取它的实部和虚部。

bool

bool类型比较简单,需要知道的是bool的true和false不会隐式地和1,0互相转换,除非是在if,for等场景中。其余的按照正常用即可。

字符串

字符串本质上是不可修改的byte序列。在go中或者是在c++等其他高级语言中,对string直接赋值,追加,其实是新创建了一个字符串。尤其是在字符串比较大的时候,反复追加赋值代价是比较高的。回到go,go里面有一些基本操作,比如获取字符串长度len,字符串的切片追加也是可以的,来一个例子看下这些操作:

package main

import (

"fmt"

)

func main() {

var a string = "i am chinese"

fmt.Println(a, ":" ,len(a),":", a[0:4], ":", a[:], ":" , a + " man")

}

fox@fox:~/Documents/Go/chapter3/day1$ ./inter

i am chinese : 12 : i am : i am chinese : i am chinese man

在写字符串时,会有一些特殊字符,比如单双引号,转义符号'\'。在字符串书写时需要转义一下,这在写正则表达式时不怎么方便,可以使用键盘左上角的那个符号`。 比如`\\\`, 就可以正常打印出三个转义符号。

unicode

(这儿不需要新起一小节,所以没有加横线,unicode是字符串的基础。)

介绍一下unicode,世上本来是没有unicode的,计算机刚出现时,用到的字符并不多,数字+字母+标点符号+控制字符,用7个bit位128位足够表示了,这就是ASCII码。

随着计算机的普及,世界上到处的人都开始使用计算机,这时候就出现麻烦了,因为世界上有上百种语言文字,而这些语言文字居然在电脑里面没法表示,也就是不管是哪里的人,讲什么语言,使用计算机就都必须按照英语来,这样对于从来没学过英语的人民就麻烦了,用电脑前需要学英语?后来就有人设想,为什么不把世界上所有的字符进行编号?这样用编号就能表示世界上所有的字符,这样电脑就可以显示各种字符,这样多好?然后有人就将每个字符用4个字节表示,这样4个字节,2^32数量接的字符都可以表示出来。这就是unicode编码,也叫做UTF-32或UCS-4. 这时候可以再回顾一下go中的新增类型rune,rune本质上就是int32,每个字符的unicode编码就是rune。这样就一下子彻底理解rune了吧。

不过这时候故事还没有结束,因为我们平时主要使用的字符并不多,对于英文体系国家,ASCII码足够了,甚至对于所有的计算机用户,最常用的字符也不会超过65536,也就是2^16,这样如果还是每个字符32bit,这会浪费多少空间?所以有一批人就想能否对符号的编码做做修改,不要定长的,常用的字符编码短一点,用7个bit,一般的用2-3字节,最不常用的再用32bit,不过加上区分字节长度的控制字符,会超过32bit。于是著名的Ken Thompson和Rob Pike出来了,制定了一套编码规范,在每个编码前加上几个控制bit,用于表示控制信息。具体点就是编码最高位有多少个1,就表示有多少字节编码,除了首字节,其余字节全部以10开头。具体点就是:

0xxxxxxx 表示0-127,也就是ASCII码,这样就兼容了ASCII码

11xxxxxx 10xxxxxx 2字节

111xxxxx 10xxxxxx 10xxxxxx 3字节

就是这个规律,最多的情况就是32个x

111111xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx,也就是6个字节。

这个就是今天著名的UTF-8编码,这就是为啥我们用记事本打开一个文件,发现是乱码,鼠标点点,转成UTF8,瞬间就是友好的字符出现的原因了。这里面每个编码值也叫作rune,不过仍然是4字节的。

这时候我们可以再来讨论一下len这个函数。

package main

import (

"fmt"

)

func main() {

var i string = "Hello, 中国"

n := 0

for range i {

n++

}

fmt.Println(len(i), n)

}

fox@fox:~/Documents/Go/chapter3/day1$ ./string

13 9

看到了吧,len是计算字符个数,每个汉字转换成UTF8会是3个字节,所以一共13字节,而range这个函数会对字符串进行解码,也就是在遍历的时候,会将字符当做rune来遍历,一个汉字就是一个rune。

这时候再来一个要点,将整数传给字符串,go会把该整数作为一个rune,也就是unicode编码,看下例子:

package main

import (

"fmt"

)

func main() {

var me string = string(65)

fmt.Println(me, string(11111111))

}

fox@fox:~/Documents/Go/chapter3/day1$ ./string

A �

对于非法rune就是用一个黑砖石包起来的空问号样子。

现在介绍些字符串的操作吧。

有几个操作字符串的包,bytes,strings,strconv,unicode。strings里面包含了一些字符串基本操作的函数。bytes包的功能功能和strings差不多,区别是bytes的操作对象是[]byte, 还有一点,字符串的修改,截取,追加都会涉及到空间分配和拷贝操作,而bytes里面提供了一个bytes.Buffer,可以随意修改,而不会有分配和拷贝操作。unicode里面提供的是一些判断是否是字母,是否是数字等基础字符处理函数。看一个例子吧,包含上面的bytes包。

File Edit Options Buffers Tools Help

package main

import (

"fmt"

"bytes"

)

func main() {

var str1 string = "machine learning"

var bs []byte = ([]byte)(str1)

fmt.Println(str1, string(bs))

var str = covertIntToString([] int )

fmt.Println(str)

}

func covertIntToString(digits []int) string {

var buf bytes.Buffer

buf.WriteByte('[')

for i,v := range digits {

if i > 0 {

buf.WriteString(", ")

}

fmt.Fprintf(&buf, "%d", v)

}

buf.WriteByte(']')

return buf.String()

}

fox@fox:~/Documents/Go/chapter3/day1$ ./string

machine learning machine learning

[1, 2, 3, 4, 23]

在字符串处理中,还有一种情况,就是数字和字符串的来回转换,现在介绍常见的两种:

package main

import (

"fmt"

"strconv"

)

func main() {

x := 123

y := fmt.Sprintf("%d", x)

fmt.Println(x,y)

int2str := strconv.Itoa(x)

str2int,_:= strconv.Atoi(int2str)

fmt.Println(int2str, str2int)

}

fox@fox:~/Documents/Go/chapter3/day1$ ./string2int

123 123

123 123

常量

常量就是编译期间值已经确定的变量,而且后续不可以更改。在go中常量就是用const修饰的变量。这点和c++中类似,介绍点不一样的,在go中,多个常量可以一块声明,而且可以忽略其中一些变量的赋值,第一个始终需要赋值。看一个例子:

package main

import "fmt"

const (

a = 1

b

c = 2

d

)

func main() {

fmt.Println(a,b,c,d)

fmt.Printf("%T, %T, %T, %T\n",a,b,c,d)

}

fox@fox:~/Documents/Go/chapter3/day1$ ./constExample

1 1 2 2

int, int, int, int

可以按照,如果常量安祖赋值的话,未给值的就直接按照前面一个来了。这儿了解下%T,这个可以打印变量类型。

这时候可能让我们想起了枚举,我们有时希望值可以一次增长,那有没有方法呢?有,就是iota。iota就是常量产生器,使用它可以达到和枚举一样的效果:

import (

"fmt"

)

type WEEKDAY int

const (

SUNDAY WEEKDAY = iota

MON

TUE

WEN

THU

FRI

SAT

)

func main() {

fmt.Println(SUNDAY, MON, TUE,WEN, THU, FRI, SAT)

}

fox@fox:~/Documents/Go/chapter3/day1$ ./enumExam

0 1 2 3 4 5 6

untyped constants

go中还支持了一种常量,比如下面所示:

const (

e = 2.71828182845904523536028747135266249775724709369995957496696763

pi = 3.14159265358979323846264338327950288419716939937510582097494459

)

这时候e,pi明显不是float64了,在go中,这叫做untyped floating-point,一种有6种,untyped boolean,untyped integer,untyped rune,untyped floating-point,untyped complex,untyped string,举一个例子就是我们经常直接用的字面的true,0,'\u0000',0/0,0i, "hello"。和基本类型是对应的。那和基本类型有啥区别呢?至少对于浮点,untyped 可以表示更大的精度。

总结

这篇主要就是介绍了下go中的基本类型,大体都是一样的,了解下新增的complex和rune即可。对于字符串操作那块,介绍了下从ASCII,到unicode UTF-32,到UTF-8,作为一个背景知识。常量那块介绍了下常量产生器iota,效果和枚举一样。其余就可以按正常理解了。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180317G02OR000?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

同媒体快讯

扫码关注云+社区

领取腾讯云代金券