首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >『Go 语言学习专栏』-- 第十三期

『Go 语言学习专栏』-- 第十三期

作者头像
谢伟
发布2018-06-04 17:51:05
1.1K0
发布2018-06-04 17:51:05
举报
文章被收录于专栏:GopherCoderGopherCoder

go-13.png

13.png

大家好,我叫谢伟,是一名程序员。

这个选题我认真思考了很久,决定把现在的方案分享出来,即:如何从 Github 的开源代码中学习?(中级版本)

下文介绍的方法是我目前的做法,但我希望能不断的进行迭代,达到更佳的效果

如果你跟着这个栏目,进行了学习,私底下也花了些时间,不管是看了更多的书籍,学习了更多的教程,还是写了更多的示例。今天的主题便是带你突破:即如何从入门选手达到中级选手。

假设,你已经大概掌握了Go 语言的基本语法。能独立写一些代码。实现一些基本的需求,即已经入门Go。

那么如何进入到中级水平?

有人说,做项目。

确实,项目确实能够引领你达到中级水平。但问题是,初级阶段,你可能不知道该选择一些什么项目。

  • 哪些项目刚刚好是你需要掂一掂脚刚好够得着?
  • 哪些项目是你还需要更多点的知识才能够的着?
  • 从项目中学什么?
  • 怎么从开源项目中学?梳理流程?抄代码?复现一遍?

这些都是问题。

下面给出我的策略,希望对你有所启发。

1. 评估自己的水平

首先第一点,需要评估自己的水平,知道自己的水平,你才能对一些开源的项目,在一定程度上理解项目的难易复杂度。

比如 Go 里面的明星产品Docker, 是一个非常热门的开源项目,作为初学者的你,你能凭一己之力,就开始学习或者模仿它吗?

答案是可以,但是很难。很容易就打击你的信心,初学者,信心很重要的,不然轻而易举的容易放弃。

那如何评估自己的水平?自己能评估出自己的水平吗?

这个问题,我准备从下面几点来进行评估。首先,确保你对自己真诚。如实的反馈自己的水平。

  • 代码量
  • 写代码的速度
  • 对内置库的使用程度
1.1 代码量

从代码量的角度来看,一定程序上能反映出,你到底写了多少行代码。当然这里的代码量不是粘贴复制,写重复的代码,而是有一定水平的代码,至少完成了某些功能、需求。

你可能没什么概念,一般来说,如果你是在企业内,一天8小时的工作量,连续写代码的时间不会超过 2小时,意味着,一天的核心代码量大概会是 200 行(数据仅供参考),如果你是学生,自己学习,那我也不太相信,你一天能连续写代码超过 2 小时,能一天写出几千行代码。一天的核心代码量大概也就几百行的量级,更何况在学校,你完成的代码,可能都不是一些略带难度,完成一定需求的代码。

我从入门一门编程语言的代码量衡量角度来说,大概需要5000行左右。(个人估算:200 * 5 * 5)

1.2 写代码的速度

这点来说,不是越快越好,一般的写代码,前期的规划、思考、构建等都极其的重要,这些决定了你编码实现的具体分工以及实现的可能性。

那怎么评估写代码的速度?

我认为,第一:不过分依赖现有网上的实现方案。即你上网查阅的比较少,即可实现你的需求;第二:运行出错都能根据IDE 提示解决。而不是频繁的依赖于 搜素引擎。

1.3 内置库的使用

内置库可以说是你编写程序的基石,不一定对内置库的用法了然于胸,但是需要根据文档或者内置的库代码,知道最基础的用法。能快速的知道用哪个库。

比如你需要执行操作系统的一些命令,那么你要清楚知道需要使用的os/exec库。

知道这个命令相关的知识:

  • 指定目录下运行
  • 带什么参数
  • 命令存在环境变量中的目录
  • 是否存在该命令等

即:需要对内置库有一定的使用经验。

2. 找感兴趣的项目

正确评估自己的水平之后,需要寻找到一些自己感兴趣的项目。

我推荐两个平台吧:

  • Github
  • 掘金

Github 几乎是最佳的选择, 掘金这个平台,最近我发现也是挺好的,虽然也是属于技术聚合类的平台,但质量或者颜值还算可以。但是存在一个问题。即自己感兴趣的项目如何能寻找到?

我推荐下面的方法:

  • 热门
  • 趋势:Github Trending

即合理使用 Github Trending :

go-2018-06-03.png

你可以选择你感兴趣的编程语言,查阅到最佳热门的项目都有哪些。继而可以关注感兴趣的作者。通过感兴趣的作者,继而可以发现一些好玩的项目。

另外一个是使用掘金插件,可以尽可能多的机会发现好玩的项目。

掘金-2018-06-03.png

比如,我可能比较关注后端这块,这些侧边栏可以发现很多的分享者,进而可能关注到项目和源代码。

总之,一句话,合理使用平台,尽可能创造机会发现感兴趣的项目。

大概,你现在知道如何发现感兴趣的项目了。

那如何评估,是否适合你来学习呢?

  • 看源代码

第一步我们已经评估了自己的水平,达到了一定的水平,那么看源代码就是检阅你的时候了,第一,你需要看懂。第二,根据自己的水平,尝试是否进行花时间练习。

3. 实现最小代码

如果你根据源代码之后,决定花时间在这个项目上,那么下一步便是学习。学习这个项目的实现方法。不一定任何方面都值得你学习,我认为,比你更好的实现方式都值得学习。借鉴过来,有些是参考具体的实现方式,有些是参考技术的选择。

比如这个:抖音机器人 具体的实现其实不是太复杂,包括这个项目 微信跳一跳小助手

两者本质上选择的技术方案都是一致的:Python + ADB

无外乎使用编程和接口完成对手机的操作。不管是截图还是图像识别。

如果你之前不知道有这样的技术方案能对手机进行操作。那么你就增加了技术广度,知道面对这样的场景,应该选择的方案是 Python + ADB ,当然 Python 不是必须的,编程语言只是工具,你也可以使用 Go + ADB 来实现,都可以。

具体怎么从源代码中学习?我认为下面几点:

  • 确保实现最小的功能,摈弃完美主义
  • 主体功能实现

首先,你需要大概阅读下项目的源代码。不管是你Clone 下来,还是使用Github 源代码阅读插件:比如 Octotree、GayHub

其次,你需要了解项目结构:知道这块是干什么的,那块是干什么的。

然后,你需要抓住核心的东西。从最核心的东西入手,先自己实现这个项目的最小功能。

最后,如果你依然有兴趣。你可以这么操作。第一,换种编程语言重新实现,比如别人方案使用 Python ,你可以使用 Go; 第二,换个场景重新实现,比如别人是完成的是对知乎数据的分析抓取,那么你可以对简书,或者你感兴趣的网站数据分析抓取;第三,优化,有可能你能想出更好的实现方案,或者你仅仅只是优化这个项目的某一个层面而已。

举个例子吧:

我最近发现一个项目:汉子转拼音(https://github.com/mozillazg/go-pinyin)

因为我对 Go 感兴趣,所以,选择了 Go 实现的汉子转拼音的版本。这个工具还有其他的实现方式。

这个项目引起了我的注意,于是我阅读源代码,从帮助文档开始。

帮助文档这么写:

package main

import (
    "fmt"
    "github.com/mozillazg/go-pinyin"
)

func main() {
    hans := "中国人"

    // 默认
    a := pinyin.NewArgs()
    fmt.Println(pinyin.Pinyin(hans, a))
    // [[zhong] [guo] [ren]]

    // 包含声调
    a.Style = pinyin.Tone
    fmt.Println(pinyin.Pinyin(hans, a))
    // [[zhōng] [guó] [rén]]

    // 声调用数字表示
    a.Style = pinyin.Tone2
    fmt.Println(pinyin.Pinyin(hans, a))
    // [[zho1ng] [guo2] [re2n]]

    // 开启多音字模式
    a = pinyin.NewArgs()
    a.Heteronym = true
    fmt.Println(pinyin.Pinyin(hans, a))
    // [[zhong zhong] [guo] [ren]]
    a.Style = pinyin.Tone2
    fmt.Println(pinyin.Pinyin(hans, a))
    // [[zho1ng zho4ng] [guo2] [re2n]]

    fmt.Println(pinyin.LazyPinyin(hans, pinyin.NewArgs()))
    // [zhong guo ren]

    fmt.Println(pinyin.Convert(hans, nil))
    // [[zhong] [guo] [ren]]

    fmt.Println(pinyin.LazyConvert(hans, nil))
    // [zhong guo ren]
}

看上去,是输入一个汉字,区分各种模式,比如默认的形式:不包含声调;比如包含声调;比如声调的一二三四声使用数字来表示;比如多音字模式;等等。

看上去核心来自于:pinyin 这个包。

func SinglePinyin(r rune, a Args) []string {
    if a.Fallback == nil {
        a.Fallback = Fallback
    }
    value, ok := PinyinDict[int(r)]
    pys := []string{}
    if ok {
        pys = strings.Split(value, ",")
    } else {
        pys = a.Fallback(r, a)
    }
    if len(pys) > 0 {
        if !a.Heteronym {
            pys = pys[:1]
        }
        return applyStyle(pys, a)
    }
    return pys
}

// Pinyin 汉字转拼音,支持多音字模式.
func Pinyin(s string, a Args) [][]string {
    pys := [][]string{}
    for _, r := range s {
        py := SinglePinyin(r, a)
        if len(py) > 0 {
            pys = append(pys, py)
        }
    }
    return pys
}

// LazyPinyin 汉字转拼音,与 `Pinyin` 的区别是:
// 返回值类型不同,并且不支持多音字模式,每个汉字只取第一个音.
func LazyPinyin(s string, a Args) []string {
    a.Heteronym = false
    pys := []string{}
    for _, v := range Pinyin(s, a) {
        pys = append(pys, v[0])
    }
    return pys
}

看上去核心来自于这三个函数。遍历字符串。现在你的问题应该是如何将汉字字符串转换为拼音。

继续阅读,发现这个 pinyin_dict.go 文件

var PinyinDict = map[int]string{
    0x3007:  "líng,yuán,xīng",
    0x3400:  "qiū",
    0x3401:  "tiàn",
    0x3404:  "kuà",
    0x3405:  "wǔ",
    0x3406:  "yǐn",
}

看上去一个完整的对照表。即将字符串中字符转换为整型,通过整型能知道拼音是哪个。

好,至此,大概知道了思路。

将字符串中字符转换为十六进制数,通过十六进制数能得到拼音。

那么为了实现最小功能。我可能会这么想:

即:将自己的名字转换为拼音。

所以我这么做。

  • 找到"谢伟"两个拼音,转化为 map
  • 遍历字符串,将字符转换为 十六进制数
package main

import (
    "flag"
    "fmt"
    "strings"
)


func main() {
    var dictMap = map[int32]string{}

    dictMap[0x8c22] = "xiè"
    dictMap[0x4f1f] = "wěi"

    var a = "谢伟"
    pys := [][]string{}
    for _, v := range a {
        py, ok := dictMap[v]
        pyr := []string{}
        if ok {
            pyr = strings.Split(py, ",")
        }
        pys = append(pys, pyr)
    }

    fmt.Println(pys)

}

结果:

[[xiè] [wěi]]

好,上面一步的实现,只是完成了特定的汉子转拼音。

那么如何将任意汉子转换为拼音。

  • 将 pinyin_dict.go 的map 全部复制下来
  • 使用命令行解析参数
package main

import (
    "flag"
    "fmt"
    "go-example-for-live/thirteen/infra"
    "strings"
)

func Pinyin() {

    var name string

    flag.StringVar(&name, "n", "谢伟", "")
    flag.Parse()
    pys := []string{}

    for _, arg := range flag.Args() {
        for _, v := range arg {
            py, ok := infra.PinyinDict[v]
            if ok {
                pyList := strings.Split(py, ",")
                if len(pyList) > 0 {
                    pys = append(pys, pyList[0])
                }
            }
        }

    }

    fmt.Println(pys)

}

func main() {

    Pinyin()

}

结果:(windows 平台 go build main.go, 这么运行 main.exe 参数; Linux 平台 go build main.go , ./main 参数), 下文以 windows 平台为例。

main.exe 谢伟

结果:

[xiè wěi]
main.exe 谢小路

结果:

[xiè xiǎo lù]
main.exe 编程语言

结果:

[biān chéng yǔ yán]
main.exe 鹅鹅鹅,曲项向天歌

结果:

[é é é qū xiàng xiàng tiān gē]
main.exe 莫愁前路无知己,天下谁人不识君

结果:

[mò chóu qián lù wú zhī jǐ tiān xià shéi rén bù shí jūn]

通过这个例子,大概我们已经知道这个项目的核心代码了。差不多就已经解构了这个项目。

4. 扩展

上面的实现最小的基本功能,通过示例演示了如何操作,但不够。你还需要继续思考。

  • 理解其他模块
  • 哪些不足

还是以上文pinyin 项目为例,你或许会想拼音数据来自于哪?

顺藤摸瓜,作者已经告诉你了:pinyin 数据

Unihan Database 数据版本:

Date: 2017-05-14 07:01:48 GMT [JHJ] Unicode version: 10.0.0

  • kHanyuPinyin.txt: Unihan DatabasekHanyuPinyin 部分的拼音数据(来源于《漢語大字典》的拼音数据)
  • kXHC1983.txt: Unihan DatabasekXHC1983 部分的拼音数据(来源于《现代汉语词典》的拼音数据)
  • kHanyuPinlu.txt: Unihan DatabasekHanyuPinlu 部分的拼音数据(来源于《現代漢語頻率詞典》的拼音数据)
  • kMandarin.txt: Unihan DatabasekMandarin 部分的拼音数据(普通话中最常用的一个读音。zh-CN 为主,如果 zh-CN 中没有则使用 zh-TW 中的拼音)
  • kMandarin_overwrite.txt: 手工纠正 kMandarin.txt 中有误的拼音数据(可以修改
  • GBK_PUA.txt: Private Use Area 中有拼音的汉字,参考 GB 18030 - 维基百科,自由的百科全书可以修改
  • nonCJKUI.txt: 不属于 CJK Unified Ideograph 但是却有拼音的字符(可以修改
  • kMandarin_8105.txt: 《通用规范汉字表》(2013 年版)里 8105 个汉字最常用的一个读音 (可以修改)
  • overwrite.txt: 手工纠正的拼音数据(可以修改
  • pinyin.txt: 合并上述文件后的拼音数据
  • zdic.txt: 汉典网 的拼音数据

如果让你自己来做,你可能需要用到爬虫。把数据抓取下来。

你还可能思考,这个项目哪些值得你借鉴?

比如:作者是如何区分各种模式的?比如各种声调模式。为什么要区分各种声调模式啊?

等等,诸如此类。

5. 循坏

等你花了些时间,度过这个阶段,你可能需要练习更高层次的项目,不断的选择,或是工作中的启发、或是工作中的需求等,不断的实现最小的功能,完成阅读、编写代码。不断的思考。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018.06.04 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 评估自己的水平
    • 1.1 代码量
      • 1.2 写代码的速度
        • 1.3 内置库的使用
        • 2. 找感兴趣的项目
        • 3. 实现最小代码
        • 4. 扩展
        • 5. 循坏
        相关产品与服务
        容器镜像服务
        容器镜像服务(Tencent Container Registry,TCR)为您提供安全独享、高性能的容器镜像托管分发服务。您可同时在全球多个地域创建独享实例,以实现容器镜像的就近拉取,降低拉取时间,节约带宽成本。TCR 提供细颗粒度的权限管理及访问控制,保障您的数据安全。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档