GO入门学习

36次阅读

共计 5338 个字符,预计需要花费 14 分钟才能阅读完成。

go 环境安装
go 不像 java 这种成熟的语言有 eclipse 这种编译器,但是 go 提供了很多插件首先先选择一个编译器,我这边使用的 vscode,接着在 vscode 中配置 go 的开发环境配置开发环境之后,接着需要安装一些 go 的插件方便开发,首先先了解每种插件的作用,像 gocode 的作用就是代码补全,具体可参考 https://blog.csdn.net/langzi7… 安装插件有几种方式,可以通过 vscode 自动安装,也可以通过命令行安装,但因为有些插件需要 vpn,故可先从 github 上 clone 插件包,然后再进行安装,过程中可能会相关的问题 ….. 可跟着一下博文安装 https://blog.csdn.net/Yo_oYgo…
go build go install go getValue

go build:在当前目录下生成可执行文件,注意:go build 指令会调用所有引用包的源码,重新编译,而不是直接使用 pkg 里的编译后的文件,如果在 $GOROOT 或者 $GOPATH 下没有找到 import 引入的项目源码,就会报错。
go install:编译源代码,如果为可执行文件(package “main” 且包含 main 方法),则会编译生成可执行文件到 $GOPATH\bin 目录下,可执行文件 import 引入其他包,就会被编译到 $GOPATH/pkg/$GOOS_$GOARCH 目录下。
go get:git clone 到 $GOPATH\src + go install

method 和 function 的关系
method 是特殊的 function,定义在某一特定的类型上,通过类型的实例来进行调用,这个实例被叫 receivermethod belongs to instancefuction is a global function belongs to package
使用 method 的时候注意几点:

虽然 method 的名字一模一样,但是如果接受者不一样,那么 method 就不一样
method 里面可以访问接收者的字段
调用 method 通过. 访问,就像 struct 里面访问字段一样

指针
类似于 java 的引用,但是也保证的内存安全,类似 C 语言内存泄漏而程序崩溃的指针运算(所谓的指针算法,如:pointer+2,移动指针指向字符串的字节数或数组的某个位置)是不允许的。指针的传递很廉价,只占用 4 或 8 个字节。但传递一个变量的引用(函数的参数),这样不会传递变量的拷贝。
s := “good bye”
var p *string = &s
*p = “hello”
fmt.Printf(“Here is the pointer p:%p\n”, p)
fmt.Printf(“Here is the string *p:%s\n”, *p)
fmt.Printf(“Here is the string s:%s\n”, s)

map 的 value 值可以为任何类型 interface 的实现通过结构体实现相同的方式
package main

import (
“fmt”
)

type stockPosition struct {
ticker string
sharePrice float32
count float32
}

func (s stockPosition) getValue() float32 {
return s.sharePrice * s.count
}

type car struct {
make string
model string
price float32
}

func (c car) getValue() float32 {
return c.price
}

func getValue() float32 {
return 0
}

type valueable interface {
getValue() float32
}

func showValue(asset valueable) {
fmt.Printf(“Value of the asset is %f\n”, asset.getValue())
}

func main() {

s := getValue()
fmt.Println(s)

// 接口实现
// var o valueable = stockPosition{“GOOG”, 577.20, 4}
// showValue(o)
// o = car{“BMW”, “M3”, 66500}
// showValue(o)

//map 的 value 可以为任何类型
// mf := map[int]func() int{
// 1: func() int { return 10},
// 2: func() int { return 20},
// 3: func() int { return 50},
// }
// fmt.Println(mf)

//map 的 value 为 interface 时
// 当 value 为 interface,即 map 中的 value 值为 interface 的实现
// 跟 java 的面向对象有点绕,go 的 struct 在 java 完全可以用 class 来实现
// 具有接口相同的方法就可以算是实现了接口
var c car = car{“BMW”, “M3”, 66500}
var v valueable = stockPosition{“GOOG”, 577.20, 4}
mf := map[string]interface{getValue() float32 }{
“account”: c,
“password”: v,
}

for _, value := range mf {
fmt.Println(value)
fmt.Println(value.getValue())
}

}

interface 万能模型
测试
测试文件的后缀为_test.go,并且应该跟被测试文件放在同一个目录下测试数据放在一个特殊的 testdata 目录中,使用 go build 时,testdata 目录和_test.go 文件都会被编译器忽略
new 跟 make
func new(Type) *Type 分配空间,参数一个类型,返回值指向这个新分配的零值的指针 func make(Type,size IntegerType)分配并且初始化一个 slice,或者 map 或者 chan 对象,并且只能是这三种对象。第一个参数为类型,第二个参数为长度返回值是这个类型.
int 类型跟 string 类型的切换
go 主要通过 strings 包来完成对字符串的主要操作 strings.HasPrefix(s,prefix string) bool 等
多返回值函数的错误
Go 中函数经常使用两个返回值表示执行是否成功,返回某个值以及 true 表示成功,返回零值(或 nil)和 false 表示失败。当不使用 true 或 false 的时候,也可以使用一个 error 类型的变量来替代第二个返回值。习惯用法:value,err := pack1.Function(param1)if err != nil{
fmt.Printf(“An error occured in pack1.Function1 with parameter %v”,param1)
return err
}// 未发生错误,继续执行
// 测试用例需要包括

正常的用例
反面的用例
边界检查用例

单元测试 gomock
go 中的实现泛型
go 中并没有泛型的概念,但可通过 interface 来实现例如下面的冒泡排序
package main

import “fmt”

type Sortable interface {
Len() int
Less(int, int) bool
Swap(int, int)
}

func bubbleSort(array Sortable) {
for i := 0; i < array.Len(); i++ {
for j := 0; j < array.Len()-1-i; j++ {
if array.Less(j+1, j) {
array.Swap(j, j+1)
}
}
}
}

// 实现接口的整形切片
type IntArr []int

func (array IntArr) Len() int {
return len(array)
}

func (array IntArr) Less(i int, j int) bool {
return array[i] < array[j]
}

func (array IntArr) Swap(i int, j int) {
array[i], array[j] = array[j], array[i]
}
func main() {
intArr1 := IntArr{3, 5, 1, 2, 3, 7, 88}
bubbleSort(intArr1)
fmt.Println(intArr1)
}

参考:https://studygolang.com/artic…
闭包
当不希望给函数起名字的时候,可以使用匿名函数,例如:func(x, y int) int {return x + y}这样一个函数不能够独立存在,但可以被赋值为某个变量,例如 fplus := func(x, y int) int {return x + y},然后通过变量名对函数进行调用 fplus(3,4)
当然可以直接对匿名函数进行直接调用:func(x, y int) int {return x + y}(3,4)表示参数列表的第一对括号必须紧着着关键字 func,因为匿名函数没有名称,花括号 {} 涵盖着函数体,最后一堆括号表示对匿名函数的直接调用
linq
defer panic recover
defer
defer 相当于 java 的 finally
panic
panic 是用来表示非常严重的不可恢复的错误,在 Go 语言是一个内置函数,接收一个 interface{}类型的值作为参数。panic 的作用就像我们平常接触的异常,不过 Go 没有 try…catch,所以 panic 一般会导致程序挂掉(除非 recover), 所以在 go 语言中的异常就是真的异常了。关键的一点,函数执行的时候 panic 了,将先到 defer 中执行完,panic 再想传递
recover
recover 用来捕获 panic,被 recover 捕获到的 panic 将不会向上传递 recover 之后,逻辑并不会恢复到 panic 那个点去,函数还在 defer 之后返回
导包下划线 ”_” 的作用
引入该包,但是并非真的需要使用使用这些包,同时会执行它的 init()函数 //mysql 的关键字 index,处理,给该字段加上单引号反单引号 Index
构建 http 服务
func IndexHander(w http.ResponseWriter,r *http.Request){
fmt.Fprintln(“hello wrold”)
}func main(){
http.HandleFunc(“/”,IndexHander)
http.ListenAndServer(“127.0.0.1:8080”,nil)
}
接收 request 的过程,最重要的莫过于路由(router),即实现一个 Multiplexer 器,Go 中既可以使用内置的 multiplexer–DefaultServerMux,也可以自定义。Multiplexer 路由的目的就是为了找到处理器函数(handle),后者讲对 request 进行处理,同时构建 response
函数作为参数的优势?
init 函数
不能够有任何参数,虽然每个 package 里面可以写任意多个 init 函数,但这无论是可读性还是以后的可维护性来说,我们都强烈建议用户在一个 package 中每个文件中只写一个 init 函数
struct 的声明方式
type person struct{
name string
age int
}
//1、
var P person
p.name = “dack”
p.age = 21
//2、
p := person{“dack”,21}
//3、
p := person{
age : 21
name : “dack”
}
//4、可以通过 new 函数分配一个指针,此处 P 的类型为 *person

struct 的匿名字段
当一个匿名字段是一个 struct 的时候,那么这个 struct 所拥有的全部字段都被隐式地引入当前定义的这个 struct
type Human struct{
name string
age int
weight int
}

type Student struct{
Human // 匿名字段,那么默认 Student 就包含了 Human 的所有字段
speciality string
}

func main(){
mark := Student{Human{“dacl”,21,65},”Go Science”}
mark.speciality = “AI”
mark.age = 25
mark.weight = 70
}

Student 可以访问 name 和 age 就像自己用自己的字段一样匿名对象能够实现字段的继承 Student 还能访问 Human
mark.Human = Human{“tony”,22,55}
mark.Human.age = 1

不仅 struct 可以作为匿名字段,自定义类型、内置类型也可以作为匿名字段
如果遇到 human 里面有一个字段 phone,student 里面的字段 phone,那么优先访问最外最外层
golang API json ,struct 结构中标签 (Tag) 的使用
在 golang 中,命名都是推荐用驼峰方式,并且在首字母大小写有特殊含义:包外无法引用但由于经常需要和其他系统进行数据交互,例如转换成 json 格式,存储到 Redis 等。这个时候如果直接使用属性名来作为键值会不符合项目要求
于是就有了 tag,也就是有了 json:name

正文完
 0