日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

Go 語言標(biāo)準(zhǔn)庫中最常用的標(biāo)識(shí)符是什么?

 

這篇文章是來自最新 justforfunc 中同標(biāo)題的一段。這個(gè)程序的代碼可以在 justforfunc 倉庫 中找到。

問題陳述

想象一下,對(duì)于下面的代碼段,你如何將其中所有的標(biāo)識(shí)符都提取出來。

package main
import "fmt"
func main() {
 fmt.Println("Hello, world")
}

我們期望可以得到一個(gè)包含 mainfmt 和 Println 的列表。

標(biāo)識(shí)符到底是什么?

為了回答這個(gè)問題, 我們需要了解一下有關(guān)計(jì)算機(jī)語言的理論知識(shí)。 但只要一點(diǎn)就足夠了,不用擔(dān)心有多復(fù)雜。

計(jì)算機(jī)語言,是由一系列有效的規(guī)則組成的。比如下面這個(gè)規(guī)則:

IfStmt = "if" [ SimpleStmt ";" ] Expression Block [ "else" ( IfStmt | Block ) ] .

上面這個(gè)規(guī)則告訴我們 if 語句在 Go 語言中的樣子。“if”“;”, 和 “else” 是幫助我們理解程序結(jié)構(gòu)的關(guān)鍵詞。與此同時(shí),還有 Expression Block, SimpleStmt 之類的其他規(guī)則。

這些規(guī)則組成的集合就是語法,你可以在 Go 語言規(guī)范中找到它們的詳細(xì)定義。

這些規(guī)則不是簡(jiǎn)單的由程序的單個(gè)字符定義的,而是有一系列 token 組成。 這些token除了像 if 和 else 這樣的原子 token 外, 還有像整數(shù) 42,浮點(diǎn)數(shù) 4.2 和字符串 “hello” 這樣的復(fù)合 token, 以及像 main 這樣的標(biāo)識(shí)符。

但是,我們是怎么知道 main 是一個(gè)標(biāo)識(shí)符,而不是一個(gè)數(shù)字呢? 原來它也是有專門的規(guī)則來定義的。如果你讀過 Go 語言規(guī)范中的標(biāo)識(shí)符部分,你就會(huì)發(fā)現(xiàn)如下的規(guī)則:

identifier = letter { letter | unicode_digit } .

在這條規(guī)則中,letter 和 unicode_digit 不是 token 而是字符。 所以有了這些規(guī)則,就可以寫一個(gè)程序來逐個(gè)字符地分析,一旦檢測(cè)到一組字符匹配到某一條規(guī)則,就 “發(fā)射”(emits) 出一個(gè) token。

所以,如果我們以 fmt.Println 為例, 它可以產(chǎn)生這些 token:標(biāo)識(shí)符 fmt“.”, 以及標(biāo)識(shí)符 Println。 這是一個(gè)函數(shù)調(diào)用嗎? 在這里我們還無法確定,而且我們也不關(guān)心。它的結(jié)構(gòu)就是一個(gè)序列,表明 token 出現(xiàn)的順序。

Go 語言標(biāo)準(zhǔn)庫中最常用的標(biāo)識(shí)符是什么?

 

這種能夠?qū)⒔o定的字符序列生成 token 序列的程序被稱為掃描器。Go 標(biāo)準(zhǔn)庫中的 go/scanner 就自帶一個(gè)掃描器。它生成的記號(hào)定義在 go/token 里。

使用 go/scanner

我們已經(jīng)了解了什么是掃描器,那它如何使用呢?

從命令行中讀取參數(shù)

讓我們先從一個(gè)簡(jiǎn)單程序開始,將傳給它的參數(shù)打印出來:

package main
import (
 "fmt"
 "os"
)
func main() {
 if len(os.Args) < 2 {
 fmt.Fprintf(os.Stderr, "usage:nt%s [files]n", os.Args[0])
 os.Exit(1)
 }
 for _, arg := range os.Args[1:] {
 fmt.Println(arg)
 }
}

接下來,我們需要掃描從參數(shù)傳進(jìn)來的文件:需要先創(chuàng)建一個(gè)新的掃描器,然后用文件的內(nèi)容來初始化。

打印每個(gè) token

在我們調(diào)用 scanner.Scanner 的 Init 方法之前,需要先讀取文件內(nèi)容,然后為每個(gè)掃描過的文件創(chuàng)建一個(gè) token.FileSet 以便來保存 token.File

掃描器一經(jīng)初始化,我們就能調(diào)用其 Scan 方法來打印 token。 一旦我們得到一個(gè) EOF(End Of File) token,就說明達(dá)到文件末尾了。

fs := token.NewFileSet()
for _, arg := range os.Args[1:] {
 b, err := ioutil.ReadFile(arg)
 if err != nil {
 log.Fatal(err)
 }
 f := fs.AddFile(arg, fs.Base(), len(b))
 var s scanner.Scanner
 s.Init(f, b, nil, scanner.ScanComments)
 for {
 _, tok, lit := s.Scan()
 if tok == token.EOF {
 break
 }
 fmt.Println(tok, lit)
 }
}

統(tǒng)計(jì) token

太棒了,我們已經(jīng)能夠打印出所有的 token 了,但是我們還需要跟蹤每個(gè)標(biāo)識(shí)符出現(xiàn)的次數(shù),然后按照出現(xiàn)次數(shù)排序,并打印出前 5 位。

在 Go 中,實(shí)現(xiàn)以上需求的最好的方法是用一個(gè) map,讓標(biāo)識(shí)符來做 key, 其出現(xiàn)次數(shù)做 value。

每當(dāng)一個(gè)標(biāo)識(shí)符出現(xiàn)一次,計(jì)數(shù)器就加一。最后,我們將 map 轉(zhuǎn)換為一個(gè)能夠排序和打印的數(shù)組。

counts := make(map[string]int)
// [code removed for clarity]
for {
 _, tok, lit := s.Scan()
 if tok == token.EOF {
 break
 }
 if tok == token.IDENT {
 counts[lit]++
 }
}
// [為了閱讀清晰,移除部分代碼]
type pair struct {
 s string
 n int
}
pairs := make([]pair, 0, len(counts))
for s, n := range counts {
 pairs = Append(pairs, pair{s, n})rm -f 
}
sort.Slice(pairs, func(i, j int) bool {
 return pairs[i].n > pairs[j].n
})
for i := 0; i < len(pairs) && i < 5; i++ {
 fmt.Printf("%6d %sn", pairs[i].n, pairs[i].s)
}

為了不影響理解,有些代碼被刪除了。你可以在這里獲取完整的源碼。

哪些是最常用的標(biāo)識(shí)符?

我們來用這個(gè)程序分析一下 github.com/golang/go 上的代碼:

$ go install github.com/campoy/justforfunc/24-ast/scanner
$ scanner ~/go/src/**/*.go
 82163 v
 46584 err
 44681 Args
 43371 t
 37717 x

在短標(biāo)識(shí)符里,最常用的標(biāo)識(shí)符是字母 v 。那我們修改下代碼來計(jì)算一些長(zhǎng)標(biāo)識(shí)符:

for s, n := range counts {
 if len(s) >= 3 {
 pairs = append(pairs, pair{s, n})
 }
}

再來一次:

$ go install github.com/campoy/justforfunc/24-ast/scanner
$ scanner ~/go/src/**/*.go
 46584 err
 44681 Args
 36738 nil
 25761 true
 21723 AddArg

果不其然,err 和 nil 是最常見的標(biāo)識(shí)符,畢竟每個(gè)程序中都有 if err != nil 這樣的語句。 但 Args 出現(xiàn)頻度這么高怎么回事?

欲知詳情如何,且聽下回分解。


via: https://medium.com/@francesc/whats-the-most-common-identifier-in-go-s-stdlib-e468f3c9c7d9

作者:Francesc Campoy 譯者:kaneg 校對(duì):polaris1119

分享到:
標(biāo)簽:標(biāo)識(shí)符 語言
用戶無頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定