C語言中文網 目錄
首頁 > Go語言教程 > Go語言函數 閱讀:3,526

Go語言函數中的參數傳遞效果測試

Go 語言中傳入和返回參數在調用和返回時都使用值傳遞,這里需要注意的是指針、切片和 map 等引用型對象指向的內容在參數傳遞中不會發生復制,而是將指針進行復制,類似于創建一次引用。

下面通過一個例子來詳細了解 Go 語言的參數值傳遞。請先看完整的代碼:
package main

import "fmt"

// 用于測試值傳遞效果的結構體
type Data struct {
    complax []int // 測試切片在參數傳遞中的效果

    instance InnerData // 實例分配的innerData

    ptr *InnerData // 將ptr聲明為InnerData的指針類型
}

// 代表各種結構體字段
type InnerData struct {
    a int
}

// 值傳遞測試函數
func passByValue(inFunc Data) Data {

    // 輸出參數的成員情況
    fmt.Printf("inFunc value: %+v\n", inFunc)

    // 打印inFunc的指針
    fmt.Printf("inFunc ptr: %p\n", &inFunc)

    return inFunc
}

func main() {

    // 準備傳入函數的結構
    in := Data{
        complax: []int{1, 2, 3},
        instance: InnerData{
            5,
        },

        ptr: &InnerData{1},
    }

    // 輸入結構的成員情況
    fmt.Printf("in value: %+v\n", in)

    // 輸入結構的指針地址
    fmt.Printf("in ptr: %p\n", &in)

    // 傳入結構體,返回同類型的結構體
    out := passByValue(in)

    // 輸出結構的成員情況
    fmt.Printf("out value: %+v\n", out)

    // 輸出結構的指針地址
    fmt.Printf("out ptr: %p\n", &out)
}

1) 測試數據類型

為了測試結構體、切片、指針及結構體中嵌套的結構體在值傳遞中會發生的情況,需要定義一些結構,代碼如下:
// 用于測試值傳遞效果的結構體
type Data struct {
    complax []int    // 測試切片在參數傳遞中的效果

    instance InnerData    // 實例分配的innerData

    ptr *InnerData    // 將ptr聲明為InnerData的指針類型
}

// 代表各種結構體字段
type InnerData struct {
    a int
}
代碼說明如下:
  • 第 2 行,將 Data 聲明為結構體類型,結構體是擁有多個字段的復雜結構。
  • 第 3 行,complax 為整型切片類型,切片是一種動態類型,內部以指針存在。
  • 第 5 行,instance 成員以 InnerData 類型作為 Data 的成員。
  • 第 7 行,將 ptr 聲明為 InnerData 的指針類型。
  • 第 11 行,聲明一個內嵌的結構 InnerData。

2) 值傳遞的測試函數

本節中定義的 passByValue() 函數用于值傳遞的測試,該函數的參數和返回值都是 Data 類型。在調用中,Data 的內存會被復制后傳入函數,當函數返回時,又會將返回值復制一次,賦給函數返回值的接收變量。代碼如下:
// 值傳遞測試函數
func passByValue(inFunc Data) Data {

    // 輸出參數的成員情況
    fmt.Printf("inFunc value: %+v\n", inFunc)

    // 打印inFunc的指針
    fmt.Printf("inFunc ptr: %p\n", &inFunc)

    return inFunc
}
代碼說明如下:
  • 第 5 行,使用格式化的%+v動詞輸出 in 變量的詳細結構,以便觀察 Data 結構在傳遞前后的內部數值的變化情況。
  • 第 8 行,打印傳入參數 inFunc 的指針地址。在計算機中,擁有相同地址且類型相同的變量,表示的是同一塊內存區域。
  • 第 10 行,將傳入的變量作為返回值返回,返回的過程將發生值復制。

3) 測試流程

測試流程會準備一個 Data 格式的數據結構并填充所有成員,這些成員類型包括切片、結構體成員及指針。通過調用測試函數,傳入 Data 結構數據,并獲得返回值,對比輸入和輸出后的 Data 結構數值變化,特別是指針變化情況以及輸入和輸出整塊數據是否被復制,代碼如下:
// 準備傳入函數的結構
in := Data{
    complax: []int{1, 2, 3},
    instance: InnerData{
            5,
    },

    ptr: &InnerData{1},
}

// 輸入結構的成員情況
fmt.Printf("in value: %+v\n", in)

// 輸入結構的指針地址
fmt.Printf("in ptr: %p\n", &in)

// 傳入結構體, 返回同類型的結構體
out := passByValue(in)

// 輸出結構的成員情況
fmt.Printf("out value: %+v\n", out)

// 輸出結構的指針地址
fmt.Printf("out ptr: %p\n", &out)
代碼說明如下:
  • 第 2 行,創建一個 Data 結構的實例 in。
  • 第 3 行,將切片數據賦值到 in 的 complax 成員。
  • 第 4 行,為 in 的 instance 成員賦值 InnerData 結構的數據。
  • 第 8 行,為 in 的 ptr 成員賦值 InnerData 的指針類型數據。
  • 第 12 行,打印輸入結構的成員情況。
  • 第 15 行,打印輸入結構的指針地址。
  • 第 18 行,傳入 in 結構,調用 passByvalue() 測試函數獲得 out 返回,此時,passByValue() 函數會打印 in 傳入后的數據成員情況。
  • 第 21 行,打印返回值 out 變量的成員情況。
  • 第 24 行,打印輸出結構的地址。

運行代碼,輸出結果為:
in value: {complax:[1 2 3] instance:{a:5} ptr:0xc042008100}
in ptr: 0xc042066060
inFunc value: {complax:[1 2 3] instance:{a:5} ptr:0xc042008100}
inFunc ptr: 0xc0420660f0
out value: {complax:[1 2 3] instance:{a:5} ptr:0xc042008100}
out ptr: 0xc0420660c0

從運行結果中發現:
  • 所有的 Data 結構的指針地址發生了變化,意味著所有的結構都是一塊新的內存,無論是將 Data 結構傳入函數內部,還是通過函數返回值傳回 Data 都會發生復制行為。
  • 所有的 Data 結構中的成員值都沒有發生變化,原樣傳遞,意味著所有參數都是值傳遞。
  • Data 結構的 ptr 成員在傳遞過程中保持一致,表示指針在函數參數值傳遞中傳遞的只是指針值,不會復制指針指向的部分。

精美而實用的網站,提供C語言C++STLLinuxShellJavaGo語言等教程,以及socketGCCviSwing設計模式JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo