Golang 简介

golang指的是google公司推出的一种高效、可靠、简洁并具有强大并行处理能力的编程语言.

Golang的设计理念是简介性、高效性和安全性。它的语法简洁且易于理解,使得程序员可以更快地进行开发和维护代码。这也使得Golang成为一种非常适合于开发网络应用和大数据处理的语言。

与其他流行的编程语言相比,Golang在许多方面都具有优势。首先,它有一个独特的 Goroutine 机制,这使得并发编程变得更加容易。其次,它有一个强大的标准库,其中包括了许多有用的工具和功能,例如网络编程、加密、解析和操作系统相关的函数。此外,Golang还支持交叉编译功能,让程序员能够在不同的平台上轻松地构建和运行应用程序。

Golang 安装

Windows系统安装步骤

  1. 下载golang安装包

访问golang官方网站,下载适用于Windows系统的golang安装包。

  1. 安装golang

双击下载的安装包,按照安装向导的提示完成golang的安装。

  1. 配置环境变量

将golang的安装目录添加到系统的PATH环境变量中,以便在命令行中能够直接访问golang相关的命令。

Mac 系统安装步骤

  1. 安装go 软件 brew install go

  2. 查看golang 当前版本 go version

  3. 配置环境变量(只需要设置GOPATH和GOROOT 环境变量)
    ​Mac brew 安装基本GOROOT 已经设置好了,只需要配置GOPATH 加入环境变量
    查看当前golang环境 执行 go env

设置GOPATH 及环境变量(GOPATH 是工作目录)

(1).先创建工作目录 本人位置家目录下go文件夹 $ mkdir $HOME/work

(2).添加环境变量 我使得zsh,如果使用bash 请编辑~/.bash_profile文件

​ 编辑 vim .zshrc 添加两条:

1
2
3
export GOPATH=$HOME/go 工作目录

export PATH = $PATH:$GOPATH/bin 加入环境变量,$PATH 不可省略

执行 source ~/.zshrc

或者
下载压缩包安装(创建工作目录文件)
下载golang 发布版本tar 包 地址:https://golang.org/dl/ (可查看文档查找)

Golang 目录介绍

go整个目录就是一个SDK,包括了一些基础的工具,如编译,运行,测试等。

api目录:包含了各种API接口。
bin目录:包含了各种 go 命令行工具(go.gofmt)。
src目录:包含了源码文件

Golang 代码

  1. 创建一个 test.go 文件。
1
2
3
4
5
6
7
8
9
package main //程序的包名
// main函数
//多个文件导入
import (
"fmt"
)
func main() { //函数的"{"必须和函数名在一行,换到下一行就是语法错误,强制代码风格
fmt.Println("hellow Go!")//go语言不需要";",可有可无
}
  1. 对源文件 test.go 文件进行编译: go build test.go => 会生成一个可执行文件:test(二进制可执行文件,在windos下生成test.exe)可以直接运行(无需环境也可运行)。 【编译的文件也可以另外指定名字 : go build -o 新的名字xxx test.go

  2. 通过go run test.go 运行代码可以直接帮我们编译执行源文件。 (相比较 go build 运行速度更快 因为省去编译的过程)

语法的注意事项

  1. 源文件以 go 为扩展名。
  2. 参与的执行入口时main()函数。
  3. 严格区分大小写。
  4. 方法由一条条语句构成,每一个语句后不需要分号(Go语言会在每行后自动添加分号)
  5. Go编译器时一行行进行编译的,因此我们一行就写一条语句,不能多条语句写在同一个,否则报错.
  6. 定义变量或者import的包没有使用到,代码就无法编译通过。
  7. 大括号都是成对出现的,缺一不可。

通过命令完成格式化操作:
gofmt test.go 格式化代码,但只会展示格式后的代码,不会修改源文件。如果需要修改源文件,需要使用gofmt -w test.go命令。

API (应用程序编程接口)

http://docscn.studygolang.com/pkg/ 当前没有中文,需要用到翻译软件。

变量

声明 -> 赋值 -> 使用

1
2
//其中 var 是声明变量的关键字,int 是变量类型,10 是变量值。
var a int = 10
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main 
import "fmt"

func main() {
var age int
age = 10
fmt.Println("age = ", age)

var age2 int = 19

fmt.Println("age2 = ", age2)


/** 变量重复定义会报错 */
//var age2 int = 20
//fmt.Println("age = ", age)

/** 不可以在赋值的时候给与不匹配的类型 */
// var num int = 12.66
// fmt.Println("num = ", num)

fmt.Println("hellow Go!")
}

变量的4种使用方式

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package main
import "fmt"

//全局变量,在()外的叫,全局变量
var n4 = 100

//可以一次性声明多个变量
var (
n10 = 200
n11 = 300
n12 = "你好呀"
)


func main() {
//定义在()中的叫,局部变量


//第一种: 指定变量的类型,并且赋值
var num int = 10
fmt.Println(num)

//第二种: 指定变量的类型,但不赋值,使用默认值
var num2 int
fmt.Println(num2)

//第三种: 如果没有写变量的类型,那么根据= 后面的值自动判断
var num3 = "hello world"
fmt.Println(num3)

//第四种: 省var,注意 := 不能写为 =
sex := "男"
fmt.Println(sex)

fmt.Println("---------------------------------------")

// 声明多个变量
var n1,n2,n3 int

fmt.Println(n1)
fmt.Println(n2)
fmt.Println(n3)

var n5,n6,n7 = 10,"luo",37.9

fmt.Println(n5)
fmt.Println(n6)
fmt.Println(n7)

n8,n9 := 7.2,"hello"

fmt.Println(n8)
fmt.Println(n9)

fmt.Println("---------------------------------------")

fmt.Println(n4)
fmt.Println(n10)
fmt.Println(n11)
fmt.Println(n12)

}

变量的类型

数值类型: 整型类型(int,byte,uint,uint8,uint16,uint32,uint64,int8,int16,int32,int64),浮点类型(float32,float64)
字符类型:(没有单独的字符类型,使用byte来保存耽搁字母字符)
布尔类型: bool
字符串类型:string

派生数据类型/复杂数据类型: 指针(pointer)、函数(function)、管道(channel)、数组(array)、切片(slice)、结构体(struct)、接口(interface)、map。

扩展:
举例 int8 有符合 占1字节 数值范围 -128~127
ps: 127 怎么算出来的?
首先正数 所以首字肯定为 0, 然后最大值 后面肯定都是1 ,所以是 01111111
01111111 -> 二进制转为十进制 :
12^6 + 12^5 + 12^4 + 12^3 + 12^2 + 12^1 + 1*2^0 = 127

ps: -127怎么算出来的?
首先负数 所以首字肯定为 1, 然后最大值 后面肯定都是0 ,所以是 10000000

10000000 -> 负数的二进制
减1:01111111
取反:100000000 —》得到一个正数 2^7=128
加负号:-

整型类型

1
2
3
4
5
6
7
8
9
10
package main
import "fmt"

var nmu int8 = 129
func main() {
fmt.Println(num)
}

// 会报错,说超出范围 cannot use 129 (untyped int constant) as int8 value in variable declaration (overflows)

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"
"unsafe"
)

func main() {
var num int8 = 120
fmt.Println(num)

var num2 = 127

fmt.Printf("num2的类型是:%T",num2) //num2的类型是: int
fmt.Println()
fmt.Println(unsafe.Sizeof(num2))

//在变量使用范围中,尽量使用范围小的类型。
//表示学生的年龄
var age uint8 = 18 // 或 var age byte = 18
fmt.Println(age)
}

字符类型

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
package main    
import "fmt"

func main() {
//定义字符类型数据
var c1 byte = 'a'
fmt.Println(c1) //97
var c2 byte = '6'
fmt.Println(c2) //64
var c3 byte = '('
fmt.Println(c3) //40

//字符类型,本质上就是一个整数,也可以直接参与运算,输出字符时候,会将整数转换成对应的字符
//字母,数字,标点等字符,底层是按照ASCII码进行存储的

var c4 int = '中'
fmt.Println(c4) //20013
//汉字字符,底层对应的是Unicode码值
//对应的码值为20013,byte类型溢出,能存储的范围可以使用int
//总结:Golang的字符对应使用的是utf-8编码 (Unicode是对应的字符集,utf-8是Unicode的其中一种编码方案)

var c5 int = 'A'
//想显示对应的字符,必须采用格式化输出
fmt.Printf("c5对应的具体字符为: %c",c5)

}

转义字符

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

func main() {
// \n 换行
fmt.Println("hello\nworld")
// \t 制表符
fmt.Println("hello\tworld")
// \b 退格
fmt.Println("hello\bworld")
// \r 换行
fmt.Println("hello\rworld")
// \" 双引号"
fmt.Println("hello\"world")
// \\ 反斜杠
fmt.Println("hello\\world")
}

字符串类型

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
38
39
40
41
42
43
package main
import "fmt"

func main() {
//1. 定义一个字符串
var s1 string = "你好世界"
fmt.Println(s1)

//2. 字符串是不可变的:指的是字符串一旦定义好,其中的字符的值不可改变
var s2 string = "hello world"
//s2 = "1213" //是可以的
//s2[0] = '1' //是不可以的
fmt.Println(s2)

//3. 字符串的表现形式:
//(1)如果字符串中没有特殊字符,字符串的表示形式用双引号
//(2)如果字符串中有特殊字符,字符串的表现形式用反引号 ``
var s3 string = `
func main() {
// \n 换行
fmt.Println("hello\nworld")
// \t 制表符
fmt.Println("hello\tworld")
// \b 退格
fmt.Println("hello\bworld")
// \r 换行
fmt.Println("hello\rworld")
// \" 双引号"
fmt.Println("hello\"world")
// \\ 反斜杠
fmt.Println("hello\\world")
}
`
fmt.Println(s3)

//4. 字符串拼接
var s5 string = "hello" + "world"
s5 += "hello"
fmt.Println(s5)

//当字符串过长时: + 保留在上一行的最后
}

数据类型默认值

数据类型默认值

整数类型: 0
浮点类型: 0
布尔类型: false
字符串类型: “”

类型转换

(1)Go在不同类型的变量之间赋值需要显式转换,并且只有在显式转换(强制转换)
(2) 语法:

表达式T(v)将值v转换为类型T
T:就是数据类型
v:就是需要转换的变量

(3)案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package main
import "fmt"
func main() {
var n1 int = 10
fmt.Println(n1)
//var n2 float32 = n1 在这里自动转换不了,需要如下
var n2 float32 = float32(n1)
fmt.Println(n2)

//注意:n1的类型其实还是int类型,只是将n1的值转换为float32.
fmt.Printf("%T", n1)

//注意:n3的类型其实还是int32类型,只是将n3的值转换为int64
var n3 int32 = 12
var n4 int64 = int64(n3) + 30
fmt.Println(n4)
}

基本数据类型和string类型的转换

(1)在程序开发中,我们经常需要将基本数据类型转换成string类型。或者将string类型转成基本数据类型。
(2)基本类型转换string类型

方式1: ft.Sprintf(“%参数”,表达式)
方式2: 使用strconv包的函数

(3)案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package main
import fmt
func main() {
var n1 int = 10
var n2 float32 = 12.3
var n3 byte = '中'

var s1 string = fmt.Sprintf("%d", n1)
fmt.Println("s1对应的类型是:%T, s1 = %q \n", s1, s1)

var s2 string = fmt.Sprintf("%f", n2)
fmt.Println("s2对应的类型是:%T, s2 = %q \n", s2, s2)

var s3 string = fmt.Sprintf("%f", n3)
fmt.Println("s3对应的类型是:%T, s3 = %q \n", s3, s3)
}
1
2
3
4
5
6
7
8
9
10
11
package main
import (
"fmt"
"strconv"
)
func main() {
var n1 int = 10

var s1 string = strconv.FormatInt(int64(n1), 10) //参数:第一个参数是int64类型,第二个参数是进制
fmt.Println("s1对应的类型是:%T, s1 = %q \n", s1, s1)
}

指针

总结:指针就是内存地址
&获取内存地址
*从地址里取值

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
38
39
package main
import fmt
func main() {
var age int = 18
//&表示取变量的内存地址
fmt.Println(&age) // 0x14000112018

//定义一个指针变量:
//var 代表声明一个变量
//prt 指针变量的名字
//* 代表指针类型
//int 代表指针指向的数据类型
//&age 代表取变量的内存地址
var ptr *int = &age
fmt.Println(ptr)
fmt.Println("ptr本身这个存储空间的地址是:",ptr)

//想获取ptr这个指针或者这个地址指向的那个数据:
fmt.printf("ptr指向的数值为:%v\n", *ptr) // 18



// 可以通过指针修改变量的值
var num int = 18
fmt.Println(num) // 18

//指针变量接收的一定是地址值
var ptrs *int = &num
*ptr = 20
fmt.Println(num) // 20


//指针变量的地址不可以不匹配
// var ptrs *float32 = &num 是错误的


//基本数据类型(又叫值类型),都有对应的指针类型,形式为*数据类型,
//比如 int 的对应的指针就是*int,float32对应的指针就是*float32.以此类推
}

导入语句

import 导入语句通常放在文件开头包声明语句下。
导入的包名需要使用双引号包裹起来。
包名是从$GOPATH/src/后开始计算的,使用/进行分隔。

在mac上已经设置好了 $GOPATH ,查看 $GOPATH 输入 go env 即可查看所在路径。
在windows 上需要配置一个环境变量 $GOPATH 指定到对应的工作目录上。

1
2
3
4
5
6
7
8
9
10
11
package main
import (
"fmt"
"test" //使用的是test包下的test.go文件, 即在 $GOPATH/src/test/test.go 文件
)
func main() {
//如果test包下没有test.go文件,则会报错
//test.go文件 变量 Nums 为 首字小写,当前是访问不到数值的,变量必须大写
fmt.Println(test.Nums) //
}

$GOPATH/src/test/test.go

1
2
3
package test

var Nums int = 99

运算符

+加号
正数,相加操作,字符串拼接

% 取模
两个int 类型运输时,结果也是int类型 如 fmt.Println(10%3) 值 1

/ 除号
两个int 类型运输时,结果也是int类型 如 fmt.Println(10/3) 值 3
浮点类型参与运算,结果为浮点类型 fmt.Println(10.0/3) 值 3.3333333335

获取用户终端输入

在编程中,需要接收用户输入的数据,可以使用标准输入(stdin)来获取用户输入。

1
2
3
4
5
6

//Scanln类似Scan,但在遇到换行符(\n)后立即返回。
func Scanln(a ...interface{}) (n int, err error)

//Scanf从标准输入中读取文本,根据fomat参数指定的格式将成功读取的空白分隔的值保存进成功传递给本函数的参数。返回成功读取的参数个数和遇到的错误。
funcScanf(format string, a ...interface{}) (n int, err error)
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
package main
import "fmt"
func main() {
//实现功能:键盘收入学生的年龄,姓名,成绩,是否是vip
var age int
fmt.Println("请输入年龄")
//传入age的地址的目的:在Scanln函数中,对地址中的值进行改变的时候,实际外面的age被影响
fmt.Scanln(&age)

var name string
fmt.Println("请输入姓名")
fmt.Scanln(&name)


var score float32
fmt.Println("请输入成绩")
fmt.Scanln(&score)


var isVip bool
fmt.Println("是否是vip")
fmt.Scanln(&isVip)

//将上述数据在控制台打印输出:
fmt.Printf("学生的年龄为:%v,姓名为:%v,成绩为:%v,是否是vip为:%v",age, name, score, isVip)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
package main
import "fmt"
func main() {
var age int
var name string
var score float32
var isVip bool

fmt.Println("学生的年龄 ,姓名,成绩,是否是vip, 使用空格进行分割")
fmt.Scanf("%d %s %f %t", &age, &name, &score, &isVip)

fmt.Printf("学生的年龄为:%v,姓名为:%v,成绩为:%v,是否是vip为:%v",age, name, score, isVip)
}

流出控制

PS:条件表达式左右到()可以不写
PS: if和表达式中间,一定要有空格
PS: 在Golang中,{} 是必须有的,就算你只写一行代码

注意事项:
case 后面的表达式如果是常量值,则要求不能重复
case 后的各个值的数据类型,必须和switch表达式的数据类型一致
case 后面可以带多个值,使用逗号间隔
case 后面不需要带break
default语句不是必须,可以任意位置
switch后也可以不带表达式,当if分支来使用
switch后也可以直接声明/定义一个变量,分号结束(不举荐)
swicth穿透,利用fallthrough关键字,如果在case语句后增加fallthrough,则会继续执行下一个case,也叫switch穿透

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package main
import "fmt"
func main() {
// if
var count int = 10
if count > 10 {
fmt.Println("数量充足!")
} else if count > 5 && count < 10 {
fmt.Println("数量不足10")
} else {
fmt.Println("库存吃紧")
}

//在golang里,if后面可以并列的加入变量的定义:
if num := 20; num > 10 {
fmt.Println("数量充足!")
}

//switch

var score int = 8
var A int = 10
//给出一个学生等级
switch score {
case A:
fmt.Println("A")
case 9,5,6,7:
fmt.Println("B")
case 8:
fmt.Println("C")
fallthrough
default:
fmt.Println("D")
}

//for 循环 实现一个求和功能
var sum int
for i :=1; i <5; i++ {
sum += i
}
fmt.Println(sum)

//for循环灵活写法
q :=1
for q < 5 {
fmt.Println("你好")
q++
}


//定义一个字符串:
var str string = "hello"
//方式1:普通for循环:按照字节进行遍历输出到
for i := 0; i < len(str); i++ {
fmt.Printf("str[%v]=%v\n",i,str[i])
}

//方式2:for range
for i, v := range str {
fmt.Printf("str[%v]=%v\n",i,v)
}

//对str进行遍历,遍历的每个结果都赋值给v
//遍历对字符进行遍历
}

函数

func 函数名(参数名 参数类型) 返回值类型 {
//函数体
}

函数不支持重载
基本数据类型和数组默认都是传递的,即进行值拷贝,在函数内修改,不回影响到原来的值
以值传递方式的数据类型,如果希望在函数内的变量能修改函数外的变量,可以传入变量的地址&,函数内以指针的方式操作变量,从效果来看类似引用传递

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 test (args...int) {
fmt.Println(args)
}

func demo(num *int) {
//对地址对应的变量进行改变数值
*num = 30

}

func main() {
test (1,2,3,4,5,6,7)

var num int = 10
fmt.Println(&num)
demo(&num) //调用demo函数,传入num的地址
fmt.Println(num)
}
  • 函数也是一个数据类型,可赋值给一个变量,则该变量就是一个函数类型的变量。通过该变量可以对函数调用。
  • 函数既然是一种数据类型,因此函数可以作为参数并调用
  • 为来简化数据类型定义,Go支持自定义数据类型,可以通过type关键字定义
  • 支持对函数返回值命名
    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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    package main
    import "fmt"

    func test(num int) {
    fmt.Println(num)
    }

    func test2(num int, num2 int, testFunc func(int)) {
    fmt.Println("-----test02 \n")
    }

    type myFunc func(int)
    func test3(num int, num2 int, testFunc myFunc) {
    fmt.Println("-----test03 \n")
    }

    //定义一个函数:求两数的和 与 差 (传统写法)
    func test4(num int, num2 int) (int, int) {
    result1 := num - num2
    result2 := num + num2
    return result1, result2
    }

    //定义一个函数:求两数的和 (升级写法:对函数返回值命名,里面顺序就无所谓,顺序不用对应)
    func test5(num int, num2 int) (sum int, sub int) {
    sum = num + num2
    sub = num - num2
    return
    }

    func main() {
    a := test
    fmt.Printf("a的类型是 %T,test函数的类型是 %T \n", a, test)
    //输出: a的类型是 func(int),test函数的类型是 func(int)%

    //通过变量可以对函数调用
    a(10)

    //调用test2函数
    test2(2,12,test)

    test2(2,12,a)

    //自定义数据类型:(相当于起了别买):给int类型数据起了叫myInt类型
    type myInt int

    var num1 myInt = 30
    fmt.Println(num1)

    var num2 int = 40
    //num2 = num1 //虽然是别名,但是在go中编译识别时候还是认为myInt与int不是一种数据类型
    num2 = int(num1)
    fmt.Println(num2)


    test3(2,12,a)

    b,c := test4(5,3)
    fmt.Println(b,c)


    b,c = test5(4,3)
    fmt.Println(b,c)

    }
init函数
  1. init函数:初始化函数,可以用来进行一些初始化的操作
    每一个源文件都可以包含一个init函数,该函数会在main函数之前执行。

  2. 全局变量定义,init函数,mian函数的执行流程?
    答: 全局变量 –》 init函数 –》 main函数

  3. 多个源文件都有init函数的时候,如何执行
    答:重上往下,先执行导入所有包的init函数

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

var num int = test()

func test() int {
fmt.Println("调用了 test函数")
return 10
}

func init() {
fmt.Println("调用了 init函数")
}
func main() {
fmt.Println("调用了 main函数")
}

avatar
懒觉猫先生
欢迎你们的到来!
关注我吧
最新文章
最新评论
正在加载中...
网站资讯
文章数目 :
177
已运行时间 :
本站总字数 :
120.4k
本站访客数 :
本站总访问量 :
最后更新时间 :