Un vistazo rápido a cuáles son los tipos de datos básicos en go

entero

Dividido por longitud de bits: 8 bits, 16 bits, 32 bits, 64 bits.

Corresponde a enteros con signo: int8, int16, int32, int64.

Corresponde a enteros sin signo: uint8, uint16, uint32, uint64.

Reglas para calcular números máximos y mínimos:

  • Entero con signo: debido al signo, el bit más alto del número de bits se usa para almacenar el signo, y los demás se usan para almacenar el valor de los datos, por lo que para el número de nbits, el rango de valores es: -2^( n-1)^~2^ (n-1)^-1, que corresponde a int8, es -127 ~ 127.
  • Número positivo sin signo: No es necesario registrar el signo con el dígito más alto, todos los dígitos representan el número. El rango de valores es: 0 ~ 2^n^-1. Para int8, es 0 ~ 255.

tipos enteros especiales

inty uinttambién uintptr_

intY uintdependiendo de la plataforma específica, su tamaño es el mismo que el entero nativo o el valor computacionalmente más eficiente en esa plataforma. O 64 bits o 32 bits al mismo tiempo, pero no se puede suponer que sean enteros de 64 o 32 bits. Incluso bajo el mismo hardware, diferentes compiladores pueden elegir diferentes tamaños.

En cuanto a uintptrsu tamaño, no está claro. Pero definitivamente es lo suficientemente grande como para sostener un puntero. A menudo se utiliza para la programación de bajo nivel.

Aunque int, uintpuede tener la misma longitud que int32, int64y ..otros tipos de enteros, son tipos diferentes.

Si desea determinar el tamaño de la intsumauint

fmt.Println(runtime.GOARCH)		// 看看CPU型号
fmt.Println(strconv.IntSize)	// 这才是int的大小,上面只是提供一个对照

Desbordamiento

Ya sea que esté firmado o no, si el número de bits necesarios para calcular el resultado supera el rango del tipo, se denomina desbordamiento . Los bits altos desbordados se descartan silenciosamente.

var i int8 = -128
fmt.Println(i-1)	// 127
var i2 int8 = 127
fmt.Println(i2+1)	// -128
var u uint8 = 0
fmt.Println(u-1)	// 255
var u2 uint8 = 255
fmt.Println(u2+1)	// 0

número de coma flotante

float32, float64. Sigue el IEEE 754estándar.

math.MaxFloat32float32El valor máximo del tipo se da : 3.4028234663852886e+38.

math.MaxFloat64则是float64类型的最大值:1.7976931348623157e+308

浮点数可以用来表示小数。

十进制下,float32有效位大约是6位。float64有效位大约是15位。

浮点数的打印可以使用:

  1. %g,保留足够的精度显示
  2. %e,使用指数形式显示
  3. %f,使用无指数形式显示
f := 2.71828
fmt.Printf("%g, %[1]e, %[1]f \n", f)	// 2.71828, 2.718280e+00, 2.718280

复数

complex64complex128 ,二者分别由float32float64组成。

使用real函数提取复数的实部,使用imag函数提取复数的虚部。

浮点数或者整数后面加i就会变成一个虚数,且它的实部为0

x := 1+2i
y := 3+4i

布尔值

bool类型就是布尔值,有true(真)和false(假)两个值。

布尔值无法隐式转换成数值,数值也不能转成布尔值。

它的零值是false

一元操作符!表示逻辑取反。!true表示false

字符串

string表示字符串。它是不可变的字节序列。Go中的字符串内部实现用UTF-8编码。

字符串的“长度”与遍历字符串的做法

字符串的“长度”

对字符串调用len函数,获取到的不是字符串的长度(字符的个数),而是字符串的字节数(字节切片的长度)。

如下,尽管字符个数只有6,但字节长度len(s)却有18,这是因为中文字符以UTF-8存储,通常包含3~4个字节。

s := "中文字节数多"
fmt.Println("len: ", len(s))	// len:  18

对字符串使用下标索引操作,会返回对应索引的字节,而不是字符。

s := "中文字节数多"
fmt.Println("len: ", len(s))	// len:  18
for i :=0; i < len(s); i++ {
    fmt.Printf("%d, %[1]c, %[1]T\n",s[i])
}

对应的输出如下:

len: 18
228, ä, uint8
184, ¸, uint8
173, ­, uint8
230, æ, uint8
150, �, uint8
135, �, uint8
229, å, uint8
173, ­, uint8
151, �, uint8
232, è, uint8
138, �, uint8
130, �, uint8
230, æ, uint8
149, �, uint8
176, °, uint8
229, å, uint8
164, ¤, uint8
154, �, uint8

因此不要随便乱用字符串的下标操作,否则可能获得有意想不到的结果。

遍历字符串

由上面的下标操作可以看出,对字符串的下标索引操作会获得单个字节而不是字符,假如现在我们想处理的是UTF-8解码的字符的话,有两种方式,基本思路都是处理成rune类型:

第一种,用UTF-8解码器显式处理这些字符,unicode/utf8包示例。

utf8.RuneCountInString(s)返回字符串转为rune后的个数,Go使用rune代表一个UTF-8字符。

utf8.utf8.DecodeRuneInString(s[i:])处理当前字符串,并算出下一个rune以及它所占的字节数。

s := "What? 中文字节数多"
runeCount := utf8.RuneCountInString(s)
fmt.Println("runeCount:", runeCount)	// runeCount: 12
for i:= 0; i<len(s); {
	r, size:= utf8.DecodeRuneInString(s[i:])
	fmt.Printf("i: %d, r:%q, type:%T \n", i, r, r)
	i += size
}

输出如下:

runeCount: 12
i: 0, r:'W', type:int32
i: 1, r:'h', type:int32
i: 2, r:'a', type:int32
i: 3, r:'t', type:int32
i: 4, r:'?', type:int32
i: 5, r:' ', type:int32
i: 6, r:'中', type:int32
i: 9, r:'文', type:int32
i: 12, r:'字', type:int32
i: 15, r:'节', type:int32
i: 18, r:'数', type:int32
i: 21, r:'多', type:int32

第二种,用range循环,Go会隐式的进行UTF-8解码。

注意,这里的i,指的是字节的下标,而不是字符的下标。

s := "What? 中文字节数多"
for i, r := range s {
    fmt.Printf("i: %d, rune: %q, type: %T \n", i, r, r)
}

输出如下:

i: 0, rune: 'W', type: int32
i: 1, rune: 'h', type: int32
i: 2, rune: 'a', type: int32
i: 3, rune: 't', type: int32
i: 4, rune: '?', type: int32
i: 5, rune: ' ', type: int32
i: 6, rune: '中', type: int32
i: 9, rune: '文', type: int32
i: 12, rune: '字', type: int32
i: 15, rune: '节', type: int32
i: 18, rune: '数', type: int32
i: 21, rune: '多', type: int32

Rune与Byte(字节)

int32的别名是rune,天然适合存储单个文字符号,为Go所采用的。

rune类型值代表一个UTF-8字符。以字节(byte)为单位对Unicode码点作变长编码。现在计算机都用UTF-8来表示单个字符。

字符串的是由“字符”组成的,字符用单引号包裹起来,如:

var b = 'h'
c := '冲'
fmt.Printf("%d, %q \n", b, b)	// 104, 'h'
fmt.Printf("%d, %q \n", c, c)	// 20914, '冲'

字节,byte类型,底层类型是uint8,由8个bit组成,它可以代表一个ASCII码。ASCII码是满足早期计算机的使用的,它用7位表示128个“字符”(ASCII字符):大小写英文字母、数字、标点符号和设备控制符。

字符串与字节slice的转换

字符串底层是一个字节数组,所以可以和[]byte类型互换。

s := "abc"
b := []byte(s)
s2 := string(b)

概念上,[]byte(s)转换操作会分配新的字节数组,拷贝填入s含有的字节,并生成一个slice的引用,指向整个数组。反之,用string(b)也会产生一份副本而不是操作真正的b,以此保证上面s2不变。

字符串不可变

字符串是不可变的,表现在其字符串值不可修改。平时我们看到的字符串修改操作、拼接操作并不改变原有的字符串值,而是将操作后生成新的字符串值赋予原来的变量。

s := "left foot"
t := s
s += ", right foot"

尽管字符串创建后,它底层的字节slice不可变,但是普通的字节slice是可以随意改变的。

var a = []byte{'h', 'e', 'l', 'l', 'o'}
fmt.Printf("%p, %[1]q \n", a)	// 0xc00000a098, "hello"
a[4] = ' '
fmt.Printf("%p, %[1]q \n", a)	// 0xc00000a098, "hell "

由于字符串的不可变以及避免频繁的操作字符串而导致的多次内存分配和复制,可以使用bytes.Buffer类型。

见GOPL的一个例子:

func intsToString(values []int) string {
	var buf bytes.Buffer
	buf.WriteByte('[')
	for i, v := range values {
		if i > 0 {
			buf.WriteString(",")
		}
		fmt.Fprintf(&buf, "%d", v)
	}
	buf.WriteByte(']')
	return buf.String()
}

func main() {
	fmt.Println(intsToString([]int{1, 2, 3})) // [1,2,3]
}

追加ASCII字符可以用writeByte,追加UTF-8编码的文字符号,最好用WriteRune方法。

基本类型的值都是可比较的

基本类型的值都是可比较的,如布尔值、数值、字符串等。

数值的类型转换

很多整型—整型的转换不会引起值的变化,仅告知编译器如何解读这么值。但缩减大小的类型转换,以及整型与浮点型的相互转换,会因此值的改变或者损失精度。

浮点型转整型会舍弃小数部分并向0取整。

var f = 3.526
i := int(f)
fmt.Printf("f: %v, i: %v \n", f, i) // f: 3.526, i: 3 
var i16 = int16(555)
var i8 = int8(i16)
fmt.Printf("i16: %v, i8: %v \n", i16, i8) // i16: 555, i8: 43 

运算符

运算符降序排列:

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

二元运算符分为五大优先级。同级别的运算符满足左结合律,可以用圆括号指定次序。

常量

常量是一种表达式,保证在编译阶段就计算出对应的值。所有常量本质上都属于基本类型:布尔型、字符串或者数字。

常量自编译后,其值恒定不变。

type Integer int

const I Integer = 10

const S string = "important_secret"

const (
	NUM1 = 1
	NUM2 = 2
	NUM3
	NUM4 = 5.5
	STR1 = "STR1"
)

func main() {
	fmt.Printf("I: %v \n", I)
	fmt.Printf("S: %v \n", S)
	fmt.Printf("NUM1: %v \n", NUM1)
	fmt.Printf("NUM2: %v \n", NUM2)
	fmt.Printf("NUM3: %v \n", NUM3)
	fmt.Printf("NUM4: %v \n", NUM4)
	fmt.Printf("STR1: %v \n", STR1)
}

输出如下:

I: 10
S: important_secret
NUM1: 1
NUM2: 2
NUM3: 2
NUM4: 5.5
STR1: STR1

本文正在参加技术专题18期-聊聊Go语言框架

Supongo que te gusta

Origin juejin.im/post/7120939408051994638
Recomendado
Clasificación