從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桌布的資料夾即可。
總的來說,找到自己的興趣點,然後去一點點的實現就好了,過程中對我自己熟悉,應用一門語言也會大有脾益。