GO 使用记录以及遇到的各种坑

这篇日志主要是用来记录学习go的过程中,遇到的各种大大小小的坑以及感觉很不习惯的地方

GO非常严格!

GO中只有报错和不报错, 以前其他语言中的警告, 都被GO归类为错误, 比如申明了一个变量, 却并没有使用, 如果是C#等其他语言, 就会出现警告, 提示变量未被使用, 然后使用将申明的代码串变为灰色作为提醒, 但是也仅此而已。而GO会将这种警告直接视为错误! 会直接导致无法运行, 抛出异常.

打印到输出

GO打印到输出使用自带的fmt包(感觉是format的缩写), fmt.Println("你好呀")

字符串

只有双引号中的内容才是字符串, 单引号是rune类型

字符串长度

    var t string
    t = "hello你好呀"
    fmt.Println(len(t))

结果是什么呢? 很明显我既然举例了, 那么结果肯定不是8, 结果是14! way???

golang中string底层是通过byte数组实现的。中文字符在unicode下占2个字节,在utf-8编码下占3个字节,而golang默认编码正好是utf-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在声明变量的时候, 可以使用多种方式

    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, 定义表的问题

比如使用以下代码进行表定义

    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" 结果如下

    type ProxyList struct {
        Id        bson.ObjectId `bson:"_id,omitempty"`
        Ip        string        //ip
        Port      int           //端口
        Anonymity string        //透明度
        Timeout   int           //延时(ms)
    }

GO使用Mongodb findOne查询的问题

其实findOne这个东西, 我感觉蛮恶心的。“通过Query.One()可以获得一个结果,注意如果没有数据或者数量超过一个,One()会报错。” 居然多余一个记录或者没有记录就会报错?!感觉很奇怪啊…我只想要一条记录结果还需要我自己去做容错, 是不是python太宠开发者了..

最后修改代码如下

    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一模一样

    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

发表评论

电子邮件地址不会被公开。