网络相关和Go语言踩坑

IP预留部分

RFC 1918 为私有网络预留出了三个IP 地址块,如下:
A 类:10.0.0.0~10.255.255.255
B 类:172.16.0.0~172.31.255.255
C 类:192.168.0.0~192.168.255.255
上述三个范围内的地址不会在因特网上被分配,因此可以不必向ISP 或注册中心申请而在公司或企业内部自由使用。

安装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 )为下列所示之一,则一个分号将自动插入在此字段后(即行尾):
    • 一个标识符;
    • 一个整数、浮点数、虚部、码点或者字符串字面表示形式;
    • 这几个跳转关键字之一:breakcontinuefallthroughreturn
    • 自增运算符++或者自减运算符--
    • 一个右括号:)]}
  • 为了允许一条复杂语句完全显示在一个代码行中,分号可能被插入在一个右小括号)或者右大括号}之前。
  • 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

原文地址:https://www.cnblogs.com/smileglaze/p/13893794.html