这篇日志主要是用来记录学习go的过程中,遇到的各种大大小小的坑以及感觉很不习惯的地方
GO非常严格!
GO中只有报错和不报错, 以前其他语言中的警告, 都被GO归类为错误, 比如申明了一个变量, 却并没有使用, 如果是C#等其他语言, 就会出现警告, 提示变量未被使用, 然后使用将申明的代码串变为灰色作为提醒, 但是也仅此而已。而GO会将这种警告直接视为错误! 会直接导致
无法运行, 抛出异常.
打印到输出
GO打印到输出使用自带的fmt包(感觉是format的缩写),
fmt.Println("你好呀")
字符串
只有双引号中的内容才是字符串, 单引号是rune类型
字符串长度
1 2 3 4 |
var t string t = "hello你好呀" fmt.Println(len(t)) |
结果是什么呢? 很明显我既然举例了, 那么结果肯定不是8, 结果是14! way???
golang中string底层是通过byte数组实现的。中文字符在unicode下占2个字节,在utf-8编码下占3个字节,而golang默认编码正好是utf-8。
那么要怎么才能获得我们期望的长度?
1 2 3 4 5 6 7 8 |
//以下两种都可以得到t的字符串长度 //golang中的unicode/utf8包提供了用utf-8获取长度的方法 fmt.Println("RuneCountInString:", utf8.RuneCountInString(t)) //通过rune类型处理unicode字符 fmt.Println("rune:", len([]rune(t))) |
GO的变量命名规则
GO推荐使用驼峰命名法, 如果你在声明变量的时候使用
var my_name string
, 则会遭到go-lint插件的友情提示:don't use underscores in Go names; var my_name should be myName
变量、方法等公有、私有权限
GO根据首字母的大小写来确定可以访问的权限。无论是方法名、常量、变量名还是结构体的名称,如果首字母大写,则可以被其他的包访问;如果首字母小写,则只能在本包中使用可以简单的理解成: 首字母大写是公有的,首字母小写是私有的文件的命名,全小写,测试的文件:xxx_test.go包名和文件夹名字最好一样
GO奇特的变量声明方式
GO在声明变量的时候, 可以使用多种方式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
var name string name = "xiaoC" fmt.Println(name) var name, nick string // 声明的变量必须为同一类型 var ( name = "" nick = "" age = 5 ) // 声明的变量可为不同类型, 根据赋予的值来确定类型 type( mytype1 string mytype2 int mytype3 bool ) // type 可以申明自定义类型 var isOk mytype3 //还有一种比较稀奇的声明变量方式 myName := "xiaoC" //等同于 var myName string myName = "xiaoC" |
GO使用Mongodb, 定义表的问题
比如使用以下代码进行表定义
1 2 3 4 5 6 7 8 |
type ProxyList struct { _id bson.ObjectId ip string //ip port int //端口 anonymity string //透明度 timeout int //延时(ms) } |
就算查出来有N条记录,但是每条记录的字段都将会是空的!定义struct时,字段名必须首字母大写,不然就会没有数据,然而_id又比较特殊, _Id是无效的, 需要使用Id bson.ObjectId `bson:"_id,omitempty"
结果如下
1 2 3 4 5 6 7 8 |
type ProxyList struct { Id bson.ObjectId <code>bson:"_id,omitempty" Ip string //ip Port int //端口 Anonymity string //透明度 Timeout int //延时(ms) } |
GO使用Mongodb findOne查询的问题
其实findOne这个东西, 我感觉蛮恶心的。“通过Query.One()可以获得一个结果,注意如果没有数据或者数量超过一个,One()会报错。” 居然多余一个记录或者没有记录就会报错?!感觉很奇怪啊...我只想要一条记录结果还需要我自己去做容错, 是不是python太宠开发者了..
最后修改代码如下
1 2 3 4 5 6 7 8 9 10 |
func FindOne(ip string, port int) *ProxyList { collection := ConnecToDB() //链接数据库的方法 result := new(ProxyList) //也可以使用 result := ProxyList{} err := collection.Find(bson.M{"ip": ip, "port": port}).Limit(1).One(&result) if err != nil { return nil } return result } |
GO要求公开方法填写备注
所有首字母大写的方法, go-line都要求填写备注, 将会提示
exported function FindOne should have comment or be unexported
, 并且备注前必须是方法名称开头, 如//FindOne 用来查询数据库中的一条数据
, 否则将会提示comment on exported function FindOne should be of the form "FindOne ..."
指针
之前一直都没有接触过指针, 今天算是接触了一下, 发现有点吊啊...
指针,或者说pointer
是一串指向某个内存地址的字符串
,所谓指向是指这串字符串的内容是内存地址的值
&表示取地址
,例如你有一个变量a那么&a就是变量a在内存中的地址,对于golang,指针也是有类型的,比如如果a是一个string那么&a是一个string的指针类型
,在go里面叫&string所以你看到b := &a,a,b是两个不同的变量,a是string类型,b是&string类型,你用fmt去打印b,你会发现它是一串内存地址,而非a的值
所以为了拿到a的值,有个操作,用来取出指针对应内存地址里存的值,所以当你fmt打印一下b它会跟a一模一样
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
package main import ( "fmt" ) type UserInfo struct { name string } func main() { user := UserInfo{} user.name = "xiaoc" fmt.Println("我现在叫", user.name) go1(user) fmt.Println("我现在叫", user.name) go2(&user) fmt.Println("我现在叫", user.name) } func go1(user UserInfo) { user.name = "xiaocc" } func go2(user *UserInfo) { user.name = "xiaocc" } //最后结果 //我现在叫 xiaoc //我现在叫 xiaoc //我现在叫 xiaocc |