从go语言看“如何快速入门一门语言”
最近在看go语言的语法,使用Python和PHP这种动态语言习惯了之后,再回头使用静态语言,多多少少有点别扭。看了go的语法之后,go给我的最直观的感受就是C+Python,为什么这么说呢?因为从语言的类型角度看,go语言衍生自C语言,很多地方有C语言的身影;但是从易用性和强大的第三方库支持的角度,go语言和Python有异曲同工之妙。
对我来说,学习一门语言,语法可能不是最为重要的,但是这也不是说语法一点都不重要。从陌生到简单的应用大致会有如下阶段:
先大致浏览下这种语言的语法,对变量类型,流程控制,接口实现,然后这个阶段结束后,我们就可以写出简单的脚本了。
再就是对各种库的熟悉,都说站在巨人的肩膀桑,才能看得更远。而go语言有大量的第三方优秀的库,可以大大的简化我们的编码量,并能提高程序的稳定性。
写工具。严格来说,第三个阶段和第二个阶段的界限不是很明显。写自己的一些工具的时候往往会发现更优秀的实现,所以我们拿过来直接用就好,消化吸收到我们自己的代码中。
学习一门语言的目的,实际上就是为了应用。我个人比较推崇的方式就是写工具。漫无目的的去生搬硬套每一个编程范式,意义不是很大。相反,写工具的过程中往往会伴随着各种需求,而这些需求基本上都是我们自己来定义的,所以会有很大的灵活性,对实现每一个小功能,我们都会有比较清晰的认识。这个过程也能不断提升我们应用一门语言的能力。
至于写什么工具,完全有我们自己而定。撇开具体的实现,我们只需要进行大量的头脑风暴即可。天马行空的将我们的设想落地,这就够了。也许你会说,我没有什么特别的需求啊,我要做什么呢?其实,需求是无处不在的,只要去想,总会有的。
另外一个比较好的应用一门语言的例子就是给自己找乐子。当然这个乐子不能保证对每一个人都适用。比如有的人就是喜欢刷题,写算法,现在有很多刷题网站,牛客网,LeetCode等等,都是比较好的去处;但是有的人,比如我对写算法题就不怎么感兴趣,相反,我对写爬虫,做小工具情有独钟,所以我只需要把我的想法用这门语言去实现就好了,这也是一种锻炼,而且从头到尾自身的参与度都很高,对语言的认识也能更透彻一点。当然了,这也只是我自己的看法,其他人也许不这么看。
下面通过一个具体的例子,来“走一遍”应用语言的道路。
需求:给我的Mac弄一些高清壁纸
头脑风暴:
- 从哪儿能弄到高清壁纸呢?
- 找到壁纸了怎么能搞到本地呢?
- 怎么每天自动换壁纸呢?
寻求解决方案:
- 必应的官网每天都有1920*1080分辨率的高清图片,很精美,就从这搞吧。
- 刚看了看go语言,就用go语言进行实现吧,这里先不管具体实现,留给后面去思考。
- Mac有一个功能可以选择一个文件夹,定时切换壁纸。
思考部分:
思考部分是对具体实现的处理,这里就是如何将必应官网的图片下载到本地。这就涉及到网络请求,正则表达式,文件操作。为了更好的使用代码,可以适当的放开一些处理,比如保存位置可以指定,添加额外的参数,这或许就会涉及到命令行参数的使用等等。总之,只要我们具体的去思考实现,就总会有新的需求,伴随而来的就是更多的思考,以及对库和语言的更好的认识,这对于锻炼自己也有一定的帮助。
因此,针对每一个具体的细节,我们就可以将问题细化到每一个小模块。网络请求可以通过http模块解决;正则表达式通过regex处理,字符串拼接、分割等可以使用strings模块,文件操作使用ioutil,os模块处理,命令行参数我们还会使用flag模块来解决等等。
具体实现:
思考完具体的细节,我们就可以着手进行实现了。对于每一个小功能,我们就可以切分到一个个的函数中。下面简单来看下代码:
package main
import (
"net/http"
"log"
"io/ioutil"
"regexp"
"strings"
"os"
"io"
"bytes"
"fmt"
"flag"
)
// 获取必应首页的背景大图
func DownloadHTML(url string) string {
resp, err := http.Get(url)
if err != nil {
log.Fatal(err)
}
defer resp.Body.Close()
bytes, error := ioutil.ReadAll(resp.Body)
if error != nil {
log.Fatal(error)
}
return string(bytes)
}
func GetImageURL(content string) string{
reg := regexp.MustCompile(`url:(.*?).jpg`)
ret := reg.FindString(content)
if len(ret) > 5 {
// url: "/az/hprichbg/rb/OtterChillin_ZH-CN11488013572_1920x1080.jpg
ret = "https://cn.bing.com" + strings.Split(ret, "\"")[1]
}else{
log.Fatal("解析图片链接出错!")
ret = ""
}
return ret
}
func DownloadImage(url string, folderpath string) int {
splits := strings.Split(url, "_")
imagename := splits[len(splits)-2] + ".jpg"
_, err := os.Stat(folderpath)
if err != nil {
log.Fatal("路径:" + folderpath + " 不存在")
}
if strings.LastIndex(folderpath, "/") != len(folderpath)-1 {
folderpath = folderpath + "/"
}
imagename = folderpath + imagename
// 下载图片,保存到本地
resp, error1 := http.Get(url)
if error1 != nil {
log.Fatal(error1)
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
f, error2 := os.Create(imagename)
if error2 != nil {
log.Fatal("文件创建失败:", error2)
}
io.Copy(f, bytes.NewReader(body))
// 没有异常,就是正常
return 0
}
func main() {
// 图片输出路径
folder := flag.String("o", "/tmp", "图片输出路径")
flag.Parse()
url := "https://cn.bing.com/"
html := DownloadHTML(url)
fmt.Println("输出文件路径:", *folder)
imgurl := GetImageURL(html)
if ret := DownloadImage(imgurl, *folder); ret==0 {
fmt.Println("壁纸下载成功啦~")
}else{
fmt.Println("对不起,壁纸下载失败!")
}
}
如此,便可以简单完成我们的预期目标。下面将代码编译出来,通过crontab来每天自动化帮我们抓取图片。
go build daily-bing-wallpaper.go
然后就可以在同级目录下获得daily-bing-wallpaper名称的二进制文件,这样就可以直接执行了。
下面写个crontab,因为我是10点上班,所以安排到10:50去执行就挺合适的。
50 10 * * * cd /abolutepath && ./daily-bing-wallpaper -o /outputpath >> /tmp/get-wallpaper.log 2>&1
最后再设置下Mac壁纸的文件夹即可。
总的来说,找到自己的兴趣点,然后去一点点的实现就好了,过程中对我自己熟悉,应用一门语言也会大有脾益。
下一篇: 如何高效又快速的学会一门编程语言