Deepin安装Go开发环境

1.Go安装包下载

到Go语言中文网下载Go安装包 go1.15.6.linux-amd64.tar.gz

image-20201219202143224

2.解压安装Go

解压Go安装包 go1.11.5.linux-amd64.tar.gz

1
tar zxvf go1.15.6.linux-amd64.tar.gz

tips:

我这里将安装包直接解压到了自定义目录中,linux系统一般还有如下的目录可以用于存放自己安装的软件的文件夹,放在如下目录中时后续命令需要对应改变。

/usr : 系统软件安装目录

/usr/local : 用户软件安装目录

/opt : 大型软件安装目录

3.配置环境变量

1
vim ~/.bashrc 或者 vim ~/profile

(bashrc对系统所有用户有效,profile对当前用户有效)

这里我用的profile

image-20201219204649605

三个变量GOPATH、PATH、GOROOT:·GOROOT就是go的安装路径;·GOPATH就是go的工作目录;·PATH是go安装路径下的bin目录。

让更改的环境变量进行生效,在终端中输入以下命令内容:

1
source ~/.bashrc 或者 source ~/profile

4.查看安装结果

1
go version

image-20201219204934424

Go程序语言结构

Go 语言的基础组成有以下几个部分:

  • 包声明
  • 引入包
  • 函数
  • 变量
  • 语句 & 表达式
  • 注释

例如:

go程序中的**{** 不能单独放在一行

1
2
3
4
5
6
7
8
package main

import "fmt"

func main() {
/* 这是我的第一个简单的程序 */
fmt.Println("Hello, World!")
}
  1. 第一行代码 package main 定义了包名。必须在源文件中非注释的第一行指明这个文件属于哪个包,如:package main。package main表示一个可独立执行的程序,每个 Go 应用程序都包含一个名为 main 的包。
  2. import “fmt” ,fmt 包实现了格式化 IO(输入/输出)的函数。
  3. *func main()*, 是程序开始执行的函数。main 函数是每一个可执行程序所必须包含的,一般来说都是在启动后第一个执行的函数(如果有 init() 函数则会先执行该函数)。
  4. /…/ 是注释,在程序执行时将被忽略。
  5. fmt.Println(…) 将字符串输出到控制台,并在最后自动增加换行字符 \n。
    使用 fmt.Print(“hello, world\n”) 可以得到相同的结果。
    Print 和 Println 这两个函数也支持使用变量。
  6. 当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 protected )。

执行Go程序

1
go run hello.go

或者

1
2
3
go build hello.go     //生成二进制文件

./hello //执行

输入输出

1
import "fmt"

fmt包实现了类似C语言printf和scanf的格式化I/O。格式化动作(’verb’)源自C语言但更简单。

输出

fmt.Println()//输出任意类型数据,并换行
fmt.Print()  //输出任意类型数据,不换行
fmt.Printf()//格式化输出数据,不换行

输入

fmt.Scan()//扫描,必须所有参数都被填充后换行才结束扫描
fmt.Scanln()//扫描,但是遇到换行就结束扫描
fmt.Scanf()//格式化扫描,换行就结束

需要使用地址来取得扫描到的数据

如fmt.Scan(&x,&y)

基础语法

行分隔符

在 Go 程序中,一行代表一个语句结束。每个语句不需要像 C 家族中的其它语言一样以分号 ; 结尾,因为这些工作都将由 Go 编译器自动完成。

字符串连接

Go 语言的字符串链接可以通过 + 实现:

1
fmt.Println("Hello" + "World")

数据类型

布尔型

布尔型的值只可以是常量 true 或者 false。

1
var b bool = true。

数字类型

1.整型 int

2.浮点型 float32、float64、complex64(复数)、complex128(复数)

字符串

派生类型

包括:

  • (a) 指针类型(Pointer)
  • (b) 数组类型
  • (c) 结构化类型(struct)
  • (d) Channel 类型
  • (e) 函数类型
  • (f) 切片类型
  • (g) 接口类型(interface)
  • (h) Map 类型

变量

变量声明

第一种,用:= 注意 := 左侧如果没有声明新的变量,就产生编译错误,格式:

1
2
3
4
5
var intVal int 

intVal :=1 // 这时候会产生编译错误

intVal,intVal1 := 1,2 // 此时不会产生编译错误,因为有声明新的变量,因为 := 是一个声明语句

第二种,指定变量类型,如果没有初始化,则变量默认为零值。

var a int

1
2
3
4
5
6
7
8
9
10
11
12
package main
import "fmt"
func main() {

// 没有初始化就为零值
var b int
fmt.Println(b)

// bool 零值为 false
var c bool
fmt.Println(c)
}

运行结果为:

1
2
0
false

第三种,根据值自行判定变量类型。

var a = “hello”

1
2
3
4
5
6
package main
import "fmt"
func main() {
var a = "hello"
fmt.Println(a)
}

运行结果为:

1
hello

多变量声明

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

var x, y int
var (
a int
b bool
)

var c, d int = 1, 2
var e, f = 123, "hello"

func main(){
g, h := 123, "hello" //这种不带声明格式的只能在函数体中出现,不能用于全局变量

println(x, y, a, b, c, d, e, f, g, h)
}

常量

常量是一个简单值的标识符,在程序运行时,不会被修改的量。

常量中的数据类型只可以是布尔型、数字型(整数型、浮点型和复数)和字符串型。

  • 显式类型定义: const b string = "abc"
  • 隐式类型定义: const b = "abc"

例如:

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

import "fmt"

func main() {
const LENGTH int = 10
const WIDTH int = 5
var area int
const a, b, c = 1, false, "str" //多重赋值

area = LENGTH * WIDTH
fmt.Printf("面积为 : %d", area)
println()
println(a, b, c)
}

运行结果:

1
2
面积为 : 50
1 false str

iota

iota,特殊常量,可以认为是一个可以被编译器修改的常量。

iota 在 const关键字出现时将被重置为 0(const 内部的第一行之前),const 中每新增一行常量声明将使 iota 计数一次(iota 可理解为 const 语句块中的行索引)。

第一个 iota 等于 0,每当 iota 在新的一行被使用时,它的值都会自动加 1;所以 a=0, b=1, c=2 可以简写为如下形式:

1
2
3
4
5
const (
a = iota
b
c
)

实例:

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

import "fmt"

func main() {
const (
a = iota //0
b //1
c //2
d = "ha" //独立值,iota += 1
e //"ha" iota += 1
f = 100 //iota +=1
g //100 iota +=1
h = iota //7,恢复计数
i //8
)
fmt.Println(a,b,c,d,e,f,g,h,i)
}

运行结果为:

1
0 1 2 ha ha 100 100 7 8

运算符

和C++类似

条件语句

语句 描述
if 语句 if 语句 由一个布尔表达式后紧跟一个或多个语句组成。
if…else 语句 if 语句 后可以使用可选的 else 语句, else 语句中的表达式在布尔表达式为 false 时执行。
if 嵌套语句 你可以在 if 或 else if 语句中嵌入一个或多个 if 或 else if 语句。
switch 语句 switch 语句用于基于不同条件执行不同动作。
select 语句 select 语句类似于 switch 语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。

循环语句

for循环

计算 1 到 10 的数字之和:

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

import "fmt"

func main() {
sum := 0
for i := 0; i <= 10; i++ {
sum += i
}
fmt.Println(sum)
}

无限循环

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

import "fmt"

func main() {
sum := 0
for {
sum++ // 无限循环下去
}
fmt.Println(sum) // 无法输出
}

For-each range 循环

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

func main() {
strings := []string{"google", "runoob"}
for i, s := range strings {
fmt.Println(i, s)
}


numbers := [6]int{1, 2, 3, 5}
for i,x:= range numbers {
fmt.Printf("第 %d 位 x 的值 = %d\n", i,x)
}
}

函数

函数定义

Go 语言函数定义格式如下:

1
2
3
func function_name( [parameter list] ) [return_types] {
函数体
}
  • 有些功能不需要返回值,这种情况下 return_types 不是必须的。
1
2
3
4
5
6
7
8
9
10
11
12
/* 函数返回两个数的最大值 */
func max(num1, num2 int) int {
/* 声明局部变量 */
var result int

if (num1 > num2) {
result = num1
} else {
result = num2
}
return result
}

函数返回多个值

Go 函数可以返回多个值,例如:

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

import "fmt"

func swap(x, y string) (string, string) {
return y, x
}

func main() {
a, b := swap("hello", "world")
fmt.Println(a, b)
}

数组

一维数组

Go 语言数组声明需要指定元素类型及元素个数,语法格式如下:

1
var variable_name [SIZE] variable_type

如:

1
var balance [10] float32

多维数组

1
var variable_name [SIZE1][SIZE2]...[SIZEN] variable_type

以下实例声明了三维的整型数组:

1
var threedim [5][10][4]int

实例:

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

import "fmt"

func main() {
/* 数组 - 5 行 2 列*/
var a = 5int{ {0,0}, {1,2}, {2,4}, {3,6},{4,8}}
var i, j int

/* 输出数组元素 */
for i = 0; i < 5; i++ {
for j = 0; j < 2; j++ {
fmt.Printf("a%d = %d\n", i,j, ai )
}
}
}

运行结果:

1
2
3
4
5
6
7
8
9
10
a[0][0] = 0
a[0][1] = 0
a[1][0] = 1
a[1][1] = 2
a[2][0] = 2
a[2][1] = 4
a[3][0] = 3
a[3][1] = 6
a[4][0] = 4
a[4][1] = 8

向函数传递数组

方式一

形参设定数组大小:

1
2
3
4
5
6
void myFunction(param [10]int)
{
.
.
.
}

方式二

形参未设定数组大小:

1
2
3
4
5
6
void myFunction(param []int)
{
.
.
.
}

指针

和C++类似

结构体

定义结构体

1
2
3
4
5
6
type struct_variable_type struct {
member definition
member definition
...
member definition
}

访问结构体成员

访问结构体成员,需要使用点号 . 操作符,格式为:

1
结构体.成员名"

切片

动态数组

定义切片

声明一个未指定大小的数组来定义切片:

1
var identifier []type

或使用make()函数来创建切片:

1
2
3
4
5
var slice1 []type = make([]type, len)

也可以简写为

slice1 := make([]type, len)

也可以指定容量,其中capacity为容量大小,即最大支持几个元素。

1
make([]T, length, capacity)

切片初始化

1
s :=[] int {1,2,3 } 

直接初始化切片,[]表示是切片类型,{1,2,3}初始化值依次是1,2,3.其cap=len=3

1
s := arr[:] 

初始化切片s,是数组arr的引用

1
s := arr[startIndex:endIndex] 

将arr中从下标startIndex到endIndex-1 下的元素创建为一个新的切片

1
s := arr[startIndex:] 

默认 endIndex 时将表示一直到arr的最后一个元素

1
s := arr[:endIndex] 

默认 startIndex 时将表示从arr的第一个元素开始

1
s1 := s[startIndex:endIndex] 

通过切片s初始化切片s1

1
s :=make([]int,len,cap) 

通过内置函数make()初始化切片s,[]int 标识为其元素类型为int的切片

len() 和 cap() 函数

切片是可索引的,并且可以由 len() 方法获取长度。

切片提供了计算容量的方法 cap() 可以测量切片最长可以达到多少。

切片截取

可以通过设置下限及上限来设置截取切片 *[lower-bound:upper-bound]*,实例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package main

import "fmt"

func main() {
/* 创建切片 */
numbers := []int{0,1,2,3,4,5,6,7,8}
printSlice(numbers)

/* 打印原始切片 */
fmt.Println("numbers ==", numbers)

/* 打印子切片从索引1(包含) 到索引4(不包含)*/
fmt.Println("numbers[1:4] ==", numbers[1:4])

/* 默认下限为 0*/
fmt.Println("numbers[:3] ==", numbers[:3])

/* 默认上限为 len(s)*/
fmt.Println("numbers[4:] ==", numbers[4:])

numbers1 := make([]int,0,5)
printSlice(numbers1)

/* 打印子切片从索引 0(包含) 到索引 2(不包含) */
number2 := numbers[:2]
printSlice(number2)

/* 打印子切片从索引 2(包含) 到索引 5(不包含) */
number3 := numbers[2:5]
printSlice(number3)

}

func printSlice(x []int){
fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}

append() 和 copy() 函数

如果想增加切片的容量,我们必须创建一个新的更大的切片并把原分片的内容都拷贝过来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package main

import "fmt"

func main() {
var numbers []int
printSlice(numbers)

/* 允许追加空切片 */
numbers = append(numbers, 0)
printSlice(numbers)

/* 向切片添加一个元素 */
numbers = append(numbers, 1)
printSlice(numbers)

/* 同时添加多个元素 */
numbers = append(numbers, 2,3,4)
printSlice(numbers)

/* 创建切片 numbers1 是之前切片的两倍容量*/
numbers1 := make([]int, len(numbers), (cap(numbers))*2)

/* 拷贝 numbers 的内容到 numbers1 */
copy(numbers1,numbers)
printSlice(numbers1)
}

func printSlice(x []int){
fmt.Printf("len=%d cap=%d slice=%v\n",len(x),cap(x),x)
}

Map

定义 Map

1
2
3
4
5
/* 声明变量,默认 map 是 nil */
var map_variable map[key_data_type]value_data_type

/* 使用 make 函数 */
map_variable := make(map[key_data_type]value_data_type)

如果不初始化 map,那么就会创建一个 nil map。nil map 不能用来存放键值对

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main

import "fmt"

func main() {
var countryCapitalMap map[string]string /*创建集合 */
countryCapitalMap = make(map[string]string)

/* map插入key - value对,各个国家对应的首都 */
countryCapitalMap [ "France" ] = "巴黎"
countryCapitalMap [ "Italy" ] = "罗马"
countryCapitalMap [ "Japan" ] = "东京"
countryCapitalMap [ "India " ] = "新德里"

/*使用键输出地图值 */
for country := range countryCapitalMap {
fmt.Println(country, "首都是", countryCapitalMap [country])
}

/*查看元素在集合中是否存在 */
capital, ok := countryCapitalMap [ "American" ] /*如果确定是真实的,则存在,否则不存在 */
/*fmt.Println(capital) */
/*fmt.Println(ok) */
if (ok) {
fmt.Println("American 的首都是", capital)
} else {
fmt.Println("American 的首都不存在")
}
}

delete() 函数

delete() 函数用于删除集合的元素, 参数为 map 和其对应的 key。实例如下:

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

import "fmt"

func main() {
/* 创建map */
countryCapitalMap := map[string]string{"France": "Paris", "Italy": "Rome", "Japan": "Tokyo", "India": "New delhi"}

fmt.Println("原始地图")

/* 打印地图 */
for country := range countryCapitalMap {
fmt.Println(country, "首都是", countryCapitalMap [ country ])
}

/*删除元素*/ delete(countryCapitalMap, "France")
fmt.Println("法国条目被删除")

fmt.Println("删除元素后地图")

/*打印地图*/
for country := range countryCapitalMap {
fmt.Println(country, "首都是", countryCapitalMap [ country ])
}
}

并发