Go 的几大坑 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
hijoker
V2EX    Go 编程语言

Go 的几大坑

  •  1
     
  •   hijoker 2018-09-30 14:19:21 +08:00 6749 次点击
    这是一个创建于 2657 天前的主题,其中的信息可能已经有所发展或是发生改变。
    可能有些不准确,别跟我说用了 N 多的 trick 怎么实现了,我说的是开箱即用
    1. 接口没有默认实现, 几个数据结构实现了某个接口需要有统一的行为,每个都得写一个几乎同样的方法,太蛋疼了
    2. panic 的堆栈信息,捕获是捕获了,我要把他打到日志里去??
    3. 日志框架,默认能做到打印行号,打印时间,打印级别,控制按日志级别输出,对日志自动分片压缩的几乎没有
    4. 蛋疼的类型信息
    48 条回复    2018-10-01 18:30:21 +08:00
    hijoker
        1
    hijoker  
    OP
       2018-09-30 14:44:13 +08:00
    panic 的堆栈信息可以如下做
    defer func() {
    if r := recover(); r != nil {
    logUtil.Error.Printf("panic, %s, collecing ends", fmt.Sprintf("%v",r))
    return
    }
    }()
    Mohanson
        2
    Mohanson  
       2018-09-30 14:52:19 +08:00
    现在日志很少会靠程序自动写了, 都是程序打印到标准输出, 然后 supervisor 或 heka 等服务捕获, 并做日志分割, 存储等功能.
    heimeil
        3
    heimeil  
       2018-09-30 15:03:19 +08:00
    1. 你可以考虑一下把接口拆分得颗粒度小一点,再组合合适的功能到一起
    2. 最好做到 no panic,做好错误检查比 defer recover 好得多
    hijoker
        4
    hijoker  
    OP
       2018-09-30 15:48:56 +08:00
    @Mohanson 并不是每个都搞这些高大上的
    Immortal
        5
    Immortal  
       2018-09-30 15:59:34 +08:00
    对日志自动分片压缩的几乎没有
    这个倒是真的 得自己实现了
    xkeyideal
        6
    xkeyideal  
       2018-09-30 16:04:57 +08:00   12
    1 -> 对语言了解不深,既然是 interface,自己不实现,难道用意念编程?
    2 -> panic 对应的还有个叫 recover, 参考一楼的答案,学艺不精
    3 -> 日志框架,你别告诉大家说你用标准库的,现在都用第三方或自己写,有个叫 logrus 的据说挺好用
    4 -> 类型信息缺失挺蛋疼,还不支持 int,int32 这些类型的自动转义,这个算个槽点

    楼主应该是刚入门的级别,建议多修炼修炼,吐槽的都没到点上

    你应该吐槽:
    1. 为毛没有泛型?
    2. 从来没见过这么垃圾的包管理?
    3. 什么玩意,写个项目还要定义 gopath 这个环境变量?
    4. error 处理这他妈垃圾!!!
    5 为毛编译这么快,老子都没反应过来,c++不是 make 一下可以玩一把手游的么
    bonfy
        7
    bonfy  
       2018-09-30 16:09:47 +08:00
    包管理是可以吐槽

    error 处理写多了,倒是没有感觉了,至少好处是每个 error 都处理,问题比以前写 Python 少多了
    tourist2018
        8
    tourist2018  
       2018-09-30 16:17:07 +08:00
    日志框架,默认能做到打印行号,打印时间,打印级别,控制按日志级别输出,对日志自动分片压缩的几乎没有

    这个一般是第三方实现的吧 而且 go 的 log 能提供的东西已经很多了
    ikw
        9
    ikw  
       2018-09-30 16:21:05 +08:00
    @xkeyideal #6 日志框架也真的是 槽点,logrus 的 issue 好几年了,行号的功能楞是没加上
    feiyuanqiu
        10
    feiyuanqiu  
       2018-09-30 16:22:00 +08:00
    感觉最近 go 代替了 php,成为了最引战语言...是不是说明 go 最近发展势头还不错?
    hcymk2
        11
    hcymk2  
       2018-09-30 16:23:43 +08:00
    golang 中根据首字母的大小写来确定可以访问的权限
    当初没看文档,被这个坑的不要不要的。
    xkeyideal
        12
    xkeyideal  
       2018-09-30 16:32:22 +08:00
    @zwpaper 打印行号,打印时间,打印级别,控制按日志级别输出,对日志自动分片压缩,打印调用的堆栈信息,按照执行完整流程作用域输出等等,这些功能好像并不难实现,所以自己写个就好啦,想要啥功能自己加,还能为项目需要个性化定制
    lideshun123
        13
    lideshun123  
       2018-09-30 16:35:31 +08:00
    学艺不精也来喷,你看 V2 多友善
    zarte
        14
    zarte  
       2018-09-30 16:58:47 +08:00
    map slice 默认传引用这个比较坑。
    janxin
        15
    janxin  
       2018-09-30 17:00:34 +08:00
    1 无解,换个语言可破;
    2 是用法你没了解;
    3 这个库有的,你再找找?不过这样程序会慢,个人建议性能敏感程序不要打印文件行号信息;
    4. 换个 Rust 试试?
    Aruforce
        16
    Aruforce  
       2018-09-30 17:01:44 +08:00   1
    我想吐槽的是 p1 *P =&P{}和 p2 *P=P{}。。居然都尼玛可以。。。还有接受指针压栈的函数。。在写代码的时候 p3 P =P{}。。p3 也能直接调用。。。
    综上 。。所写非所得。。。 每次写代码前都要先想下 p 到底是不是指针。。。也许是我写的太少的原因。。。
    其他的泛型。。。error 处理方式。。包管理。。。还没有 ThreadLocalStorage。。其他什么的就不 BB 了。。。
    jitongxi
        17
    jitongxi  
       2018-09-30 17:04:16 +08:00
    楼主玩 go 一两天的经验。。。
    janxin
        18
    janxin  
       2018-09-30 17:07:08 +08:00
    @Aruforce 我想要 ThreadContext 啊,一个 ctx 显示传来传去非常蛋疼。

    没 get 到第一个问题是什么问题,编译不过的吧?能否给个代码看看?另外那个真的不是传统意义上的“指针”...
    darrh00
        19
    darrh00  
       2018-09-30 17:08:50 +08:00
    打印行号: 默认有

    打印时间 : 默认有

    打印级别,控制按日志级别输出: 关于这个非常同意 Dave cheney 的观点,完全没必要分很细的日志界别 [链接]!( https://dave.cheney.net/2015/11/05/lets-talk-about-logging)

    日志自动分片压缩: logrotate 写个几行配置,然后程序里响应一下 SIGHUP 信号,重新开一下日志文件,搞定。
    ikw
        20
    ikw  
       2018-09-30 17:15:08 +08:00 via iPhone
    @xkeyideal 自己写一个是一方面,我现在确实是改的 logrus,但是有一个好的库,还是会更好
    hijoker
        21
    hijoker  
    OP
       2018-09-30 17:15:58 +08:00
    @darrh00 我觉得根据日志级别控制输出是很常用的功能。。。。
    还有 logrotate 这个,真心在 windows 上就不好搞了
    aliipay
        22
    aliipay  
       2018-09-30 17:16:49 +08:00
    @Aruforce 我都是跟这感觉写的,都不管指针不指针的
    hijoker
        23
    hijoker  
    OP
       2018-09-30 17:18:50 +08:00
    @xkeyideal 你看懂了么,interface 的默认实现??
    就是说几个
    type struct1 struct{...}
    type struct2 struct{...}
    都实现了某个接口,这个接口其实对于大家都是一样的,如果有个默认实现就好了,不用每个 struct 都去写同样的方法,除了 receiver 不一样之外
    hijoker
        24
    hijoker  
    OP
       2018-09-30 17:19:17 +08:00
    @lideshun123 请指教
    hijoker
        25
    hijoker  
    OP
       2018-09-30 17:19:49 +08:00
    @jitongxi 我玩了几天也这就遇到了这些问题,实在惭愧
    silov
        26
    silov  
       2018-09-30 17:20:54 +08:00
    Golang 新手签到,刚刚遇到一个小坑。。。时间格式化的 Fomat、Parse 方法的格式参数。。。。竟然是那种写死的字符串。。。真是写的时候就透露着一股尴尬。。。

    ```golang
    datetime := time.Now().Format("2006-01-02 15:04:05") //后面的参数是固定的 否则将无法正常输出
    ```
    hijoker
        27
    hijoker  
    OP
       2018-09-30 17:21:06 +08:00
    @zwpaper 我也是这样想的,感觉 Go 社区走的路子怪怪的
    janxin
        28
    janxin  
       2018-09-30 17:22:09 +08:00
    @hijoker 如果是这样你试试 embed struct ?
    xkeyideal
        29
    xkeyideal  
       2018-09-30 17:22:24 +08:00
    @Aruforce 你这个完全是 go 好心办坏事,go 怕一些不懂或者不完全懂指针的用户指针的用法不对,造成一些他们意向不到的问题,所以将你说的这些情况都给兼容了。如果是玩过 C/C++的,根本不会有这种疑问,指针和形参还是很好区分的,另建议使用指针操作。
    go 里面玩指针就按照 C/C++那套整就完全没问题,注意一下 map, slice 默认是引用传递( go 官方不承认用“引用传递”这个说法)
    xkeyideal
        30
    xkeyideal  
       2018-09-30 17:24:32 +08:00   2
    @silov 对于操作时间,给你个建议,任何时候都带上时区去计算,否则对时间强依赖的项目,死都不知道怎么死的,运维给你服务器整个 UTC 时区,你按照北京时间算
    lwldcr
        31
    lwldcr  
       2018-09-30 17:25:06 +08:00
    log 确实没有像 java log4j 那种功能齐备的库
    不过我自己用的时候标准库的 log 上自定义部分功能+logrotate 基本满足需求了
    hijoker
        32
    hijoker  
    OP
       2018-09-30 17:26:04 +08:00
    @janxin 是个办法,谢谢,
    xkeyideal
        33
    xkeyideal  
       2018-09-30 17:28:40 +08:00
    @hijoker 所以说你是第一天玩呢!!
    你在 struct1 和 struct2 上都”继承“一个基类 struct3,然后让 struct3 去实现你想要的同一样且不需要写两次的接口不就行了么?

    想玩面向对象编程那套,go 并不是不是可以,只不过现有的基础设施比较简陋,实现的面向对象不能像 C++和 Java 那么简便和高大上罢了

    多看看一些开源项目对深入提升比较有好处
    silov
        34
    silov  
       2018-09-30 17:31:21 +08:00
    @xkeyideal 感谢提醒,我看下
    darrh00
        35
    darrh00  
       2018-09-30 17:40:11 +08:00
    @hijoker

    光要控制日志输出,很容易, 错误信息 info 输出,调试信息 debug 输出,加一个控制开关关闭 debug 输出
    分那么多 info,warn,erro,fatal 就是脱裤子放*, 你真的会用那么多级别来控制程序的日志输出?
    交给运维人员,运维人员会用你那么多的参数设置?

    windows 这个真不懂了,没有在 windows 上跑服务程序的经验。
    whoami9894
        36
    whoami9894  
       2018-09-30 17:47:21 +08:00 via Android   1
    哈哈我也来说一个坑:
    结构体是值类型,切片是引用类型
    我把一个结构体传入函数(不传指针),函数里修改结构体内容(比如 append 结构体替换原有结构体只全局可见)。如果直接修改结构体里的切片则是全局可见
    RaynorGu
        37
    RaynorGu  
       2018-09-30 17:49:07 +08:00
    @darrh00 debug, info, warning, error 这四个级别还是要的,debug 是调试的时候打印信息,info 是线上一些做事情的日志,比如定时器啊之类的,这样查问题可以看到有没有做,warning 就是一些不是很重要的错误,error 就是重要的错误
    whoami9894
        38
    whoami9894  
       2018-09-30 17:50:21 +08:00 via Android
    @whoami9894
    append 结构体替换原有结构体只局部可见
    jinzhe
        39
    jinzhe  
       2018-09-30 18:06:03 +08:00
    @silov 自己写个辅助函数转一下即可
    ```go

    // Format time.Time struct to string
    // MM - month - 01
    // M - month - 1, single bit
    // DD - day - 02
    // D - day 2
    // YYYY - year - 2006
    // YY - year - 06
    // HH - 24 hours - 03
    // H - 24 hours - 3
    // hh - 12 hours - 03
    // h - 12 hours - 3
    // mm - minute - 04
    // m - minute - 4
    // ss - second - 05
    // s - secOnd= 5
    func FormatDate(format string, t ...time.Time) string {
    var datetime time.Time
    if len(t) == 0 {
    datetime = time.Now()
    } else {
    datetime = t[0]
    }

    res := strings.Replace(format, "MM", datetime.Format("01"), -1)
    res = strings.Replace(res, "M", datetime.Format("1"), -1)
    res = strings.Replace(res, "DD", datetime.Format("02"), -1)
    res = strings.Replace(res, "D", datetime.Format("2"), -1)
    res = strings.Replace(res, "YYYY", datetime.Format("2006"), -1)
    res = strings.Replace(res, "YY", datetime.Format("06"), -1)
    res = strings.Replace(res, "HH", fmt.Sprintf("%02d", datetime.Hour()), -1)
    res = strings.Replace(res, "H", fmt.Sprintf("%d", datetime.Hour()), -1)
    res = strings.Replace(res, "hh", datetime.Format("03"), -1)
    res = strings.Replace(res, "h", datetime.Format("3"), -1)
    res = strings.Replace(res, "mm", datetime.Format("04"), -1)
    res = strings.Replace(res, "m", datetime.Format("4"), -1)
    res = strings.Replace(res, "ss", datetime.Format("05"), -1)
    res = strings.Replace(res, "s", datetime.Format("5"), -1)
    return res
    }```
    bobuick
        40
    bobuick  
       2018-09-30 18:26:40 +08:00
    日志是你没用对库吧。std 里日志没有那么完整的支持,这种一般都不会在 std 里,c++, java 也是这样。
    Leigg
        41
    Leigg  
      &nbs;2018-09-30 19:24:56 +08:00 via iPhone
    为什么要把 panic 错误打印到日志?这说明程序写的并不够健壮,panic 错误是要爆出来给人看的,不然程序多少暗坑都不知道
    reus
        42
    reus  
       2018-09-30 20:49:17 +08:00   1
    1, embedded field
    2, runtime.Callers
    3, 自己写
    4, 蛋疼可能是肾亏
    icris
        43
    icris  
       2018-09-30 22:41:13 +08:00
    @xkeyideal #6
    是 interface 就得自己实现没有什么理论依据啊,连 Java 的 interface 都能放 default 了,Go 以后也不一定不加
    xeaglex
        44
    xeaglex  
       2018-10-01 01:06:41 +08:00
    @xkeyideal 并非引用传递,看源码就知道了,是值传递了指针成员变量。
    blless
        45
    blless  
       2018-10-01 09:14:45 +08:00 via Android
    我也说一个…遍历一个结构体 slice 然后在循环内部取遍历出来的结构体地址…发现都是同一个地址
    sxw11
        46
    sxw11  
       2018-10-01 09:36:59 +08:00 via Android
    包管理,泛型,gopath 三大坑!谁用税知道!
    mosliu
        47
    mosliu  
       2018-10-01 10:27:58 +08:00
    感觉最大的坑就是包管理
    现在 go mod 稍有改善的迹象
    wenzhoou
        48
    wenzhoou  
       2018-10-01 18:30:21 +08:00 via Android
    @silov 这个真的是很尴尬啊。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     5771 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 35ms UTC 06:23 PVG 14:23 LAX 22:23 JFK 01:23
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86