GO是編譯性語言,所以函數(shù)的順序是無關(guān)緊要的,為了方便閱讀,建議入口函數(shù) main 寫在最前面,其余函數(shù)按照功能需要進(jìn)行排列
成都創(chuàng)新互聯(lián)公司是專業(yè)的準(zhǔn)格爾網(wǎng)站建設(shè)公司,準(zhǔn)格爾接單;提供成都網(wǎng)站制作、網(wǎng)站設(shè)計,網(wǎng)頁設(shè)計,網(wǎng)站設(shè)計,建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行準(zhǔn)格爾網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊,希望更多企業(yè)前來合作!
GO的函數(shù) 不支持嵌套,重載和默認(rèn)參數(shù)
GO的函數(shù) 支持 無需聲明變量,可變長度,多返回值,匿名,閉包等
GO的函數(shù)用 func 來聲明,且左大括號 { 不能另起一行
一個簡單的示例:
輸出為:
參數(shù):可以傳0個或多個值來供自己用
返回:通過用 return 來進(jìn)行返回
輸出為:
上面就是一個典型的多參數(shù)傳遞與多返回值
對例子的說明:
按值傳遞:是對某個變量進(jìn)行復(fù)制,不能更改原變量的值
引用傳遞:相當(dāng)于按指針傳遞,可以同時改變原來的值,并且消耗的內(nèi)存會更少,只有4或8個字節(jié)的消耗
在上例中,返回值 (d int, e int, f int) { 是進(jìn)行了命名,如果不想命名可以寫成 (int,int,int){ ,返回的結(jié)果都是一樣的,但要注意:
當(dāng)返回了多個值,我們某些變量不想要,或?qū)嶋H用不到,我們可以使用 _ 來補(bǔ)位,例如上例的返回我們可以寫成 d,_,f := test(a,b,c) ,我們不想要中間的返回值,可以以這種形式來舍棄掉
在參數(shù)后面以 變量 ... type 這種形式的,我們就要以判斷出這是一個可變長度的參數(shù)
輸出為:
在上例中, strs ...string 中, strs 的實際值是b,c,d,e,這就是一個最簡單的傳遞可變長度的參數(shù)的例子,更多一些演變的形式,都非常類似
在GO中 defer 關(guān)鍵字非常重要,相當(dāng)于面相對像中的析構(gòu)函數(shù),也就是在某個函數(shù)執(zhí)行完成后,GO會自動這個;
如果在多層循環(huán)中函數(shù)里,都定義了 defer ,那么它的執(zhí)行順序是先進(jìn)后出;
當(dāng)某個函數(shù)出現(xiàn)嚴(yán)重錯誤時, defer 也會被調(diào)用
輸出為
這是一個最簡單的測試了,當(dāng)然還有更復(fù)雜的調(diào)用,比如調(diào)試程序時,判斷是哪個函數(shù)出了問題,完全可以根據(jù) defer 打印出來的內(nèi)容來進(jìn)行判斷,非常快速,這種留給你們?nèi)崿F(xiàn)
一個函數(shù)在函數(shù)體內(nèi)自己調(diào)用自己我們稱之為遞歸函數(shù),在做遞歸調(diào)用時,經(jīng)常會將內(nèi)存給占滿,這是非常要注意的,常用的比如,快速排序就是用的遞歸調(diào)用
本篇重點(diǎn)介紹了GO函數(shù)(func)的聲明與使用,下一篇將介紹GO的結(jié)構(gòu) struct
除了GCC和MSVC的noinline語法,我想你也可以試試函數(shù)指針,構(gòu)造出一個functions call site給后面的object使用。
void (*ptrfunc)(int);
ptrfunc = some_func;
ptrfunc(25);
而寫到這里的時候,我的確也測試了一下你說的有關(guān)類加上__attribute__(noinline),的確如樓主所說的還是被inline了。
如:
#include stdio.h
class X
{
public:
X(int i) : x_(i){}
int getX() __attribute__((noinline)){return x_;}
int x_;
};
int main()
{
X x(7);
}
g++ -c
readelf -Ws a.o | c++filt
Symbol table '.symtab' contains 14 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS
2: 0000000000000000 0 SECTION LOCAL DEFAULT 2
3: 0000000000000000 0 SECTION LOCAL DEFAULT 4
4: 0000000000000000 0 SECTION LOCAL DEFAULT 5
5: 0000000000000000 0 SECTION LOCAL DEFAULT 6
6: 0000000000000000 0 SECTION LOCAL DEFAULT 8
7: 0000000000000000 0 SECTION LOCAL DEFAULT 9
8: 0000000000000000 0 NOTYPE LOCAL DEFAULT 1 _ZN1XC5Ei
9: 0000000000000000 0 SECTION LOCAL DEFAULT 7
10: 0000000000000000 0 SECTION LOCAL DEFAULT 1
11: 0000000000000000 22 FUNC WEAK DEFAULT 6 X::X(int)
12: 0000000000000000 22 FUNC WEAK DEFAULT 6 X::X(int)
13: 0000000000000000 32 FUNC GLOBAL DEFAULT 2 main
但是,如上文所說,我們可以手動把這個function call site弄出來,因為inline的本質(zhì)就在這里
#include stdio.h
class X
{
public:
X(int i) : x_(i){}
int getX() {return x_;}
int x_;
};
int (X::* ptrmfunc)();
int main()
{
X x(7);
ptrmfunc = X::getX;
// if you want to use pointer to member function.
// printf("%d\n", (x.*ptrmfunc)());
}
g++ -c
readelf -Ws a.o | c++filt
Symbol table '.symtab' contains 18 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FILE LOCAL DEFAULT ABS
2: 0000000000000000 0 SECTION LOCAL DEFAULT 3
3: 0000000000000000 0 SECTION LOCAL DEFAULT 5
4: 0000000000000000 0 SECTION LOCAL DEFAULT 6
5: 0000000000000000 0 SECTION LOCAL DEFAULT 7
6: 0000000000000000 0 SECTION LOCAL DEFAULT 8
7: 0000000000000000 0 SECTION LOCAL DEFAULT 10
8: 0000000000000000 0 SECTION LOCAL DEFAULT 11
9: 0000000000000000 0 NOTYPE LOCAL DEFAULT 1 _ZN1XC5Ei
10: 0000000000000000 0 SECTION LOCAL DEFAULT 9
11: 0000000000000000 0 SECTION LOCAL DEFAULT 1
12: 0000000000000000 0 SECTION LOCAL DEFAULT 2
13: 0000000000000000 22 FUNC WEAK DEFAULT 7 X::X(int)
14: 0000000000000000 22 FUNC WEAK DEFAULT 7 X::X(int)
15: 0000000000000000 16 FUNC WEAK DEFAULT 8 X::getX()
16: 0000000000000000 16 OBJECT GLOBAL DEFAULT 6 ptrmfunc
17: 0000000000000000 70 FUNC GLOBAL DEFAULT 3 main
這樣就可以出來了。
區(qū)別:
1、Go不允許函數(shù)重載,必須具有方法和函數(shù)的唯一名稱;java允許函數(shù)重載。
2、Java默認(rèn)允許多態(tài),Go沒有。
3、Go代碼可以自動擴(kuò)展到多個核心;而Java并不總是具有足夠的可擴(kuò)展性。
4、Java不支持多繼承,Go支持多繼承。
什么是go語言?
Go也稱為Golang,是一種編程語言。作為一種開源編程語言,Go可以輕松構(gòu)建可靠,簡單和高效的軟件。
Go是鍵入的靜態(tài)編譯語言。Go語言提供垃圾收集,CSP風(fēng)格的并發(fā)性,內(nèi)存安全性和結(jié)構(gòu)類型。
什么是java?
Java是一種用于一般用途的計算機(jī)編程語言,它是基于類的,并發(fā)的和面向?qū)ο蟮摹ava專門設(shè)計為包含很少的實現(xiàn)依賴項。Java應(yīng)用程序在JVM(Java虛擬機(jī))上運(yùn)行。它是當(dāng)今最著名和最著名的編程語言之一。
在上一篇文章的golang代碼中,函數(shù)add的上一行,增加了一條注釋語句: //go:noinline 。在bpftrace追蹤時,是否可以去掉?有什么作用?
為了說明該問題,設(shè)計一個例子。
golang代碼中,有兩個求和函數(shù)。其中,add1加上 //go:noinline ,另一個add2不加。代碼如下:
bpftrace程序分別對函數(shù)add1和add2的輸入?yún)?shù)、返回值進(jìn)行追蹤,代碼如下:
執(zhí)行程序后,可以看到bpftrace程序能夠正常追蹤到函數(shù)add1,但是無法追蹤到函數(shù)add2。
通過上文中的示例代碼,可以看到,沒有加 //go:noinline 的函數(shù)無法被bpftrace程序追蹤到。通過查閱golang相關(guān)文檔,可以知道, //go:noinline 表示該函數(shù)在編譯時,不會被內(nèi)聯(lián)。
使用 objump -S 生成golang程序的匯編代碼如下:
通過匯編代碼,我們可以看到,主函數(shù)中,地址 0x498e52 處 callq 498e00 調(diào)用了add1函數(shù),地址 0x498ebb 處 movq $0x4,(%rsp) 直接計算求值。
因此,golang編譯器在編譯代碼時,會對代碼進(jìn)行分析,并按照內(nèi)聯(lián)規(guī)則,將某些函數(shù)生成內(nèi)聯(lián)代碼。一旦函數(shù)被內(nèi)聯(lián),bpftrace將無法追蹤到對應(yīng)函數(shù)。也就是,上文中函數(shù) add2 無法被追蹤到。
針對golang程序中編譯器內(nèi)聯(lián)的問題,可以通過禁止內(nèi)聯(lián)的方式來解決。禁止內(nèi)聯(lián)的方式有:
在實踐中,可以通過 go build -gcflags="-m -m" 來查看,哪些函數(shù)會在編譯時執(zhí)行內(nèi)聯(lián),如:
從輸出中,可以看到:
關(guān)于golang編譯器進(jìn)行內(nèi)聯(lián)的場景,可以參考golang源碼:。
由于golang編譯器內(nèi)聯(lián)優(yōu)化,bpftrace可能無法正常追蹤golang程序。在編寫bpftrace腳本時,可以先使用 nm 命令查看一下可執(zhí)行程序,是否存在需要追蹤的函數(shù)的符號信息。如果沒有則bpftrace將不能對其進(jìn)行追蹤。
前面的示例中,都是對 int 類型的參數(shù)進(jìn)行追蹤,那對于 string 類型的參數(shù),是否也可以用同樣的方式進(jìn)行追蹤?將在下一篇中進(jìn)行討論。
常見的不能聲明為虛函數(shù)的有:普通函數(shù)(非成員函數(shù))、靜態(tài)成員函數(shù)、內(nèi)聯(lián)成員函數(shù)、構(gòu)造函數(shù)、友元函數(shù)。1、為什么C++不支持普通函數(shù)為虛函數(shù)? 普通函數(shù)(非成員函數(shù))只能overload,不能被override,聲明為虛函數(shù)也沒有什么意思,因此編譯器會在編譯時綁定函數(shù)。2、為什么C++不支持構(gòu)造函數(shù)為虛函數(shù)?這個原因很簡單,主要是從語義上考慮,所以不支持。因為構(gòu)造函數(shù)本來是為了明確初始化對象成員才產(chǎn)生的,然而virtual function主要是為了在不完全了解細(xì)節(jié)的情況下也能正確處理對象。另外,虛函數(shù)是在不同類型的對象產(chǎn)生不同的動作,現(xiàn)在對象還沒有產(chǎn)生,如何使用虛函數(shù)來完成你想完成的動作。3、為什么C++不支持靜態(tài)成員函數(shù)為虛函數(shù)? 靜態(tài)成員函數(shù)對于每個類來說只有一份代碼,所有的對象都共享這一份代碼,他不歸某個對象所有,所以他也沒有動態(tài)綁定的必要性。4、為什么C++不支持內(nèi)聯(lián)成員函數(shù)為虛函數(shù)? 其實很簡單,內(nèi)聯(lián)函數(shù)就是為了在代碼中直接展開,減少函數(shù)調(diào)用話費(fèi)的代價,虛函數(shù)是為了在繼承后對象能夠準(zhǔn)確的執(zhí)行自己的動作,這是不可能統(tǒng)一的。再說,inline函數(shù)在編譯時被展開,虛函數(shù)在運(yùn)行時才能動態(tài)的綁定函數(shù)。5、為什么C++不支持友元函數(shù)為虛函數(shù)?
分享名稱:Go語言禁止函數(shù)內(nèi)聯(lián),go語言閉包和匿名函數(shù)
網(wǎng)站路徑:http://jinyejixie.com/article0/hsigio.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供建站公司、商城網(wǎng)站、營銷型網(wǎng)站建設(shè)、動態(tài)網(wǎng)站、網(wǎng)頁設(shè)計公司、移動網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)