go基础语法
注意点
包和目录的关系
go 用文件目录来管理包,一个文件目录可以有多个.go 文件,要求目录内所有的文件的包名要一致
默认包名和目录名称保持一致,不强制要求
用包来管理元素的可见行,大写开头的元素包外也可见,小写开头的元素只能在包内使用
目录 p1 内的俩个go 文件
第一个.go 文件
1 | package p1 |
第二个 .go 文件
1 | package p1 |
main .go 文件
1 | package main |
引入包的注意点
包别名
1
2
3
4
5
6
7
8
9
10
11
12package main
//引用包别名
import p2 "awesomeProject/p1"
func main() {
p2.F1()
//私有成员包外不可见
//p2.f2()
p2.F3()
//私有成员包外不可见
//p2.f4()
}省略包名直接使用
通过 . 号 来省略包名
1
2
3
4
5
6
7
8
9
10
11
12
13package main
//引用包
import ."awesomeProject/p1"
func main() {
F1()
//私有成员包外不可见
//f2()
F3()
//私有成员包外不可见
//f4()
}不使用包但是使用包里的初始化方法
1
2
3
4
5
6
7
8
9
10
11
12
13package p1
import "fmt"
var I = 10
//包的初始化
//在包被引入的时候执行
func init() {
fmt.Printf("初始化包,%d\n", I)
}
func F1() {
fmt.Println("F1")
}1
2
3
4
5
6
7
8
9
10
11package main
//引用包
import (
//通过 _ 引入的包表示只执行包的初始化方法
_ "awesomeProject/p1"
)
func main() {
//不能使用包内成员
//p1.F1()
}
值类型和引用类型
值类型包括基本数据类型,int,float,bool,string,以及数组和结构体(struct)。值类型变量声明后,不管是否已经赋值,编译器为其分配内存,此时该值存储于栈上.
当使用等号=将一个变量的值赋给另一个变量时,如 j = i ,实际上是在内存中将 i 的值进行了拷贝,可以通过 &i 获取变量 i 的内存地址。此时如果修改某个变量的值,不会影响另一个
引用类型包括指针,slice切片,map,chan,interface,func。变量直接存放的就是一个内存地址值,这个地址值指向的空间存的才是值。所以修改其中一个,另外一个也会修改(同一个内存地址)。引用类型必须申请内存才可以使用,make()是给引用类型申请内存空间
数组是值类型 ,切片是引用类型
数组是一组同类型数据的集合,它是值类型,通过从0开始的下标索引访问元素值。在初始化后长度是固定的,无法修改其长度。当作为方法的参数传入时将复制一份数组而不是引用同一指针。数组的长度也是其类型的一部分,通过内置函数len(array)获取其长度
1 | //数组 值类型 |
与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大。切片中有两个概念:一是len长度,二是cap容量,长度是指已经被赋过值的最大下标+1,可通过内置函数len()获得。容量是指切片目前可容纳的最多元素个数,可通过内置函数cap()获得。切片是引用类型,因此在当传递切片时将引用同一指针,修改值将会影响其他的对象。
切片可以通过数组来初始化,也可以通过内置函数make()初始化.初始化时len=cap,在追加元素时如果容量cap不足时将按len的2倍扩容
1 | //切片 引用类型 |
切片切出来的部分和原来的切片是共享一个堆内存对象
1 | { |
空切片
1 | { |
完整的切片和原来切片一样
1 | { |
用 copy 在原有切片的基础上生成一个全新的切片
1 | { |
结构体
结构体定义
结构体是值类型,类似与Java 的 Class ,但是 Go 的结构体内不能定义方法实现,静态成员
结构体没有继承的概念,使用组合代替继承
定义父类
1 | type Animal struct { |
父类构造函数
1 | func New(name string) *Animal { |
父类的实例方法
1 | //(this *Animal) 通过指针确保方法内的 this 和调用方法的变量指向的是同一个实例 |
子类定义 通过嵌套继承父类
1 | //子类 |
结构体初始化及使用
初始化方法1
1 | var i Animal = Animal{name: ""} |
初始化方法2
对结构体进行&取地址操作时,视为对该类型进行一次 new 的实例化操作
1 | var l *Animal = &Animal{name: ""} |
初始化方法3
1 | //创建指针类型的结构体 |
子类初始化
1 | var iSon = Bird{maxFlyDistance: 1000, Animal: Animal{name: ""}} |
接口
接口是引用类型,接口可以通过组合的形式形成继承接口
接口定义
接口内定义方法的声明,接口可以通过组合的形式达到继承接口的效果
1 | type Base interface { |
接口的实现
接口有多个实现的实例,多态的效果
1 | type Dog struct { |
接口的使用
1 | func bar(i Animal) { |
反射
反射可以反射基础类型和和明确类型
反射是指在程序运行期对程序本身进行访问和修改的能力。程序在编译时,变量被转换为内存地址,变量名不会被编译器写入到可执行部分。在运行程序时,程序无法获取自身的信息。
支持反射的语言可以在程序编译期将变量的反射信息,如字段名称、类型信息、结构体信息等整合到可执行文件中,并给程序提供接口访问反射信息,这样就可以在程序运行期获取类型的反射信息,并且有能力修改它们。
Go程序在运行期使用reflect包访问程序的反射信息。
反射是由 reflect 包提供的。它定义了两个重要的类型,Type 和 Value。一个 Type 表示一个Go类型。它是一个接口
反射字段,方法,tag 及基础类型
需要反射的结构体
结构体可以加标签 相当于是 Java 注解
1 | type str struct { |
反射字段
1 | func GetFields(ty reflect.Type, val reflect.Value) { |
反射公有方法
1 | func GetMethods(ty reflect.Type, val reflect.Value) { |
反射 tag
1 | func GetTags(ty reflect.Type) { |
1 | func main() { |
GOPATH 工作方式
在 GOPATH 指定的工作目录下,代码总是会保存在 $GOPATH/src 目录下。在工程经过 go build、go install 或 go get 等指令后,会将产生的二进制可执行文件放在 $GOPATH/bin 目录下,生成的中间缓存文件会被保存在 $GOPATH/pkg 下。
GOPATH 有两种
- 全局的GOPATH,来源于系统环境变量中的 GOPATH
- 项目的GOPATH
指定了GOPATH 也就指定了包的搜索路径 ,项目的GOPATH 随项目设定 GOPATH 定义了绝对的文件搜索路径
GOPATH 项目演示
指定工作目录 F:/GoWorkPath
工作目录下建立src 目录
在 src 下建立目录 libs1,libs2,main 目录
libs1 目录 .go 代码
1
2
3
4
5
6
7package libs1
import "fmt"
func F() {
fmt.Println("libs1 func F Z 执行")
}libs2 目录 .go 代码
1
2
3
4
5
6
7package libs2
import "fmt"
func F() {
fmt.Println("libs2 func F Z 执行")
}main 目录 .go 代码
import 根据指定的 项目 GOPATH 可以直接导入 src 下的 包,1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16package main
import (
//不需要指定路径
"libs1"
//如果没有指定项目 GOPATH ,需要根据当前的 .go 文件的目录指定相对的.go 包文件路径
//"../libs1"
"libs2"
"time"
)
func main() {
libs1.F()
libs2.F()
time.Sleep(5 * time.Second)
}
GO MOD 工作方式
Modules是相关Go包的集合,是源代码交换和版本控制的单元。go命令直接支持使用Modules,包括记录和解析对其他模块的依赖性。Modules替换旧的基于GOPATH的方法,来指定使用哪些源文件。
Modules和传统的GOPATH不同,不需要包含例如src,bin这样的子目录,一个源代码目录甚至是空目录都可以作为Modules,只要其中包含有go.mod文件.
父目录里有.mod 文件,父目录里的文件及父目录的子目录里的文件都受mod管理,
目前的推荐在 MOD 模式下工作.
GO MOD 项目演示
GO 版本1.11以上
设置GO111MODULE
GO111MODULE=off,go命令行将不会支持module功能,寻找依赖包的方式将会沿用旧版本那种 通过vendor目录或者GOPATH模式来查找。GO111MODULE=on,go命令行会使用modules,而一点也不会去GOPATH目录下查找。
GO111MODULE=auto,默认值,go命令行将会根据当前目录来决定是否启用module功能。这种情况下可以分为两种情形:
- 当前目录在GOPATH/src之外且该目录包含go.mod文件
- 当前文件在包含go.mod文件的目录下面。
在GOPATH/src 目录之外新建工程目录
在此目录下新建俩个目录 project1,project2 分别在这俩个目录内
执行 go mod int project1, go mod int project2在俩个目录生成 go.mod 文件
这是一个关键文件,之后的包的管理都是通过这个文件管理在目录project2内新建目录libs 目录,在此目录新建f.go 文件
1
2
3
4
5
6
7package libs
import "fmt"
func F() {
fmt.Println("project2 libs F 执行")
}在目录project1内修改 go.mod 文件
project1 这个模块需要引用本地的其他自定义模块 project2 需要指定相对当前go.mode 文件的路径
replace project2 => ../project2
require project2 v0.0.01
2
3
4
5
6
7
8
9
10
11
12
13module project1
replace project2 => ../project2
require project2 v0.0.0
//引入第三模块的依赖
require (
github.com/sirupsen/logrus v1.8.1 // indirect
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037 // indirect
)
go 1.18
在在目录project1 内新建目录libs 在此目录新建 f.go 文件
1
2
3
4
5
6
7package libs
import "fmt"
func F() {
fmt.Println("project1 libs F 执行")
}在目录project1 内新建目录mainX 在此目录新建 main.go 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17package mainX
import (
"fmt"
log "github.com/sirupsen/lours"
p1 "project1/libs"
p2 "project2/libs"
"time"
)
func main() {
fmt.Println("main")
p1.F()
p2.F()
log.Info("我是一条日志")
time.Sleep(5 * time.Second)
}在 main.go文件所在目录执行 go mod tidy 会清理无用的模块引用
go build 下载引用的模块及执行编译生成 mainX.exe 文件
执行文件 ./mainX.exe 结果mainX
project1 libs F 执行
project2 libs F 执行
time=”2022-04-20T11:33:05+08:00” level=info msg=”我是一条日志”
本次笔记记录时间 2022-04-20,疫情期间,下次开始学习框架
mvc 数据库
mvc 数据库 网络通讯