Golang 函式呼叫機制分析 值傳遞與引用傳遞

2021-10-02 18:14:20 字數 3146 閱讀 6395

4. 總結

基本資料型別和陣列作為引數會進行值傳遞

接下來看乙個最簡單的例子

import

"fmt"

func

test

(num int

)func

main()

如果大家有其他語言的開發經驗,應該很容易看出來程式的輸出結果是

test :

11main :

10

我們再來看看引用傳遞是什麼結果

還是與上面的例子相同,只不過函式引數改為指標型別

import

"fmt"

func

test

(ptr *

int)

func

main()

我們再來看一下輸出結果

test :

11main :

11

這兩種不同的輸出結果,底層到底是如何實現的呢,

對於程式而言,在執行是作業系統會為其分配一塊記憶體,以滿足程式的執行需要,程式的程序會將這塊記憶體分為三個部分,分別是:1. 棧區 2. 堆區 3. **區。這是人為的邏輯上的劃分。

後面會有專門的文章來做golang的gc分析以及涉及到的逃逸分析等

下面我們就來對照一下**與邏輯上的分割槽來看一下到底是什麼輸出結果

首先,**從main函式開始執行,會在棧中開闢一塊區域用來儲存main函式的相關變數,注意這裡只是人為的邏輯分割槽。此時就在main函式的棧區中開闢出一塊空間用來儲存變數num

test函式處,此時在棧中開闢一塊空間作為test函式的棧區,其中也會開闢一塊空間儲存乙個num變數,只不過此時的test函式棧區中的nummain函式棧區中的num是兩個變數,其中test函式棧去中的num的值為main函式棧區中num值的拷貝。

此時程式執行到test函式中,將test函式棧區中num+1操作,操作結束之後執行輸出語句,輸出的是test函式棧區中的num,故輸出test : 11,之後程式返回到main函式中繼續執行。

注意此時test函式已經執行完畢,所以將test函式的棧去已經自動從棧區中刪除了,此時再執行輸出語句,輸出的是main函式棧區中儲存的num,故輸出num : 10

與前面類似,也首先在棧去中開闢一塊空間儲存main函式的相關變數。

程式向下執行,此時會在堆區中分配一塊空間,用來存放main函式的一些引用變數,其中的ptrint型別的指標,其值為main函式中num的位址,也就是ptr為指向num的指標。

函式執行到這裡的時候,會在棧區和堆區也分別建立test函式的空間,其中在test函式堆中儲存了乙個ptr指標,其值為main函式堆中ptr值的拷貝,所以這兩個ptr指標儲存的都是main函式中num的位址,也就是說test函式堆區中的ptr指標也指向main函式棧區的num變數。

此時操作test堆區中的ptr指標,也就像相當於操作main函式中的num變數,將其執行+1操作,程式繼續執行故輸出為test : 11

程式繼續執行到main函式中的輸出語句,此時已將test棧區所佔空間自動釋放,test堆區由gc機制決定何時釋放。main函式輸出的值就是main : 11

以上就是值傳遞與引用傳遞的分析。注意其中的棧,堆等均為人為的邏輯分割槽,每個程式在執行過程中也未必會嚴格按照此進行記憶體的分配,這裡是為了解釋方便,後期在做gc等分析的時候也會有更詳細的說明。

Golang反射呼叫函式

首先,來看看這段 php view source print?1functionfoobar 4 funcs array 5 foobar foobar 6 hello foobar 7 8 funcs foobar 9 funcs hello 它會輸出 view source print?1mik...

C 函式呼叫機制

區域性變數占用的記憶體是在程式執行過程中 動態 地建立和釋放的。這種 動態 是通過棧由系統自動管理進行的。當任何乙個函式呼叫發生時,系統都要作以下工作 1 建立棧空間 3 為被調函式中的區域性變數分配空間,完成引數傳遞 4 執行被調函式函式體 5 釋放被調函式中區域性變數占用的棧空間 7 繼續主調函...

函式呼叫和傳值呼叫

在使用函式時,所有的實參都是通過 傳值 方式傳遞的。這意味著每個實參都被求值,求值結果代替對應的形式引數,並且在函式中作為區域性變數使用。如果乙個變數傳遞給乙個函式,這個變數在呼叫環境中所儲存的值並不會被函式所修改。include int compute sum int n int main voi...