Go語言基礎學習二-簡單的代碼分析

Go語言基礎學習二

一點經驗:

    main()函數作爲整個程序的入口,沒有參數,也沒有返回值,還有一個函數init()先於main()執行,以後待講。

    導入包中fmt提供格式化文本和讀入格式文本的函數,os包提供了跨平臺的操作系統層面變量及函數,包括保存命令行參數的類型os.Args  strings包提供處理字符串的函數。

    go程序中不含有分號,分號由編譯器自動添加。

    filepath.Base()函數會返回傳入路徑的基礎名,Go語言採用單引號表達字符,Go語言具有強類型轉換,將int16與int32不能直接相加,需要進行類型轉換。

     棧-自定義類型及其方法,自定義棧可以通過空接口來實現將異構(類型不同的)的元素混合存儲,因爲go語言的所有類型都實現了空接口。

     func (stack *Stack) Top() (interface{},error){

       return stack[len(stack)-1],nil

}   函數的聲明,第一個圓括號 stack *Stack表示一個類型爲指向Stack的參數,名爲stack,最後一個圓括號表示返回的值,返回兩個值,一個是空接口,一個是錯誤信息

      切片(在我的理解,就是數組),切片的內容可以通過索引來表示[first:end]一定範圍的值。

      buffo包提供了帶緩衝的I/O處理能力,io包提供了底層I/O能力,包含有io.Reader及io.Writer接口,io/ioutil包提供了一系列高級文件處理函數。regexp包則提供了強大的正則表達式支持。

package main


import (

    "bufio"

    "fmt"

    "io"

    "io/ioutil"

    "log"

    "os"

    "path/filepath"

    "regexp"

    "strings"

)

var britishAmerican = "british-american.txt"


func init() {/*進入函數main()之前,首先要執行init()內部的內容,獲取當前目錄並構建單詞轉化所需的文本路徑*/

    dir, _ := filepath.Split(os.Args[0])

    britishAmerican = filepath.Join(dir, britishAmerican)

}


func main() {

    inFilename, outFilename, err := filenamesFromCommandLine()

/*調用filenamesFromCommandLine()函數獲取命令行中的數據輸入文件和輸出文件,返回值爲輸入文件名和輸出文件名及錯誤信息*/

    if err != nil {/*當錯誤信息不爲空時,輸出並退出程序*/

        fmt.Println(err)

        os.Exit(1)

    }

    inFile, outFile := os.Stdin, os.Stdout

    if inFilename != "" {

        /*打開只讀輸入文件,返回指向文件的指針和錯誤信息*/

        if inFile, err = os.Open(inFilename); err != nil {

            log.Fatal(err)

        }

        /*defer是指推遲執行,直到main()函數正常返回會調用該執行語句,關閉文件,回收內存,當程序崩潰時,不會執行,但是go語言系統會自動關閉所有打開的文件,垃圾回收器會回收內存*/

        defer inFile.Close()

    }

    if outFilename != "" {

        /*os.Create()讀取一個文件,若文件不存在創建該文件,若存在,將該文件長度截爲0*/

        if outFile, err = os.Create(outFilename); err != nil {

            log.Fatal(err)

        }

        defer outFile.Close()

    }

     /*americanise該函數用於替換英式單詞爲美式單詞*/

    if err = americanise(inFile, outFile); err != nil {

        log.Fatal(err)

    }

}



/*該函數用於分析命令行*/

func filenamesFromCommandLine() (inFilename, outFilename string,

    err error) {

    /*os.Args保存有命令行參數,命令行參數大於1,且可以分析-h及--help等參數爲命令解釋請求*/

    if len(os.Args) > 1 && (os.Args[1] == "-h" || os.Args[1] == "--help") {

        err = fmt.Errorf("usage: %s [<]infile.txt [>]outfile.txt",

            filepath.Base(os.Args[0]))

        return "", "", err

    }

    if len(os.Args) > 1 {

        inFilename = os.Args[1]

        if len(os.Args) > 2 {

            outFilename = os.Args[2]

        }

    }

    if inFilename != "" && inFilename == outFilename {

        log.Fatal("won't overwrite the infile")

    }

    return inFilename, outFilename, nil

}


/*該函數實現替換英式單詞爲美式單詞*/

func americanise(inFile io.Reader, outFile io.Writer) (err error) {

    /*向bufio.NewReader傳入實現io.Rreader接口的值,提供緩衝機制*/

    reader := bufio.NewReader(inFile)

    writer := bufio.NewWriter(outFile)

    /*延遲至main()函數返回,刷新寫緩衝區,確保全部寫入*/

    defer func() {

        if err == nil {

            err = writer.Flush()

        }

    }()

    /*定義一個替換器函數,參數爲string,返回string*/

    var replacer func(string) string

    /*makeReplacerFunction根據單詞替換文本britishAmerican生成替換器replacer*/

    if replacer, err = makeReplacerFunction(britishAmerican); err != nil {

        return err

    }

    /*正則表達式*/

    wordRx := regexp.MustCompile("[A-Za-z]+")

    eof := false

    /*循環讀取文件,直到讀到文件末尾*/

    for !eof {

        var line string

        line, err = reader.ReadString('\n')

        if err == io.EOF {

            err = nil   // io.EOF isn't really an error

            eof = true  // this will end the loop at the next iteration

        } else if err != nil {

            return err  // finish immediately for real errors

        }

        /*對讀取的每一行進行替換器替換並寫入輸出文件*/

        line = wordRx.ReplaceAllStringFunc(line, replacer)

        /*這裏的_表示空標記符,作爲一個佔位符放在一個需要變量的地方,並忽略掉該變量的值。*/

        if _, err = writer.WriteString(line); err != nil {

            return err

        }

    }

    return nil

}

/*根據單詞替換文本生成替換器replacer*/

func makeReplacerFunction(file string) (func(string) string, error) {

    /*首先讀取單詞替換文本*/

    rawBytes, err := ioutil.ReadFile(file)

    if err != nil {

        return nil, err

    }

    text := string(rawBytes)

    /*創建一個映射對象*/

    usForBritish := make(map[string]string)

    /*將文本逐行分解*/

    lines := strings.Split(text, "\n")

    for _, line := range lines {

        /*每一行將根據空格符生成對應切片,strings.Fields這個函數就是以空白分割符來分隔字符串*/

        fields := strings.Fields(line)

        if len(fields) == 2 {

            /*將切片填充到映射對象中去*/

            usForBritish[fields[0]] = fields[1]

        }

    }


    return func(word string) string {

        /*根據映射對象的映射關係生成替換器*/

        if usWord, found := usForBritish[word]; found {

            return usWord

        }

        return word

    }, nil

}

go語言中字符串類型的內部表示統一爲utf-8編碼的。

go語言中的映射,切片和通道都是要通過make()函數來創建的。

for。。range語法用於遍歷切片和數組非常方便,每次迭代它會返回切片的索引和在該切片上的元素值。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章