go語言基礎知識整理
1.歷史拒談,只記錄屬于go的知識
2.安裝環(huán)境可以看官網(wǎng)
正文
1.小知識:本地瀏覽器打開go文檔
在終端輸入 godoc -http=:9090,之后再瀏覽器輸入地址localhost:9090即可,端口自己決定
mac下操作
export GOPATH=$HOME/goWorkSpace 將此路徑設置goPath,類似環(huán)境變量的東西
cd $GOPATH/src/hello 打開這個項目
go build 編譯當前路徑下的go項目
./hello 運行編譯好的hello項目
go install命令和go build類似,但有點區(qū)別
2.導入包 :
import "os"
同時導入多個包:
import (
"fmt"
"os"
"strings"
)
3.數(shù)據(jù)類型和結構
3.1 值類型
包括:字符串,整型,浮點型,布爾類型等
3.2變量
變量要顯示的聲明,編譯階段就能檢查到類型的正確性
聲明方式
//var 聲明一個或者多個變量
var a string = "My First String"
var b,c int = 1,2
var d = true //自動推到變量的類型
var e int //沒有初始值時,默認為'零值'
f := "short"
//:=聲明的變量,一般用在局部變量的聲明上,不作全局變量的命名
3.3 常量
支持字符,字符串,布爾和數(shù)值常量
聲明常量的方式const關鍵字
const s string = "hello world!"
const n = 300004
const d = 3e20 / n //類型會自動推導
3.3 For循環(huán)
for 是Go中唯一的循環(huán)結構,常用的三種格式
i := 1
for i < 3{
fmt.Println(i)
i = i + 1
}
for j:=7;j<=9;j++{
fmt.Println(j)
}
for{
fmt.Println("For Loop")
break
}
3.4 if else 分支
if true{
fmt.Println("true")
}else{
fmt.Println("false")
}
if number := 6;number<0{
fmt.Println(number,"是負數(shù)")
}else if number<10{
fmt.Println("一位數(shù)")
}else{
fmt.Println("多位數(shù)")
}
3.4 switch分支
i := 2
fmt.Print(i,"is equal ")
switch i {
case 1:
fmt.Println("one")
case 2:
fmt.Println("two")
case 3:
fmt.Println("three")
}
switch time.Now().Weekday(){
case time.Saturday,time.Sunday:
fmt.Println("it is the weekend")
default:
fmt.Println("it is weekday")
}
t := time.Now()
switch{
fmt.Println("Before noon")
default:
fmt.Println("After Noon")
}
3.5 數(shù)組:一個固定長度的數(shù)列
var arr [5]int //創(chuàng)建大小為5,元素類型int的數(shù)組,默認值都是0
fmt.Println("empty:",a) //[0,0,0,0,0]
a[4] = 100 //賦值
len(a) //數(shù)組長度
arr1 := [5]int{1,2,3,4,5} //有初始值的數(shù)組
//二維數(shù)組
var arr3 [2][3]int
for i:=0;i<2;i++{
for j:=0;j<3;j++{
arr3[i][j] = i * j
}
}
fmt.Println(arr3)
3.6 切片 slice,和數(shù)組類似,但是更加強大,是可變的數(shù)組,也是一個關鍵的數(shù)據(jù)類型
slice := make([]string,3) //必須用slice來初始化,申請內(nèi)存
fmt.Println(slice)
s[0] = "a"
s[1] = "b"
s[2] = "c"
len(slice) //3長度
slice.append(slice,"d")
slice.append(slice,"e","f") //添加元素
//復制
c := make([]string,len(slice))
copy(c,slice) //復制一個slice的元素到另外一個slice
//截取部分元素
slice2 := slice[2,4] //slice[low:high]切片操作,不包含high的元素
//二維的切片
twoDSlice := make([][]int,3)
for i:=0;i<3;i++{
innerLen := i+1
twoDSlice[i] = make([]int,innerLen)
for j:=0;j<innerLen;j++{
twoDSlice[i][j] = i + j
}
}
fmt.Println("twoDSlice:",twoDSlice);
3.7 關聯(lián)數(shù)組(字典)
m := make(map[string]int)
//一個空map,使用make創(chuàng)建
//賦值
m["k1"] = 7
m["k2"] = 16
len(m) //鍵值對數(shù)目
delete(m,"k2") //刪除某個元素
_,ok := m["k2"] //ok當有值時為true,可以判斷是否有值,防止nil引起的崩潰
//另外一種初始化方式
m2 := map[string]int{"k1":2,"k2":4}
3.8 Range遍歷
numbers := []int{2,3,4}
sum := 0
//數(shù)組,slice的Range遍歷
for index,num := range numbers{
sum += num
fmt.Println(index)
}
//map遍歷
m := map[string]string{"k1":v1,"k2":v2}
for k,v := range m{
fmt.Printf("%s-->$s \n",k,v)
}
//遍歷字符串
for i,word := range "Hello world!"{
fmt.Println(i,n)
}
3.9 函數(shù)
//一個返回值
func sub(a int,b int)(int){
return a-b
}
//多個返回值:其實是元組
func values(a int)(int,int){
return a,0
}
4.0 參數(shù)可變函數(shù)
7月4日
11.0 Defer:用來確保一個函數(shù)在程序結束之前執(zhí)行.類似其他語言的ensure和finally
func main(){
f := createFile("/temp.defer.txt")
defer closeFile(f) //最后會執(zhí)行關閉文件夾操作
writeFile(f)
}
func createFile(p string) *os.File{
fmt.Println("creating")
f,err := os.Create(p)
if err != nil{
panic(err)
}
return f
}
func writeFile(f *os.File){
fmt.Println("writing")
fmt.Fprintln(f,"data")
}
func closeFile(f *os.File){
fmt.Println("closing")
f.Close()
}
11.1 組合函數(shù):我們經(jīng)常需要程序在數(shù)據(jù)集上執(zhí)行操作,比如選擇滿足給定條件的所有項,或者將所有的項通過一個自定義函數(shù)映射到一個新的集合上。
在某些語言中,會習慣使用泛型。Go 不支持泛型,在 Go 中,當你的程序或者數(shù)據(jù)類型需要時,通常是通過組合的方式來提供操作函數(shù)。
這是一些 strings 切片的組合函數(shù)示例。你可以使用這些例子來構建自己的函數(shù)。注意有時候,直接使用內(nèi)聯(lián)組合操作代碼會更清晰,而不是創(chuàng)建并調(diào)用一個幫助函數(shù)
//獲取目標字符串t出現(xiàn)的第一個索引位置,沒有就返回-1
func Index(vs []sring,t string) int{
for i,v := range vs{
if v == t{
return i
}
}
return -1
}
func Include(vc []string,t string) bool{
return Index(vc,t) >= 0
}
func Any(vc []string,f func (string)bool) bool{
for _,v := range vc{
if f(v){
return true
}
}
return false
}
func All(vs []string,f func(string) bool) bool{
for _,v := range vs{
if !f(v){
return false
}
}
return true
}
//滿足條件的元素
func Filter(vs []string,f func(string)bool) []string{
vcf := make([]string,0)
for _,v := range vs{
if f(v){
vsf = append(vsf,v)
}
}
return vsf
}
//返回一個對原始切片中所有字符串執(zhí)行函數(shù) f 后的新切片。
func Map(vs []string,f func(string)bool) []string{
vsm := make([]string,len(vs))
for i,v := range vs{
vsm[i] = f(v)
}
return vsm;
}
func main(){
var strs = []string{"peach", "apple", "pear", "plum"}
//這里試試這些組合函數(shù)。
//下面的例子都是用的匿名函數(shù),但是你也可以使用類型正確的命名函數(shù)
fmt.Println(Index(strs, "pear"))
fmt.Println(Include(strs, "grape"))
fmt.Println(Any(strs, func(v string) bool {
return strings.HasPrefix(v, "p")
}))
fmt.Println(All(strs, func(v string) bool {
return strings.HasPrefix(v, "p")
}))
fmt.Println(Filter(strs, func(v string) bool {
return strings.Contains(v, "e")
}))
fmt.Println(Map(strs, strings.ToUpper))
}
11.2 字符串函數(shù):操作字符串
func main(){
var p = fmt.Println
p("Contains:",strings.Contains("test","es"))
p("Count:",strings.Count("test","t"))
p("HasPrefix:",strings.HasPrefix("test","te"))
p("HasSuffix:",strings.HasSuffix("test","st"))
p("Index",strings.Index("test","s"))
p("Join:", strings.Join([]string{"a", "b"}, "-"))
p("Repeat:", strings.Repeat("a", 5))
p("Replace:", strings.Replace("foo", "o", "0", -1))
p("Replace:", strings.Replace("foo", "o", "0", 1))
p("Split:", strings.Split("a-b-c-d-e", "-"))
p("ToLower:", strings.ToLower("TEST"))
p("ToUpper:", strings.ToUpper("test"))
p()
p("Len:",len("hello"))
p("Char:","hello"[2])
}
11.3 字符串格式化
type point{
x,y int
}
func main(){
p := point{1,2}
fmt.Printf("%v \n",p) //打印了一個對象
fmt.Printf("%+v \n",p) //包括字段名一起打印出
fmt.Printf("%#v \n",p) //值的運行源代碼片段
fmt.Printf("%T \n",p) //值的類型
fmt.Printf("%t \n",true) //bool值
fmt.Printf("%d \n",123)
fmt.Printf("%b \n",12) //二進制
fmtPrintf("%c \n",21)
fmt.Printf("%x \n",456) //十六進制
fmt.Printf("%f \n",889.1) //浮點數(shù)
fmt.Printf("%e \n",123400000.0)
fmt.Printf("%E \n",123400000.0) //科學計數(shù)法的形式表示
fmt.Printf("%s \n","\"string\"")
fmt.Printf("%q \n","\"string\"") //包含雙引號
fmt.Printf("%x","hex") //base-16編碼
fmt.Printf("%p \n",&p) //輸出一個指針的值
fmt.Printf("|%6d|%6.2f| \n",12,234.0) //控制位數(shù),不足的空格代替,默認右對齊
fmt.Printf("|%-6.2f|%-6.2f\n",1.2,123.2) //左對齊-
//控制字符串的寬度
fmt.Printf("|%6s|%6s| \n","hello","world")
//格式化返回一個字符串,不輸出
s := fm.Sprintf(" a %s","string")
fmt.Println(s)
//Fprintf格式化并輸出到io.Writers而不是os.Stdout
fmt.Fprintf(os.Stderr," an %s \n","error")
}
正則表達式
12.1 Go內(nèi)置的正則表達式
import "regexp"
func main(){
match,_ := regexp.MatchString("p([a-z]+)ch","peach")
fmt.Println(match) //true
//優(yōu)化的regexp結構
r,_ := regexp.Compile("p([a-z+]ch)")
fmt.Println(r.MatchString("peach"))
//fmt.Println(r.FindString("peach punch")) //查找匹配字符串的
fmt.Println(r.FindStringIndex("peach punch"))//得到的是匹配內(nèi)容的起始和結束的下標
fmt.Println(r.FindAllString("peadch punch pinch")) //返回所有的匹配項
fmt.Println(r.FindStringSubmatchIndex("peach punch"))
//返回完全匹配和局部匹配的索引位置
fmt.Println(r.FindAllStringSubmatchIndex(
"peach punch pinch", -1))
//All對應到上面的所有函數(shù)
fmt.Println(r.Match([]byte("peach")))
r = regexp.MustCompile("p([a-z]+)ch") //Compile的變體
fmt.Println(r)
fmt.Println(r.ReplaceAllString("a peach","<fruit>")) //替換
in := []byte("a peach")
out := r.ReplaceAllFunc(in,bytes.ToUpper)
fmt.Println(string(out))
//Func變量允許傳遞匹配內(nèi)容到一個給定的函數(shù)中
}
JSON:
12.1 Go內(nèi)置的JSON編碼支持,包括內(nèi)置或者自定義類型與json數(shù)據(jù)之間的轉(zhuǎn)換
import "encoding/json"
import "fmt"
import "os"
//將使用這兩個結構體來演示自定義類型的編碼和解碼。
type Response1 struct {
Page int
Fruits []string
}
type Response2 struct {
Page int `json:"page"`
Fruits []string `json:"fruits"` //自定義json數(shù)據(jù)鍵名
}
func main(){
//基本數(shù)據(jù)類型-->JSON編碼
bolB,_ := json.Marshal(true)
fmt.Println(string(bolB))
intB,_ := json.Marshal(12)
fmt.Println(string(intB))
slc := []string{"1","2","3"}
slcB,_ := json.Marshal(slc)
fmt.Println(slcB)
mapD := map[string]int{"a":2,"b":1}
mapB,_ := json.Marshal(mapD)
fmt.Println(mapB)
resp1 := &Response1{
Page:1,
Fruits:[]string{"apple","peach","pear"}
}
resp1B,_ := json.MArshal(resp1)
fmt.Println(string(resp1B))
resp2 := &Response2{
Page:1,
Fruits:[]string{"apple","pear","peach"}
}
resp2B,_ := json.Marshal(resp2)
fmt.Println(resp2B)
//解碼JSON數(shù)據(jù)為Go值的過程
byt := []byte(`{"num":87.2,"strs":["a","c"]}`)
var data map[string]interface{} //任意類型的值
if err := json.Unmarshal(byt,&data);err != nil{
panic(err)
}
fmt.Println(data) //打印
//取值
num := data["num"].(float64)
fmt.Println(num)
strs := data["strs"].(interface{})
str1 := strs[0].(string)
fmt.Println(str1)
//解碼json值為自定義的類型
str := '{"page":1,"fruits":["apple","peach"]}'
res := &Response2{}
json.Unmarshal([]byte(str),&res)
fmt.Println(res)
fmt.Println(res.Fruits[0])
//我們經(jīng)常使用 byte 和 string 作為使用標準輸出時數(shù)據(jù)和 JSON 表示之間的中間值。我們也可以和os.Stdout 一樣,直接將 JSON 編碼直接輸出至 os.Writer流中,或者作為 HTTP 響應體。
enc := json.NewEncoder(os.Stdout)
d := map[string]int{"apple":2,"peach":987}
enc.Encode(d)
}
時間
Go對時間和時間段提供了大量的支持
func main(){
now := time.Now()
fmt.Println(now) //2016-06-31 15:50:13.793654 +0000 UTC
then := time.Date(2016,11,17,20,34,58,651387237,time.UTC) //構建一個time
//取出時間的各個部分
fmt.Println(then.Year())
fmt.Println(then.Month())
fmt.Println(then.Day())
fmt.Println(then.Hour())
fmt.Println(then.Minute())
fmt.Println(then.Second())
fmt.Println(then.Nanosecond())
fmt.Println(then.Location())
fmt.Println(then.Weekday())
//比較
fmt.Println(then.Before(now))
fmt.Println(then.After(now))
fmt.Println(then.Equal(now))
diff := now.Sub(then)
fmt.Println(diff) //兩個時間點的duration
fmt.Println(diff.Hours())
fmt.Println(diff.Minutes())
fmt.Println(diff.Seconds())
fmt.Println(diff.Nanoseconds())
fmt.Println(then.Add(diff)) //時間往后移
fmt.Println(then.Add(-diff)) //時間往前移
}
12.2 時間戳:獲取Unix 時間的秒數(shù),毫秒數(shù)或者微秒數(shù)
now := time.Now()
secs := now.Unix()
nanos := now.UnixNano()
fmt.Println(now)
millis := nanos / 1000000
fmt.Println(secs)
//將秒數(shù)或者毫秒數(shù)轉(zhuǎn)為時間
fmt.Println(time.Unix(secs,0))
fmt.Println(time.Unix(0,nanos))
12.3 時間的格式化和解析
Go支持基于描述模板的時間格式化和解析
t := time.Now()
//按照RFC3339進行格式化
fmt.Println(t.Forma(time.RFC3339))
//時間解析格式
t1,e := time.Parse(
time.RFC3339,
"2013-12-02T22:09:12+00:00"
)
fmt.Println(t1) //2013-12-02 22:09:12 +0000 +0000
fmt.Println(t.Format("2:12PM"))
fmt.Println(t.Format("Mon Jan _2 12:22:12 2091"))
p(t.Format("3:04PM"))
p(t.Format("Mon Jan _2 15:04:05 2006"))
p(t.Format("2006-01-02T15:04:05.999999-07:00"))
form := "3 04 PM"
t2, e := time.Parse(form, "8 41 PM")
p(t2)
//Format 和 Parse 使用基于例子的形式來決定日期格式,一般你只要使用 time 包中提供的模式常量就行了,但是你也可以實現(xiàn)自定義模式。模式必須使用時間 Mon Jan 2 15:04:05 MST 2006來指定給定時間/字符串的格式化/解析方式。時間一定要按照如下所示:2006為年,15 為小時,Monday 代表星期幾,等等。
fmt.Printf("%d-%02d-%02dT%02d:%02d:%02d-00:00\n",
t.Year(), t.Month(), t.Day(),
t.Hour(), t.Minute(), t.Second())
//對于純數(shù)字表示的時間,你也可以使用標準的格式化字符串來提出出時間值得組成。
ansic := "Mon Jan _2 15:04:05 2006"
_, e = time.Parse(ansic, "8:41PM")
p(e)
//Parse 函數(shù)在輸入的時間格式不正確是會返回一個錯誤。
12.3 隨機數(shù)
func main(){
//rand.Intn(m),隨機整數(shù),0.0 <= n <= m
fmt.Println(rand.Intn(170),",")
fmt.Println(rand.Intn(21))
//rand.Float64() 0.0 -- 1.0
//偽隨機數(shù)生成器
s1 := rand.NewSource(40)
r1 := rand.New(s1)
//如果使用相同的種子生成的隨機數(shù)生成器,將會產(chǎn)生相同的隨機數(shù)序列。
s2 := rand.NewSource(40)
r2 := rand.New(s2)
fmt.Print(r2.Intn(100), ",")
fmt.Print(r2.Intn(100))
fmt.Println()
}
12.4 數(shù)字解析:數(shù)字字符串轉(zhuǎn)為數(shù)字
f,_ := strconv.ParseFloat("12.3",64) //64解析的位數(shù)
/*
ParseInt
ParseUint
Atoi //基礎的10進制轉(zhuǎn)換函數(shù)
//如果數(shù)字字符串不是數(shù)字,會報錯
*/
12.5 URL解析
func main(){
s := "postgres://user:pass@host.com:5432/path?k=v#f"
//我們將解析這個 URL 示例,它包含了一個 scheme,認證信息,主機名,端口,路徑,查詢參數(shù)和片段。
u, err := url.Parse(s)
if err != nil {
panic(err)
}
//解析這個 URL 并確保解析沒有出錯。
fmt.Println(u.Scheme)
//直接訪問 scheme。
fmt.Println(u.User)
fmt.Println(u.User.Username())
p, _ := u.User.Password()
fmt.Println(p)
//User 包含了所有的認證信息,這里調(diào)用 Username和 Password 來獲取獨立值。
fmt.Println(u.Host)
h := strings.Split(u.Host, ":")
fmt.Println(h[0])
fmt.Println(h[1])
//Host 同時包括主機名和端口信息,如過端口存在的話,使用 strings.Split() 從 Host 中手動提取端口。
fmt.Println(u.Path)
fmt.Println(u.Fragment)
//這里我們提出路徑和查詢片段信息。
fmt.Println(u.RawQuery)
m, _ := url.ParseQuery(u.RawQuery)
fmt.Println(m)
fmt.Println(m["k"][0])
//要得到字符串中的 k=v 這種格式的查詢參數(shù),可以使用 RawQuery 函數(shù)。你也可以將查詢參數(shù)解析為一個map。已解析的查詢參數(shù) map 以查詢字符串為鍵,對應值字符串切片為值,所以如何只想得到一個鍵對應的第一個值,將索引位置設置為 [0] 就行了。
}
12.6 SHA1散列
SHA1 散列經(jīng)常用生成二進制文件或者文本塊的短標識。例如,git 版本控制系統(tǒng)大量的使用 SHA1 來標識受版本控制的文件和目錄
//Go 在多個 crypto/* 包中實現(xiàn)了一系列散列函數(shù)。
func main() {
s := "sha1 this string"
h := sha1.New()
//產(chǎn)生一個散列值得方式是 sha1.New(),sha1.Write(bytes),然后 sha1.Sum([]byte{})。這里我們從一個新的散列開始。
h.Write([]byte(s))
//寫入要處理的字節(jié)。如果是一個字符串,需要使用[]byte(s) 來強制轉(zhuǎn)換成字節(jié)數(shù)組。
bs := h.Sum(nil)
//這個用來得到最終的散列值的字符切片。Sum 的參數(shù)可以用來在現(xiàn)有的字符切片追加額外的字節(jié)切片:一般不需要。
fmt.Println(s)
fmt.Printf("%x\n", bs)
//SHA1 值經(jīng)常以 16 進制輸出,例如在 git commit 中。使用%x 來將散列結果格式化為 16 進制字符串。
}
//輸出結果
sha1 this string
cf23df2207d99a74fbe169e3eba035e633b65d94
可以使用和上面相似的方式來計算其他形式的散列值。例如,計算 MD5 散列,引入 crypto/md5 并使用md5.New()方法。
12.7 base64編碼
import b64 "encoding/base64"
import "fmt"
//引入 encoding/base64 包并使用名稱 b64代替默認的 base64.
func main() {
data := "abc123!?$*&()'-=@~"
//這是將要編解碼的字符串。
sEnc := b64.StdEncoding.EncodeToString([]byte(data))
fmt.Println(sEnc)
//Go 同時支持標準的和 URL 兼容的 base64 格式。編碼需要使用 []byte 類型的參數(shù),所以要將字符串轉(zhuǎn)成此類型。
sDec, _ := b64.StdEncoding.DecodeString(sEnc)
fmt.Println(string(sDec))
fmt.Println()
//解碼可能會返回錯誤,如果不確定輸入信息格式是否正確,那么,你就需要進行錯誤檢查了。
uEnc := b64.URLEncoding.EncodeToString([]byte(data))
fmt.Println(uEnc)
uDec, _ := b64.URLEncoding.DecodeString(uEnc)
fmt.Println(string(uDec))
//使用 URL 兼容的 base64 格式進行編解碼。
}
標準 base64 編碼和 URL 兼容 base64 編碼的編碼字符串存在稍許不同(后綴為 + 和 -),但是兩者都可以正確解碼為原始字符串。
12.8 讀取文件
import (
"bufio"
"fmt"
"io"
"io/ioutil"
"os"
)
//讀取文件需要經(jīng)常進行錯誤檢查
func check(e error) {
if e != nil {
panic(e)
}
}
func main(){
data,err := ioutil.ReadFile("/tmp/data") //讀取文件內(nèi)容到內(nèi)存中
check(err)
fmt.Println(string(data))
b1 := make([]byte,5) //最多讀取5個字節(jié)
n1,err := f.Read(b1)
check(err)
fmt,Printf("%d bytes: %s\n",n1,string(b1))
//從一個文件中已知的位置開始進行讀取
o2,err := f.Seek(6,0)
check(err)
b2 := make([]byte,2)
n2,err := f.Read(b2)
check(err)
fmt.Printf("%d bytes @ %d: %s\n",n2,o2,string(b2))
//io包提供了一些幫助進行文件讀取的函數(shù),ReadAtLeast 得到一個更更好的實現(xiàn)。
o3,err := f.Seek(6,0)
check(err)
b3 := make([]byte,2)
n3,err := io.ReadAtLeast(f,b3,2)
check(err)
fmt.Println("%d bytes @ %d: %s \n",n3,o3,string(b3))
_,err = f.Seek(0,0)
check(err)
//緩沖的讀取,性能好
r4 := bufio.NewReader(f)
b4,err := r4.Peek(5)
check(err)
fmt.Printf("5 bytes:%s \n",string(b4))
f.Close()//關閉文件
}
12.9 寫文件
import (
"bufio"
"fmt"
"io/ioutil"
"os"
)
func check(e error) {
if e != nil {
panic(e)
}
}
func main(){
//寫入一個字符串到文件
d1 := []byte("hello\ngo\n")
err := ioutil.WriteFile("/tmp/data",d1,0644)
check(err)
//先打開一個文件
f,err := os.Create("/tmp/data2")
check(err)
defer f.Close() //最后記得關閉文件
//寫入切片
d2 := []byte{12,3,2,1,32,55}
n2,err := f.Write(d2)
check(err)
fmt.Printf("wrote %d bytes\n",n2)
n3,err := f.WriteString("writes\n")
fmt.Printf("wrote %d bytes\n",n3)
s.Sync)//將緩沖區(qū)的數(shù)據(jù)寫入硬盤
//帶有緩沖的寫入器
w := bufio.NewWriter(f)
n4,err := w.WriteString("buffered\n")
fmt.Printf("wrote %d bytes\n",n4)
w.Flush()//確保所有的緩存操作已寫入底層寫入器
}
13.0 行為過濾器
import (
"bufio"
"fmt"
"os"
"strings"
)
func main(){
//帶有緩沖的輸入
scanner := bufio.NewScanner(os.Stdin)
for scanner.Scan(){
ucl := strings.ToUpper(scanner.Text())
fmt.Println(ucl)
}
if err := scanner.Err();err != nil{
fmt.Println(ucl)
}
//檢查Scan的錯誤.
if err := scanner.Err();err != nil{
fmt.Fprintln(os.Stderr,"error:",err)
os.Exit(1)
}
}
13.1 命令行參數(shù)
命令行參數(shù)是指定程序運行參數(shù)的一個常見方式。例如,go run hello.go,程序 go 使用了 run 和 hello.go兩個參數(shù)。
import "fmt"
import "os"
func main(){
//os.Args 提供原始命令行參數(shù)訪問功能。注意,切片中的第一個參數(shù)是該程序的路徑,并且 os.Args[1:]保存所有程序的的參數(shù)。
argsWithProg := os.Args
argsWithoutProg := os.Args[1:]
arg := os.Args[3]
//你可以使用標準的索引位置方式取得單個參數(shù)的值。
fmt.Println(argsWithProg)
fmt.Println(argsWithoutProg)
fmt.Println(arg)
}
13.2 命令行標志(參數(shù))
命令行標志是命令行程序指定選項的常用方式。例如,在wc -l 中,這個 -l 就是一個命令行標志。
import "flag"
import "fmt"
//Go 提供了一個 flag 包,支持基本的命令行標志解析。我們將用這個包來實現(xiàn)我們的命令行程序示例。
func main() {
wordPtr := flag.String("word", "foo", "a string")
//基本的標記聲明僅支持字符串、整數(shù)和布爾值選項。這里我們聲明一個默認值為 "foo" 的字符串標志 word并帶有一個簡短的描述。這里的 flag.String 函數(shù)返回一個字符串指針(不是一個字符串值),在下面我們會看到是如何使用這個指針的。
numbPtr := flag.Int("numb", 42, "an int")
boolPtr := flag.Bool("fork", false, "a bool")
//使用和聲明 word 標志相同的方法來聲明 numb 和 fork 標志。
var svar string
flag.StringVar(&svar, "svar", "bar", "a string var")
//用程序中已有的參數(shù)來聲明一個標志也是可以的。注意在標志聲明函數(shù)中需要使用該參數(shù)的指針。
flag.Parse()
//所有標志都聲明完成以后,調(diào)用 flag.Parse() 來執(zhí)行命令行解析。
fmt.Println("word:", *wordPtr)
fmt.Println("numb:", *numbPtr)
fmt.Println("fork:", *boolPtr)
fmt.Println("svar:", svar)
fmt.Println("tail:", flag.Args())
//這里我們將僅輸出解析的選項以及后面的位置參數(shù)。注意,我們需要使用類似 *wordPtr 這樣的語法來對指針解引用,從而得到選項的實際值。
}
測試這個程序前,最好將這個程序編譯成二進制文件,然后再運行這個程序
13.3 環(huán)境變量
環(huán)境變量是一個在為 Unix 程序傳遞配置信息的普遍方式。讓我們來看看如何設置,獲取并列舉環(huán)境變量。
package main
import "os"
import "strings"
import "fmt"
func main() {
os.Setenv("FOO", "1")
fmt.Println("FOO:", os.Getenv("FOO"))
fmt.Println("BAR:", os.Getenv("BAR"))
//使用 os.Setenv 來設置一個鍵值對。使用 os.Getenv獲取一個鍵對應的值。如果鍵不存在,將會返回一個空字符串。
fmt.Println()
for _, e := range os.Environ() {
pair := strings.Split(e, "=")
fmt.Println(pair[0])
}
//使用 os.Environ 來列出所有環(huán)境變量鍵值對。這個函數(shù)會返回一個 KEY=value 形式的字符串切片。你可以使用strings.Split 來得到鍵和值。這里我們打印所有的鍵。
}