AI智能
改变未来

Go语言学习笔记

此笔记是本人在学习Go语言过程中对知识点进行记录,以方便之后查阅学习,如果有不合理的地方欢迎各位大佬指出!
1.变量

  • 使用var关键字
var a,b,c bool            //定义var c string = \"helllo\"   //赋值
  • 既可以在函数体内,也可以在包内
  • 使用var()进行集中定义变量
  • 编译器可以自动判断变量类型,可以不写 变量的类型
  • 可以使用:=的方式定义变量。但是这种方式只能在函数体内使用,在变量初始化时使用

2.变量类型

  • (u)int 没有规定长度,根据操作系统位数自行决定
    (u)int8 (u)int16 (u)int32 (u)int64 uintptr 指针
  • bool string
  • byte
  • rune (char类型,32位)
  • float32 float64
  • complex64 complex128(复数类型)
  • 变量类型转换是强制的,没有隐式转换

3.常量

  • 常量用const关键字
  • 可以定义类型,也可以不定义类型,不定义类型时常量可以当做任何类型使用

4.特殊的常量———-枚举类型

  • 普通枚举类型
  • 自增值枚举类型 iota

5.条件语句
if条件中可以赋值

6.switch语句会自动添加break语句,除非使用fallthrough,最后的默认情况使用default panic。switch中也可以没有语句,直接放到case中

7.for循环
和其他语言的区别在于省略掉小括号,同时初始条件、自增条件以及所有的条件都可以不写,这样是一个死循环

8.Go语言中只有值传递,没有引用传递,但是可以利用指针达到类似引用传递的效果

9.指针

  • 变量、指针和地址三者的关系是,每个变量都拥有地址,指针的值就是地址
  • 一个简单的例子说明:ptr := &v ,假设变量v的类型为T,则变量 v 的地址使用变量 ptr 进行接收,ptr 的类型为T,称做 T 的指针类型,*为指针
  • 取地址操作符&和取值操作符* 是一对互补操作符,&取出地址,*根据地址取出地址指向的值。
    变量、指针地址、指针变量、取地址、取值的相互关系和特性如下:
    1)对变量进行取地址操作使用&操作符,可以获得这个变量的指针变量。
    2)指针变量的值是指针地址。
    3)对指针变量进行取值操作使用*操作符,可以获得指针变量指向的原变量的值。
    * 操作符根本意义就是操作指针指向的变量。当操作在赋值操作符右值时,就是取指向变量的值,当操作在赋值操作符左值时,就是将值设置给指向的变量。

10.数组

  • 数量写在类型前面
  • 数组的遍历可以使用range返回两个参数:数组下标和对应下标的值
  • 使用下划线_可以将变量省略,不止在数组中其他所有地方都可以
  • [20]int和[30]int 是不同的类型

11.Slice
关于切片可以参考以下链接:slice入门
slice初始化的问题可以参考以下链接:slice初始化

12.Map

  • 形式为map[key] value
  • 创建
m := make(map[string] string)n := map[string] string {\"cat\" : \"wanwan\",\"dog\" : \"baibai\",\"language\" : \"Chinese\",\"country\" : \"China\",}
  • 获取value值,直接使用m[key]
  • 当map的key值不存在时,不会报错
  • 判断key是否存在时,可以用value,ok = m[key]
  • delete(key)可以直接删除对应的value
  • map的遍历使用range

13.结构体struct

  • struct的定义
type treeNode struct {value intright,left *treeNode}
  • struct的创建
var root treeNoderoot = treeNode{value : 3}root.right =&treeNode{}root.left = &treeNode{5,nil,nil}root.right.left = &treeNode{8,nil,nil}root.left.right = new(treeNode)root.right.right = createTreeNode(7)
  • go语言中没有构造函数,但是可以通过工厂函数达到类构造函数的效果
func createTreeNode(v int) *treeNode {return &treeNode{value:v}}
  • 结构体中的方法定义及使用
    func (recevier type ) methodName(参数列表)(返回值列表){}
func (node *treeNode) setValue (value int) {node.value = value}root.right.setValue(12)

注意:struct中的方法接收者的类型可以是值类型,也可以是指针类型,但是只有指针类型才会改变值。而且,在调用方法时自动做了优化处理对传入的指针和值进行处理

  • nil指针也可以调用方法,但是需要加return
  • 值接收者可以接受值/指针接收者

14.封装

  • 首字母小写:private
  • 首字母大写:public

15.包

  • 每个目录一个包
  • 结构体定义的方法必须放在一个包内,但可以是不同的文件
  • main包包含可执行入口

在练习包和封装时,出现了无法导入工程中的包,我使用的IDE是idea,在另一个文件中使用另一个包的函数时,只需要包名.方法即可使用,并且会自动import相应的包名,但是我的毫无反应,经过多次度娘寻求帮助,最后发现时GoROOT配置错误,它的配置可以具体参考如下这篇博客,很详细
Intellij IDEA创建Go工程

16.官方推荐:所有项目和第三方库都放在同一个GOPATH下
也可以将每个项目放在不同的GOPATH下
1)go get下载第三方库
2)gopm来获取无法下载的包
3)安装gopm命令:

go get github.com/gpmgo/gopm

有时候去遇到网站可以打开,但是go get一直不动的状态,还没有找到解决的办法
执行完此条命令后,会在bin目录下生成gopm.exe
4)接下来可以运行以下指令

gopm get -g -v -u golang.org/x/tools/cmd/goimports

在下载的过程中,有时会出现缺少某些包的情况,只需要在对应的路径下下载相应的包即可解决问题
5)

go build golang.org/x/tools/cmd/goimports

会在bin文件夹中生成imports的exe,go install有时不好使,只需要使用go build即可

17.Go中每个目录下面都有一个main文件,如果每个目录下有多个main函数,则无法编译成功

18.接口
Go语言中没有继承和多态,这些是通过接口来实现的
1)duck typing的概念
描述事物的外部行为而非内部结构
严格来说go属于结构化类型系统,类似duck typing
2)实现者指明不需要实现某个接口,只需要实现接口中的方法,由使用者规定必须有接口中的方法
3)接口定义

type Retriever interface {Get (source string) string}func download(r Retriever) string{return r.Get(\"http://www.imooc.com\")}

4)接口的值类型

  • 接口变量自带指针
  • 接口变量同样采用值传递,几乎不需要使用接口的指针
  • 接口变量中包含两部分:一部分为实现者的类型,另一部分为实现者的值,或者是指向实现者的指针,具体是只还是指针,视具体情况而定,在实际使用中,一定不要使用接口变量的地址,因为本身接口变量有指针
  • 指针接收者实现只能以指针方式使用,值接收者都可以
  • 任何类型表示法:
interface{}
  • 查看接口变量类型
//type switchswitch v := r.(type) {case baidu.Retriever: {fmt.Println(\"Contents:\",v.Contents)}case *real.Retriever: {fmt.Println(\"UserAgent:\",v.UserAgent)}//type assertionif realRetriever,ok := r.(*real.Retriever); ok {fmt.Println(realRetriever.UserAgent)}else {fmt.Println(\"not realRetriever\")}

-接口的组合

type Retriever interface {Get(url string) string}type Poster interface {Post(url string,form map[string] string) string}//组合接口type RetrieverPoster interface {RetrieverPoster}
  • 常用的接口
    1)Stringer(类似于java中的tostring)
type Stringer interface {String() string}

可以通过重写string方法实现Stringer接口
2)

type Reader interface {Read(p []byte) (n int, err error)}type Writer interface {Write(p []byte) (n int, err error)}

19.函数式编程

  • 函数式一等公民:参数、变量、返回值都可以是函数
  • 高阶函数:函数传入的参数是函数
  • 闭包
    对于我来说,特别难理解的闭包:网上找到一个通俗易懂的概念
    闭包就是能够读取其他函数内部变量的函数,闭包可以简单理解成“定义在一个函数内部的函数“。
    所以,在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

20.资源管理与出错处理

  • defer调用确保调用在函数结束时发生
  • 参数在defer语句时计算
  • defer列表为先进后出
    一种错误处理方式如下:
file,err := os.OpenFile(filename,os.O_EXCL|os.O_CREATE,0666)err = errors.New(\"This is a custom error\")  //自定义errorif err != nil {if pathError,ok := err.(*os.PathError); ok {fmt.Println(pathError.Err)}else {fmt.Printf(\"unkown error\",err)}}

21.panic

  • 停止当前程序执行
  • 一直向上返回,执行每一层的defer
  • 如果没有遇到recover,程序退出

22.recover

  • 仅在defer调用中使用
  • 获取panic的值
  • 如果无法处理,可重新panic

23.测试
测试的文件名可以命名为xxx_test

  • 测试代码示例
package mainimport (\"fmt\"\"math\")func calTriangle(a,b int) int {var c intc = int(math.Sqrt(float64(a*a+b*b)))return c}func triangle() {var a,b int = 3,4fmt.Println(calTriangle(a,b))}func main() {triangle()}
package mainimport (\"testing\")//测试代码,注意此处的测试代码的函数名开头必须为Testxxx,系统方可识别func TestTriangle**(t *testing.T) {tests := []struct{a,b,c int} {{3,4,5},{5,12,13},{8,15,17},{12,15,19},}for _, v:= range tests {if actual := calTriangle(v.a,v.b); actual != v.c {t.Errorf(\"calTriangle(%d,%d);\"+\"got %d; expected %d\",v.a,v.b,actual,v.c)}}}
  • 系统能够自动识别test代码,从而可以正常运行,进入该测试程序所在的目录,执行命令go test 获得测试结果
  • 测试程序也可以获得测试代码的覆盖率,如下图所示:

    通过命令行执行指令go test -coverprofile=c.out,也可以得到代码覆盖率,如下图所示:

    当然,也可以借助浏览器查看哪些被覆盖到,哪些没有被覆盖到,只需要在命令行执行以下命令:
go tool cover -html=c.out

此时,将跳转到浏览器界面,如下图所示:

  • 测试代码性能示例如下:
func BenchmarkDupStr(b *testing.B) {s := \"黑化肥挥发发灰会花飞灰化肥挥发发黑会飞花\"a := 8for i:=0;i<b.N;i++ {actual := maxLengthOfString(s)if actual != a {b.Errorf(\"got %d for input %s\" +\"expected %d\",a,s,actual)}}}

代码性能测试结果如下:

同样,通过终端输入以下命令也可以得到类似的结果

go test -bench .
赞(0) 打赏
未经允许不得转载:爱站程序员基地 » Go语言学习笔记