Go基础知识整理

go语言基础知识整理

1.历史拒谈,只记录属于go的知识
2.安装环境可以看官网

正文

1.小知识:本地浏览器打开go文档
在终端输入 godoc -http=:9090,之后再浏览器输入地址localhost:9090即可,端口自己决定

mac下操作
export GOPATH=$HOME/goWorkSpace 将此路径设置goPath,类似环境变量的东西

cd $GOPATH/src/hello 打开这个项目
go build 编译当前路径下的go项目
./hello 运行编译好的hello项目
go install命令和go build类似,但有点区别

2.导入包 :
import "os"

同时导入多个包:
import (
"fmt"
"os"
"strings"
)

3.数据类型和结构
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 常量

支持字符,字符串,布尔和数值常量

声明常量的方式const关键字

const s string = "hello world!"
const n = 300004
const d = 3e20 / n //类型会自动推导

3.3 For循环

for 是Go中唯一的循环结构,常用的三种格式

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,"是负数")
}else if number<10{
    fmt.Println("一位数")
}else{
    fmt.Println("多位数")
}

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 数组:一个固定长度的数列

var arr [5]int //创建大小为5,元素类型int的数组,默认值都是0
fmt.Println("empty:",a) //[0,0,0,0,0]

a[4] = 100 //赋值
len(a)       //数组长度

arr1 := [5]int{1,2,3,4,5} //有初始值的数组

//二维数组

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,和数组类似,但是更加强大,是可变的数组,也是一个关键的数据类型

    slice := make([]string,3) //必须用slice来初始化,申请内存
    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

3.7 关联数组(字典)

m := make(map[string]int)
//一个空map,使用make创建

//赋值
m["k1"] = 7
m["k2"] = 16

len(m) //键值对数目
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

//数组,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 函数

//一个返回值
func sub(a int,b int)(int){
    return a-b
}

//多个返回值:其实是元组
func values(a int)(int,int){
    return a,0
}

4.0 参数可变函数



7月4日

11.0 Defer:用来确保一个函数在程序结束之前执行.类似其他语言的ensure和finally

func main(){
    f := createFile("/temp.defer.txt")
    defer closeFile(f) //最后会执行关闭文件夹操作
    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 组合函数:我们经常需要程序在数据集上执行操作,比如选择满足给定条件的所有项,或者将所有的项通过一个自定义函数映射到一个新的集合上。

在某些语言中,会习惯使用泛型。Go 不支持泛型,在 Go 中,当你的程序或者数据类型需要时,通常是通过组合的方式来提供操作函数。

这是一些 strings 切片的组合函数示例。你可以使用这些例子来构建自己的函数。注意有时候,直接使用内联组合操作代码会更清晰,而不是创建并调用一个帮助函数

//获取目标字符串t出现的第一个索引位置,没有就返回-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
}

//返回一个对原始切片中所有字符串执行函数 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"}
    //这里试试这些组合函数。

//下面的例子都是用的匿名函数,但是你也可以使用类型正确的命名函数
    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 字符串函数:操作字符串

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) //浮点数
    fmt.Printf("%e \n",123400000.0)
    fmt.Printf("%E \n",123400000.0) //科学计数法的形式表示
    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) //控制位数,不足的空格代替,默认右对齐
    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内置的正则表达式

import "regexp"

func main(){
    match,_ := regexp.MatchString("p([a-z]+)ch","peach")
    fmt.Println(match) //true
    
    //优化的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"))//得到的是匹配内容的起始和结束的下标
    
    fmt.Println(r.FindAllString("peadch punch pinch")) //返回所有的匹配项
    
     fmt.Println(r.FindStringSubmatchIndex("peach punch"))
    //返回完全匹配和局部匹配的索引位置
    
    fmt.Println(r.FindAllStringSubmatchIndex(
        "peach punch pinch", -1))
    //All对应到上面的所有函数
    
    fmt.Println(r.Match([]byte("peach")))
    
    r = regexp.MustCompile("p([a-z]+)ch") //Compile的变体
    fmt.Println(r)
    
    fmt.Println(r.ReplaceAllString("a peach","")) //替换
    
    in := []byte("a peach")
    out := r.ReplaceAllFunc(in,bytes.ToUpper)
    fmt.Println(string(out))
    //Func变量允许传递匹配内容到一个给定的函数中
}


JSON:

12.1 Go内置的JSON编码支持,包括内置或者自定义类型与json数据之间的转换

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数据键名
}

func main(){
    //基本数据类型-->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数据为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])
    
    //我们经常使用 byte 和 string 作为使用标准输出时数据和 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 时间的秒数,毫秒数或者微秒数

now := time.Now()
secs := now.Unix()
nanos := now.UnixNano()
fmt.Println(now)


millis := nanos / 1000000

fmt.Println(secs)

//将秒数或者毫秒数转为时间

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 包中提供的模式常量就行了,但是你也可以实现自定义模式。模式必须使用时间 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())
    //对于纯数字表示的时间,你也可以使用标准的格式化字符串来提出出时间值得组成。

    ansic := "Mon Jan _2 15:04:05 2006"
    _, e = time.Parse(ansic, "8:41PM")
    p(e)
    //Parse 函数在输入的时间格式不正确是会返回一个错误。
    

12.3 随机数

func main(){

    //rand.Intn(m),随机整数,0.0 <= n <= m
    fmt.Println(rand.Intn(170),",")
    fmt.Println(rand.Intn(21))
    
    //rand.Float64() 0.0 -- 1.0
    
    //伪随机数生成器
    s1 := rand.NewSource(40)
    r1 := rand.New(s1)
    
    //如果使用相同的种子生成的随机数生成器,将会产生相同的随机数序列。
    s2 := rand.NewSource(40)
    r2 := rand.New(s2)
    fmt.Print(r2.Intn(100), ",")
    fmt.Print(r2.Intn(100))
    fmt.Println()
    
}

12.4 数字解析:数字字符串转为数字

f,_ := strconv.ParseFloat("12.3",64) //64解析的位数
/*
    ParseInt
    ParseUint
    Atoi //基础的10进制转换函数
    
    //如果数字字符串不是数字,会报错
*/

12.5 URL解析

func main(){
    s := "postgres://user:[email protected]:5432/path?k=v#f"
    //我们将解析这个 URL 示例,它包含了一个 scheme,认证信息,主机名,端口,路径,查询参数和片段。

    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 包含了所有的认证信息,这里调用 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 这种格式的查询参数,可以使用 RawQuery 函数。你也可以将查询参数解析为一个map。已解析的查询参数 map 以查询字符串为键,对应值字符串切片为值,所以如何只想得到一个键对应的第一个值,将索引位置设置为 [0] 就行了。
}

12.6 SHA1散列
SHA1 散列经常用生成二进制文件或者文本块的短标识。例如,git 版本控制系统大量的使用 SHA1 来标识受版本控制的文件和目录


//Go 在多个 crypto/* 包中实现了一系列散列函数。

func main() {
    s := "sha1 this string"

    h := sha1.New()
    //产生一个散列值得方式是 sha1.New(),sha1.Write(bytes),然后 sha1.Sum([]byte{})。这里我们从一个新的散列开始。

    h.Write([]byte(s))
    //写入要处理的字节。如果是一个字符串,需要使用[]byte(s) 来强制转换成字节数组。

    bs := h.Sum(nil)
    //这个用来得到最终的散列值的字符切片。Sum 的参数可以用来在现有的字符切片追加额外的字节切片:一般不需要。

    fmt.Println(s)
    fmt.Printf("%x\n", bs)
    //SHA1 值经常以 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 类型的参数,所以要将字符串转成此类型。

    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"
)

//读取文件需要经常进行错误检查
func check(e error) {
    if e != nil {
        panic(e)
    }
}


func main(){
    data,err := ioutil.ReadFile("/tmp/data") //读取文件内容到内存中
    check(err)
    fmt.Println(string(data))
    
    b1 := make([]byte,5) //最多读取5个字节
    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包提供了一些帮助进行文件读取的函数,ReadAtLeast 得到一个更更好的实现。

    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)//将缓冲区的数据写入硬盘
    
    //带有缓冲的写入器
    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 命令行参数
命令行参数是指定程序运行参数的一个常见方式。例如,go run hello.go,程序 go 使用了 run 和 hello.go两个参数。

import "fmt"
import "os"

func main(){

//os.Args 提供原始命令行参数访问功能。注意,切片中的第一个参数是该程序的路径,并且 os.Args[1:]保存所有程序的的参数。
    argsWithProg := os.Args
    argsWithoutProg := os.Args[1:]

    arg := os.Args[3]
    //你可以使用标准的索引位置方式取得单个参数的值。

    fmt.Println(argsWithProg)
    fmt.Println(argsWithoutProg)
    fmt.Println(arg)
}


13.2 命令行标志(参数)

命令行标志是命令行程序指定选项的常用方式。例如,在wc -l 中,这个 -l 就是一个命令行标志。

import "flag"
import "fmt"
//Go 提供了一个 flag 包,支持基本的命令行标志解析。我们将用这个包来实现我们的命令行程序示例。

func main() {

    wordPtr := flag.String("word", "foo", "a string")
    //基本的标记声明仅支持字符串、整数和布尔值选项。这里我们声明一个默认值为 "foo" 的字符串标志 word并带有一个简短的描述。这里的 flag.String 函数返回一个字符串指针(不是一个字符串值),在下面我们会看到是如何使用这个指针的。

    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")
    //用程序中已有的参数来声明一个标志也是可以的。注意在标志声明函数中需要使用该参数的指针。

    flag.Parse()
    //所有标志都声明完成以后,调用 flag.Parse() 来执行命令行解析。

    fmt.Println("word:", *wordPtr)
    fmt.Println("numb:", *numbPtr)
    fmt.Println("fork:", *boolPtr)
    fmt.Println("svar:", svar)
    fmt.Println("tail:", flag.Args())
    //这里我们将仅输出解析的选项以及后面的位置参数。注意,我们需要使用类似 *wordPtr 这样的语法来对指针解引用,从而得到选项的实际值。
}

测试这个程序前,最好将这个程序编译成二进制文件,然后再运行这个程序

13.3 环境变量

环境变量是一个在为 Unix 程序传递配置信息的普遍方式。让我们来看看如何设置,获取并列举环境变量。

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 来列出所有环境变量键值对。这个函数会返回一个 KEY=value 形式的字符串切片。你可以使用strings.Split 来得到键和值。这里我们打印所有的键。
}

你可能感兴趣的:(Go基础知识整理)