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

坐忘峰 golang 入坑系统

  •  
  •   ztao8607 · 2017-11-23 09:49:23 +08:00 · 1900 次点击
    这是一个创建于 2550 天前的主题,其中的信息可能已经有所发展或是发生改变。

    史前必读: 本文实际写于 20 日,首发于 gitbook。因为调侃部分是即兴发挥,所以提前说明一下,以免大家看到下面内容之后产生疑惑。 凭心而论,刚写前几篇文章的时候,就是因为闲着无聊,写着好玩。 写作时没有任何顾忌,想哪写哪。写得好不好,有没有人看都不重要。但后来慢慢发现,还真能帮助到一些人,才感觉到了一丝责任。这种责任说大也大,说小也小。 我并非名人大拿,也扛不起振兴 Golang 的大梁,如果就此打住对我也没什么损失。 但看到在 gitbook 上面点赞的同学和在 V2 上面留言鼓励的同学,我就感觉不坚持下去,都对不起这些鼓励。因此只要能帮到大家,我就坚持会把这个系列写下去。

    好,抒完怀,开始上菜。

    告别昨日梦,今朝艳阳天。

    大道通四方,车影舞翩翩。

    不做旁观者,去向应了然。

    白云绕远树,飞燕春汛传。

    天下万千景,彩绘壮河山。

    我辈当努力,敢把宏图展。

    迈步似虎跃,挥臂龙盘旋。

    天地更广阔,豪气入云端。

    送给刚度过周末,又要开始上班的程序员们。按照惯例,每周的周一都应该是复盘上周进度,制定本周计划的时间点。每每到了这一天,都是几家欢喜几家愁,有的庆幸进度正常,有的发愁扯皮何时休。欢喜也罢,发愁也罢,在这个天干物燥的冬季,还是要保持乐观平和的心态。气大伤身,提防感冒🤧。老人说得好,酒是穿肠毒药,色是刮骨钢刀, 财是惹祸根苗,气是无烟火炮。这世上吧,没有无缘无故的夸奖,也没有无缘无故的批评。轮到自己挨批评了,别真真计较,心怀宽广,莞尔一笑,世界就变得美好了许多。

    话说太多就是烦, 本文也不是心理访谈,所以就此打住不再延伸。总之一句话,工作就是一个工作,又不是你的全部,干嘛那么较真。真要较真,咱们就应该较真一下 Golang 🙄。 毕竟,我是写技术文章的,技术才是老本行。 开导人生,那是鞠萍姐姐的工作,下面才是我的工作。

    Golang 的判断

    golang 的判断也就是 If..else.. , switch 和 select。 通俗点就是如果满足条件去干嘛,如果不满足条件去干嘛。每种编程语言都有这么一套判断机制,而且判断的标准也大同小异。而唯一不同的地方,就是语法细节千奇百怪。 大胆猜测一下,可能目前流行的编程语言都或多或少受到了 C 语言的影响,而且绝大多数的程序员开山之课都是 C 语言,也就造成先入为主的影响。因此 C 语言是什么风格,新的语言就要仿造的八九不离十,要不学习曲线太陡,光吓就要吓走一大波人。

    所以,如果你有其它语言的学习基础,本节基本可以一扫而过。 如果你没有其它语言基础,或者对自己没有足够的自信,就看一看吧。 技多不压身,多学点没坏处。

    先来看 If。

    If 是典型的判断语句。 语法是:

    If <条件> {}
    
    例如:
    If a >= 0 {
        xxxxx
    }
    

    在条件中括号不是必须存在的,可加可不加。 如果你从 JS 转过来学 Golang,那么恭喜你了,加上也没事。 如果 Golang 转过去学 Js,每次都要记得添加括号,这个习惯不是一会半会能扳过来的。

    然后再看 If ... else ...

    上面是如果满足怎么办,属于单元判断。 而 If ... else... 是双元判断,如果满足怎么办,否则怎么办.

    If <条件>{
        满足的情况
    } else{
        不满足的情况
    }
    

    双元+单元=多元。将 If .. else ..级联起来,就是多元判断。例如:

    if <条件 1> {
    
    } else if <条件 2> {
    
    } else if <条件 3> {
    
    }
    

    同样是多元判断,switch 的语法看起来就会比 If .. else if 要简洁。

    switch <表达式>{
        case <值 1>:
        case <值 2>:
        defalut:
    }
    

    上面说过,每个语言在细节上面都有不同。 在 Golang 中:

    • switch 判断不需要添加 break。别问为什么,编译器就是这么规定的,匹配一个后,就会退出这个语义块,所以不需要 break
    • default 是可选项,同样不需要问为什么,如果都匹配不成功,那就是匹配不成功。没有异常,没有报错。所以有可能程序出现非预期结果。
    • 表达式部分必须是一个完整的布尔表达式,或者是一个推算出唯一结果的函数。 如果表达式为空,或者计算失败,则默认为 True。
    • 所有的 case 必须是同一种数据类型,如果类型不一致,就有可能出现非预期的计算结果
    • 通过 fallthrough 可以跳过 case 判断。例如:
    a := 1
    switch {
        case a >= 1:
            fmt.Println("a>=1")
            fallthrough
        case a >= 2:
            fmt.Println("a>=2")
            fallthrough
        case a >= 3:
            fmt.Println("a>=3")
            fallthrough
        case a >= 4:
            fmt.Println("a>=4")
            fallthrough
        default:
        }
    

    执行后的结果是:

    a>=1
    a>=2
    a>=3
    a>=4
    

    因为满足条件一后,执行 fallthrough,则跳过 case2 的判断直接执行 case2 的语句,后面依次类推,因为在 case4 时也存在 fallthrough,所以必须存在 defalut,要不然语义解析失败。如果 case4 没有 fallthrough,那么 default 就可以删除。

    switch 除了这种用法之外,在生产环境中,还经常用来判断值类型,例如:

    switch x.(type){
       case type:
          statement(s);      
       case type:
          statement(s); 
       default: 
          statement(s);
    }
    

    将表达式替换为 x 类型断言,如果是 int 型则怎么办? 如果是 string 类型则怎么办? 这种用法经常出现在接口中,当可能返回多种类型时,通过这种方式来逐一判断处理。下面举一个例子来说明问题:

    var x interface{}
    
       switch i := x.(type) {
          case nil:      
             fmt.Printf("type of x :%T",i)                
          case int:      
             fmt.Printf("x is int")                       
          case float64:
             fmt.Printf("x is float64")           
          case func(int) float64:
             fmt.Printf("x is func(int)")                      
          case bool, string:
             fmt.Printf("x is bool or string")       
          default:
             fmt.Printf("don't know the type")     
       }
    
    在 Golang 判断环节,还有经常使用的一种判断: Select

    select 语法和 switch 语法非常相像,有些初学者很容易将两者弄混。但除了样子相近之外,二者作用完全不同。先看外表:

    select {
       case communication clause  :
          statement(s);      
       case communication clause  :
          statement(s); 
       default :
          statement(s);
    }
    

    如果把 select 换成 switch,活脱脱一个条件判断表达式。 所以外表极其相似。但你要注意:

    • select 后面没有表达式
    • case 后面的类型必须是 chan。(chan 我们还没有提到,提前剧透一下,chan 是一种数据通信管道,golang 封装成了数据类型)
    • default 是可选的。如果有 default,必须放到 select 最后。

    因为我们没有讲到 chan,所以目前来说记住上面的部分就可以了。

    Golang 的判断相对于其它语言来说,只有 If,switch 和 select 三种。 其中 select 还属于特殊的判断。所以只剩下 if 和 switch 两种。相当好记,相当好用。

    如果本节就这么结束了,不用你说,我都感觉内容不详实(不详实也不是一次两次了,这次是由衷的感觉不详实)。所以再写一下 Golang 里面的循环。放心内容不会多的,我就想写成口袋书,一次就看一部分,不用长篇累牍的写那么多。 你们看着累,我写的也累。

    Golang 的循环只有 For 循环

    好了,写完了。 板砖尽情的扔过来吧,让我来感受一下遭人抨击的感觉吧。 虽说你们扔了板砖,但我仍然要说 Golang 只有 For 循环一种循环语法。 没有什么 while 循环,do..for 循环,foreach 循环,....map()循环之类的东西。在 Golang 当中需要使用循环,记住只有 For 循环。

    for [condition |  ( init; condition; increment ) | Range] {
       statement(s);
    }
    

    上面就是 For 循环的三种写法。

    • condition。 条件判断。 也就是传说中的 for true{} 循环,某种意义上等于与 while 循环
    • init; condition; increment。初始化循环,预定俗称的写法就是初始化 i:=0,然后当 i<=N 时循环,每次 i++。
    • Range,迭代循环。基本用来迭代数组.例如;
    numbers := [6]int{1, 2, 3, 5} 
    for i,x:= range numbers {
          fmt.Printf("value of x = %d at %d\n", x,i)
    }
    

    下面用一个例子,来演示三种情况:

       var b int = 15
       var a int
       numbers := [6]int{1, 2, 3, 5} 
    
       /* for loop execution */
       for a := 0; a < 10; a++ {
          fmt.Printf("value of a: %d\n", a)
       }
       for a < b {
          a++
          fmt.Printf("value of a: %d\n", a)
       }
       for i,x:= range numbers {
          fmt.Printf("value of x = %d at %d\n", x,i)
       }
    

    如果一个 For 循环使用的不过瘾,可以嵌套多个 For 循环。直接看语法:

    for [condition |  ( init; condition; increment ) | Range] {
       for [condition |  ( init; condition; increment ) | Range] {
          statement(s);
       }
       statement(s);
    }
    

    语法看不懂,那就给你一个实例,比对着看吧:

       var i, j int
    
       for i = 2; i < 100; i++ {
          for j = 2; j <= (i/j); j++ {
             if(i%j==0) {
                break; // if factor found, not prime
             }
          }
          if(j > (i/j)) {
             fmt.Printf("%d is prime\n", i);
          }
       }
    

    上面实例中,出现了一个 break。这是标准的退出循环的方式。 那么 Golang 中有几种退出循环的方式呢?

    • Break。 使用率最高的方式,当满足退出条件时,直接 break 退出
    • Continue。有人说不算出退出循环,因为它只是跳出了本次循环,继续下次循环。但如果不放这里,我又把 continue 放哪里呢?所以暂且就把 continue 当做跳出循环吧。只不过是跳出本次循环而已。
    • Goto。 武林界失传已久的 Goto 大法,在 Golang 中重出江湖。 与其它语言,强制半强制的屏蔽 Goto 不同,golang 很大方的推出 goto。没有什么其它限制条件,只要你认为 goto 使用的正确就可以大胆的使用。(小心陷入死循环)。使用 Goto 时,需要提前定义标签,然后 goto 标签即可。 下面是一个实例:
       var a int = 10
    
       LOOP: for a < 20 {
          if a == 15 {
             a = a + 1
             goto LOOP
          }
          fmt.Printf("value of a: %d\n", a)
          a++     
       }
    

    如果你认真的分析一下代码,或者自己执行一下代码就会发现:你死循环了!所以不限制用,不等于滥用。 不是老司机,就别调试小寡妇。 寡妇不是病,真闹起来,要你命。所以用之前,慎重考虑一下是否真的要用。 记住:no zuo no die!

    侯门一入深如海, 从此萧郎是路人。 代码之路漫漫而长,如果从头开始一直在跟着本文的更新,那么你现在已经算是踏入了 Golang 的大门,至少我还没有开始摧残你那颗幼小的心灵。 由易而难,慢慢来。 跟着练,悄然之间你就会发现 Golang 原来就是这么一回事。

    20 条回复    2017-11-27 15:24:49 +08:00
    Carseason
        1
    Carseason  
       2017-11-23 09:53:31 +08:00 via iPhone
    愣是把简单明了是教程写的长篇大论
    torbrowserbridge
        2
    torbrowserbridge  
       2017-11-23 09:57:27 +08:00 via Android
    啰里啰嗦
    daizongxyz
        3
    daizongxyz  
       2017-11-23 10:00:17 +08:00
    支持楼主布道
    northisland
        4
    northisland  
       2017-11-23 10:04:41 +08:00
    (2 x 2GB ) GPU

    吐彩虹
    northisland
        5
    northisland  
       2017-11-23 10:05:00 +08:00
    抱歉,回复错帖子了
    ztao8607
        6
    ztao8607  
    OP
       2017-11-23 12:02:59 +08:00
    @Carseason 76 集甄嬛传不去说,专批布道小书童,为何为何? 难不成是老江湖遇到了小菜鸟,只喜欢欺软怕硬?若随您愿,恐水浒需改为 108 个流氓的故事了。道行浅,只能写入门,还请老司机多多包涵。
    NullMan
        7
    NullMan  
       2017-11-23 12:19:05 +08:00
    文字表达方式复杂了,以至于感觉 golang 复杂了,其实没必要说那么多解释,更没必要贴难以理解的语法格式,直接贴 if,if...else 之类的实例代码片段就行了,每种最多一句解释就行了。

    play.golang.org 绝对是最简明扼要的教程,也是最简明的布道文。

    @torbrowserbridge @Carseason 这两位评价中肯,稍显直接了。
    NullMan
        8
    NullMan  
       2017-11-23 12:21:14 +08:00
    贴错链接,是 tour.golang.org
    Cooky
        9
    Cooky  
       2017-11-23 12:21:52 +08:00 via Android
    你这个要是按行数算工资稳赚
    sss3600123
        10
    sss3600123  
       2017-11-23 12:55:48 +08:00 via iPhone
    很详细
    ztao8607
        11
    ztao8607  
    OP
       2017-11-23 14:44:24 +08:00
    我这里做个说明吧。 因为大家没有看这个系列的开篇语,所以可能产生了误会。 在开篇语当中,我将此系列定位于入门,同时假设读者几乎没有或者有少量编码经验。 因为有其它语言使用经验现在想学 Golang 的人,会优先选择查看官方文档,而不是去网上搜各种 Golang 教程。
    同时,针对"话贫",应该是受众不同所造成的吧。如果让 Rainer Weiss、Kip S. Thorne 和 Barry C. Barish 去看霍金先生的<时间简史>,可能也会看不下去。我不认为技术文章一定要是严肃,干练和枯燥的,为什么就不能用轻松的语言去普及技术呢?
    会者不难,难者不会。 如果看了开头就猜中了结尾,那说明您功力深厚,已经不屑于这类“水货”文章,但试问,有多少人刚开始学 golang 的时候,不是从一个一个的"水货"文章中看出来的?
    这里只是把以前学习过程中遇到的坑,掰开揉碎,多说了点。 所谓技多不压身,多看看又有何妨?
    solee
        12
    solee  
       2017-11-23 14:54:34 +08:00
    我就问问作者,平时用什么包管理,项目进程管理用的什么,ORM 一般用什么啊,go 现在算是百花齐放,不知道哪个好用哪个不好用。需要有经验的指指路哈。
    ztao8607
        13
    ztao8607  
    OP
       2017-11-23 15:05:19 +08:00
    @solee 希望不是抱着挑衅语气来发问的 :D。 我只说我用的工具, 包管理用 dep( https://github.com/golang/dep)。 项目进程不知道和 golang 有啥关联,用 git 来管理代码,用 trello 来控制进度( https://trello.com)。ORM,以前用过 gorm,但最近都是用 NOSQL,所以也就不用 ORM 了。 使用 Golang 最大的问题是翻墙。如果翻墙翻不好,很多工具都不好用。
    jameshuazhou
        14
    jameshuazhou  
       2017-11-23 18:35:12 +08:00
    以前刚开始学 go 都是从 effective go 开始的,然后是官方的 faq, blog, wifi, faq,没人会从“水货”文章开始。而现在有了 K 老的书,其他的书都没必要了。一般来说,一个刚毕业的这样学个 2 周就可以上手项目了。

    我因为要培训新人,所以但凡这类教程都会搜罗看看。说实话,这个系列,虽然讲得多,但实际上很粗,称不上"掰开揉碎"的程度,而印象中也只见过谭浩强的书是这样的---当然他段子讲得不行。

    不管怎样,作者的用意是好的,而且花费了大量时间精力,值得赞一个,也希望能越写越好。只是希望能听进一些建议,虽然刺耳了点。相信作者是聪明人,但不要聪明到“智足以拒谏 言足以饰非”的地步。
    IllBeBack
        15
    IllBeBack  
       2017-11-23 19:34:38 +08:00
    @jameshuazhou 请问 K 老的书是什么书?
    jameshuazhou
        16
    jameshuazhou  
       2017-11-23 19:36:29 +08:00
    @IllBeBack

    <<The Go Programming Language>>

    https://book.douban.com/subject/26337545/
    naixiaoxin
        17
    naixiaoxin  
       2017-11-23 22:30:20 +08:00 via iPhone
    哇 涛哥
    Mitt
        18
    Mitt  
       2017-11-24 12:49:04 +08:00
    我记得 V2EX 是不接受这种入门新手教程的 对我个人而言。如果我喜欢这门语言 我肯定去看文档去学了,我来这个节点是为了看相关 go 的更进一步的学习,而不是看满页的新手教程,我不抱有恶意,但是希望如果要发这类帖子能不能打包一下,进来看到满页的新手教程真的还是挺厌恶的。
    teemoer
        19
    teemoer  
       2017-11-24 15:01:03 +08:00
    给你点赞、、、、、
    ztao8607
        20
    ztao8607  
    OP
       2017-11-27 15:24:49 +08:00
    @Mitt 打包这个建议不错。 等写完了,最后发一个完整链接。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2658 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 11:26 · PVG 19:26 · LAX 03:26 · JFK 06:26
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.