Go基础数据类型

布尔类型

布尔类型用于表示真假,类型名为bool,只有两个值true和false,占用一个字节宽度,0为false

var (
    isTrue bool = true
    isFalse bool = false
)

逻辑运算

(1)    与&&
只有左右两边表达式结果都为true,运算结果才为true

	fmt.Println(true && true)	//true
	fmt.Println(true && false)	//false
	fmt.Println(false && true)	//false
	fmt.Println(false && false)	//false

(2)    或||

	fmt.Println(true || true)	//true
	fmt.Println(true || false)	//true
	fmt.Println(false || true)	//true
	fmt.Println(false || false)	//false

(3)    非!

	fmt.Println(!true)	//false
	fmt.Println(!false)	//true

关系运算

	fmt.Println(true == true)	//等于==
	fmt.Println(true != true)	//不等于!=

整数类型

Go语言提供了5种有符号、5种无符号、1种指针、1种单字节、1种单个unicode字符(unicode码点),共13种整数类型,零值均为0

类型名 字节宽度 说明&取值范围
int 与平台有关,32位系统4字节,64位系统8字节 有符号整型
uint 与平台有关,32 位系统 4 字节,64 位系统 8 字节 无符号整形
int8 1 字节 用 8 位表示的有符号整型,取值范为:[-128, 127]
int16 2字节 用 16 位表示的有符号整型,取值范围为:[-32768,32767]
int32 4字节 用 32 位表示的有符号整型,取值范围为:[-2147483648,2147483647]
int64 8字节 用 64 位表示的有符号整型,取值范围为:[-9223372036854775808,9223372036854775807]
uint8 1 字节 用 8 位表示的有符号整型,取值范为:[0, 255]
uint16 2字节 用 16 位表示的有符号整型,取值范围为:[0,65535]
uint32 4字节 用 32 位表示的有符号整型,取值范围为:[0,4294967295]
uint64 8字节 用 64 位表示的有符号整型,取值范围为:[0,18446744073709551615]
rune 4字节 Unicode 码点,取值范围同int32
byte 1 字节 字节类型,取值范围同 uint8
uintptr 与平台有关,32 位系统 4 字节,64 位系统 8 字节 指针值的无符号整型

字面量:

十进制表示法: 以 10 为基数,采用 0-9 十个数字,逢 10 进位,如:10
八进制表示法:以 8 为基数,采用 0-7 八个数字,逢 8 进位,使用 0 开头表示为八进制表示,如:010
十六进制表示法:以 16 为基数,采用 0-9 十个数字和 A-F 六个字母,逢 16 进位,使用0X 开头表示为十六进制 ,如:0X10

	// 分别打印十进制,八进制,十六进制的字面量
	fmt.Println(10, 010, 0X10)	//10 8 16

算术运算

+、-、*、/、%、++、--,注意:针对/除数不能为0,且结果依然为整数

	var n1, n2, n3 int = 1, -8, -2
	var n4 uint = 4
	// 算术运算
	fmt.Println(n1 + n2)	//-7
	fmt.Println(n1 - n2)	//9
	fmt.Println(n1 * n2)	//-8
	fmt.Println(n1 / n2)	//0 /向下取整
	fmt.Println(n1 % n2)	//1

	n3++
	n4--
	fmt.Println(n3, n4)	//-1 3

关系运算

、>=、 <、 <=、 ==、 !=

	fmt.Println(1 > 2)
	fmt.Println(1 >= 2)
	fmt.Println(1 < 2)
	fmt.Println(1 <= 2)
	fmt.Println(1 == 2)
	fmt.Println(1 != 2)

位运算

&、|、^、<<、 >>、 &^
对于负整数在计算机中使用补码进行表示,对应正整数二进制表示取反+1
针对左、右移的右操作数必须为无符号整型

二进制表示法	
	原码 正数
	反码
	补码	负数
	// 位运算
	// 2 二进制=> 0010
	// 7 二进制=> 0111
	// -2 二进制=> 1110  负整数在计算机中使用补码进行表示,对应正整数二进制表示取反+1
	fmt.Println(4 & 2)	// 0100 & 0010 => 0000
	fmt.Println(4 | 2)	// 0100 | 0010 => 0110
	fmt.Println(4 ^ 2)	// 0100 ^ 0010 => 0110
	fmt.Println(4 &^ 2)	// 0100 &^ 0010 => 0100
	fmt.Println(4 << 2)	// 0100 <<移2位 => 0001 0000
	fmt.Println(8 >> 2)	// 1000 >>移2位 => 0010

赋值运算

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

	// 赋值运算
	var n1, n2 int = 1, 2
	n1 += n2	// n1 = n1 + n2
	fmt.Println(n1)	//3
	n1 <<= n2	// n1 = n1 << n2
	fmt.Println(n1)	//12

类型转换

Go不会自动对数据类型转换,因此左、右操作数类型必须一致或int莫个字面量,可通过类型名(数据)的语法将数据转换为对应类型。需要大转小需要注意值截断和值溢出问题

不建议这种类型转换写法:大转小,有符号转无符号,无符号转有符号
// 类型转换
	var n1, n2 int = 1, 4
	fmt.Printf("%T %T %T %T %T %T\n", n1, uint(n1), n2, int(n2), uint8(n2), int64(n2))	//int uint int int uint8 int64

fmt.Printf进行格式化参数输出, 占位符:

%T    变量名类型
%b    二进制
%c    字符
%d    十进制
    %+d    表示对正整数带+符号
    %nd    表示最小占位n个宽度且右对齐
    %-nd    表示最小占位n个宽度且左对齐
    %0nd    表示最小占位n个宽度且右对齐,空字符使用0填充
%o    八进制
    %#o    带0的前缀
%x、%X 十六进制
    %#x(%#X)带0x(0X)的前缀
%U    Unicode码点
    %#U    带字符的Unicode码点
%q    带单引号的字符
// fmt打印
	var (
		n1	int = 10
		n2	int	= -10
		n3	byte = 'a'
		n4  rune = '虎'
	)
	fmt.Printf("%d %b %o %x %X %#o %#x %#X\n", n1, n1, n1, n1, n1, n1, n1, n1,)	//10 1010 12 a A 012 0xa 0XA
	fmt.Printf("|%d|%+d|%10d|%-10d|%010d|%+-10d|%+010d|\n", n1, n1, n1, n1, n1, n1, n1)	//10|+10|        10|10        |0000000010|+10       |+000000010
	fmt.Printf("%d|%+d|%10d|%-10d|%010d|%+-10d|%+010d|\n", n2, n2, n2, n2, n2, n2, n2)	//-10|-10|       -10|-10       |-000000010|-10       |-000000010
	fmt.Printf("%c %c %q %q\n", n3, n4, n3, n4)	//a 虎 'a' '虎'
	fmt.Printf("%U %#U\n", n4, n4)	//U+864E U+864E '虎'

浮点型

浮点数用于表示带小数的数字,Go提供float32和float64两种浮点类型,非精确值类型,零值0.0

主要是为了表示小数,也可细分为float32和float64两种。浮点数能够表示的范围可以从很小到很巨大,这个极限值范围可以在math包中获取,math.MaxFloat32表示float32的最大值,大约是3.4e38,math.MaxFloat64大约是1.8e308,两个类型最小的非负值大约是1.4e-45和4.9e-324。

float32大约可以提供小数点后6位的精度,作为对比,float64可以提供小数点后15位的精度。通常情况应该优先选择float64,因此float32的精确度较低,在累积计算时误差扩散很快,而且float32能精确表达的最小正整数并不大,因为浮点数和整数的底层解释方式完全不同。

类型 长度
float32 IEEE-754 32位浮点型数
float64 IEEE-754 64位浮点型数

字面量

十进制表示法:3.1415926
科学计数法:1e-5

格式

	// 浮点型
	var (
		f1 float32 = 3.1415926
		f2 float32 = 3E-3
		f3 float64 = 3.1E10
	)

算术运算

+、-、*、/、++、--
注意:针对/除数不能为0

// 浮点型-算术运算
	var (
		f1 float32 = 3.1415926
		f2 float32 = 3E-3
	)
	fmt.Println(f2)	//0.003
	fmt.Println(f1 + f2)	//3.1445925
	fmt.Println(f1 - f2)	//3.1385925
	fmt.Println(f1 * f2)	//0.009424778
	fmt.Println(f1 / f2)	//1047.1975
	f1++
	f2--
	fmt.Println(f1, f2)	//4.1415925 -0.997

关系运算

、>=、<、<=
浮动型不能进行==或者!=比较,可选择使用两个浮点数的差在一定区间内则认为相等

	// 浮点型-关系运算
	var (
		f1 float32 = 3.1415926
		f2 float32 = 3E-3
	)
	fmt.Println(f1 > f2)
	fmt.Println(f1 >= f2)
	fmt.Println(f1 < f2)
	fmt.Println(f1 <= f2)

赋值运算

=、-=、*=、/=

var (
		f1 float32 = 3.1415926
		f2 float32 = 3E-3
	)
	f1 += f1
	f2 -= f2
	fmt.Println(f1)
	fmt.Println(f2)

类型转换

Go不会自动对数据类型转换,因此左、右操作数类型必须一致或int莫个字面量,可通过类型名(数据)的语法将数据转换为对应类型。需要注意值截断和值溢出问题

var (
		f1 float32 = 3.1415926
	)

	fmt.Printf("%T %T\n", f1, float64(f1))

fmt.Printf进行格式化参数输出,占位符:

%f、%F    十进制表示法
%n.mf 表示最小占n个宽度并且最多保留m位小数
%e、%E    科学计数法表示
%g、%G    自动选择最紧凑得表示方法%e\%E和%f\%F
//  fmt.Printf打印
	var (
		f1 float32 = 3.1415926
		f3 float32 = 3E-3
	)

	fmt.Printf("%f %f %F %F\n", f1, f3, f1, f3)	//3.141593 0.003000 3.141593 0.003000
	fmt.Printf("%e %e %E %E\n", f1, f3, f1, f3)	//3.141593e+00 3.000000e-03 3.141593E+00 3.000000E-03
	fmt.Printf("%g %g %G %G\n", f1, f3, f1, f3)	//3.1415925 0.003 3.1415925 0.003
	fmt.Printf("|%5.2f| |%5.2f|\n", f1, f3)	//| 3.14| | 0.00|

复数型

Go 提供 complex64 和 complex128 两种复数类型,针对 complex64 复数的实部和虚部均使用
float32,针对 complex128 复数的实部和虚部均使用 float64

类型 长度
complex64 32位实数和虚数
complex128 64位实数和虚数

字面量

十进制表示法:1 + 2i,i*i = -1; 1为实部,2为虚部

常用函数

complex: 工厂函数,通过两个参数创建一个复数

real: 用于获取复数的实部

imag:用于获取复数的虚部

	//  复数
	var (
		c1 complex64 = 1 + 2i
		c2 complex64 = complex(3, 4)
	)

	fmt.Println(c1 + c2)	//(4+6i)
	fmt.Println(real(c1), imag(c1))	//1 2

字符串类型

Go语言内置了字符串类型,使用类型名string表示,零为空字符串""

只读的Unicode字节序列,Go语言使用UTF-8格式编码Unicode字符,每个字符对应一个rune类型。一旦字符串变量赋值之后,内部的字符就不能修改,英文是一个字节,中文是三个字节。

字面量

​ 可解析字符串:通过双引号"来创建,不包含多行,支持特殊字符转义序列

​ 原生字符串:通过反引号`来创建,包含多行,不支持特殊字符转义序列

特殊字符

	\\	反斜杠
	\'	单引号
	\"	双引号
	\a	响铃
	\b	退格
	\f	换页
	\n	换行
	\r	回车
	\t	制表符
	\v	垂直制表符
	\ooo	3个8位数字给定的八进制码点的Unicode字符(不能超过\377)
	\uhhhh	4个16位数字给定的十六进制码点的Unicode字符
	\Uhhhhhhhh	8个32位数字给定的十六进制码点的Unicode字符
	\xhh	2个8位数字给定的十六进制码点的Unicode字符
//  字符串
	var (
		s1 string = "aaa\nbbb"
		s2 string = `aaa\nbbb`
		s3 string = `aaa
							bbb`
		s4 string = "qwertyuiopasdfghjklzxcvbnm"
		s5 string = "我爱中国"
	)

	fmt.Println(s1)
	fmt.Println(s2)	//aaa\nbbb
	fmt.Println(s3)	/*aaa
													bbb*/

	fmt.Println(s4)
	fmt.Println(s5)	//我爱中国

常用操作

字符串拼接 +

关系运算符 >、>=、<、<=、==、!=

赋值运算符 +=

索引 s[index],针对只包含ascii字符的字符串

切片 s[start:end],针对只包含ascii字符的字符串

//  字符串
	var (
		s1 string = "aaa\nbbb"
		s2 string = `aaa\nbbb`
		s3 string = `aaa
							bbb`
		s4 string = "qwertyuiopasdfghjklzxcvbnm"
		s5 string = "我爱中国"
	)

	fmt.Println(s4+"aaaaaaaaaaaaaaaasssdscas")	//qwertyuiopasdfghjklzxcvbnmaaaaaaaaaaaaaaaasssdscas
	s5 += "--来自南方"
	fmt.Println(s5)	//我爱中国--来自南方
	fmt.Println(s1 == s2)	//false
	fmt.Println(s1 != s3)	//true
	fmt.Println("abc" > "abe")	//false
	fmt.Println("abc" >= "abe")	//false
	fmt.Println("abc" <= "abe")	//true

	fmt.Println(s4[0])	//索引0的ascii:113
	// 切片前包后不包
	fmt.Println(s4[:], s4[3:], s4[:8], s4[3:8])	//qwertyuiopasdfghjklzxcvbnm rtyuiopasdfghjklzxcvbnm qwertyui rtyui

常用函数

​ len 获取字符串长度(针对只包含ascii字符的字符串)

​ string 将byte或rune数组转换为字符串

使用fmt.Printf进行格式化参数输出,占位符:

%s	基本的字符串输出

%d	十进制
	//  字符串
	var (
		s1 string = "aaa\nbbb"
		s5 string = "我爱中国"
	)

	fmt.Printf("%s len %d\n", s1, len(s1))
	fmt.Printf("%s len %d\n", s5, len(s5))

类型转换

string转int:    int, err := strconv.Atoi(string)
string转int64:  int64, err := strconv.ParseInt(string, 10, 64)
int转string:    string := strconv.Itoa(int)
int64转string:  string := strconv.FormatInt(int64, 10)

枚举类型

常使用iota生成器用于初始化一系列相同规则的常量,批量声明常量的第一个常量的使用iota进行赋值,此时 iota 被重置为 0,其他常量省略类型和赋值,在每初始化一个常量则加 1

const (
	i1 int = iota
	i2
	i3 int = iota
	i4
)

func main() {
	//  枚举类型
	const (
		i5 = iota
		i6
		i7 = 7
		i8 = iota
		i9
	)

	fmt.Println(i1, i2, i3, i4, i5, i6, i7, i8, i9)	//0 1 2 3 0 1 7 3 4

}

指针类型(Pointer)

一个指针变量可以指向任何一个值的内存地址。它指向那个值的内存地址,在 32 位机器上占用 4 个字节,在 64 位机器上占用 8 个字节,并且与它所指向的值的大小无关。当然,可以声明指针指向任何类型的值来表明它的原始性或结构性;你可以在指针类型前面加上号(前缀)来获取指针所指向的内容,这里的号是一个类型更改器。使用一个指针引用一个值被称为间接引用。

当一个指针被定义后没有分配到任何变量时,它的值为 nil,表示空指针

一个指针变量通常缩写为 ptr。

符号 ““ 可以放在一个指针前,如 “intP”,那么它将得到这个指针指向地址上所存储的值;这被称为反引用(或者内容或者间接引用)操作符;另一种说法是指针转移。

对于任何一个变量 var, 如下表达式都是正确的:var == *(&var)

注意事项:
你不能得到一个数字或常量的地址,下面的写法是错误的。
//例如:
const i = 5
ptr1 := &i // error: cannot take the address of i
ptr2 := &10 // error: cannot take the address of 10

所以说,Go 语言和 C、C++ 以及 D 语言这些低级(系统)语言一样,都有指针的概念。

但是对于经常导致 C 语言内存泄漏继而程序崩溃的指针运算(所谓的指针算法,如:pointer+2,移动指针指向字符串的字节数或数组的某个位置)是不被允许的。

Go 语言中的指针保证了内存安全,更像是 Java、C# 和 VB.NET 中的引用。

因此 c = *p++ 在 Go 语言的代码中是不合法的。

指针的一个高级应用是你可以传递一个变量的引用(如函数的参数),这样不会传递变量的拷贝。指针传递是很廉价的,只占用 4 个或 8 个字节。当程序在工作中需要占用大量的内存,或很多变量,或者两者都有,使用指针会减少内存占用和提高效率。被指向的变量也保存在内存中,直到没有任何指针指向它们,所以从它们被创建开始就具有相互独立的生命周期。

另一方面(虽然不太可能),由于一个指针导致的间接引用(一个进程执行了另一个地址),指针的过度频繁使用也会导致性能下降。

指针也可以指向另一个指针,并且可以进行任意深度的嵌套,导致你可以有多级的间接引用,但在大多数情况这会使你的代码结构不清晰。

如我们所见,在大多数情况下 Go 语言可以使程序员轻松创建指针,并且隐藏间接引用,如:自动反向引用。

对一个空指针的反向引用是不合法的,并且会使程序崩溃:

package main
func main() {
    var p *int = nil
    *p = 0
}
// 结果err: panic: runtime error: invalid memory address or nil pointer dereference
// 紧急:运行时错误:无效的内存地址或nil指针取消引用

指针的使用方法:

  • 定义指针变量;
  • 为指针变量赋值;
  • 访问指针变量中指向地址的值;
  • 在指针类型前面加上*号来获取指针所指向的内容。
package main

import "fmt"

func main() {
    var a, b int = 20, 30 // 声明实际变量
    var ptra *int         // 声明指针变量
    var ptrb *int = &b
    
    ptra = &a // 指针变量的存储地址 // 取出a的地址赋值给ptra => 取引用
    
    fmt.Printf("a  变量的地址是: %x\n", &a)
    fmt.Printf("b  变量的地址是: %x\n", &b)
    
    // 指针变量的存储地址
    fmt.Printf("ptra  变量的存储地址: %x\n", ptra)
    fmt.Printf("ptrb  变量的存储地址: %x\n", ptrb)
    
    // 使用指针访问值
    fmt.Printf("*ptra  变量的值: %d\n", *ptra)  // 获取ptra内存地址中对应的存储的值 => 解引用
    fmt.Printf("*ptrb  变量的值: %d\n", *ptrb)	// 获取ptrb内存地址中对应的存储的值 => 解引用
}

数组值类型

package main

import "fmt"

func main() {
	nums := [5]int{1, 2, 3, 4, 5}
	nums2 := nums

	fmt.Println(nums, nums2)

	nums2[0] = 100
	fmt.Println(nums, nums2) // nums的[0]不受影响
    // 指针
    // 值类型
    // int, float, bool, string => 值类型
    // 赋值 原有的数据复制一份给新的变量
    // 两个变量之间没有任何联系
    // 对nums进行任何修改都不会影响nums2
    // 对nums2进行任何修改也不会影响nums
    
    var numsPoint *[5]int = &nums  // 取出nums数组地址赋值给numsPoint => 取引用
	fmt.Printf("%T\n", numsPoint)
	numsPoint[0] = 100
	fmt.Println(nums, numsPoint) // 指针影响
}
原文地址:https://www.cnblogs.com/Otiger/p/13701181.html