Go语言入门笔记

参照https://www.bilibili.com/video/BV1gf4y1r79E做的笔记

包定义

package mainmain函数所在的包, 定义为main包

方法定义

func关键字, 花括号左边和func要在同一行

func main () {
}

有返回值, 参数值的

func function(a int, b string) (int,string){
}

函数名大写 可供外部包调用,小写则只能在本包内调用

声明变量

var a int
var a int =100
var a = 100
var a, b = 100, "abc"

//以上可以声明全局变量

a:=100

常量定义 枚举定义

var改成const

const(
    BEIJING = iota * 10 //每行iota依次累加1, 第一行iota默认值0
    SHANGHAI //省略后, 会重复上一行
    NANJING
)

导包与路径

递归导包
20220915180127

导包会执行包的func init(){}函数

导包时, go从goroot开始搜索路径, 也就是go的安装目录, 以后会用模块化管理, 进行go库的管理

导包时可指定别名, 此时即使包在后续没有被调用, 也可以编译成功

import lib "mylib/lib"

别名为.时, 表示直接导入当前包

defer

defer修饰的语句会在当前代码块最后运行–不论其写在代码块中的哪个地方
例如打开文件后, 紧跟defer关闭文件, 很方便
多个defer满足栈的调用顺序, 即先进后出
defer后的语句甚至会在return后的语句运行之后, 再运行

循环

for i:=0; i<10; i++ {}
for index, value := myArray {}

数组

var a [10] int
b:=[10]int{1,2,3,4}
数组作为函数参数时, 必须长度也一致, 但这里全是数据拷贝
只希望有一个副本, 则需要使用指针/动态数组

动态数组(切片)

array:=[]{1,2,3,4}
此时用函数传参, 传的是同一个对象引用

需要为动态数组开辟空间, 使用make

slice := make([]int, 3)//:=可以让编译器推测出slice是一个切片, 不用事先var定义

除了指定大小, 还可以指定容量

slice := make([]int, 3, 6)
cap(slice) == 6

存在尾指针:
20220916131450

使用append追加元素:

slice = append(slice, 1)

append超过容量, 则会新开辟之前cap空间一倍的新空间追加在尾指针后

slice支持和python一致的切片截取功能, 其中截取使用的是对原切片的引用

sliceSub = slice[0:2] //从0到下标2的前一个元素截取出来
copy(sliceCopy, slice) //copy函数深拷贝

map

中括号内是key的数据类型, 外面是value的数据类型,
虽然也会动态增加空间, 但需要在使用前先开辟依次空间

myMap := map[string]string
myMap = make(map[string]string, 10)
//当然也可以直接填充
myMap := map[string]string{
    "1":"a",
    "2":"b"
}
delete(myMap,"1")

在函数形参中以引用导入

type

基本同C中的type of

type myInt int

定义一个结构体

type Book struct{
    title string
    auth string
}

func main(){
    var book Book
    book.title = "cake"
}

直接在函数形参列表中传入的是对象的副本

func function(Book book){

}

通过添加*符号, 可以传入指针, 当然调用时也需要指定是传入地址

func function(Book *book){
}

func main(){
    function(&book)
}

面向对象->将结构体转化为类

绑定类方法

func (this Book) PrintBookInfo(){
    fmt.Println("%v", this)
}
func (this Book) SetBookTitle(newName string){
    this.title = newName
}

注意this是调用的对象的一个拷贝
比较好的是换成this*
可以将this*替换别名t*
类的构造(结构体的成员变量的初始化)

book:=Book{title:"cake", auth:"cakecn"}

函数指针

book:=Book{title:"cake", auth:"cakecn"}
tempfunciton:=book.PrintBookInfo
tempfunction()
//等同于
book.PrintBookInfo()

访问权限

同包内函数一样, 类名首字母大写, 说明其他包可访问, 小写则为private
成员变量, 方法也一样
封装主要在的层面

继承

type NiceBook struct{
    Book
    readersNum int
}
func (t* NiceBook) AddReader(){
    t.readersNum++
}

子类的构造, 需要写出父类才能定义父类的成员

func main(){
    niceBook:=NiceBook{Book{"cake","cakecn"}, 0}
}

接口/抽象类 interface

type Animal interface{
    Sleep()
    GetColor() string
    GetType() string
}

对这个接口的实现, 无需像刚刚继承一个类一样, 在类定义里写出来
只需要实现同签名的函数, 那么这个接口指针就可以指向这个实现的类

type Cat struct{
    name string
    color string
}
func (t* Cat) Sleep(){
}
func (t* Cat) GetColor()string{
}
func (t* Cat) GetType()string{
}
func main(){
    c:=Cat("Ketty", "white")
    var animalPtr Animal
    animalPtr = &c
    animalPtr.Sleep()
}

interface{} 与 数据类型断言

interface{}可以作为一种通用万能指针, 类似于C中的void*, 可以用来引用任意的数据对象
所有的数据类型都实现interface{}类型

断言就是将interface{}类型转化为实际的类型,
若interface{}指针指向的数据实际就是断言的类型,
那么ok为true, value就是实际类型的数据

value, ok := a.(string)//a是一个interface{}

在函数形参传递interface{}时, 内部可以对实参类型进行断言校验

func interfaceFunction(t interface{}){
switch t := t.(type) {
    default:
        fmt.Printf("unexpected type %T", t)       // %T prints whatever type t has
    case bool:
        fmt.Printf("boolean %t\n", t)             // t has type bool
    case int:
        fmt.Printf("integer %d\n", t)             // t has type int
    case *bool:
        fmt.Printf("pointer to boolean %t\n", *t) // t has type *bool
    case *int:
        fmt.Printf("pointer to integer %d\n", *t) // t has type *int
}
}

变量内部的pair 和 反射

变量构造的时候有一个typevalue的指针对,
其中type有两种可能, 一是指向基本数据类型的static type, int, string之类的
二是指向interface{}所指向的具体数据类型, 运行时类型concrete type
20220917201857

而通过反射机制, 我们可以得到变量的concrete type或者是value中的值

package main

import (
	"fmt"
	"reflect"
)

func main() {
	s := "hello"
	fmt.Println("type of s : ", reflect.TypeOf(s))
	fmt.Println("value of s : ", reflect.ValueOf(s))
}

两个指针能否互相断言, 其核心在于两者的type指针是否一致

结构体标签

可以给结构体的成员变量添加标签, 类似一种可以在代码运行中做判断的高级注释
如下通过在结构体的成员变量后面添加"``"飘号对, 对其添加标签

type Book struct{
    Name string `info:"name of a book" doc:"should be read-only access"`
    Price int `info:"price of a book"`
}

通过反射机制可以获取到变量的标签

type Book struct {
	Name  string `info:"name of a book" doc:"should be read-only access"`
	Price int    `info:"price of a book"`
}

func main() {
	var virtualbook interface{}
	virtualbook = Book{"CPP入土", 10}

	tags := reflect.TypeOf(virtualbook)
	for i := 0; i < tags.NumField(); i++ {
		info := tags.Field(i).Tag.Get("info")
		fmt.Println("info: ", info)
	}
}

标签在json中运用

使用encoding/json库, 对结构体进行序列化时, 在标签中添加json:"name"等语法, 就可以实现在json序列自定义键值对的键

jsonStr, err := json.Marshal(book)
book1 := Book{}
err = json.Unmarshal(jsonStr, &book1)

协程

语言支持 https://www.bilibili.com/video/BV1gf4y1r79E?p=26
Go语言开启一个协程只用一个go关键字即可:

func newTask(routineName string) {
	i := 0
	for {
		i++
		fmt.Printf("%s : i = %d\n", routineName, i)
		time.Sleep(1 * time.Second)
	}
}

func main() {
	go newTask("goRoutine")
	time.Sleep(time.Second / 2)
	newTask("mainRoutine")
}

如果用runtime.Goexit()会直接结束当前的整个协程. 与return类似defer修饰的语句依然会最后按顺序运行一次

协程之间通信 channel

使用make创建channel

make(chan Type, capacity = 0)//指定Type数据类型, 和capacity为缓冲大小

channel <- value //写入管道
<- channel       //弹出
x := <- channel  //弹出并读取
x, ok := <- channel

channel具有同步功能, 读取的协程, 在管道还打开着的情况下, 会阻塞住直到能从管道中读取到数据
同样, 写入的协程也会阻塞住直到成功写入(除非缓冲区不为空)

关闭管道, 及时关闭管道可以防止持续等待导致死锁

close(channel)

关闭管道, 依然可以从中读取数据

一种简写, 可以方便的实现一个阻塞接收器:

for data := range c {
}

select 监听多个channel(读写均可)

select {
    case x <- chan1:

    case chan2 <-1:

    default
}

使用gomodules管理模块

几个比较重要的环境变量
GO111MODULE是否开启gomodules, 推荐开启

GOPROXY设置下载模块的代理网站
go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/,direct
其中direct表示如果代理网站找不到就去github源找

GOPRIVATE
如果从一个私有仓库拉取
go env -w GOPRIVATE="*.example.com, github.com/cakecn/privateRepository"

使用GoModules初始化项目

  1. go env -w GO111MODULE=on
  2. 在想要的文件夹下go mod init myTestModules/test1 创建go.mod文件, 说明这个项目名称
  3. 手动下载三方模块(默认最新) go get github.com/C/D
    三方模块会放在$GOPATH/src下
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值