2018-07-16 16:40:28

goweb-031-golang-基础数据类型

所有的数据都是由比特组成

整型

  • Go语言的数值类型包括几种不同大小的整数、浮点数和复数。
  • 每种数值类型都决定了对应的大小范围和是否支持正负符号。
  • Go语言同时提供了有符号和无符号类型的整数运算。

四种不同大小的有符号整数类型int8int16int32int64,分别对应8、16、32、64bit大小,与此对应的是uint8uint16uint32uint64四种无符号整数类型。

✋还有两种一般对应特定CPU平台机器字大小的有符号和无符号整数intuint,其中int是应用最广泛的数值类型。

  • Unicode字符rune类型是和int32等价的类型,通常用于表示一个Unicode码点。
  • byte是uint8类型的等价类型,byte类型一般用于强调数值是一个原始的数据而不是一个小的整数。
  • 无符号的整数类型uintptr,没有指定具体的bit大小但是足以容纳指针。

intint32也是不同的类型,即使int的大小也是32bit。

  1. 有符号整数采用2的补码形式表示,最高bit位用来表示符号位,一个n-bit的有符号数的值域是从-2^(n-1)2^(n-1)-1
  2. 无符号整数的所有bit位都用于表示非负数,值域是02^n-1
    eg: int8类型整数的值域是从-128到127,而uint8类型整数的值域是从0到255。

算术运算、逻辑运算和比较运算的二元运算符,按照优先级递减的顺序排列:

*      /      %      <<       >>     &       &^
+      -      |      ^
==     !=     <      <=       >      >=
&&
||

二元运算符有五种优先级。在同一个优先级,使用左优先结合规则,但是使用括号可以明确优先顺序,使用括号也可以用于提升优先级,例如mask & (1 << 28)

⛲️逻辑表达式的结果是布尔类型。

==    等于
!=    不等于
<     小于
<=    小于等于
>     大于
>=    大于等于

⌛️ 一元的加法和减法运算符

+      一元加法(无效果)
-      负数

2️⃣bit位操作运算符 前面4个操作运算符不区分是有符号还是无符号数

&      位运算 AND
|      位运算 OR
^      位运算 XOR
&^     位清空(AND NOT)
<<     左移
>>     右移

位操作运算符^作为二元运算符时是按位异或(XOR),当用作一元运算符时表示按位取反,位操作运算符&^用于按位置零(AND NOT)

对于每种类型T,如果转换允许的话,类型转换操作T(x)x转换为T类型 许多整数之间的相互转换并不会改变数值;它们只是告诉编译器如何解释这个值。
对于将一个大尺寸的整数类型转为一个小尺寸的整数类型,或者是将一个浮点数转为整数,可能会改变数值或丢失精度

f := 3.141 // a float64
i := int(f)
fmt.Println(f, i) // "3.141 3"
f = 1.99
fmt.Println(int(f)) // "1"

整数字面值都可以用以0开始的八进制格式书写, 或用以0x0X开头的十六进制格式书写。

ioutil.WriteFile("fileName", []byte("xxx"), 0777)//rwx

浮点数

  • Go语言提供了两种精度的浮点数,float32float64
    它们的算术规范由IEEE754浮点数国际标准定义。
  • 浮点数的范围极限值可以在math包找到。
    eg 常量math.MaxFloat32表示float32能表示的最大数值。

小数点前面或后面的数字都可能被省略(.707或1.)。也可以用科学计数法书写,通过eE来指定指数部分

const e = 10e2//1000

复数

  • 两种精度的复数类型:complex64complex128,分别对应float32float64两种浮点数精度。
  • 内置的complex函数用于构建复数,realimag函数分别返回复数的实部和虚部:
//(a+bi)(c+di)=(ac-bd)+(bc+ad)i
var x complex128 = complex(1, 2) // 1+2i
var y complex128 = complex(3, 4) // 3+4i
fmt.Println(x * y)               // "(-5+10i)"
fmt.Println(real(x * y))         // "-5"
fmt.Println(imag(x * y))         // "10"

一个浮点数面值或一个十进制整数面值后面跟着一个i,(3.141592i或2i),它将构成一个复数的虚部,复数的实部是0:

fmt.Println(1i * 1i) // "(-1+0i)", i^2 = -1

布尔

  • 布尔类型的值只有两种:truefalse
  • 逻辑运算符会产生布尔型的值。
  • 一元操作符!对应逻辑非操作,!true的值为false
  • 布尔值和&&||操作符结合可能会短路
  • 布尔值并不会隐式转换为数字值0或1,反之亦然。

字符串

  • 一个字符串是一个不可改变的字节序列。
  • 字符串可以包含任意的数据,通常是用来包含人类可读的文本。
  • 文本字符串通常被解释为采用UTF8编码的Unicode码点(rune)序列。
  • 内置的len函数可以返回一个字符串中的字节数目不是rune字符数目。
  • 索引操作s[i]返回第i个字节的字节值,i必须满足0 ≤ i< len(s)条件约束。
s := "hello, world"
fmt.Println(len(s))     // "12"
fmt.Println(s[0], s[7]) // "104 119" ('h' and 'w')

访问超出字符串索引范围的字节将会导致panic异常:

c := s[len(s)] // panic: index out of range

i个字节并不一定是字符串的第i个字符,对于非ASCII字符的UTF8编码会要两个或多个字节。

子字符串操作s[i:j]基于原始的s字符串的第i个字节开始到第j个字节不包含j生成一个新字符串。生成的新字符串将包含j-i个字节。

fmt.Println(s[0:5]) // "hello"

i或者j都可能被忽略,当它们被忽略时将采用0作为开始位置,采用len(s)作为结束的位置。

fmt.Println(s[:5]) // "hello"
fmt.Println(s[7:]) // "world"
fmt.Println(s[:])  // "hello, world"

+操作符将两个字符串连接构造一个新字符串

fmt.Println("goodbye" + s[5:]) // "goodbye, world"

字符串可以用==<进行比较;比较通过逐个字节比较完成的,比较的结果是字符串自然编码的顺序。

字符串的值是❌不可变的。

func main() {
    s := "left"
    t := s
    s += ", right"
    fmt.Println(s, "<-->", t)
}

alt

字符串是不可修改的,修改字符串内部数据的操作也被禁止

s[0] = 'L' // compile error: cannot assign to s[0]

✌不变性意味着如果两个字符串共享相同的底层数据的话也是安全的,复制任何长度的字符串代价是低廉的。 alt

字符串面值

字符串直接写在双引号里面

"Hello, 世界"

转义

\a      响铃
\b      退格
\f      换页
\n      换行
\r      回车
\t      制表符
\v      垂直制表符
\'      单引号(只用在 '\'' 形式的rune符号面值中)
\"      双引号(只用在 "..." 形式的字符串面值中)
\\      反斜杠

可以通过十六进制或八进制转义在字符串面值中包含任意的字节

  • 一个十六进制的转义形式是\xhh,其中两个h表示十六进制数字(大写或小写都可以)。
  • 一个八进制转义形式是\ooo,包含三个八进制的o数字(0到7),不能超过\377❓ 。

一个原生的字符串面值形式是`...`,使用反引号代替双引号。
在原生的字符串面值中,没有转义操作;全部的内容都是字面的意思。

func main() {
    s := `
    很多
    很多\
    行`
    fmt.Println(s)
}

Unicode

在很久以前,世界还是比较简单的,起码计算机世界就只有一个ASCII字符集:美国信息交换标准代码。ASCI,使用7bit来表示128个字符:包含英文字母的大小写、数字、各种标点符号和设备控制符。随着互联网的发展,混合多种语言的数据变得很常见。如何有效处理这些包含了各种语言的丰富多样的文本数据呢❓
alt

Unicode http://unicode.org,它收集了这个世界上所有的符号系统,包括重音符号和其它变音符号,制表符和回车符,还有很多神秘的符号,每个符号都分配一个唯一的Unicode码点。

UTF-8

  • UTF8是一个将Unicode码点编码为字节序列的变长编码。UTF8编码是由Go语言之父Ken Thompson和Rob Pike共同发明的。
  • UTF8编码使用1到4个字节来表示每个Unicode码点,ASCII部分字符只使用1个字节,常用字符部分使用2或3个字节表示。

每个符号编码后第一个字节的高端bit位用于表示编码总共有多少个字节。如果第一个字节的高端bit为0,则表示对应7bit的ASCII字符,ASCII字符每个字符依然是一个字节,和传统的ASCII编码兼容。如果第一个字节的高端bit是110,则说明需要2个字节;后续的每个高端bit都以10开头。

0xxxxxxx     
110xxxxx 10xxxxxx       
1110xxxx 10xxxxxx 10xxxxxx      
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx 

字符串和Byte切片

字符串和Byte切片转换

s := "zxysilent"
b := []byte(s)
s1 := string(b)
fmt.Println(s, b, s1)

标准库中有四个包对字符串处理尤为重要:bytesstringsstrconvunicode包。

  • strings包提供了许多如字符串的查询、替换、比较、截断、拆分和合并等功能。
  • bytes包也提供了很多类似功能的函数,但是针对和字符串有着相同结构的[]byte类型。 因为字符串是只读的,因此逐步构建字符串会导致很多分配和复制。在这种情况下,使用bytes.Buffer类型将会更有效。
  • strconv包提供了布尔型、整型数、浮点数和对应字符串的相互转换,还提供了双引号转义相关的转换。
  • unicode包提供了IsDigitIsUpper和IsLower等类似功能,它们用于给字符分类。

alt

字符串和数字的转换

除了字符串、字符、字节之间的转换,字符串和数值之间的转换也比较常见。 strconv包提供这类转换功能。

将一个整数转为字符串,一种方法是用fmt.Sprintf返回一个格式化的字符串;另一个方法是用strconv.Itoa(“整数到ASCII”):

x := 123
y := fmt.Sprintf("%d", x)
fmt.Println(y, strconv.Itoa(x)) // "123 123"

FormatIntFormatUint函数可以用不同的进制来格式化数字

fmt.Println(strconv.FormatInt(int64(x), 2)) // "1111011"

fmt.Printf函数的%b%d%o%x等也可用来格式化:

s := fmt.Sprintf("x=%b", x) // "x=1111011"

将一个字符串解析为整数,可以使用strconv包的AtoiParseInt,ParseUint(无符号整数)函数

x, err := strconv.Atoi("123")          
y, err := strconv.ParseInt("123", 10, 64) // base 10, up to 64 bits

ParseInt函数的第三个参数是用于指定整型数的大小;eg16表示int160则表示int, 返回的结果总是int64类型。 也可使用fmt.Scanf来解析输入的字符串和数字。

fmt.Printf(format string, a ...interface{})
fmt.Fprintf(w io.Writer, format string, a ...interface{})
fmt.Sprintf(format string, a ...interface{})

fmt.Scanf(format string, a ...interface{})
fmt.Fscanf(r io.Reader, format string, a ...interface{})
fmt.Sscanf(str string, format string, a ...interface{})

常量

  • 常量表达式的值在编译期计算,而不是在运行期。
  • 每种常量的潜在类型都是基础类型。
const pi = 3.14159

批量声明多个常量。

const (
    e  = 2.718281
    pi = 3.141592
)

常量间的所有算术运算、逻辑运算和比较运算的结果也是常量,对常量的类型转换操作或以下函数调用都是返回常量结果:lencaprealimagcomplexunsafe.Sizeof

const L=len("adcd")//4
const L = unsafe.Sizeof(int(1))//8

一个常量的声明也可以包含一个类型和一个值,但是如果没有显式指明类型,那么将从右边的表达式推断类型。通过%T参数打印类型信息

//type Duration int64
const noDelay time.Duration = 0
const timeout = 2 * time.Minute
fmt.Printf("%T %[1]v\n", noDelay) 
fmt.Printf("%T %[1]v\n", timeout)   

批量声明的常量,除了第一个外其它的常量右边的初始化表达式都可以省略,如果省略初始化表达式则表示使用前面常量的初始化表达式写法,对应的常量类型也一样的

const (
    a = 1
    b
    c = 2
    d
)

fmt.Println(a, b, c, d) // "1 1 2 2"

iota 常量生成器

在一个const声明语句中,在第一个声明的常量所在的行,iota将会被置为0,然后在每一个有常量声明的行加一。

const (
        a = iota
        b
        c
    )
    const (
        d = iota
        e
        f
    )
    fmt.Println(a, b, c, d, e, f)

本文链接:https://www.paishouba.com/post/goweb-03-1.html

-- EOF --

Comments