生活札记
golang学习笔记 - goquery、zookeeper、kafka、k8s、fyne、etcd(五)
1、goquery
goquery是一个爬虫库,可以非常方便的进行html页面分析,元素提取,类似jQuery。它基于 HTML 解析库net/html和 CSS 库cascadia,提供与 jQuery 相近的接口。Go 著名的爬虫框架colly就是基于 goquery 的。
官网:https://github.com/PuerkitoBio/goquery
教程:https://www.bilibili.com/video/BV1H3411W7h4?p=7
下载:go get -u github.com/PuerkitoBio/goquery
导入:import "github.com/PuerkitoBio/goquery"
示例代码:
// goquery测试
func Test() {
url := "https://gorm.io/zh_CN/docs/"
d, _ := goquery.NewDocument(url)
d.Find(".sidebar-link").Each(func(i int, s *goquery.Selection) {
// text
// fmt.Println(i)
fmt.Printf("Text:%v\n", s.Text())
// href
href, _ := s.Attr("href")
fmt.Printf("herf:%v\n", href)
// base_url
base_url := url + href
fmt.Printf("base_url:%v\n", base_url)
// 获取新的内容页面
d2, _ := goquery.NewDocument(base_url)
// 标题
fmt.Printf("标题:%v\n", d2.Find(".article-title").Text())
// 内容
content, _ := d2.Find(".article-content").Html()
fmt.Printf("内容:%v\n", content)
})
}
// 通过请求响应创建Document
func GoqueryResponse() {
url := "https://gorm.io/zh_CN/docs/"
// 请求
req, _ := http.NewRequest(http.MethodGet, url, nil)
// 客户端发起请求
client := &http.Client{}
res, _ := client.Do(req)
// 创建文档
d, _ := goquery.NewDocumentFromResponse(res)
d.Find(".sidebar-link").Each(func(i int, s *goquery.Selection) {
// text
// fmt.Println(i)
fmt.Printf("Text:%v\n", s.Text())
// href
href, _ := s.Attr("href")
fmt.Printf("herf:%v\n", href)
})
}
// 通过html字符串创建Document
func GoqueryReader() {
// html字符串
html := `<html><div>111</div><div>222</div></html>`
// 创建文档
d, _ := goquery.NewDocumentFromReader(strings.NewReader(html))
d.Find("div").Each(func(i int, s *goquery.Selection) {
// text
// fmt.Println(i)
fmt.Printf("Text:%v\n", s.Text())
})
}
// 选择器,类型jQuery的选择器
func GoquerySelection() {
// html字符串
html := `<html>
<div id="id1">111</div>
<div class="id2">222</div>
<span aaa="bbb">3333</span>
</html>`
// 创建文档
d, _ := goquery.NewDocumentFromReader(strings.NewReader(html))
d.Find("#id1").Each(func(i int, s *goquery.Selection) {
// text
// fmt.Println(i)
fmt.Printf("Text:%v\n", s.Text())
})
// 1、函数位置操作
Eq(index int) *Selection //根据索引获取某个节点集
First() *Selection //获取第一个子节点集
Last() *Selection //获取最后一个子节点集
Next() *Selection //获取下一个兄弟节点集
NextAll() *Selection //获取后面所有兄弟节点集
Prev() *Selection //前一个节点兄弟元素
Get(index int) *html.Node //根据索引获取一个节点
Index() int //返回选择对象中第一个元素的位置
Slice(start, end int) *Selection //根据起始位置获取子节点集
// 2、循环遍历选择节点
Each(f func(int, *Selection)) *Selection //遍历
EachWithBreak(f func(int, *Selection) bool) *Selection //可中断遍历
Map(f func(int, *Selection) string) (result []string) //返回字符串数组
// 3、检测或获取节点属性
Attr()、RemoveAttr()、SetAttr() //获取、移除、设定属性值
AddClass()、HasClass()、RemoveClass()、ToggleClass() //添加、判断是否存在、移除、切换class
Html() //获取节点HTML
Text() //获取节点文本
Length() //获取节点的Selection数量
// 4、查找节点方法
Children() //返回Selection节点下的所有子节点
Contents() //获取当前节点下的所有节点
Find() //查找当前匹配的元素
Prev() //上一个元素
Next() //下一个元素
}
2、gocolly
Colly 是一个采用 Go 语言编写的 Web 爬虫框架,旨在提供一个能够写任何爬虫/采集器/蜘蛛的简洁模板。通过 Colly ,你可以轻松从网站中提取结构化的数据,然后进行数据挖掘、处理或归档。
项目特性
清晰明了的 API
速度快(单个内核上的请求数大于1k)
管理每个域的请求延迟和最大并发数
自动 cookie 和会话处理
同步/异步/并行抓取
高速缓存
自动处理非 Unicode 编码
支持 Robots.txt
支持 Google App Engine
通过环境变量配置
可扩展
官网:https://github.com/gocolly/colly
教程:https://www.bilibili.com/video/BV1H3411W7h4?p=12
下载:go get -u github.com/gocolly/colly
导入:import "github.com/gocolly/colly"
示例代码:
// 测试Colly
func TestColly() {
// url
url := "https://gorm.io/zh_CN/docs/"
// 创建colly
c := colly.NewCollector()
// 抓取到对应HTML就调用
c.OnHTML(".sidebar-link", func(e *colly.HTMLElement) {
// fmt.Printf("colly.HTMLElement:%v\n", e.Attr("href"))
e.Request.Visit(e.Attr("href"))
})
// 请求就执行
c.OnRequest(func(r *colly.Request) {
// fmt.Printf("请求了:%#v\n", r)
fmt.Printf("URL:%v\n", r.URL)
fmt.Printf("长度:%v\n", r.Depth)
})
// 访问
c.Visit(url)
}
// colly回调方法
func TestCollyCallBack() {
// url
url := "https://gorm.io/zh_CN/docs/"
// 创建colly
c := colly.NewCollector()
// 设置UserAgent
c.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36"
// 设置cookie方式1
c.OnRequest(func(r *colly.Request) {
r.Headers.Add("cookie", "_ga=GA1.2.1327397407.1654479750; _gid=GA1.2.1930832040.1658133030; __atuvc=0%7C25%2C5%7C26%2C0%7C27%2C6%7C28%2C6%7C29")
})
// 设置cookie方式2
cookie := c.Cookies("url")
fmt.Println("cookie:", cookie)
c.SetCookies("", cookie)
// 1.OnRequest
// 在请求之前调用
c.OnRequest(func(r *colly.Request) {
fmt.Println("请求之前调用:OnRequest")
})
// 2.OnError
// 在请求期间发生错误时调用
c.OnError(func(r *colly.Response, err error) {
fmt.Println("发生错误时调用:OnError")
})
// 3.OnResponseHeaders
// 在收到响应标头后调用
// c.OnResponseHeaders(func(r *colly.Response) {
// })
// 4.OnResponse
// 收到响应后调用
c.OnResponse(func(r *colly.Response) {
fmt.Println("收到响应后调用:OnResponse")
})
// 5.OnHTML
// OnResponse如果接收到的内容是 HTML ,则立即调用
c.OnHTML("a[href]", func(e *colly.HTMLElement) {
fmt.Println("OnResponse如果接收到的内容是 HTML:OnHTML")
})
// 6.OnXML
// OnHTML如果接收到的内容是 HTML 或 XML ,则立即调
c.OnXML("//h1", func(e *colly.XMLElement) {
fmt.Println("OnHTML如果接收到的内容是 HTML 或 XML:OnXML")
})
// 7.OnScraped
// 抓取完成后调用
c.OnScraped(func(r *colly.Response) {
fmt.Println("抓取完成后调用:OnScraped")
})
// 访问
c.Visit(url)
}
// colly案例
func TestCollyDemo() {
// url
url := "https://gorm.io/zh_CN/docs/"
// 创建colly
c := colly.NewCollector()
// HTML
c.OnHTML(".sidebar-link", func(e *colly.HTMLElement) {
// fmt.Printf("href: %v\n", e.Attr("href"))
href := e.Attr("href")
if href != "index.html" {
e.Request.Visit(e.Request.AbsoluteURL(href))
}
})
// HTML
c.OnHTML(".article-title", func(e *colly.HTMLElement) {
fmt.Printf("Title: %v\n", e.Name) //h1
fmt.Printf("Title: %v\n", e.Text) //标题
})
// HTML
c.OnHTML(".article-content", func(e *colly.HTMLElement) {
html, _ := e.DOM.Html()
fmt.Printf("Title: %v\n", html)
})
// 请求时触发
c.OnRequest(func(r *colly.Request) {
fmt.Printf("请求:%v\n", r.URL)
})
// 访问
c.Visit(url)
}
3、zookeeper:https://zookeeper.apache.org/
zookeeper是apache开源的,使用java开发的,分布式的服务配置管理系统。主要功能是:存储数据、动态监听;依赖zookeeper的软件:HBase、Spark、Flink、Storm、Kafka、Dubbo
zookeeper的存储结构:目录树结构,类似linux文件系统,key - value 方式存储
教程:https://www.bilibili.com/video/av550142391
下载地址:https://dlcdn.apache.org/zookeeper/
JAVA环境:https://www.oracle.com/java/technologies/javase/javase8-archive-downloads.html
1)、安装java环境
解压:tar -zxvf jdk-8u202-linux-i586.tar.gz -C /java
配置:vim /etc/.bashrc 或者 vim $HOME/.bashrc
#java
export JAVA_HOME=/java/jdk1.8.0_202
export PATH=$PATH:$JAVA_HOME/bin
配置完成重新加载文件:source /etc/.bashrc 或者 source $HOME/.bashrc
查看java版本:java -version
[root@CopyLian ~]# java -version
java version "1.8.0_202"
Java(TM) SE Runtime Environment (build 1.8.0_202-b08)
Java HotSpot(TM) Client VM (build 25.202-b08, mixed mode)
2)、安装zookeeper
下载:wget --no-check-certificate https://dlcdn.apache.org/zookeeper/zookeeper-3.8.0/apache-zookeeper-3.8.0-bin.tar.gz
解压:tar -zxvf apache-zookeeper-3.8.0-bin.tar.gz -C /java
配置:
cd /java/apache-zookeeper-3.8.0-bin/conf
mv zoo_sample.cfg zoo.cfg
启动服务端:
cd /java/apache-zookeeper-3.8.0-bin/bin
./zkServer.sh start
启动失败报错:Starting zookeeper ... FAILED TO START,版本:3.6.1,实际上只要 >= 3.5.5 版本都会出现这种问题,需要下载bin版本。可能是版本问题参考:
http://www.javashuo.com/article/p-rpfyqsnr-tp.html
https://www.freesion.com/article/88151361202/
启动客户端链接服务器:
./zkCli.sh #连接本地的zookeeper服务器
./zkCli.sh -server ip:port #连接指定的服务器
3)、基础命令:
列出znode:
ls -R /
ls /
创建znode:
create [-s] [-e] path data acl
-s:创建的是带序列号的节点,序列号用0填充节点路径
-e:创建的是临时节点。
path:znode的路径,ZooKeeper中没有相对路径,所有路径都必须以 '/' 开头
data:znode携带的数据
acl:这个节点的ACL
create /site abc
create /site/course go
create -s /site/lang go
获取znode、节点状态:
get /site
get /site/lang
stat /site
设置znode:
set /site/course php
删除znode:
delete /site/course
delete /site
history和redo:
history:列出历史命令
redo:根据历史命编号令调用命令
connect和close:
connect:用于连接其他ZooKeeper服务器
close:关闭当前连接
quit:退出
4)、zoo.cnf配置文件:
tickTime:client与server通信的心跳时间(ms)
initLimit:集群中从服务与主服务器之间初始连接时最多的心跳数(tickTime的数量)
syncLimit:集群中从服务与主服务器之间请求和应答的最多心跳数(tickTime的数量)
dataDir:数据存储目录
clientPort:客户端连接端口号,默认2181
服务器名称与地址:
规则:server.N=YYY:A:B
N:N是一个数字,代表这个服务器的编号;
YYY:服务器的IP地址;
A:ZooKeeper服务器之间的通信端口;
B:Leader选举的端口
示例:
server.1=139.196.86.20:2888:3888
server.2=139.196.86.21:2888:3888
server.3=139.196.86.22:2888:3888
maxClientCnxns:最大的客户端连接数,默认60
autopurge:日志清理
autopurge.snapRetainCount:保留多少个snapshot
autopurge.purgeInterval:设置多少小时清理一次
5)、权限控制:
ip模式:基于ip白名单的方式指定某个服务器具体哪些权限
digest模式:基于用户名密码方式指定某个人的权限
权限:在ZooKeeper中,有create(c)、delete(d)、read(r)、write(w) 和 admin(a) 这五种权限类型
create -s -e /test test01_data ip:192.168.100.100:crwda
create -s -e /test/test02 test02_data digest:jufengya:password:crwda
setquota -n | -b val path:给节点分配配额
n:可选,表示子节点的最大个数
b:可选,表示数据值的最大长度
val:子节点最大个数或者数据值的最大长度
path:节点路径
6)、集群配置:
配置:vim zoo.cnf
server.1=139.196.86.20:2888:3888
server.2=139.196.86.21:2888:3888
server.3=139.196.86.22:2888:3888
在/var/ookeeper 先新增myid,写入对应ID,重启 ./zkServer.sh,服务器会自动进行CAP选举,选出Leader那台服务器,其他作为follower
7)、go操作ZooKeeper:
下载:go get github.com/samuel/go-zookeeper
加载:import "github.com/samuel/go-zookeeper/zk"
代码:
// go 操作ZooKeeper
func GetConn() *zk.Conn {
// ip
hosts := []string{"139.196.86.20:2181"}
// 连接
conn, _, err := zk.Connect(hosts, time.Second*5)
// 关闭
// defer conn.Close()
// 处理错误
if err != nil {
fmt.Println(err)
return nil
}
fmt.Println("连接成功")
return conn
}
// 创建
func Create() {
// 连接zk
conn := GetConn()
// 关闭zk
defer conn.Close()
// 定义数据
path := "/home2"
data := []byte("飓风呀")
// flags值:
// 0-永久,除非手动删除;
// 1(zk.FlagEphemeral)-短暂,session断开则该节点也删除
// 2(zk.FlagSequence)-会自动在节点后面增加序号
// 3-FlagEphemeral和FlagSequence,短暂且自动增加序号
var flags int32 = 0
// 控制访问权限模式
acls := zk.WorldACL(zk.PermAll)
// 创建
s, err := conn.Create(path, data, flags, acls)
if err != nil {
fmt.Println(err)
return
}
fmt.Printf("s: %v\n", s)
// 获取
b, s2, _ := conn.Get(path)
fmt.Printf("b: %v\n", string(b))
fmt.Printf("s2: %#v\n", s2)
}
// 设置
func Set() {
// 连接zk
conn := GetConn()
// 关闭zk
defer conn.Close()
// 定义数据
path := "/home1"
data := []byte("飓风呀111")
// 设置
s, err := conn.Set(path, data, -1) // 第三个参数是版本
if err != nil {
fmt.Println(err)
return
}
fmt.Println(s)
// 获取
b, s2, _ := conn.Get(path)
fmt.Printf("b: %v\n", string(b))
fmt.Printf("s2: %#v\n", s2)
}
// 删除
func Delete() {
// 连接zk
conn := GetConn()
// 关闭zk
defer conn.Close()
// 定义数据
path := "/home1"
// 删除
err := conn.Delete(path, -1)
if err != nil {
fmt.Println("删除失败")
} else {
fmt.Println("删除成功")
}
// 获取
b, s2, _ := conn.Get(path)
fmt.Printf("b: %v\n", string(b))
fmt.Printf("s2: %#v\n", s2)
}
// 监听回调
func WatchCallBack(event zk.Event) {
fmt.Println("******************")
fmt.Println("path:", event.Path)
fmt.Println("type:", event.Type.String())
fmt.Println("state:", event.State.String())
fmt.Println("************************************")
}
// 监听
func Watch() {
// ip
hosts := []string{"139.196.86.20:2181"}
// 参数
option := zk.WithEventCallback(WatchCallBack)
// 连接
conn, _, err := zk.Connect(hosts, time.Second*5, option)
defer conn.Close()
if err != nil {
fmt.Println(err)
return
}
fmt.Println("连接成功")
// 获取
path := "/home2"
b, s2, _ := conn.Get(path)
fmt.Printf("b: %v\n", string(b))
fmt.Printf("s2: %#v\n", s2)
}
8)、zookeeper管理工具:
使用参考:https://www.jb51.net/article/190648.htm
java环境:https://www.oracle.com/java/technologies/downloads/#java8-windows
zookeeper管理工具:https://issues.apache.org/jira/secure/attachment/12436620/ZooInspector.zip
启动管理工具:java -jar zookeeper-dev-ZooInspector.jar & # 其中 zookeeper-dev-ZooInspector.jar 是目录下 D:\Program Files\ZooInspector\build 的文件
9)、使用JMX监控zookeeper:
简介:JMX(Java Management Extensions,即Java管理扩展)是一个为应用程序、设备、系统等植入管理功能的框架。JMX可以跨越一系列异构操作系统平台、系统体系结构和网络传输协议,灵活的开发无缝集成的系统、网络和服务管理应用。
配置:conf 目录下新建 zookeeper-env.sh
JMXLOCALONLY=false
JMXDISABLE=false
JMXPORT=4048
JMXAUTH=false
JMXSSL=false
重启zkServer:
./zkServer.sh stop
./zkServer.sh start
ZooKeeper JMX enabled by default
ZooKeeper remote JMX Port set to 4048
ZooKeeper remote JMX authenticate set to false
ZooKeeper remote JMX ssl set to false
ZooKeeper remote JMX log4j set to true
Using config: /java/apache-zookeeper-3.8.0-bin/bin/../conf/zoo.cfg
Starting zookeeper ... FAILED TO START #这里启动失败了应该是4048端口的原因,具体暂时也找不到解决方案
打开jconsole.exe:C:\Program Files\Java\jdk1.8.0_341\bin\jconsole.exe
4、kafka消息中间件:消息中间件是基于队列与消息传递技术,在网络环境中为应用系统提供同步或异步、可靠的消息传输的支撑性软件系统。
教程:https://www.bilibili.com/video/BV1US4y1f78X
1)、概念:
应用场景:异步处理、流量削峰、应用解耦、日志处理、分布式事务
常用协议:JMS协议(java消息服务)、AMQP协议(高级队列协议:https://www.amqp.org/)、MQTT协议(消息队列遥测传输,IBM开发的即时通信协议)、STOMP协议(流文本定向消息协议)、XMPP协议(可扩展消息现场处理协议)、TCP/IP协议
常见中间件:RabbitMQ(基于AMQP:https://rabbitmq.com/)、RocketMQ(阿里参考kafka开发:https://rocketmq.apache.org/)、ActiveMQ(Apache开发)、Kafka(分布式消息发布订阅系统:https://kafka.apache.org/)
中间件模式:点对点模式(p2p)、发布订阅模式
Kafka概念:生产者Producer、消费者Consumer、主题Topic、分区Partition、偏移量Offset
2)、安装:https://blog.51cto.com/u_15127581/4257661
Java、ZooKeeper安装:参考ZooKeeper那节
下载:不要下载带src的版本,否则会报错:Classpath is empty. Please build the project first e.g. by running './gradlew jar -PscalaVersion=2.13.6'
直接下载:https://dlcdn.apache.org/kafka/3.2.0/kafka_2.13-3.2.0.tgz
Linux下载:wget --no-check-certificate https://dlcdn.apache.org/kafka/3.2.0/kafka_2.13-3.2.0.tgz
解压:tar -zvxf kafka_2.13-3.2.0.tgz -C /java
配置:vim /java/kafka_2.13-3.2.0/config/server.properties
broker.id=1 #配置的是集群环境,要求每台kafka都有唯一的brokerid
log.dirs=/var/kafka-logs #数据存放的目录
listeners=PLATNTEXT://localhost:9092
zookeeper.connect=localhost2181 #zookeeper连接池地址信息
delete.topic.enable=true #是否直接删除topic
host.name=localhost #主机名称
启动:./kafka-server-start.sh ../config/server.properties 或者守护方式:./kafka-server-start.sh -daemon ../config/server.properties
1)、报错:Java HotSpot(TM) Server VM warning: INFO: os::commit_memory(0xa6c00000, 1073741824, 0) failed; error 内存不足
打开kafka安装位置,在bin目录下找到kafka-server-start.sh文件,将
export KAFKA_HEAP_OPTS="-Xmx1G -Xms1G"修改为
export KAFKA_HEAP_OPTS="-Xmx256M -Xms128M"。
查看kafka进程: ps -ef | grep kafka
3)、kafka可视化管理工具:
1、CNAK:https://github.com/yahoo/CMAK/releases
下载:https://github.com/yahoo/CMAK/releases/download/3.0.0.6/cmak-3.0.0.6.zip
2、kafkatool:https://kafkatool.com/
死活连不上。。。。。。
4)、使用eagle监控kafka:http://download.kafka-eagle.org/
5)、kafka生产者客户端:
go get github.com/Shopify/sarama
6)、kafka消费者客户端:
go get github.com/bsm/sarama-cluster
N、其他补充:https://golang-tech-stack.com/tutorial/topic/golang-unit-testing
1)、单元测试
import "testing"
2)、错误处理
errors.New()
3)、正则表达式
go doc regexp/syntax
4)、反射
go doc reflect Type
go doc reflect Value
5)、验证码
go get github.com/dchest/captcha
6)、日期处理库Carbon:https://github.com/golang-module/carbon
go get -u github.com/golang-module/carbon/v2
7)、发送邮件库email
go get -u github.com/jordan-wright/email
8)、加密和解密应用
import golang.org/x/crypto/bcrypt
9)、访问权限控制框架casbin:是一个强大的、高效的开源访问控制框架,其权限管理机制支持多种访问控制模型。支持的语言也很多,例如:go、java、node.js、python等等.
go get -u github.com/casbin/casbin
go get -u github.com/casbin/gorm-adapter
10)、使用swagger生成api接口文档
go get -u github.com/swaggo/swag/cmd/swag
11)、go jwt跨域鉴权:全称JSON Web Token是一种跨域认证解决方案,属于一个开放的标准,它规定了一种Token实现方式,目前多用于前后端分离项目和OAuth2.0业务场景下。
参考:https://www.bilibili.com/video/BV14p4y1x7kF
go get -u github.com/dgrijalva/jwt-go
12)、配置管理库viper:是一个golang配置管理库,很多项目都使用viper来构建,例如:docker、Hugo等等
go get -u github.com/spf13/viper
13)、gin nginx Centos部署:go交叉编译,window改为Linux
$env:GOOS="linux"
$env:GOARCH="amd64"
14)、Golang 1.18新特性工作区workspace,解决大型项目子项目依赖问题
go work init .\common\
go work use .\project\
生成go.work文件:
go 1.18
use (
.\project\
.\common\
)
15)、Golang 1.18新特性泛型,让编程更简单,功能更强大:泛型的英文是Generics,就是函数的参数,或者容器元素的类型,支持更广泛的类型,不再是特定的类型。
版本要求:使用泛型必须要求golang版本1.18以上
// 泛型
func Addany[T int | float64](a, b T) T {
return a + b
}
// 泛型map:comparable - 可比较类型,V - 整型或者浮点型
func SumIntOrFloats[K comparable, V int | float64](m map[K][V]) V {
var s V
for _, v := range m {
s += v
}
return s
}
// 约束:any - interface{}任何类型,Interger - int类型,Float - 所有float类型,comparable - 可以比较的类型
// 泛型切片
func ArrayAny(){
// 切片
type Vector[T any] []T
type NumSlice[T int | float64] []T
// map
type MapType[K string, V any] map[K]V
// chan
type ChanType[T any] chan T
// 示例
v := Vector[string]{"a", "b", "c"}
m := MapType[string, int]{
"a":1,
"b":2,
}
ct := make(ChanType[int], 1)
}
16)、类型转换工具库cast:cast可以在 Go 中轻松安全地从一种类型转换为另一种类型,Cast 提供了简单的函数来轻松地将数字转换为字符串,将接口转换为布尔值等。当需要显示类型转换时,Cast 会智能地执行转换操作。
go get github.com/spf13/cast
17)、web项目热部署air库:代码热更新
go install github.com/cosmtrek/air@latest
安装之后GOPATH下的bin目录会生成air.exe文件,必须保证bin目录添加到了环境变量
执行:air 命令可实时更新代码调试
执行:air init 命令会生成 .air.toml 配置文件
18)、标准命令行工具(go build 跨平台编译、交叉编译、go clean、go run、go fmt、go install、go get、go vet)
参考资料&教程
1、go get 快速导入GitHub中的包:https://www.jianshu.com/p/16aceb6369b6
2、goland编写go语言导入自定义包出现: package xxx is not in GOROOT (/xxx/xxx) 的解决方案:https://blog.csdn.net/qq_27184497/article/details/122160400
3、Vscode中Golang引入自定义包报错 package xxx is not in GOROOT:https://blog.csdn.net/qq_40209780/article/details/123133467
4、GO111MODULE的设置(及GOPROXY):https://www.cnblogs.com/pu369/p/12068645.html
5、关于go反射中的NumMethod方法的一点发现:https://www.bilibili.com/read/cv8985976/
6、VS Code 安装go插件失败分析及解决方案:https://blog.csdn.net/qq_36564503/article/details/124509832
7、VSCode: Could not import Golang package:https://stackoverflow.com/questions/58518588/vscode-could-not-import-golang-package
8、vscode 远程开发 go 提示 You are outside of a module and outside of $GOPATH/src:https://www.jianshu.com/p/089efae0bdd3
基础教程:
视频1:https://www.bilibili.com/video/BV1gf4y1r79E
笔记1:https://www.yuque.com/aceld/mo95lb/zwukev
视频2:https://www.bilibili.com/video/BV1s341147US
笔记2:https://www.bilibili.com/read/readlist/rl496566
教程:https://www.bilibili.com/video/BV1hv411x7we
进阶教程:
文明上网理性发言!
已完结!