Golang中的变量

Summary

声明变量

1
var 变量名 变量类型

例:声明变量num的类型为int

1
var num int 

使用关键字var和小括号,可以同时声明多个变量。

1
2
3
4
5
var(
a int
b string
c bool
)

初始化变量

每种类型的变量初始化后都会有对应的默认值:

  • 整型和浮点型变量的默认值为0。
  • 字符串变量的默认值为空字符串。
  • 布尔型变量默认为false。
  • 切片、映射、函数和指针变量默认为nil。

注意:nil相当于其他编程语言中的null、None和NULL等,指代零值,在Go语言中只能赋值给切片、映射、函数、接口、指针或通道类型。

1
var 变量名 变量类型 = 表达式

例:声明变量num类型为int并赋值为1

1
var num int = 1 

在标准格式基础上,把变量类型省略后,编译器会根据等号右边的表达式推导变量的类型。
例:初始化变量age值为20

1
var age = 20

同样会根据等号右边的表达式推导变量的类型。

1
age := 30

多重赋值

1
name, age := "Tom", 18

注意:在多重赋值时需要注意变量重复声明的情况

1
2
var name string
name := "Tom" //报错

多个短变量声明并初始化时,至少要有一个新声明的变量出现在左值中

1
2
3
4
var name string
name, age := "Tom", 18 //正常运行

//这样即使其他变量名存在重复声明的情况,编译器也不会报错。

变量值交换

交换变量a和变量b的值

通过中间变量c进行交换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import "fmt"

func main(){
var c int
a:= 1
b:= 2
c=a //变量c临时存储变量a的值
a=b
b=c
fmt.Println(a)
fmt.Println(b)
}
//2 1

通过多重赋值的特性,完成变量值的交换工作。

1
2
3
4
5
6
7
8
9
10
11
12
package main

import "fmt"

func main(){
a := 1
b := 2
a ,b =b,a
fmt.Println(a)
fmt.Println(b)
}
//2 1

匿名变量

赋值给多个变量时,如果存在不需要接收值的变量,可以使用匿名变量来代替。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main

import "fmt"

func ReturnData() (int, int) {
return 10, 20
}

func main() {
a, _ := ReturnData()
_, b := ReturnData()
fmt.Println(a, b)
}
//10 20

Golang中的基础数据类型

Summary
Go语言的数据类型十分丰富,常见的包括整型、浮点型、字符串和布尔型等。Go语言特有的数据类型包括接口和通道等。

整形主要分为有符有符号整型:int8、int16、int32、int64。号无符号两大类

  • 有符号整型:int8、int16、int32、int64。
  • 无符号整型:uint8、uint16、uint32、uint64。

有符号整型其二进制最高位储存符号,因此两者的区别就是无符号整型可以存放的正数范围比有符号整型中的正数范围大一倍。
例如:int16的范围为-32768(即-2^15)到32767(即2^15-1),uint16的范围为0到65535(即2^16-1)。

1
2
3
4
5
6
7
8
9
10
11
//在Go语言中,对于两个整型变量的除法运算,小数部分将会直接被截取,只取整数部分,不会存在四舍五入的情况。
package main

import "fmt"

func main() {
a := 3
b := 2
fmt.Println(a / b)
}
//1

Go语言支持两种浮点数:float32和float64。float32浮点数的最大范围约为3.4e38,float64浮点数最大范围约为1.8e308。

用以下方式获取除法计算的精确值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package main

import (
"fmt"
"reflect"
)

func main(){
//浮点数精确整除
a := 3.0
b := 2.0
fmt.Println(a/b)
fmt.Println("变量a的类型为:",reflect.TypeOf(a))
fmt.Println("变量b的类型为:",reflect.TypeOf(b))
}

//1.5
//变量a的类型为:float64
//变量b的类型为:float64

//上面调用了reflect.TypeOf()函数来打印变量a和b的类型。

代码所在计算机为64位系统, 我们通过赋值时带上小数点来告诉编译器该变量类型为float64,这样除法得到的结果也是float64类 型,即可以显示出精确结果。

Go语言中,字符串的值为双引号中的内容,而且可以直接输入中文。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package main

import (
"fmt"
)

func main(){
str := "你好:Hello"
fmt.Println(str)

//多行字符串
str2 := `Hello
World
`
fmt.Println(str)
fmt.Println(str2)

}

//你好:Hello
//Hello
//World

遇到输入多行字符串的情况,此时需要使用“`”字符,即反引号。

字符
字符串中的每个元素就是字符。 Go语言中,字符的值为单引号中的内容,而且可以直接输入中文。
字符有以下两种类型:

  • uint8类型:代表了ASCII码的一个字符。
  • rune类型:代表了UTF格式的一个字符(如中文、日文或其他复合字符),本质是int32类型。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import (
"fmt"
)

func main(){
english := 'a'
chinese := '我'
fmt.Println(english)
fmt.Println(chinese)
}
//97
//25105
//第一行打印了字符“a”的ASCII码值97,第二行打印了中文“我”的int32类型值25105。

转义字符
使用反斜线“\”来对字符进行转义,转义字符具有特定的含义,不同于字符原有的意义,所以称为转义字符。
常见转义字符:

转义符 含义
\n 匹配换行符
\r 匹配回车符
\t 匹配制表符
\‘ 匹配单引号
\“ 匹配双引号
\\ 匹配反斜杠

布尔型是最简单的数据类型,只有两个值:false(假)和true(真)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main

import (
"fmt"
)

func main(){
var a bool
fmt.Println(a)
a = true
fmt.Println(a)
}
//false
//true

数据类型操作

如果需要判断变量的类型,可以使用Go语言标准库中的reflect包,通过将变量传入此包的 TypeOf()方法,得到变量的数据类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
"fmt"
"reflect"
)

func main(){
a := 1
b := "test"
c := true
fmt.Println(reflect.TypeOf(a))
fmt.Println(reflect.TypeOf(b))
fmt.Println(reflect.TypeOf(c))
}

//int
//string
//bool
// TypeOf()方法直接返回传入变量的类型,通过Println()方法打印到控制台。

Go语言常见的数据类型之间能够互相进行类型转换,通过使用类型前置加小括号的方式进行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main

import (
"fmt"
"reflect"
)

func main(){
var a int16 = 97
fmt.Println("变量a值为:",a,",变量类型为:",reflect.TypeOf(a))
var b = int32(a)
fmt.Println("变量a值为:",a,",变量类型为:",reflect.TypeOf(b))
fmt.Println("转换变量b类型为string:",string(b))
}
//变量a值为: 97 ,变量类型为: int16
//变量a值为: 97 ,变量类型为: int32
//转换变量b类型为string: a

注意⚠️:在转换变量类型时,需要注意变量原本的值是否会发生改变。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main

import (
"fmt"
"reflect"
)

func main(){
var a int32 = 1234567891
fmt.Println("变量a值为:",a,",变量类型为:",reflect.TypeOf(a))
fmt.Println("转换变量a类型为int16,变量a类型为:",int16(a),"变量a的类型为:",reflect.TypeOf(int16(a)))
}
//变量a值为: 1234567891 ,变量类型为: int32
//转换变量a类型为int16,变量a类型为: 723 变量a的类型为: int16

由于16位有符号整型的范围为-32768~32767,而变量a的值1234567891不在这个范围内,导致变量a原本的值发生改变。

1234567891对应的十六进制为0x499602d3,转变为16位变量后,长度缩短一半,丢失了前(高)4位十六进制,即变为:0x02d3,其对应的十进制值为723。

Golang中的指针

概述:指针是一种地址值,这个地址值代表着计算机内存空间中的某个位置。指针变量就是存放地址值的变量

指针变量的声明格式如下:

1
var 变量名 *int

一般情况下,会将指针变量的类型声明为*int,变量名为“p”开头(指代“point”)的单 词,如“p”或“ptr”。

1
2
3
4
5
6
7
8
9
10
11
package main

import "fmt"

func main() {
//var p *int
//fmt.Println(p)
}

//<nil>
//由于指针变量未指向任何地址,所以打印值为nil。

Go语言中,使用操作符“&”取变量地址,取得的地址值可以赋给指针变量。

1
2
3
4
5
6
7
8
9
10
11
12
package main
import "fmt"
func main() {
num := 1
var p *int //声明指针变量
p = &num //将num变量的指向地址赋值给指针变量
fmt.Println("num变量地址为:",p)
fmt.Println("指针变量p的地址为:",&p) //指针变量本身也是变量,所以他拥有自己的内存地址
}

//num变量的地址为:0xc042066080
//指针变量p的地址为:0xc042086018

由于指针变量本身也是变量,因此指针变量在计算机内存中也有自己的地址。需注意的是,运行上面时得到的实际结果可能与以上结果不符,多次运行该程序得到的结果可能都不一致,这是由于变量在内存中的位置都是随机分配的。

指针变量存储的值为地址值,通过在指针变量前面加上“*”符号可以获取指针所指向地址值 的内容。

1
2
3
4
5
6
7
8
9
10
package main
import "fmt"
func main() {
num := 1
var p *int //声明指针变量
p = &num //将num变量的指向地址赋值给指针变量
fmt.Println("指针变量p所指向的内容",*p)
}

//指针变量p所指向的内容 1

注意⚠️: p指针声明后其值为nil,这时如果获取指针p指向的地址内容,则会出错。

1
2
3
4
5
6
7
8
9
10
11
package main

import "fmt"

func main() {
var p *int
fmt.Println("指针变量p指向的地址为:",p)
fmt.Println("指针变量p所指向的内容:",*p)
}
// 指针变量p指向的地址为: <nil>
// panic: runtime error: invalid memory address or nil pointer dereference

在指针变量有实际指向的地址值后,可以通过如下格式直接修改指针所指向内存地址的内容:

1
*变量名 =修改值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main
import (
"fmt"
"reflect"
)
func main() {
num:=1
var p *int
p = &num //取内存地址
fmt.Println("指针p所指向的内容:",*p,"变量num此时值为:",num)
*p = 10
fmt.Println("指针p的所指向的内容为:",*p,"变量num此时值为:",num,"p的数据类型:",reflect.TypeOf(p))
}

//指针p所指向的内容: 1 变量num此时值为: 1
// 指针p的所指向的内容为: 10 变量num此时值为: 10 p的数据类型: *int

在使用指针修改值时也需注意,可使用new()函数来给指针分配地址并初始化地址对应的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main

import "fmt"

func main() {
var p *int
p = new(int)
fmt.Println("指针变量p所指向的内容:",*p,"指针变量p所指向的地址是",p)
*p=10
fmt.Println("指针变量p所指向的内容:",*p,"指针变量p所指向的地址是",p)
}

//指针变量p所指向的内容: 0 指针变量p所指向的地址是 0xc0000180a0
//指针变量p所指向的内容: 10 指针变量p所指向的地址是 0xc0000180a0

Golang中的字符串操作

方法1:
Go语言的字符串拼接操作可以通过“+”操作符来完成

1
2
3
4
5
6
7
8
9
10
11
12
package main

import "fmt"

func main() {
a := "9623"
b := "503"
c := a+b
fmt.Println(c)
}

// 9623503

方法2:
需要拼接的字符串较长时,使用“+”操作符进行字符串的拼接并不高效,使用字节缓冲的方式来进行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main

import (
"bytes"
"fmt"
"reflect"
)

func main() {
a:= "012345"
b := "6789"
var c bytes.Buffer
c.WriteString(a)
c.WriteString(b)
fmt.Println(c.String())
fmt.Println(reflect.TypeOf(c))
}

// 0123456789
// bytes.Buffer

其中bytes包中的Buffer数据结构如下,其本质是字节数组,字符串本质上也是一种字节数组,可以通过WriteString()方法来写入。

1
2
3
4
5
type Buffer struct {
buf []byte // contents are the bytes buf[off : len(buf)]
off int // read at &buf[off], write at &buf[len(buf)]
lastRead readOp // last read operation, so that Unread* can work correctly.
}

Go语言中的strings包的Index()方法会从头对字符串进行搜索,获得搜索内容所属下标,完成对字符串的截取。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main

import (
"fmt"
"strings"
)

func main() {
str := "go语言"
index := strings.Index(str,"语")
fmt.Println(index)
fmt.Println(str[index:])
}

// 2
// 语言

strings包中还提供了LastIndex()方法来反向搜索字符串。例如,我们只想截取字符串“Go语言,Python语言”中最后的“语言”,就可以使用LastIndex()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main

import (
"fmt"
"strings"
)

func main() {
str := "go语言,Python语言"
index := strings.LastIndex(str,"语")
fmt.Println(index)
fmt.Println(str[index:])
}

// 15
// 语言

Go语言无法对字符串直接进行修改,只能将字符串转换为字节数组后再进行操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
package main

import "fmt"

func main() {
str := "go语言"
bytes := []byte(str)
for i := 0;i<2;i++{
bytes[i] = ' '
}
fmt.Println(string(bytes))
}
// 语言

对字符串的格式化使用fmt包的Sprintf()方法,Sprintf()方法的调用格式如下:

1
Sprintf(format,arg1,arg2...)

第一个参数为需要格式化的字符串,其中包含格式化动词,格式化动词以“%”开头。调用样例如下:

1
2
3
4
5
6
7
8
9
10
11
12
package main

import "fmt"

func main() {
var day = 1
var hour = 24
str := fmt.Sprintf("%d天包含%d个小时",day,hour)
fmt.Println(str)
}

// 1天包含24个小时
格式化动词 动词功能
%v 按值的本来值输出
%+v 在 %v 基础上,对结构体字段名和值进行展开
%#v 输出 Go 语言语法格式的值
%T 输出 Go 语言语法格式的类型和值
%% 输出 % 本体
%b 整型以二进制方式显示
%o 整型以八进制方式显示
%d 整型以十进制方式显示
%x 整型以十六进制方式显示
%X 整型以十六进制、字母大写方式显示
%U Unicode 字符
%f 浮点数
%p 指针,以十六进制方式显示