go语言基本数据类型和变量

简介: go语言基本数据类型和变量

变量

Go 是静态类型语⾔,不能在运⾏期改变变量类型。

使⽤关键字 var 定义变量,⾃动初始化为零值。如果提供初始化值,可省略变量类型,由编译器⾃动推断。

var

声明变量的一般形式是使用 var 关键字: var identifier type 。

var x int
var f float32 = 1.6
var s = "abc"

:=

在函数内部,可⽤更简略的 “:=” ⽅式定义变量,

func main() {
  x := 123
  n, s := 0x1234, "Hello, World!"
  b := 123
  b := 1234 //会出现错误no new variables on left side of := 。因为在上一行已经定义过变量
  println(x, n, s, b)
}

变量赋值

多变量赋值时,先计算所有相关值,然后再从左到右依次赋值。

data, i := [3]int{0, 1, 2}, 0 
i, data[i] = 2, 100 // (i = 0) -> (i = 2), (data[0] = 100) 

特殊只写变量 “_”,⽤于忽略值占位。

func test() (int, string) {
 return 1, "abc"
}
func main() {
 _, s := test()
 println(s)
}

注意

在go语言中交换两个变量的值十分容易,不需要像c语言中定义一个中间量

i,j = j,i

匿名变量 “_”

我们在使用传统的强类型语言编程时,经常会出现这种情况,即在调用函数时为了获取一个值,却因为该函数返回多个值而不得不定义一堆没用的变量。在Go中这种情况可以通过结合使用多重返回和匿名变量来避免这种丑陋的写法,让代码看起来更加优雅。

而且,在go语言中编译器会将未使⽤的局部变量当做错误,为了避免这种情况必须用匿名变量进行占位。

var s string // 全局变量没问题。
func GetName() (firstName, lastName, nickName string) { 
 return "May", "Chan", "Chibi Maruko" 
} 
func main() {
//若只想获得nickName,则函数调用语句可以用如下方式编写:
 _, _, nickName := GetName() 
 i := 0 // Error: i declared and not used。(可使⽤ "_ = i" 进行占位)
}

注意重新赋值与定义新同名变量的区别

s := "abc"
println(&s)
s, y := "hello", 20 // 重新赋值: 与前 s 在同⼀层次的代码块中,且有新的变量被定义。
println(&s, y) // 通常函数多返回值 err 会被重复使⽤。
{
 s, z := 1000, 30 // 定义新同名变量: 不在同⼀层次代码块。
 println(&s, z)
}

输出:

0x2210230f30

0x2210230f30 20

0x2210230f18 30

常量

注意大写字母开头的常量在包外可见,否则只在本包内可见。

常量定义

常量值必须是编译期可确定的数字、字符串、布尔值。

const x, y int = 1, 2 // 多常量初始化
const s = "Hello, World!" // 类型推断
const ( // 常量组
 a, b = 10, 100
 c bool = false
)
func main() {
 const x = "xxx" // 未使⽤局部常量不会引发编译错误。
}

在常量组中,如不提供类型和初始化值,那么视作与上⼀常量相同。

const (
 s = "abc"
 x // x = "abc"
)

常量值还可以是 len、cap、unsafe.Sizeof 等编译期可确定结果的函数返回值。

const (
 a = "abc"
 b = len(a)
 c = unsafe.Sizeof(b)
)

预定义常量

Go语言预定义了这些常量:true、false和iota。

iota比较特殊,可以被认为是一个可被编译器修改的常量,在每一个const关键字出现时被重置为0,然后在下一个const出现之前,每出现一次iota,其所代表的数字会自动增1。从以下的例子可以基本理解iota的用法:

const ( // iota被重设为0
 c0 = iota // c0 == 0 
 c1 = iota // c1 == 1 
 c2 = iota // c2 == 2 
) 
const ( 
 a = 1 << iota // a == 1 (iota在每个const开头被重设为0) 
 b = 1 << iota // b == 2 
 c = 1 << iota // c == 4 
) 
const ( 
 u = iota * 42 // u == 0 
 v float64 = iota * 42 // v == 42.0 
 w = iota * 42 // w == 84 
) 
const x = iota // x == 0 (因为iota又被重设为0了) 
const y = iota // y == 0 (同上) 

如果两个const的赋值语句的表达式是一样的,那么可以省略后一个赋值表达式。因此,上

面的前两个const语句可简写为:

const ( // iota被重设为0
 c0 = iota // c0 == 0 
 c1 // c1 == 1 
 c2 // c2 == 2 
) 
const ( 
 a = 1 <<iota // a == 1 (iota在每个const开头被重设为0) 
 b // b == 2 
 c // c == 4

枚举

const (
 Sunday = iota // 0
 Monday // 1,通常省略后续⾏表达式。
 Tuesday // 2
 Wednesday // 3
 Thursday // 4
 Friday // 5
 Saturday // 6
)

可通过⾃定义类型来实现枚举类型限制。

type Color int
const (
 Black Color = iota
 Red
 Blue
)
func test(c Color) {}
func main() {
 c := Black
 test(c)
 x := 1
 test(x) // Error: cannot use x (type int) as type Color in function argument
 test(1) // 常量会被编译器⾃动转换。
}

基本类型

Go语言内置以下这些基础类型:

 布尔类型:bool。

 整型:int8、byte、int16、int、uint、uintptr等。

 浮点类型:float32、float64。

 复数类型:complex64、complex128。

 字符串:string。

 字符类型:rune。

 错误类型:error。

此外,Go语言也支持以下这些复合类型:

 指针(pointer)

 数组(array)

 切片(slice)

 字典(map)

 通道(chan)

 结构体(struct)

 接口(interface)

在这些基础类型之上Go还封装了下面这几种类型:int、uint和uintptr等。这些类型的

特点在于使用方便,但使用者不能对这些类型的长度做任何假设。对于常规的开发来说,用int和uint就可以了,没必要用int8之类明确指定长度的类型,以免导致移植困难。

布尔类型

Go语言中的布尔类型与其他语言基本一致,关键字也为bool,可赋值为预定义的true和

false示例代码如下:

var v1 bool
v1 = true
v2 := (1 == 2) // v2也会被推导为bool类型

布尔类型不能接受其他类型的赋值,不支持自动或强制的类型转换。以下的示例是一些错误的用法,会导致编译错误:

var b bool
b = 1 // 编译错误
b = bool(1) // 编译错误
//以下的用法才是正确的:
var b bool
b = (1!=0) // 编译正确 
fmt.Println("Result:", b) // 打印结果为Result: true 

整型

整型是所有编程语言里最基础的数据类型。

类 型 长度(字节) 值 范 围
int8 1 128 ~ 127
uint8(即byte) 1 0 ~ 255
int16 2 32 768 ~ 32 767
uint16 2 0 ~ 65 535
int32 4 -2147 483 648 ~ 2 147 483 647
uint32 4 0 ~ 4 294 967 295
int64 8 9 223 372 036 854 775 808 ~ 9 223 372 036 854 775 807
uint64 8 0 ~ 18 446 744 073 709 551 615
int 平台相关 平台相关
uint 平台相关 平台相关
uintptr 同指针 在32位平台下为4字节,64位平台下为8字节

需要注意的是,int和int32在Go语言里被认为是两种不同的类型,编译器也不会帮你自动

做类型转换,比如以下的例子会有编译错误:

var value2 int32
value1 := 64 // value1将会被自动推导为int类型
value2 = value1 // 编译错误

编译错误类似于:

cannot use value1 (type int) as type int32 in assignment。
• 1

使用强制类型转换可以解决这个编译错误:

value2 = int32(value1) // 编译通过

当然,在做强制类型转换时,需要注意数据长度被截短而发生的数据精度损失(比如

将浮点数强制转为整数)和值溢出(值超过转换的目标类型的值范围时)问题。

数值运算

Go语言支持下面的常规整数运算:+、-、*、/和%。加减乘除就不详细解释了,需要说下的是,% 和在C语言中一样是求余运算,比如:

5 % 3 // 结果为:2 
  1. 比较运算
    Go语言支持以下的几种比较运算符:>、<、==、>=、<=和!=。这一点与大多数其他语言相同,与C语言完全一致。
    下面为条件判断语句的例子:
i, j := 1, 2 
if i == j { 
 fmt.Println("i and j are equal.") 
} 

两个不同类型的整型数不能直接比较,比如int8类型的数和int类型的数不能直接比较,但

各种类型的整型变量都可以直接与字面常量(literal)进行比较,比如:

var i int32
var j int64
i, j = 1, 2 
if i == j { // 编译错误
 fmt.Println("i and j are equal.") 
} 
if i == 1 || j == 2 { // 编译通过
 fmt.Println("i and j are equal.") 
} 

位运算

运 算 含 义 样 例
x << y 左移 124 << 2 // 结果为496
x >> y 右移 124 >> 2 // 结果为31
x ^ y 异或 124 ^ 2 // 结果为126
x & y 与 124 & 2 // 结果为0
x | y 124
^x 取反 ^2 // 结果为-3

Go语言的大多数位运算符与C语言都比较类似,除了取反在C语言中是~x,而在Go语言中是^x。

浮点型

浮点型用于表示包含小数点的数据,比如1.234就是一个浮点型数据。

浮点数表示

Go语言定义了两个类型float32和float64,其中float32等价于C语言的float类型,

float64等价于C语言的double类型。

在Go语言里,定义一个浮点数变量的代码如下:

var fvalue1 float32
fvalue1 = 12 
fvalue2 := 12.0 // 如果不加小数点,fvalue2会被推导为整型而不是浮点型

浮点数比较

因为浮点数不是一种精确的表达方式,所以像整型那样直接用==来判断两个浮点数是否相等是不可行的,这可能会导致不稳定的结果。

下面是一种推荐的替代方案:

import "math" 
// p为用户自定义的比较精度,比如0.00001 
func IsEqual(f1, f2, p float64) bool { 
 return math.Fdim(f1, f2) < p 
} 

复数类型

复数实际上由两个实数(在计算机中用浮点数表示)构成,一个表示实部(real),一个表示虚部(imag)。如

复数表示

复数表示的示例如下:

var value1 complex64 // 由2个float32构成的复数类型
value1 = 3.2 + 12i 
value2 := 3.2 + 12i // value2是complex128类型
value3 := complex(3.2, 12) // value3结果同 value2 

实部与虚部

对于一个复数z = complex(x, y),就可以通过Go语言内置函数real(z)获得该复数的实

部,也就是x,通过imag(z)获得该复数的虚部,也就是y。

字符串

在Go语言中,字符串也是一种基本类型。相比之下, C/C++语言中并不存在原生的字符串类型,通常使用字符数组来表示,并以字符指针来传递。

Go语言中字符串的声明和初始化非常简单,举例如下:

str = "Hello world" // 字符串赋值
ch := str[0] // 取字符串的第一个字符
fmt.Printf("The length of \"%s\" is %d \n", str, len(str)) 
fmt.Printf("The first character of \"%s\" is %c.\n", str, ch) 

输出结果为:

The length of “Hello world” is 11

The first character of “Hello world” is H.

字符串的内容可以用类似于数组下标的方式获取,但与数组不同,字符串的内容不能在初始化后被修改,比如以下的例子:

str := "Hello world" // 字符串也支持声明时进行初始化的做法
str[0] = 'X' // 编译错误

编译器会报类似如下的错误:

cannot assign to str[0]

保存源文件时请注意编码格式必须选择UTF-8。特别是在Windows下一般编辑器都默认存为本地编码,比如中国地区可能是GBK编码而不是UTF-8,如果没注意这点在编译和运行时就会出现一些意料之外的情况。

字符串操作

运 算 含 义 样 例
x + y 字符串连接 “Hello” + “qwe” // 结果为Helloqwe
len(s) 字符串长度 len(“Hello”) // 结果为5
s[i] 取字符 “Hello” [1] // 结果为’e’

字符串遍历

Go语言支持两种方式遍历字符串。一种是以字节数组的方式遍历:

str := "Hello,世界"
n := len(str) 
for i := 0; i < n; i++ { 
 ch := str[i] // 依据下标取字符串中的字符,类型为byte 
 fmt.Println(i, ch) 
} 

这个例子的输出结果为:

0 72

1 101

2 108

3 108

4 111

5 44

6 32

7 228

8 184

9 150

10 231

11 149

12 140

可以看出,这个字符串长度为13。尽管从直观上来说,这个字符串应该只有9个字符。这是因为每个中文字符在UTF-8中占3个字节,而不是1个字节。

另一种是以Unicode字符遍历:

str := "Hello,世界"
for i, ch := range str { 
 fmt.Println(i, ch)//ch的类型为rune 
} 

输出结果为:

0 72

1 101

2 108

3 108

4 111

5 44

6 32

7 19990

10 30028

字符类型

在Go语言中支持两个字符类型,一个是byte(实际上是uint8的别名),代表UTF-8字符串的单个字节的值

var ch int = '\u0041'
var ch2 int = '\u03B2'
var ch3 int = '\U00101234'
fmt.Printf("%d - %d - %d\n", ch, ch2, ch3) // integer
fmt.Printf("%c - %c - %c\n", ch, ch2, ch3) // character
fmt.Printf("%X - %X - %X\n", ch, ch2, ch3) // UTF-8 bytes
fmt.Printf("%U - %U - %U", ch, ch2, ch3)   // UTF-8 code point


相关文章
|
18天前
|
存储 Go 索引
go语言中数组和切片
go语言中数组和切片
27 7
|
18天前
|
Go 开发工具
百炼-千问模型通过openai接口构建assistant 等 go语言
由于阿里百炼平台通义千问大模型没有完善的go语言兼容openapi示例,并且官方答复assistant是不兼容openapi sdk的。 实际使用中发现是能够支持的,所以自己写了一个demo test示例,给大家做一个参考。
|
18天前
|
程序员 Go
go语言中结构体(Struct)
go语言中结构体(Struct)
93 71
|
17天前
|
存储 Go 索引
go语言中的数组(Array)
go语言中的数组(Array)
100 67
|
20天前
|
Go 索引
go语言for遍历数组或切片
go语言for遍历数组或切片
90 62
|
22天前
|
并行计算 安全 Go
Go语言中的并发编程:掌握goroutines和channels####
本文深入探讨了Go语言中并发编程的核心概念——goroutine和channel。不同于传统的线程模型,Go通过轻量级的goroutine和通信机制channel,实现了高效的并发处理。我们将从基础概念开始,逐步深入到实际应用案例,揭示如何在Go语言中优雅地实现并发控制和数据同步。 ####
|
18天前
|
存储 Go
go语言中映射
go语言中映射
32 11
|
20天前
|
Go
go语言for遍历映射(map)
go语言for遍历映射(map)
30 12
|
19天前
|
Go 索引
go语言使用索引遍历
go语言使用索引遍历
27 9
|
23天前
|
安全 Serverless Go
Go语言中的并发编程:深入理解与实践####
本文旨在为读者提供一个关于Go语言并发编程的全面指南。我们将从并发的基本概念讲起,逐步深入到Go语言特有的goroutine和channel机制,探讨它们如何简化多线程编程的复杂性。通过实例演示和代码分析,本文将揭示Go语言在处理并发任务时的优势,以及如何在实际项目中高效利用这些特性来提升性能和响应速度。无论你是Go语言的初学者还是有一定经验的开发者,本文都将为你提供有价值的见解和实用的技巧。 ####