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 嵌套语句 你可以在 ifelse if 语句中嵌入一个或多个 ifelse 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 ])
}
}

并发