偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

Go語言之程序符號(hào)重命名

開發(fā) 后端
Go程序源代碼中,關(guān)鍵字、接口、類型、常量、變量、方法、函數(shù)、字段、標(biāo)簽(label)等等的名稱都可以稱為符號(hào)。

[[427663]]

Go程序源代碼中,關(guān)鍵字、接口、類型、常量、變量、方法、函數(shù)、字段、標(biāo)簽(label)等等的名稱都可以稱為符號(hào)。

Go可執(zhí)行程序中,符號(hào)表主要包含兩種類型的符號(hào):

  1. 數(shù)據(jù)對(duì)象(Data object)
  2. 函數(shù)(Function)

一般情況下(不是絕對(duì)的),在源代碼編譯為可執(zhí)行程序的過程中,

  • 關(guān)鍵字、局部變量、標(biāo)簽會(huì)轉(zhuǎn)變?yōu)橹噶?、?shù)據(jù)或者消失,而不再是符號(hào)
  • 接口、類型、全局常量會(huì)被保存為不可變數(shù)據(jù),而不再是符號(hào)
  • 函數(shù)、方法、全局變量、全局常量會(huì)被重命名,保存在符號(hào)表中

本文主要總結(jié)了函數(shù)、方法、全局變量在編譯過程中通用的重命名規(guī)則,不討論類似內(nèi)聯(lián)優(yōu)化、閉包、非空接口、編譯器生成等復(fù)雜的情況。

規(guī)則

Go 1.18版本之前符號(hào)重命名常見規(guī)則列表如下:

  1. 包名.變量名
  2. 包名.函數(shù)名
  3. 包名.函數(shù)名.funcN
  4. 包名.函數(shù)名.funcN.N
  5. 包名.類型.函數(shù)名
  6. 包名.類型.函數(shù)名.funcN
  7. 包名.類型.函數(shù)名.funcN.N
  8. 包名.(*類型).函數(shù)名
  9. 包名.(*類型).函數(shù)名.funcN
  10. 包名.(*類型).函數(shù)名.funcN.N
  11. 模塊名/包名.變量名
  12. 模塊名/包名.函數(shù)名
  13. 模塊名/包名.函數(shù)名.funcN
  14. 模塊名/包名.函數(shù)名.funcN.N
  15. 模塊名/包名.類型.函數(shù)名
  16. 模塊名/包名.類型.函數(shù)名.funcN
  17. 模塊名/包名.類型.函數(shù)名.funcN.N
  18. 模塊名/包名.(*類型).函數(shù)名
  19. 模塊名/包名.(*類型).函數(shù)名.funcN
  20. 模塊名/包名.(*類型).函數(shù)名.funcN.N
  21. 包名.init
  22. 包名.init.N
  23. 模塊名/包名.init
  24. 模塊名/包名.init.N

以上規(guī)則羅列過于詳細(xì),主要是因?yàn)榘诉^多的匿名函數(shù)命名規(guī)則;本文會(huì)縮小分類粒度進(jìn)行歸納:

  1. 普通函數(shù)
  2. 匿名函數(shù)
  3. 方法
  4. 全局常量
  5. 模塊
  6. 初始化函數(shù)

環(huán)境

  1. OS : Ubuntu 20.04.2 LTS; x86_64 
  2. Go : go version go1.16.2 linux/amd64 

代碼清單

完整代碼已經(jīng)上傳到 Github 倉庫:https://github.com/fooree/go-names

目錄和文件結(jié)構(gòu)如下:

go.mod

  1. module github.com/fooree/go-names 
  2.  
  3. go 1.16 

main.go

  1. package main 
  2.  
  3. import ( 
  4.   "debug/elf" 
  5.   "fmt" 
  6.   "github.com/fooree/go-names/internal" 
  7.   "github.com/fooree/go-names/internal/foo" 
  8.   "github.com/fooree/go-names/internal/foo/ree" 
  9.   "os" 
  10.   "path/filepath" 
  11.   "reflect" 
  12.   "sort" 
  13.   "strings" 
  14.   "time" 
  15.  
  16. //go:noinline 
  17. func anonymousType() { 
  18.   t := reflect.TypeOf(struct { 
  19.     Name string 
  20.   }{ 
  21.     Name"Jack"
  22.   }) 
  23.   fmt.Printf("name=%s, string=%s, addres=%p\n", t.Name(), t.String(), t) 
  24.  
  25. func main() { 
  26.   anonymousType() 
  27.   ree.Run() 
  28.   foo.Y.Foo() 
  29.   internal.X.Foo() 
  30.    
  31.   name, _ := filepath.Abs(os.Args[0]) 
  32.   file, err := elf.Open(name
  33.   if err != nil { 
  34.     panic(err) 
  35.   } 
  36.   defer func() { _ = file.Close() }() 
  37.   symbols, err := file.Symbols() 
  38.   if err != nil { 
  39.     panic(err) 
  40.   } 
  41.  
  42.   slice := make([]string, 0, 100) 
  43.   for _, symbol := range symbols { 
  44.     const module = "github.com/fooree/go-names" 
  45.     const name = "main" 
  46.     if strings.HasPrefix(symbol.Name, module) || strings.HasPrefix(symbol.Namename) { 
  47.       slice = append(slice, symbol.Name
  48.     } 
  49.   } 
  50.  
  51.   go func() { 
  52.     sort.Slice(slice, func(i, j int) bool { 
  53.       return slice[i] < slice[j] 
  54.     }) 
  55.     go func() { 
  56.       fmt.Println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"
  57.     }() 
  58.   }() 
  59.  
  60.   time.Sleep(time.Second
  61.  
  62.   for _, sym := range slice { 
  63.     fmt.Println(sym) 
  64.   } 

internal/a.go

  1. package internal 
  2.  
  3. import ( 
  4.   "fmt" 
  5.   "reflect" 
  6.  
  7. type Foo interface { 
  8.   Foo() 
  9.  
  10. type Int int 
  11.  
  12. var X Int 
  13.  
  14. //go:noinline 
  15. func (i *Int) Foo() { 
  16.   t := reflect.TypeOf(i) 
  17.   go func() { 
  18.     fmt.Printf("i am Int, name=%s, string=%s\n", t.Name(), t.String()) 
  19.   }() 
  20.  
  21. func init() { 
  22.   X = Int(0x123) 
  23.  
  24. func init() { 
  25.   fmt.Println("X =", X) 

internal/foo/b.go

  1. package foo 
  2.  
  3. import ( 
  4.   "fmt" 
  5.   "reflect" 
  6.  
  7. type Ree struct { 
  8.   Name string 
  9.  
  10. //go:noinline 
  11. func (r Ree) Foo() { 
  12.   anonymousType() 
  13.   t := reflect.TypeOf(r) 
  14.   fmt.Printf("i am Ree, name=%s, string=%s\n", t.Name(), t.String()) 
  15.  
  16. //go:noinline 
  17. func anonymousType() { 
  18.   t := reflect.TypeOf(struct { 
  19.     Name string 
  20.   }{ 
  21.     Name"Jack"
  22.   }) 
  23.   fmt.Printf("name=%s, string=%s, addres=%p\n", t.Name(), t.String(), t) 
  24.  
  25. var Y = Ree{"Rose"
  26.  
  27. func init() { 
  28.   fmt.Println("Y =",Y) 

internal/foo/ree/c.go

  1. package ree 
  2.  
  3. import "sort" 
  4.  
  5. var arr = []int{1, 5, 6, 2, 7, 3, 7, 2} 
  6.  
  7. func Run() { 
  8.   sort.Slice(arr, func(i, j int) bool { 
  9.     return arr[i]<arr[j] 
  10.   }) 

查看符號(hào)表

編譯以上代碼并執(zhí)行,在執(zhí)行過程中,對(duì)可執(zhí)行程序本身進(jìn)行符號(hào)解析,過濾并輸出以上代碼中定義的符號(hào)。

普通函數(shù)

在Go語言中,所有的代碼都必須位于某個(gè)包(package)中。

在Go語言中,最特殊的一個(gè)包名是main,無論它所在的目錄名稱是什么,編譯后該包下的符號(hào)都必須以 main.開頭。

在Go語言中,最特殊的一個(gè)函數(shù)是main包中的main函數(shù),其編譯之后的符號(hào)名稱為main.main,Go運(yùn)行時(shí)將該函數(shù)作為程序的入口。

main包中的其它有名稱的函數(shù),都會(huì)被編譯器重命名為“包名.函數(shù)名”的格式,例如main.anonymousType。

匿名函數(shù)

顧名思義,匿名函數(shù)就是沒有名稱的函數(shù)。

函數(shù)中定義的匿名函數(shù),會(huì)被重命名為“包名.函數(shù)名.funcN”的格式,其中N是一個(gè)可遞增的數(shù)字。

例如,在以上代碼清單中,

main函數(shù)里defer關(guān)鍵字后的func() { _ = file.Close() }()是第一個(gè)匿名函數(shù),被重命名為main.main.func1。

main函數(shù)里go關(guān)鍵字后的func是第二個(gè)匿名函數(shù),被重命名為main.main.func2。

main.main.func2函數(shù)里又定義了兩個(gè)匿名函數(shù),它們不再被重命名為funcN格式,而是被重命名為funcN.N格式,分別為main.main.func2.1和main.main.func2.2。

方法

專屬于某一個(gè)數(shù)據(jù)類型的函數(shù),稱為方法。

方法,只不過是語法層面的一個(gè)稱謂而已,其本質(zhì)就是函數(shù);方法的接受者就是其第一個(gè)參數(shù),所以方法至少有一個(gè)參數(shù)。

在 A Tour of Go (https://tour.golang.org/methods/1) 中,對(duì)函數(shù)的定義為:

  1. A method is a function with a special receiver argument. 

方法的定義格式有兩種:

1.接受者為數(shù)據(jù)類型

例如,reflect/value.go源文件中的Elem方法:

  1. func (v Value) Elem() Value { 
  2.     // 此處省略方法代碼 

2.接受者為指針類型

例如,reflect/value.go源文件中的Value方法:

  1. func (it *MapIter) Value() Value {  
  2.     // 此處省略方法代碼 

通常情況下,以上兩種格式的方法定義,對(duì)應(yīng)的重命名規(guī)則分別如下:

包名.類型.方法名,例如:reflect.Value.Elem

包名.(*類型).方法名,例如:reflect.(*MapIter).Value

實(shí)際情況是:編譯過程中的方法重命名規(guī)則要復(fù)雜的多。后續(xù)其他的專題文章會(huì)逐漸介紹。

方法中如果包含匿名函數(shù),重命名規(guī)則是在其后追加funcN或funcN.N。

全局變量

全局變量的重命名規(guī)則是“包名.變量名”。

例如os/proc.go源文件中定義的Args變量。

包層級(jí)

在Go語言中,一個(gè)包可以包含和定義其他的包,這是通過子目錄實(shí)現(xiàn)的,從而形成了包的層級(jí)結(jié)構(gòu)。

如果包存在層級(jí)結(jié)構(gòu),則使用“/”進(jìn)行包名之間的連接,從而實(shí)現(xiàn)包的編譯重命名。

例如,io/fs/源碼目錄中定義包名是fs,該包中的變量和函數(shù),在編譯后它們的包名都是“io/fs”。

模塊

模塊(module)是Go語言的依賴管理工具。

一個(gè)模塊一般會(huì)包含一個(gè)或多個(gè)包(package)。

模塊中的包、函數(shù)、方法、全局變量、匿名函數(shù)的重命名規(guī)則與以上總結(jié)的規(guī)則一致,只是需要增加前綴“模塊名/”。

例如,文本代碼清單中定義的模塊名稱是github.com/fooree/go-names,模塊中定義的符號(hào)重命名如下:

  1. github.com/fooree/go-names/internal.(*Int).Foo        // 方法名 
  2. github.com/fooree/go-names/internal.(*Int).Foo.func1  // 匿名函數(shù) 
  3. github.com/fooree/go-names/internal.X                 // 全局變量 
  4. github.com/fooree/go-names/internal/foo.Ree.Foo       // 方法名 
  5. github.com/fooree/go-names/internal/foo.Y             // 全局變量 
  6. github.com/fooree/go-names/internal/foo.anonymousType // 函數(shù)名 
  7. github.com/fooree/go-names/internal/foo/ree.Run       // 函數(shù)名 
  8. github.com/fooree/go-names/internal/foo/ree.Run.func1 // 匿名函數(shù) 
  9. github.com/fooree/go-names/internal/foo/ree.arr       

初始化函數(shù)

關(guān)于初始化函數(shù)的重命名規(guī)則,請(qǐng)閱讀 【Go】初始化函數(shù)。

結(jié)語

本文總結(jié)了一些基本的符號(hào)重命名規(guī)則。

本文轉(zhuǎn)載自微信公眾號(hào)「Golang In Memory」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系Golang In Memory公眾號(hào)。

 

責(zé)任編輯:武曉燕 來源: Golang In Memory
相關(guān)推薦

2020-12-31 09:06:44

Go語言Reflect

2021-10-23 06:42:14

Go語言接口

2021-10-03 22:18:14

Go語言整數(shù)

2021-10-16 17:53:35

Go函數(shù)編程

2022-03-28 13:34:26

Go泛型部署泛型

2024-01-05 20:46:14

2010-11-19 13:48:18

2013-08-20 10:11:20

Go系統(tǒng)管理員

2021-05-12 08:53:54

Go語言調(diào)度

2021-10-18 10:53:26

Go 代碼技術(shù)

2024-09-04 08:02:12

2012-06-20 15:01:04

Web

2009-12-22 15:28:51

Linux批量重命名文

2013-03-22 15:40:32

VS項(xiàng)目整體命名.NET

2011-03-04 09:48:21

PureFTPd

2024-01-08 08:23:07

Go語言代碼

2012-08-07 09:29:09

程序員編程

2021-05-27 08:47:16

C語言C語言程序開發(fā)

2013-07-10 11:11:05

PythonGo語言

2017-06-14 09:37:05

R語言Apriori算法
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)