golang 函数传多个参数_关于Golang中方法参数的传递
結構體聲明
為了說明函數以及方法調用的過程,這里先定義一個struct,在下面的描述中會使用到它。
type Person struct {
Name string
Age uint16
}
普通函數中的參數傳遞
在Golang中,普通函數的行參如果是值類型,那么調用的實參也必須是實參,反之,如果函數行參是指針類型,那么傳入的實參必須是地址。我們來看幾個例子。
行參要求值傳遞
// 定義一個普通函數,要求值傳遞
func tell(person Person) {
fmt.Printf("Hi, my name's %v, I'm %v years old", person.Name, person.Age)
}
實參按照值的方式傳遞
// 調用函數,提供一個struct實例
person := Person{"Tom", 28}
tell(person) // Hi, my name's Tom, I'm 28 years old
我們可以看到,這種調用肯定是沒有問題的,程序能夠正常運行,當然這也是理所當然的
實參按照指針的方式傳遞
// 調用函數,提供一個struct實例的地址
person := Person{"Tom", 28}
tell(&person) // 編譯錯誤:Cannot use '&person' (type *Person) as type Person
這會直接報編譯錯誤,因為函數要求傳入的是一個值,而函數調用給的卻是一個地址,是不符合編譯器要求的。
行參要求指針傳遞
這種情況,對于普通函數來講,與上面的情形類似,即實參必須是地址,而不能是值。這里就不舉例了。
方法中的參數傳遞
由上面我們可以看出,其實對于普通函數而言,參數的傳遞方式非常直接,而且容易理解。即,函數要求什么,調用的時候就給它什么。
但是對于方法調用來說,就會稍微復雜一些了(其實這種復雜性是為了給程序員提供方便,是不是感覺有點矛盾?哈哈)
對象是值的情況
首先,讓我們把上面的函數改成一個方法,并且要求使用值對象的方式傳遞對象
func (person Person) tell() {
fmt.Printf("Hi, my name's %v, I'm %v years old", person.Name, person.Age)
}
按照我們對于普通函數的理解,調用該方法時,我們必須提供一個值對象,即
person := Person{"Tom", 28}
person.tell() // Hi, my name's Tom, I'm 28 years old
這種方式肯定工作,而且與普通函數的行為一致。但是,接下來,我要給該函數提供一個指針,我們來看
// 得到一個結構體指針
var person *Person = &Person{"Tom", 28}
person.tell() // Hi, my name's Tom, I'm 28 years old
從上面的運行結果,我們看到,這種調用也是被允許的,并沒有報錯。但是為什么?
這其實由于Go在編譯的時候,會幫我們做一些事情,把代碼轉換成類似下面這個樣子
(*person).tell()
即,會把指針類型先進行取值運算,然后再將其傳遞給方法。有了背后這一個轉換,程序員不用在調用的時候先進行取值運算,再調用方法。從這個角度來講,這種操作是不是給程序員提供了方便?
對象是指針的情況
類似的,如果方法要求傳入的對象是指針類型,Go也允許我們傳入值對象,Go在背后也是做了一個轉換,即把傳入的值,先進行地址運算,然后再將其傳入方法中。下面詳細描述一下。
假設我們的方法改成這樣
// 該方法接收一個指針對象
func (person *Person) tell() {
fmt.Printf("Hi, my name's %v, I'm %v years old", person.Name, person.Age)
}
調用的時候,我們可以傳入指針,也可以傳入值。下面是傳入值的情況
person := Person{"Tom", 28}
person.tell() // Hi, my name's Tom, I'm 28 years old
之所以這種調用沒有報錯,也是因為Go其實在編譯的時候,進行了轉換
(&person).tell()
在方法內修改對象的屬性值,是否會影響原來的對象?
讓我們來考慮一種情況,如果方法要求的對象是值對象,即
func (person Person) rename(newName string) {
person.Name = newName
}
而在調用這個方法的時候,調用的對象是個指針,那么下面的程序輸出什么?
var person *Person = &Person{"Tom", 28}
person.rename("Jimmy")
person.tell()
答案是Hi, my name's Tom, I'm 28 years old。名字并沒有改變,即,雖然我們傳遞了一個指針給rename方法,但是在rename方法里面對于person的修改,并沒有反映到外部的person對象。也就是說,方法內的對象與方法外的對象之間是值拷貝。
接下來,我們再看另外一種情況,即,方法要求傳入的對象是指針,但是調用的時候是在值對象上進行訪問
func (person *Person) rename(newName string) {
person.Name = newName
}
person := Person{"Tom", 28}
person.rename("Jimmy")
person.tell()
輸出的結果是Hi, my name's Jimmy, I'm 28 years old,也就是說名字改變了,即使我們在調用的時候傳入的是值對象。
總結
如果方法要求的是值對象,那么無論調用的時候傳遞的是值還是指針,都是值拷貝
如果方法要求的是指針,那么無論調用的時候傳遞的是值還是指針,都是地址拷貝
背后的原理:go在編譯的時候會根據方法定義的要求對傳入的對象進行取值或取地址運算
有疑問加站長微信聯系(非本文作者)
總結
以上是生活随笔為你收集整理的golang 函数传多个参数_关于Golang中方法参数的传递的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小米登录协议分析_联想前副总裁常程跳槽小
- 下一篇: 抽象方法可以有方法体_什么方法可以祛斑?