IP预留部分
安装docker后无法联网
这个直接官网装就好,安装完了还有一个初次使用的教程,看着蛮贴心的,但是笑里藏刀啊!!
docker会自动加入电脑自启动项,并且装完了docker会出现计算机无法联网的情况,用电脑管家啥的是修不好的,原因出在设置了代理。
用电脑自带的“设置-网络-网络疑难解答”可以发现提示“远程计算机或设备降不接受连接”。
解决方法为“Internet选项-连接-局域网设置-取消所有的勾选框(一般是取消代理服务器)”
docker代理设置
打开docker客户端,上方的设置(齿轮按钮),RESOURCE-PROXIES,打开Manual proxy configuration,设置http代理socks5://127.0.0.1:10808/(我用的socks协议,如果是v2光线客户端课打开参数设置查看端口)
什么时候要用代理呢?比如你访问不了gcr.io。
cannot find main module; see 'go help modules'
vscode打开go文件后报错,完整报错信息为
The code in the workspace failed to compile (see the error message below). If you believe this is a mistake, please file an issue: https://github.com/golang/go/issues/new. go [-e -json -compiled=true -test=true -export=false -deps=true -find=false -- ./]: exit status 1: go: cannot find main module; see 'go help modules' : packages.Load error
原因是你使用过go env -w GO111MODULE=on命令让强制使用go.mod,而你的go文件目录中没有。
解决方法为生成一个mod文件,或者设置GO111MODULE为auto(通过user系统环境变量的方式,否则会提示does not override conflicting OS environment variable)然后重启电脑
参考https://blog.csdn.net/u011897301/article/details/105758056/
vscode里面debug Golang的launch.json配置
{ // 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。 // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "name": "Golang", "type": "go", "request": "launch", "remotePath": "", "port": 5546, "host": "127.0.0.1", "program": "${fileDirname}", "env": { "GOPATH":"c:/gowork/mygo", "GOROOT":"c:/GO", }, "args": [ "-config", "config.json" ]//这里添加的命令行参数 } ] }
GO语言入门
推荐一个文档build-web-application-with-golang
https://github.com/wbhs614/build-web-application-with-golang/blob/master/zh/preface.md
- fmt是format的缩写,fmt包提供了格式化输入输出,你可以理解为c++的iostream,导入的方式又类似于python
- package main 定义了包名,每个 Go 应用程序都包含一个名为 main 的包。
- func main() 是程序开始执行的函数,main 函数是每一个可执行程序所必须包含的
- 注释的方法和javascript完全一致,使用 //单行注释 和 /* 这是注释块 */ 的方式
- 特殊的含义:当标识符(包括常量、变量、类型、函数名、结构字段等等)以一个大写字母开头,如:Group1,那么使用这种形式的标识符的对象就可以被外部包的代码所使用(客户端程序需要先导入这个包),这被称为导出(像面向对象语言中的 public);标识符如果以小写字母开头,则对包外是不可见的,但是他们在整个包的内部是可见并且可用的(像面向对象语言中的 protected )。
- 结束了党争:完美地解决了代码中“左花括号另起一行好还是不另起一行好”的问题,因为你另起一行就会报错或者被误解!!!有一个有趣的题目,可以看一看https://www.v2ex.com/t/562318
Go 语言的断行规则定义如下:
- 在 Go 代码中,注释除外,如果一个代码行的最后一个语法词段( token )为下列所示之一,则一个分号将自动插入在此字段后(即行尾):
- 一个标识符;
- 一个整数、浮点数、虚部、码点或者字符串字面表示形式;
- 这几个跳转关键字之一:
break
、continue
、fallthrough
和return
;- 自增运算符
++
或者自减运算符--
;- 一个右括号:
)
、]
或}
。- 为了允许一条复杂语句完全显示在一个代码行中,分号可能被插入在一个右小括号)或者右大括号}之前。
switch
代码块中开大括号{前的比较表达式可以省略,其默认值为true,可以结合上面的链接中的例子来看
- GO语言在行结尾像python一样不需要打分号;,会按照上面的断行规则由编译器自动添加。但是如果你想让多句放在同一行,就需要手动打分号;
- GO语言的变量声明和赋值https://studygolang.com/articles/1275,一般:= 用于函数内变量声明,var ( [换行写多个] )用于全局变量声明
var name type 比如 var myNumber int = 10
- 如果你想要交换两个变量的值,则可以简单地使用 a, b = b, a,两个变量的类型必须是相同。
-
为什么字符串类型的 unsafe.Sizeof() 一直是16呢?
实际上字符串类型对应一个结构体,该结构体有两个域,第一个域是指向该字符串的指针,第二个域是字符串的长度,每个域占8个字节,但是并不包含指针指向的字符串的内容,这也就是为什么sizeof始终返回的是16。要看字符的个数应该用len("abc") -
iota:const声明常量中的第一个 iota 等于 0,每增加一行都会自动加 1,第几行使用的iota就等于几;https://www.runoob.com/go/go-constants.html
- 跟c++一样有++和--运算符,存在指针*和引用&,说到底GO就是因为c编译太慢了才写的
- 函数定义有点特殊,返回类型跟在参数的后面,变量的类型都是在变量后面,可以返回多个值,如func swap(num1, num2 int) (int, int) { /*函数功能*/ } ,需要改变传入变量的值,就需要接收指针*,调用函数的时候传递引用&
func function_name( [parameter list] ) [return_types] { 函数体 }
-
数组的声明与初始化:其中第二行的[5]可以省略为[...],编译器会根据后面的元素个数自动判断数组大小。访问的方法同c++,但是也有python中冒号:自动补全剩余索引的用法arr[startIndex:],arr[:endIndex]
var balance [10] float32
var balance = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}
- fmt格式化输出的%x占位符表示十六进制,可以用于输出内存地址等,关于格式化输出占位符的说明https://www.cnblogs.com/qing123/articles/4353353.html
- Golang中的空指针指向的是nil,对应c++的Null,指针内存地址为0,可以通过p == nil判断是否为空指针
- Golang中的struct结构体声明是把var变成type,比如type Books struct,在创建变量的时候还是var Book1 Books = {“”,“”}。
- 当要将结构体对象转换为 JSON 时,对象中的属性首字母必须是大写(public),才能正常转换为 JSON。那这样 JSON 字符串以后就只能是大写了么? 当然不是,可以使用 tag 标记要返回的字段名。
type Person struct{ Name string `json:"name"` //标记json名字为name Age int `json:"age"` Time int64 `json:"-"` // 标记忽略该字段 }
-
Golang中的切片也是个神奇的用法,相当于动态数组,跟数组的区别就是创建的时候为空的方括号[ ],拥有上限cap()和实际长度len(),可以被append()和copy()。
关于从数组中生成切片,因为是使用的数组中某个开始元素的指针,所以cap()取决于数组这个开始元素到结束有多少个内存位置,详见https://www.runoob.com/go/go-slice.html#div-comment-39031,而且由于使用的是指针,数组和切片的任何修改都可能互相影响(append只改变自己)。
关于切片的容量增加,首先是将新元素数量往上取偶数,加到原cap上,如果加了之后大于原cap两倍,那这就是新cap;如果加了还不够原cap的两倍,则如果原cap小于1024,新cap就是2倍原cap;如果原cap大于等于1024,新cap为原cap循环乘以1.25,直到装得下,详见https://www.runoob.com/go/go-slice.html#comment-56326
- Golang的range关键字用法:range返回的是数组(array)、切片(slice)、通道(channel)或集合(map)的索引(map对应的是key)和元素,其中索引如果用不上,可以被抛弃,比如下面的i换成关键字_。字符串也可以用range,只是出来的是字符(Unicode的值)本身
for _, num := range nums {
sum += num
}
- Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。
var countryCapitalMap map[string]string /*创建集合 */
countryCapitalMap = make(map[string]string) /*如果不初始化 map,那么就会创建一个 nil map。nil map 不能用来存放键值对 */
- 来到最为特色的一个关键字了:go,通过 go 关键字来开启 goroutine 即实现并发多线程,在使用函数的时候前面加个go。
- 多个goroutine之间传递数据使用通道chan来进行,使用前需要用make(chan xxx)关键字申明创建,使用信道传递可以避免主函数提前于子线程结束,关于多线程更多的参考https://www.runoob.com/go/go-concurrent.html
- defer 语句是Go中一个非常有用的特性,可以将一个方法延迟到包裹该方法的方法返回时执行,在实际应用中,defer语句可以充当其他语言中try…catch…的角色,也可以用来处理关闭文件句柄等收尾操作。详见https://www.jianshu.com/p/79c029c0bd58
- 字符串分割:下面的例子吧adress字符串按照冒号分为了一个数组
strings.Split(adress, ":")
golang socketio处理json参数
gosocketio "github.com/graarh/golang-socketio"https://github.com/wbhs614/build-web-application-with-golang/blob/master/zh/07.2.md
- gosocketio.Dial()返回一个通道c,在其中注册"success"方法,其中返回的数据使用空接口f interface{}接收。
-
这个时候f里面存储了一个map类型,他们的key是string,值存储在空的interface{}里
f = map[string]interface{}{ "Name": "Wednesday", "Age": 6, "Parents": []interface{}{ "Gomez", "Morticia", }, }
那么如何来访问这些数据呢?通过断言的方式:
m := f.(map[string]interface{})
通过断言之后,你就可以通过如下方式来访问里面的数据了
for k, v := range m { switch vv := v.(type) { case string: fmt.Println(k, "is string", vv) case int: fmt.Println(k, "is int", vv) case float64: fmt.Println(k,"is float64",vv) case []interface{}: fmt.Println(k, "is an array:") for i, u := range vv { fmt.Println(i, u) } default: fmt.Println(k, "is of a type I don't know how to handle") } }
通过上面的示例可以看到,通过interface{}与type assert的配合,我们就可以解析未知结构的JSON数了。
- 上面这个是官方提供的解决方案,其实很多时候我们通过类型断言,操作起来不是很方便,目前bitly公司开源了一个叫做
simplejson
的包,在处理未知结构体的JSON时相当方便
在Golang中将两个或多个[] map [string] interface {}类型合并为一个
在实际运用中遇到了gosocketio返回的是一个切片的interface
[map[one:1 two:2] map[three:3 four:4]]
生成方法见http://www.voidcn.com/article/p-vpszqmnf-bup.html
对应的解析是使用断言m1 := v.([]interface{})[0]可以取出第一个interface map,需要注意取出后类型还是interface,然后继续断言
小技巧是在用断言的时候如果类型错误会引导进panic报错,根据报错的内容可以判断此变量为什么类型的数据,这也是我自己摸索出来的,菜的坑,哎。
m := v.([]interface{})[0]//取出第一个 data := m.(map[string]interface{})//断言取出map类型的数据 adress := data["address"].(string)//map里面还是interface类型,所以需要转换string adressArray := strings.Split(adress, ":")//adress为 xx.xx.xx.xx:xxx,需要分割出ip和port fmt.Printf("IP: %s ", adressArray[0]) fmt.Printf("Port: %s ", adressArray[1]) fmt.Printf("ID: %s ", data["id"].(string)) fmt.Printf("Room ID: %s ", data["room_id"].(string)) fmt.Printf("Name: %s ", data["name"].(string))
在Go文件运行时读取命令行参数以及读写文件
参考https://www.cnblogs.com/believepd/p/10952528.html,但是更推荐把获取的操作放在init()函数中
var ( config string ) func init() { //解析命令行输入,分别为&变量,关键字,默认值,提示词 flag.StringVar(&config, "config", "config.json", "json文件路径,默认为同目录的config.json") flag.Parse() } func main() { readJson(config)//读文件 }
读写文件https://www.cnblogs.com/zengyjun/p/10218088.html