0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

go語言底層對(duì)于命令行參數(shù)的解析

冬至子 ? 來源:我的小碗湯 ? 作者:小碗湯 ? 2022-10-11 10:50 ? 次閱讀

前段時(shí)間有群友在群里問一個(gè)go語言的問題:

就是有一個(gè)main.go的main函數(shù)里調(diào)用了另一個(gè)demo.go里的hello()函數(shù)。其中main.go和hello.go同屬于main包。但是在main.go的目錄下執(zhí)行g(shù)o run main.go卻報(bào)hello函數(shù)沒有定義的錯(cuò):

pYYBAGNE2XiAbE_6AABJdSb2xQ0407.png

代碼結(jié)構(gòu)如下:

**gopath ---- src**

          **----gohello** 

                **----hello.go** 

                    **----main.go**

main.go如下:

package main

import "fmt"

func main() {

 fmt.Println("my name is main")

 hello()
}

hello.go如下:

package main

import "fmt"

func hello() {
 fmt.Println("my name is hello")
}

當(dāng)時(shí)我看了以為是他GOPATH配置的有問題,然后自己也按照這樣試了一下,報(bào)同樣的錯(cuò),在網(wǎng)上查了,也有兩篇文章是關(guān)于這個(gè)錯(cuò)的,也提供了解決方法,即用go run main.go hello.go,試了確實(shí)是可以的。

poYBAGNE2YqAUSTjAAA_Q8R_NUQ625.png

雖然是個(gè)很簡單的問題,但是也涉及到了go語言底層對(duì)于命令行參數(shù)的解析。那就來分析一下語言底層的實(shí)現(xiàn)吧,看一下底層做了什么,為什么報(bào)這個(gè)錯(cuò)?

分析:

以下使用到的Go SDK版本為1.8.3

該版本中g(shù)o支持的基本命令有以下16個(gè):

build       compile packages and dependencies
clean       remove object files
doc         show documentation for package or symbol
env         print Go environment information
bug         start a bug report
fix         run go tool fix on packages
fmt         run gofmt on package sources
generate    generate Go files by processing source
get         download and install packages and dependencies
install     compile and install packages and dependencies
list        list packages
run         compile and run Go program
test        test packages
tool        run specified go tool
version     print Go version
vet         run go tool vet on packages

在Go SDK的src/cmd/go包下有main.go文件中,Command類型的commands數(shù)組對(duì)該16個(gè)命令提供了支持:

poYBAGNE2aGAGmHEAADVufp8n54966.png

我們首先知道go語言的初始化流程如下:

pYYBAGNE2bWAP7QzAABkuYqe9Uw995.png

在執(zhí)行main.go中的主函數(shù)main之前,對(duì)import進(jìn)來的包按順序初始化,最后初始化main.go中的類型和變量,當(dāng)初始化到commands數(shù)組時(shí),由于cmdRun定義在于main.go同包下的run.go中,那么就先去初始化run.go中的變量和init方法,如下代碼,先把cmdRun初始化為Command類型,然后執(zhí)行init()函數(shù)。

var cmdRun = &Command{
 UsageLine: "run [build flags] [-exec xprog] gofiles... [arguments...]",
 Short:     "compile and run Go program",
 Long: `
Run compiles and runs the main package comprising the named Go source files.
A Go source file is defined to be a file ending in a literal ".go" suffix.

By default, 'go run' runs the compiled binary directly: 'a.out arguments...'.
If the -exec flag is given, 'go run' invokes the binary using xprog:
 'xprog a.out arguments...'.
If the -exec flag is not given, GOOS or GOARCH is different from the system
default, and a program named go_$GOOS_$GOARCH_exec can be found
on the current search path, 'go run' invokes the binary using that program,
for example 'go_nacl_386_exec a.out arguments...'. This allows execution of
cross-compiled programs when a simulator or other execution method is
available.

For more about build flags, see 'go help build'.

See also: go build.
 `,
}

func init() {
 cmdRun.Run = runRun // break init loop

 addBuildFlags(cmdRun)
 cmdRun.Flag.Var((*stringsFlag)(&execCmd), "exec", "")
}

init()中,將runRun(其實(shí)類型是一個(gè)方法,用于處理run后的參數(shù))賦值給cmdRu.run,addBuildFlags(cmdRun)主要是給run后面增加命令行參數(shù)(如:-x是打印其執(zhí)行過程中用到的所有命令,同時(shí)執(zhí)行它們)。其他15個(gè)命令和cmdRun類似,各有各的run實(shí)現(xiàn)。

下來主要看main.go中main的這塊代碼:

for _, cmd := range commands {
   if cmd.Name() == args[0] && cmd.Runnable() {
     cmd.Flag.Usage = func() { cmd.Usage() }
     if cmd.CustomFlags {
       args = args[1:]
     } else {
       cmd.Flag.Parse(args[1:])
       args = cmd.Flag.Args()
     }
     cmd.Run(cmd, args)
     exit()
     return
   }
 }

這塊代碼遍歷commands數(shù)組,當(dāng)遍歷到cmdRun時(shí),cmd.Name()其實(shí)就是拿到cmdRun.UsageLine的第一個(gè)單詞run

bVeVF


就會(huì)進(jìn)入if分支,由于cmd.CustomFlags沒有初始化故為false,走else分支,然后開始解析args命令行參數(shù),args[1:]即取run后的所有參數(shù)。然后去執(zhí)行cmd.Run(cmd, args),對(duì)于cmdRun來說,這里執(zhí)行的就是run.go中init()的第一行賦值cmdRun.run(上面說了,這是一個(gè)函數(shù),不同命令實(shí)現(xiàn)方式不同),即去執(zhí)行run.go中的runRun函數(shù),該函數(shù)主要是將命令行參數(shù)當(dāng)文件去處理,如果是_test為后綴的,即測試文件,直接報(bào)錯(cuò)。如果是目錄也直接報(bào)錯(cuò)(而且go run后面只能包含一個(gè)含main函數(shù)的go文件)。注意到有這么一行:

p := goFilesPackage(files)

goFilesPackage(files)除了校驗(yàn)文件類型和后綴,還會(huì)入棧,加載,出棧等操作,由于啟動(dòng)的時(shí)候沒有傳遞hello.go,所以系統(tǒng)加載main.go時(shí)找不到hello函數(shù),導(dǎo)致報(bào)錯(cuò)。




審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • main
    +關(guān)注

    關(guān)注

    0

    文章

    38

    瀏覽量

    6083
  • go語言
    +關(guān)注

    關(guān)注

    1

    文章

    156

    瀏覽量

    8996
收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Shell腳本命令行解析

    Shell腳本解析命令行參數(shù)——Argparse(填坑)
    發(fā)表于 04-03 11:34

    cmd網(wǎng)絡(luò)經(jīng)典命令行

    cmd網(wǎng)絡(luò)經(jīng)典命令行:
    發(fā)表于 06-11 15:17 ?36次下載
    cmd網(wǎng)絡(luò)經(jīng)典<b class='flag-5'>命令行</b>

    C語言入門教程-命令行參數(shù)

    命令行參數(shù) 在C中,獲取用戶輸入的命令行參數(shù)是很方便的。程序的主函數(shù)會(huì)接受一個(gè)argv參數(shù)。有許多高級(jí)的庫函數(shù)都會(huì)用到argv結(jié)構(gòu),所以了
    發(fā)表于 07-29 14:22 ?2564次閱讀

    caxa命令行中的應(yīng)用

    caxa命令行中的應(yīng)用 命令行對(duì)于大多用戶來說往往只是輸入數(shù)據(jù)的作用,但是其中的奧妙還有很多,下面就給大家
    發(fā)表于 10-18 18:18 ?2258次閱讀

    博達(dá)環(huán)網(wǎng)配置命令行

    博達(dá)工業(yè)交換要環(huán)網(wǎng)配置命令行
    發(fā)表于 12-27 16:24 ?0次下載

    CMD的命令行高級(jí)教程

    CMD的命令行高級(jí)教程
    發(fā)表于 10-24 08:31 ?30次下載
    CMD的<b class='flag-5'>命令行</b>高級(jí)教程

    自己動(dòng)手實(shí)現(xiàn)命令行解析

    一、介紹嵌入式里面經(jīng)常會(huì)自己做命令行,這里分享一個(gè)命令解析器代碼實(shí)現(xiàn)二、代碼實(shí)現(xiàn)mycmd.c
    發(fā)表于 12-22 18:51 ?13次下載
    自己動(dòng)手實(shí)現(xiàn)<b class='flag-5'>命令行</b><b class='flag-5'>解析</b>器

    如何從命令行獲取和解析參數(shù)

    這是一篇技術(shù)干貨快文,能夠快速閱讀完。文章內(nèi)容是關(guān)于如何從命令行獲取和解析參數(shù),包括SystemVerilog本身支持的系統(tǒng)函數(shù)和UVM提供的函數(shù)封裝,并給出示例代碼和仿真結(jié)果。
    的頭像 發(fā)表于 05-30 14:05 ?2607次閱讀

    uvm命令行傳遞參數(shù)的小技巧

    當(dāng)我們?cè)趧?chuàng)建動(dòng)態(tài)仿真case時(shí),使用命令行參數(shù)可以非常方便地控制DUT和TB的行為,比如配置寄存器、控制激勵(lì)的發(fā)送數(shù)量、打開或關(guān)閉某些scoreboard等。
    的頭像 發(fā)表于 08-19 11:53 ?5129次閱讀

    Shell命令行解釋器簡介

    Shell 是一個(gè)命令行解釋器,Shell 為用戶提供了與設(shè)備進(jìn)行命令行交互的方式,用戶通過串口、以太網(wǎng)、無線等方式將命令傳輸給具有 Shell 功能的設(shè)備,設(shè)備會(huì)解析
    的頭像 發(fā)表于 08-19 17:20 ?3036次閱讀

    Golang基于flag庫實(shí)現(xiàn)一個(gè)命令行工具

    Golang 標(biāo)準(zhǔn)庫中的 flag 庫提供了解析命令行選項(xiàng)的能力,我們可以基于此來開發(fā)命令行工具。
    的頭像 發(fā)表于 10-28 09:26 ?1175次閱讀

    Linux命令行與shell腳本編寫

    Linux命令行與shell腳本編寫
    發(fā)表于 01-11 16:50 ?4次下載

    介紹Go里面經(jīng)常使用到的命令行工具

    優(yōu)秀的工具配合熟練的使用,往往可以讓開發(fā)效率大幅度提升,本小節(jié)介紹 Go 里面經(jīng)常使用到的命令行工具。
    的頭像 發(fā)表于 05-22 16:58 ?1155次閱讀
    介紹<b class='flag-5'>Go</b>里面經(jīng)常使用到的<b class='flag-5'>命令行</b>工具

    linux切換到命令行模式

    在Linux中,可以通過以下步驟切換到命令行模式: 打開終端??梢栽趹?yīng)用菜單中找到終端或命令行終端。 在終端中輸入命令“exit”或“l(fā)ogout”,然后按回車鍵。 系統(tǒng)會(huì)提示您輸入管理員密碼。輸入
    的頭像 發(fā)表于 11-13 16:47 ?1466次閱讀

    idea如何輸入命令行參數(shù)

    在許多軟件開發(fā)和系統(tǒng)管理的任務(wù)中,我們經(jīng)常需要向應(yīng)用程序傳遞命令行參數(shù)。命令行參數(shù)是在運(yùn)行時(shí)傳遞給程序的值,用于指定程序的行為和配置選項(xiàng)。本文將詳細(xì)介紹如何在不同的編程
    的頭像 發(fā)表于 12-06 15:01 ?822次閱讀