1.2命令行參數(shù)

命令行參數(shù)

os包提供了一些與操作系統(tǒng)交互的函數(shù)和變量聚磺,并且go對其做了一些封裝鹃栽。程序的命令行參數(shù)可以從os包的Args變量獲却┌狻;os包外部使用os.Args訪問該變量借尿。

os.Args變量是一個字符串的切片(slice)刨晴。學(xué)過Python的同學(xué)可以很容易理解切片的概念。現(xiàn)在先把切片s當(dāng)做數(shù)組元素序列路翻,序列的成長度動態(tài)變化狈癞,用s[i]訪問單個元素,用s[m:n]獲取子序列茂契。序列的元素個數(shù)為len(s)亿驾。和大多數(shù)編程語言類似,區(qū)間索引時账嚎,Go言里也采用左閉右開形式, 即莫瞬,區(qū)間包括第一個索引元素,不包括最后一個, 因?yàn)檫@樣可以簡化邏輯郭蕉。

os.Args的第一個元素疼邀,os.Args[0], 是命令本身的名字;其它的元素則是程序啟動時傳給它的參數(shù)召锈。s[m:n]形式的切片表達(dá)式旁振,產(chǎn)生從第m個元素到第n-1個元素的切片,下個例子用到的元素包含在os.Args[1:len(os.Args)]切片中涨岁。如果省略切片表達(dá)式的m或n拐袜,會默認(rèn)傳入0或len(s),因此前面的切片可以簡寫成os.Args[1:]梢薪。

下面是Unix里echo命令的一份實(shí)現(xiàn)蹬铺,echo把它的命令行參數(shù)打印成一行。程序?qū)肓藘蓚€包秉撇,用括號把它們括起來寫成列表形式, 而沒有分開寫成獨(dú)立的import聲明甜攀。兩種形式都合法,列表形式習(xí)慣上用得多琐馆。包導(dǎo)入順序并不重要规阀;gofmt工具格式化時按照字母順序?qū)Π判颉?/p>

// Echo1 prints its command-line arguments.
package main

import (
    "fmt"
    "os"
)

func main() {
    var s, sep string
    for i := 1; i < len(os.Args); i++ {
        s += sep + os.Args[i]
        sep = " "
    }
    fmt.Println(s)
}

注釋語句以//開頭。對于程序員來說瘦麸,//之后到行末之間所有的內(nèi)容都是注釋谁撼,被編譯器忽略。按照慣例滋饲,我們在每個包的包聲明前添加注釋厉碟;對于main package喊巍,注釋包含一句或幾句話,從整體角度對程序做個描述墨榄。

var聲明定義了兩個string類型的變量s和sep。變量會在聲明時直接初始化勿她。如果變量沒有顯式初始化袄秩,則被隱式地賦予其類型的零值(zero value),數(shù)值類型是0逢并,字符串類型是空字符串""之剧。這個例子里,聲明把s和sep隱式地初始化成空字符串砍聊。第2章再來詳細(xì)地講解變量和聲明背稼。

對數(shù)值類型,Go語言提供了常規(guī)的數(shù)值和邏輯運(yùn)算符玻蝌。而對string類型蟹肘,+運(yùn)算符連接字符串。所以表達(dá)式:

sep + os.Args[i]

表示連接字符串sep和os.Args俯树。程序中使用的語句:

s += sep + os.Args[i]

是一條賦值語句, 將s的舊值跟sep與os.Args[i]連接后賦值回s帘腹,等價于:

s = s + sep + os.Args[i]

運(yùn)算符+=是賦值運(yùn)算符(assignment operator),每種數(shù)值運(yùn)算符或邏輯運(yùn)算符许饿,如+或*阳欲,都有對應(yīng)的賦值運(yùn)算符。

echo程序可以每循環(huán)一次輸出一個參數(shù)陋率,這個版本卻是不斷地把新文本追加到末尾來構(gòu)造字符串球化。字符串s開始為空,即值為""瓦糟,每次循環(huán)會添加一些文本筒愚;第一次迭代之后,還會再插入一個空格菩浙,因此循環(huán)結(jié)束時每個參數(shù)中間都有一個空格锨能。這是一種二次加工(quadratic process),當(dāng)參數(shù)數(shù)量龐大時芍耘,開銷很大址遇,但是對于echo,這種情形不大可能出現(xiàn)斋竞。本章會介紹echo的若干改進(jìn)版倔约,下一章解決低效問題。

循環(huán)索引變量i在for循環(huán)的第一部分中定義坝初。符號:=是短變量聲明(short variable declaration)的一部分, 這是定義一個或多個變量并根據(jù)它們的初始值為這些變量賦予適當(dāng)類型的語句浸剩。下一章有這方面更多說明钾军。

自增語句i++給i加1;這和i += 1以及i = i + 1都是等價的绢要。對應(yīng)的還有i--給i減1吏恭。它們是語句,而不像C系的其它語言那樣是表達(dá)式重罪。所以j = i++非法樱哼,而且++和--都只能放在變量名后面,因此--i也非法剿配。

Go語言只有for循環(huán)這一種循環(huán)語句搅幅。for循環(huán)有多種形式,其中一種如下所示:

for initialization; condition; post {
    // zero or more statements
}

or循環(huán)三個部分不需括號包圍呼胚。大括號強(qiáng)制要求, 左大括號必須和post語句在同一行茄唐。

initialization語句是可選的,在循環(huán)開始前執(zhí)行蝇更。initalization如果存在沪编,必須是一條簡單語句(simple statement),即年扩,短變量聲明漾抬、自增語句、賦值語句或函數(shù)調(diào)用常遂。condition是一個布爾表達(dá)式(boolean expression)纳令,其值在每次循環(huán)迭代開始時計(jì)算。如果為true則執(zhí)行循環(huán)體語句克胳。post語句在循環(huán)體執(zhí)行結(jié)束后執(zhí)行平绩,之后再次對conditon求值。condition值為false時漠另,循環(huán)結(jié)束捏雌。

for循環(huán)的這三個部分每個都可以省略,如果省略initialization和post笆搓,分號也可以省略:

// a traditional "while" loop
for condition {
    // ...
}

如果連condition也省略了性湿,像下面這樣:

// a traditional infinite loop
for {
    // ...
}

這就變成一個無限循環(huán),盡管如此满败,還可以用其他方式終止循環(huán), 如一條break或return語句肤频。

for循環(huán)的另一種形式, 在某種數(shù)據(jù)類型的區(qū)間(range)上遍歷,如字符串或切片算墨。echo的第二版本展示了這種形式:

// Echo2 prints its command-line arguments.
package main

import (
    "fmt"
    "os"
)

func main() {
    s, sep := "", ""
    for _, arg := range os.Args[1:] {
        s += sep + arg
        sep = " "
    }
    fmt.Println(s)
}

每次循環(huán)迭代宵荒,range產(chǎn)生一對值;索引以及在該索引處的元素值。這個例子不需要索引报咳,但range的語法要求, 要處理元素, 必須處理索引侠讯。一種思路是把索引賦值給一個臨時變量, 如temp, 然后忽略它的值,但Go語言不允許使用無用的局部變量(local variables)暑刃,因?yàn)檫@會導(dǎo)致編譯錯誤厢漩。

Go語言中這種情況的解決方法是用空標(biāo)識符(blank identifier),即(也就是下劃線)岩臣×锸龋空標(biāo)識符可用于任何語法需要變量名但程序邏輯不需要的時候, 例如, 在循環(huán)里,丟棄不需要的循環(huán)索引, 保留元素值婿脸。大多數(shù)的Go程序員都會像上面這樣使用range和寫echo程序粱胜,因?yàn)殡[式地而非顯示地索引os.Args柄驻,容易寫對狐树。

echo的這個版本使用一條短變量聲明來聲明并初始化s和seps,也可以將這兩個變量分開聲明鸿脓,聲明一個變量有好幾種方式抑钟,下面這些都等價:

s := ""
var s string
var s = ""
var s string = ""

用哪種不用哪種,為什么呢野哭?第一種形式在塔,是一條短變量聲明,最簡潔拨黔,但只能用在函數(shù)內(nèi)部蛔溃,而不能用于包變量。第二種形式依賴于字符串的默認(rèn)初始化零值機(jī)制篱蝇,被初始化為""贺待。第三種形式用得很少,除非同時聲明多個變量零截。第四種形式顯式地標(biāo)明變量的類型麸塞,當(dāng)變量類型與初值類型相同時,類型冗余涧衙,但如果兩者類型不同哪工,變量類型就必須了。實(shí)踐中一般使用前兩種形式中的某個弧哎,初始值重要的話就顯式地指定變量的類型雁比,否則使用隱式初始化。

如前文所述撤嫩,每次循環(huán)迭代字符串s的內(nèi)容都會更新章贞。+=連接原字符串、空格和下個參數(shù),產(chǎn)生新字符串, 并把它賦值給s鸭限。s原來的內(nèi)容已經(jīng)不再使用蜕径,將在適當(dāng)時機(jī)對它進(jìn)行垃圾回收。

如果連接涉及的數(shù)據(jù)量很大败京,這種方式代價高昂兜喻。一種簡單且高效的解決方案是使用strings包的Join函數(shù):

func main() {
    fmt.Println(strings.Join(os.Args[1:], " "))
}

最后,如果不關(guān)心輸出格式赡麦,只想看看輸出值朴皆,或許只是為了調(diào)試,可以用Println為我們格式化輸出泛粹。

fmt.Println(os.Args[1:])

這條語句的輸出結(jié)果跟strings.Join得到的結(jié)果很像遂铡,只是被放到了一對方括號里。切片都會被打印成這種格式晶姊。

練習(xí) 1.1: 修改echo程序扒接,使其能夠打印os.Args[0],即被執(zhí)行命令本身的名字们衙。

package main

import (
    "fmt"
    "os"
)

func main() {
    s, sep := "", ""
    fmt.Println("file:",os.Args[0])
    for _, arg := range os.Args[1:] {
        s += sep + arg
        sep = " "
    }
    fmt.Println(s)
}

練習(xí) 1.2: 修改echo程序钾怔,使其打印每個參數(shù)的索引和值,每個一行蒙挑。

package main

import (
    "fmt"
    "os"
)

func main() {
    
    for idx, arg := range os.Args[1:] {
       fmt.Println(idx,arg)
    }
    
}

練習(xí) 1.3: 做實(shí)驗(yàn)測量潛在低效的版本和使用了strings.Join的版本的運(yùn)行時間差異宗侦。(1.6節(jié)講解了部分time包,11.4節(jié)展示了如何寫標(biāo)準(zhǔn)測試程序忆蚀,以得到系統(tǒng)性的性能評測矾利。)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市馋袜,隨后出現(xiàn)的幾起案子男旗,更是在濱河造成了極大的恐慌,老刑警劉巖桃焕,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剑肯,死亡現(xiàn)場離奇詭異,居然都是意外死亡观堂,警方通過查閱死者的電腦和手機(jī)让网,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來师痕,“玉大人溃睹,你說我怎么就攤上這事∫确兀” “怎么了因篇?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我竞滓,道長咐吼,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任商佑,我火速辦了婚禮锯茄,結(jié)果婚禮上茶没,老公的妹妹穿的比我還像新娘。我一直安慰自己喂急,他們只是感情好廊移,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布画机。 她就那樣靜靜地躺著,像睡著了一般响禽。 火紅的嫁衣襯著肌膚如雪芋类。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天贮竟,我揣著相機(jī)與錄音,去河邊找鬼技健。 笑死雌贱,一個胖子當(dāng)著我的面吹牛欣孤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼艾少!你這毒婦竟也來了翼悴?” 一聲冷哼從身側(cè)響起鹦赎,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤古话,失蹤者是張志新(化名)和其女友劉穎陪踩,沒想到半個月后肩狂,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體傻谁,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡谈飒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了瓤介。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖闻察,靈堂內(nèi)的尸體忽然破棺而出琢锋,到底是詐尸還是另有隱情,我是刑警寧澤钉嘹,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布跋涣,位于F島的核電站陈辱,受9級特大地震影響细诸,放射性物質(zhì)發(fā)生泄漏揍堰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一蝙眶、第九天 我趴在偏房一處隱蔽的房頂上張望幽纷。 院中可真熱鬧博敬,春花似錦偏窝、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽票编。三九已至栏妖,卻和暖如春奖恰,著一層夾襖步出監(jiān)牢的瞬間论泛,已是汗流浹背屁奏。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工坟瓢, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留犹撒,地道東北人识颊。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓清笨,卻偏偏與公主長得像抠艾,于是被迫代替她去往敵國和親首懈。 傳聞我的和親對象是個殘疾皇子谨敛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內(nèi)容

  • ¥開啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程炊甲,因...
    小菜c閱讀 6,444評論 0 17
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法卿啡,類相關(guān)的語法剑逃,內(nèi)部類的語法蛹磺,繼承相關(guān)的語法萤捆,異常的語法俗或,線程的語...
    子非魚_t_閱讀 31,662評論 18 399
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理臭觉,服務(wù)發(fā)現(xiàn),斷路器什乙,智...
    卡卡羅2017閱讀 134,696評論 18 139
  • 個人學(xué)習(xí)批處理的初衷來源于實(shí)際工作辅愿;在某個迭代版本有個BS(安卓手游模擬器)大需求点待,從而在測試過程中就重復(fù)涉及到...
    Luckykailiu閱讀 4,729評論 0 11
  • 今天在大巴車上聽了羅輯思維的兩段節(jié)目聋呢,一是愛因斯坦的崛起削锰,二是我為何不信中醫(yī)颅夺,隨手記一下碗啄。 1,科學(xué)共同體:科學(xué)共...
    咸魚茄子閱讀 524評論 0 0