GO Lang学习笔记

Go lang Learn Note

标签(空格分隔): Go


Go安装和Go目录

设置环境变量GOROOTGOPATH,前者是go的安装目录,后者是开发工作目录。go get包只会将包下载到第一个工作目录(多个GOPATH的时候)。

Go语言命令行工具介绍

  • go build 用于编译源码文件、代码包、李赖堡
  • go run 可以编译并运行go源码文件
  • go get 主要是用来动态获取远程代码包

GoLand编辑器选择和配置

GoLand下载

一、GO语言基础语法

1. 关键字、标识符

  • GO中保留的关键字(25个)
break default func interface select
case defer go map struct
chan else goto package switch
const fallthrough if range type
continue for import return var
  • GO中预定的标识符,包括基础数据类型和系统内嵌函数(36个)
append bool byte cap close complex
complex64 complex128 uint16 copy false float32
float64 imag int int8 int16 uint32
int32 int64 iota len make new
nil panic uint64 print printIn real
recover string TRUE uint uint8 uintprt

2. 注释

  • // 单行注释
  • /* 多行注释 */

3. 基础结构

// 程序所属包
package main
// 导入依赖包
import "fmt"
// 常量定义
const NAME string = "John"
// 全局变量声明与赋值
var name string = "Bob"
// 一般类型声明
type typeInt int
// 结构声明
type Learn struct { }
// 接口声明
type ILeran interface { }
// 函数定义
func learnFoo() {
	fmt.Println("learn foo")
}

// main()函数
func main() {
	fmt.Println("simple demo")
	fmt.Println(NAME)
	fmt.Println(name)

	learnFoo()
}

运行结果

simple demo
John
Bob
learn foo

Process finished with exit code 0

4. Package用法

  • package是最基本的分发单位工程管理中依赖关系的体现
  • 每个GO语言源代码文件开头都拥有一个package声明,表示源码文件所属代码包。
  • 要生成GO语言可执行程序,必须要有main的package包,且必须在该包下有main()函数。
  • 同一个路径下只能存在一个package,一个package可以拆分成多个源文件组成。
  • 建议package名称和目录名称一致
  • 同一路径下只能有同一个package名

5.1 import用法

  • 可以导入源代码文件所依赖的package包。
  • 不得导入源代码文件中没有用到的package,否则会编译错误。
  • 两种格式:
import "package1"
import "package2"
...
import (
    "package1"
    "package2"
    ...
)

导入未使用包,会抛出如下错误:

import-demoimport-demo.go:5:2: imported and not used: "time"

Compilation finished with exit code 2
  • 如果一个main导入其它包,包将被顺序导入。
  • 如果导入的包中依赖其它包(包B),会首先导入包B,然后初始化包B中的常量和变量,最后如果包B中有init,会自动执行init(),然后回到main中。
  • 所有包导入完成后才会对main中常量和变量进行初始化,然后执行main中的init函数,最后执行main函数。
  • 如果一个包被导入多次,则该包只会被导入一次。

import顺序

import-demo.go

package main

import (
	"fmt"
	"./src/show"
	"./src/learn"
	)

// 所有依赖包初始化完成后
// 才执行main的初始化函数
func init() {
	fmt.Println("import-demo init")
}

func main() {
	// learn的init函数只执行了一次
	// 可知多次导入只被导入一次
	learn.Learn()
	show.Show()
	fmt.Println("Hello world")
}

show/show.go

package show

import (
	"fmt"
	"../learn"
)

func init() {
	fmt.Println("show init")
}

func Show() {
	learn.Learn()
	fmt.Println("show func")
}

learn/learn.go

package learn

import "fmt"

func init() {
	fmt.Println("learn init")
}

func Learn() {
	fmt.Println("learn func")
}

然后我们运行import-demo.go,可见执行结果:

learn init
show init
import-demo init
learn func
learn func
show func
Hello world

Process finished with exit code 0

5.2 import别名

  • 将导入的包命名为另一个容易记忆的别名。
  • 点(.)标识的包导入后,调用改包中的函数时可以省略前缀包名。
  • 下划线(_)表示导入该包,但不导入整个包,而是执行该包中的init函数,因此无法通过包名来调用包中的其它函数。使用下划线操作往往是为了注册包里的引擎,让外部可以方便的使用。

别名

import (
    myFmt "fmt"
)

6 数据类型

数据类型的出现主要是为了把数据分成所需内存大小不同的数据,可以充分利用内存。
布尔型只可以是true或者false。
字符串类型编码统一为UTF-8。

6.1 整型
类型 描述
uint8 无符号 8 位整型 (0 到 255)
uint16 无符号 16 位整型 (0 到 65535)
uint32 无符号 32 位整型 (0 到 4294967295)
uint64 无符号 64 位整型 (0 到 18446744073709551615)
int8 有符号 8 位整型 (-128 到 127)
int16 有符号 16 位整型 (-32768 到 32767)
int32 有符号 32 位整型 (-2147483648 到 2147483647)
int64 有符号 64 位整型 (-9223372036854775808 到 9223372036854775807)
6.2 浮点型
类型 描述
float32 IEEE-754 32位浮点型数
float64 IEEE-754 64位浮点型数
complex64 32位实数和虚数
complex128 64位实数和虚数
6.3 其他数字类型
类型 描述
byte 类似 uint8
rune 类似 int32
uint 32或64位
int 与uint一样大小
uintptr 无符号整型 用于存放一个指针
package main

import (
	"fmt"
	"unsafe"
)

func main() {
	// var i uint8 = 1   // 1
	// var i uint32 = 1  // 4
	var i uint = 1   // 8
	fmt.Println(unsafe.Sizeof(i))

	var j float32 = 1 // 4
	fmt.Println(unsafe.Sizeof(j))

	var b bool = true
	fmt.Println(b)

	var bt byte = 1 // 1  类似 uint8
	fmt.Println(unsafe.Sizeof(bt))

	var r rune = 1 // 4  类似 int32
	fmt.Println(unsafe.Sizeof(r))
}
6.4 派生类型
6.5 类型零值和类型别名

类型零值不是空值,是被声明后的默认值。值类型默认值为0,布尔型默认值为false,string默认值为空字符串

package main

import (
	"fmt"
	"reflect"
	"unsafe"
)

type 别名 int32
func main() {
	var i int32
	var j float32
	var b bool
	var d complex64
	var s string

	fmt.Print("int32: ")
	fmt.Println(i) // int32: 0
	fmt.Print("float32: ")
	fmt.Println(j) // float32: 0
	fmt.Print("bool: ")
	fmt.Println(b) // bool: false
	fmt.Print("complex64: ")
	fmt.Println(d) // complex64: (0+0i)
	fmt.Print("string: ")
	fmt.Println(s) // string:

	var i_b 别名
	var i_n int32

	fmt.Print("i_b 别名 默认值: ")
	fmt.Print(i_b) // 别名: 0
	fmt.Print(", i_b 别名 数据类型: ")
	fmt.Print(reflect.TypeOf(i_b))
	fmt.Print(", i_b 别名 占用大小: ")
	fmt.Println(unsafe.Sizeof(i_b))
	// Result: i_b 别名 默认值: 0, i_b 别名 数据类型: main.别名, i_b 别名 占用大小: 4

	fmt.Print("i_n int32 默认值: ")
	fmt.Print(i_n) // 别名: 0
	fmt.Print(", i_n int32 数据类型: ")
	fmt.Print(reflect.TypeOf(i_n))
	fmt.Print(", i_n int32 占用大小: ")
	fmt.Println(unsafe.Sizeof(i_n))
	// Result: i_n int32 默认值: 0, i_n int32 数据类型: int32, i_n int32 占用大小: 4

	// 不同类型不能运算, 包括别名
}
6.6 类型存储大小

类型存储大小

7 变量与常量

7.1 变量声明 初始化与赋值
  • 变量声明和赋值

变量声明: var [变量名称] <变量类型>
变量赋值: [变量名称] = [值]
声明与赋值同时进行: var [变量名称] <变量类型> = [值]
分组声明:

var (
    i int
    j float32
    name string = "abc"
)

同一行声明多个变量和赋值: var a, b, c int = 1,2,3或者a, b := 1,2
全局变量的声明必须使用var关键字,局部变量可以省略
特殊变量下划线 _

package main

import (
	"fmt"
	"reflect"
)

// 全局变量var是必须的
var a int
var b string = "abc"
// 分组方式
var (
	c string
	d int
	e string = "小明"
)

func main() {
	fmt.Println(a) // 0

	a = 123 // 赋值
	fmt.Println(a) // 123

	fmt.Println(b) // abc

	fmt.Print("c: ")
	fmt.Print(c)
	fmt.Print(", d: ")
	fmt.Print(d)
	fmt.Print(", e: ")
	fmt.Println(e)
	// c: , d: 0, e: 小明

	var f, g, h int = 1, 2, 3
	fmt.Print("f: ")
	fmt.Print(f)
	fmt.Print(", g: ")
	fmt.Print(g)
	fmt.Print(", h: ")
	fmt.Println(h)
	// f: 1, g: 2, h: 3

	var i, j, k = 11, 21.3, 31
	fmt.Print("i: ")
	fmt.Print(i)
	fmt.Print("i 数据类型为: ")
	fmt.Print(reflect.TypeOf(i))
	fmt.Print(", j: ")
	fmt.Print(j)
	fmt.Print(", j 数据类型为: ")
	fmt.Print(reflect.TypeOf(j))
	fmt.Print(", k: ")
	fmt.Println(k)
	// i: 11i 数据类型为: int, j: 21.3, j 数据类型为: float64, k: 31

	// 冒号简写,只能在函数体内使用
	l, m, n := 11, 21.3, "c"
	fmt.Print("l: ")
	fmt.Print(l)
	fmt.Print(", m: ")
	fmt.Print(m)
	fmt.Print(", n: ")
	fmt.Println(n)
	// l: 11, m: 21.3, n: c

	// 下划线
	var o, _, p = 11, 21.3, 31
	fmt.Print("o: ")
	fmt.Print(o)
	fmt.Print(", p: ")
	fmt.Print(p)
	// fmt.Print(", _: ")
	// fmt.Println(_) // 下划线不能被打印
	// o: 11, p: 31
}
7.2 变量类型转换

不能隐式转换,必须显式
类型转换只能发生在两种兼容类型之间
类型转换格式: [变量名称] [:]= <目标类型>([需要转换的变量名称])

package main

import (
	"fmt"
	"reflect"
)

func main() {
	var a int = 1
	var b float32 = 2.3

	c := float32(a)

	fmt.Print(c)
	fmt.Print(" ")
	fmt.Println(reflect.TypeOf(c))

	d := int32(b)
	fmt.Print(d)
	fmt.Print(" ")
	fmt.Println(reflect.TypeOf(d))
}
7.3 变量可见性规则

大写字母开头的变量是可导出的,是公用变量
小写字母开头的变量是私有变量,不可导出被读取

package B

// 大写字母开头的变量是可导出的,是公用变量
// 小写字母开头的变量是私有变量,不可导出被读取
var a = "变量a"

var A = "变量A"
package main

import (
	"fmt"
	"./B"
)

func main() {
	fmt.Println(B.A) // 变量A
}
7.4 常量
  • 定义形式 类型范围

显示: const identifier <type> = value
隐式: const identifier = value ,无类型常量
常量可以使用内置表达式定义,len() unsafe.Sizeof()
只支持布尔型、数字型(整数型、浮点型和复数)、字符串型
常量不能使用 := 语法定义。

package main

import "fmt"

const a string = "常量a" // 显式
const b = "常量b" // 隐式
const (
	c string = "常量c"
	d = "常量d"
)
const e, _, f = "常量e", "下划线", 6
const g = len(a) // 只支持内置函数

func main() {
	fmt.Println(a) // 常量a
	fmt.Println(b) // 常量b
	fmt.Println(c) // 常量c
	fmt.Println(d) // 常量d
	fmt.Println(e) // 常量e
	fmt.Println(f) // 6
	fmt.Println(g) // 7
}
  • iota的使用

在const关键字出现时将被重置为0
const中每新增一行常量声明将使iota +1
跳值使用法、插队使用法、表达式隐式使用法、单行使用法

package main

import "fmt"

func main() {
	// 在const关键字出现时将被重置为0
	const h = iota
	const i = iota
	fmt.Print("h值为: ")
	fmt.Print(h)
	fmt.Print(", i值为: ")
	fmt.Println(i)
	// h值为: 0, i值为: 0


	// const中每新增一行常量声明将使iota +1
	const (
		j = iota
		k = iota
	)
	fmt.Print("j值为: ")
	fmt.Print(j)
	fmt.Print(", k值为: ")
	fmt.Println(k)
	// j值为: 0, k值为: 1


	// 跳值使用法
	const (
		l = iota
		m = iota
		_
		n = iota
	)
	fmt.Print("l值为: ")
	fmt.Print(l)
	fmt.Print(", m值为: ")
	fmt.Print(m)
	fmt.Print(", n值为: ")
	fmt.Println(n)
	// l值为: 0, m值为: 1, n值为: 3


	// 插队使用法
	const (
		o = iota
		p = 3.14
		q = iota
	)
	fmt.Print("o值为: ")
	fmt.Print(o)
	fmt.Print(", p值为: ")
	fmt.Print(p)
	fmt.Print(", q值为: ")
	fmt.Println(q)
	// o值为: 0, p值为: 3.14, q值为: 2


	// 表达式隐式使用法
	// 自动向上使用非空表达式
	const (
		r = iota * 2
		s = iota * 3
		t
		u
	)
	fmt.Print("r值为: ")
	fmt.Print(r)
	fmt.Print(", s值为: ")
	fmt.Print(s)
	fmt.Print(", t值为: ")
	fmt.Print(t)
	fmt.Print(", u值为: ")
	fmt.Println(u)
	// r值为: 0, s值为: 3, t值为: 6, u值为: 9


	const (
		aa, bb = iota, iota + 3
		cc, dd
		ee = iota
	)
	fmt.Print("aa值为: ")
	fmt.Print(aa)
	fmt.Print(", bb值为: ")
	fmt.Print(bb)
	fmt.Print(", cc值为: ")
	fmt.Print(cc)
	fmt.Print(", dd值为: ")
	fmt.Print(dd)
	fmt.Print(", ee值为: ")
	fmt.Println(ee)
	// aa值为: 0, bb值为: 3, cc值为: 1, dd值为: 4, ee值为: 2
}

8.运算符

8.1 算数运算符

+, -, *, /, %, ++, --

++, --只能在变量后面用。

8.2 关系运算符

==, !=, >, >=, <, <=

8.3 逻辑运算符

&&, ||, !

8.3 按位运算符
  • & 按位与 两者都为1则结果为1
  • | 按位或 有一个为1 结果为1
  • ^ 按位异或 对应位 不同数值时结果为1,相同数值为0
  • << 左移 把数整体向左移动
  • >> 右移 把数整体向右移动

按位运算符

package main

import "fmt"

func main() {
	a := byte(0)
	b := byte(1)

	fmt.Print("a 的值为: ")
	fmt.Println(a)
	fmt.Print("b 的值为: ")
	fmt.Println(b)

	fmt.Println("")

	fmt.Print("a&b 的值为: ")
	fmt.Println(a&b)

	fmt.Print("a|b 的值为: ")
	fmt.Println(a|b)

	fmt.Print("a^b 的值为: ")
	fmt.Println(a^b)
	fmt.Print("a^a 的值为: ")
	fmt.Println(a^a)

	fmt.Print("b << 1 的值为: ")
	fmt.Println(b << 1)

	fmt.Print("b >> 1 的值为: ")
	fmt.Println(b >>1 )
}
a 的值为: 0
b 的值为: 1

a&b 的值为: 0
a|b 的值为: 1
a^b 的值为: 1
a^a 的值为: 0
b << 1 的值为: 2
b >> 1 的值为: 0

Process finished with exit code 0
8.4 赋值运算符
  • = 赋值
  • += 加等
  • -= 减等
  • *= 乘等
  • /= 除等
  • %= 余等 a %= 2 相当于 a = a % 2
  • <<= 左移后赋值 a <<= 2 相当于 a = a << 2
  • >>= 右移后赋值 a >>= 2 相当于 a = a >> 2
  • &= 按位与后赋值 a &= 2 相当于 a = a & 2
  • ^= 按位异后赋值 a ^= 2 相当于 a = a ^ 2
  • |= 按位或后赋值 a |= 2 相当于 a = a | 2

9 控制语句

9.1 if else
9.2 switch, select
9.3 for
// for 循环
for i := 1; i <= 10; i++ {
	fmt.Println(i)
	time.Sleep(1 * time.Second)
}

// forEach 循环
b := []string{"字符串1", "字符串2", "字符串3", "字符串4", "字符串5"}
for key, value := range b {
	fmt.Print("key的值为: ")
	fmt.Println(key)
	fmt.Print("value的值为: ")
	fmt.Println(value)
}
9.4 goto, break, continue
  • goto 跳转到指定流程
  • break 跳出循环
  • continue 跳出本次循环
// goto
goto One
fmt.Println("代码块1")
fmt.Println("代码块2")
One:
	fmt.Println("代码块One")
fmt.Println("代码块Two")

// break
for i := 1; i <= 3; i++ {
	for j := 0; j < 3; j++ {
		fmt.Print("循环体-")
		fmt.Print(i)
		fmt.Print("-")
		fmt.Println(j)
		break
	}
}

// continue
for i := 0; i < 3; i++ {
	if i > 1 {
		fmt.Println("满足i > 1, continue, 跳出本次循环")
		continue
	}

	fmt.Print("当前下标为: ")
	fmt.Println(i)
}

Last updated by Jehorn, Aug 16 2018

原文地址:https://www.cnblogs.com/jehorn/p/9437664.html