傳參一直是語言中有點糾結的東西。一提到這個,總會有人說,需要區分傳值,傳遞引用,還有傳遞指針什麼的。而且,貌似不同的語言對此也有不同的實作。 我自己也對這個有點搞混了,是以需要實驗一下。
我常用的幾個語言是,c++,go語言,python這幾種。三個語言中,隻有c++有引用,而python是沒有指針的。參數傳遞主要就兩類,傳值和傳遞引用。
本文隻寫python和go語言,c++太複雜了,需要專門研究。
試驗的主要分為幾種類型,分别為:
單一的變量類型,比如int,float這種基本類型。實驗中使用int。
複雜點的變量類型,比如數組,string,有的自帶map等。試驗中使用數組。
複合類型研究,比如class,struct。
貌似python根本就沒有指針,引用的概念。是以,友善不少。
但是,這也會帶來别的問題,因為問題還是存在,傳遞參數到函數中,函數内對參數的改變,會不會影響到外面的。
代碼:
<code>01</code>
<code>#coding=utf-8</code>
<code>02</code>
<code>03</code>
<code>def</code> <code>play(x):</code>
<code>04</code>
<code> </code><code>x</code><code>+</code><code>=</code><code>1</code>
<code>05</code>
<code> </code><code>print</code> <code>"函數内:"</code><code>,x</code>
<code>06</code>
<code>07</code>
<code>x</code><code>=</code><code>1</code>
<code>08</code>
<code>print</code> <code>"初始狀态:"</code><code>,x</code>
<code>09</code>
<code>play(x)</code>
<code>10</code>
<code>print</code> <code>"執行play函數後:"</code><code>,x</code>
輸出:
<code>1</code>
<code>初始狀态: 1</code>
<code>2</code>
<code>函數内: 2</code>
<code>3</code>
<code>執行play函數後: 1</code>
基礎變量的傳參是複制傳參,也就是傳值。函數内對變量的操作不會影響外部。
<code> </code><code>x[</code><code>0</code><code>]</code><code>+</code><code>=</code><code>1</code>
<code> </code><code>x[</code><code>1</code><code>]</code><code>+</code><code>=</code><code>3</code>
<code>x</code><code>=</code><code>[</code><code>1</code><code>,</code><code>1</code><code>,</code><code>1</code><code>,</code><code>1</code><code>]</code>
<code>初始狀态: [1, 1, 1, 1]</code>
<code>函數内: [2, 4, 1, 1]</code>
<code>執行play函數後: [2, 4, 1, 1]</code>
函數内的改變影響了外部。是以這是<b>傳遞類的引用</b>。不單單是數組,python的dict等類型都是引用傳參(它們其實都是類)。是以需要注意。
<code>class</code> <code>mytest:</code>
<code> </code><code>a</code><code>=</code><code>1</code>
<code> </code><code>b</code><code>=</code><code>1</code>
<code> </code><code>def</code> <code>__repr__(</code><code>self</code><code>):</code>
<code> </code><code>return</code> <code>"a="</code><code>+</code><code>str</code><code>(</code><code>self</code><code>.a)</code><code>+</code><code>",b="</code><code>+</code><code>str</code><code>(</code><code>self</code><code>.b)</code>
<code> </code><code>x.a</code><code>+</code><code>=</code><code>1</code>
<code>11</code>
<code> </code><code>x.b</code><code>+</code><code>=</code><code>3</code>
<code>12</code>
<code>13</code>
<code>14</code>
<code>x</code><code>=</code><code>mytest()</code>
<code>15</code>
<code>16</code>
<code>17</code>
<code>18</code>
<code>初始狀态: a=1,b=1</code>
<code>函數内: a=2,b=4</code>
<code>執行play函數後: a=2,b=4</code>
這裡,對象被傳遞到函數中,函數内對執行個體的操作影響到了外面。是以,這是傳遞對象的引用。
<code>package main</code>
<code>import </code><code>"fmt"</code>
<code>func add(x </code><code>int</code><code>) {</code>
<code> </code><code>x++</code>
<code> </code><code>fmt.println(</code><code>"函數内的x:"</code><code>,x)</code>
<code>}</code>
<code>func main() {</code>
<code> </code><code>x:=1</code>
<code> </code><code>fmt.println(</code><code>"初始的x:"</code><code>,x)</code>
<code> </code><code>add(x)</code>
<code> </code><code>fmt.println(</code><code>"函數執行後的x: "</code><code>,x)</code>
<code>初始的x: 1</code>
<code>函數内的x: 2</code>
<code>函數執行後的x: 1</code>
看的出來,這是傳值,函數内對x的操作并沒有影響到外部的x。很明顯,調用add函數時,函數copy了一份x。這和python的一樣。
<code>func add(ptr *</code><code>int</code><code>) {</code>
<code> </code><code>fmt.println(</code><code>"------函數内------"</code><code>)</code>
<code> </code><code>*ptr++</code>
<code> </code><code>fmt.println(</code><code>"ptr指向的值:"</code><code>,*ptr)</code>
<code> </code><code>fmt.println(</code><code>"ptr指向的位址:"</code><code>,ptr)</code>
<code> </code><code>var ptr *</code><code>int</code><code>=&x</code>
<code> </code><code>fmt.println(</code><code>"ptr指針指向的值:"</code><code>,*ptr)</code>
<code> </code><code>fmt.println(</code><code>"ptr指向的位址:"</code><code>,ptr)</code>
<code> </code><code>add(ptr)</code>
<code> </code><code>fmt.println(</code><code>"------函數執行後-----------"</code><code>)</code>
<code>19</code>
<code> </code><code>fmt.println(</code><code>"ptr指針的值:"</code><code>,*ptr)</code>
<code>20</code>
修改了原來的代碼,在主函數聲明了一個ptr指針,指向x。然後把指針傳遞進add函數。
<code>ptr指針指向的值: 1</code>
<code>ptr指向的位址: 0xc208000150</code>
<code>4</code>
<code>------函數内------</code>
<code>5</code>
<code>ptr指向的值: 2</code>
<code>6</code>
<code>7</code>
<code>------函數執行後-----------</code>
<code>8</code>
<code>函數執行後的x: 2</code>
<code>9</code>
<code>ptr指針的值: 2</code>
執行後,外面的x也變成了2.
可以看出,add函數的修改,影響了外部的x。這也是傳值,但是,傳遞的值是一個位址。
<code>func add(array []</code><code>int</code><code>) {</code>
<code> </code><code>array[0]+=1</code>
<code> </code><code>array[1]+=2</code>
<code> </code><code>fmt.println(</code><code>"函數内的數組:"</code><code>,array)</code>
<code> </code><code>array:=[]</code><code>int</code><code>{1,1,1,1}</code>
<code> </code><code>fmt.println(</code><code>"-------初始狀态------"</code><code>)</code>
<code> </code><code>fmt.println(</code><code>"初始的數組:"</code><code>,array)</code>
<code> </code><code>add(array)</code>
<code> </code><code>fmt.println(</code><code>"函數執行後的數組:"</code><code>,array)</code>
<code>-------初始狀态------</code>
<code>初始的數組: [1 1 1 1]</code>
<code>函數内的數組: [2 3 1 1]</code>
<code>函數執行後的數組: [2 3 1 1]</code>
傳遞數組和傳遞指針有着類似的效果,在函數内改變了數組内的值,外面的數組值也改了。這個和c類語言類似。
<code>import </code><code>"strconv"</code>
<code>type test </code><code>struct</code><code>{</code>
<code> </code><code>a </code><code>int</code>
<code> </code><code>b </code><code>int</code>
<code>func (</code><code>this</code> <code>*test)str()string{</code>
<code> </code><code>var tmp string</code>
<code> </code><code>tmp=</code><code>"a:"</code><code>+strconv.itoa(</code><code>this</code><code>.a)+</code><code>" b:"</code><code>+strconv.itoa(</code><code>this</code><code>.b)</code>
<code> </code><code>return</code> <code>tmp</code>
<code>func add(test test){</code>
<code> </code><code>test.a+=1</code>
<code> </code><code>test.b+=2</code>
<code> </code><code>fmt.println(</code><code>"函數中的struct:"</code><code>,test.str())</code>
<code>21</code>
<code> </code><code>test:=test{1,10}</code>
<code>22</code>
<code>23</code>
<code> </code><code>fmt.println(</code><code>"初始的struct:"</code><code>,test.str())</code>
<code>24</code>
<code>25</code>
<code> </code><code>add(test)</code>
<code>26</code>
<code>27</code>
<code> </code><code>fmt.println(</code><code>"函數執行後的struct:"</code><code>,test.str())</code>
<code>28</code>
<code>初始的struct: a:1 b:10</code>
<code>函數中的struct: a:2 b:12</code>
<code>函數執行後的struct: a:1 b:10</code>
被作為參數傳入給函數的結構體test,在add函數裡對2個值做了加1和加2操作,但是沒有影響到外部的變量。這是傳值。
從上面的實驗來看,無論是python還是go,它們的基礎類型在傳參時都是複制傳參(傳值)。對于數組,二者也是一樣,類似傳遞指針,屬于傳遞引用。
但是對于對象,python參數傳遞類似于指針傳遞(傳對象引用),go語言則是類似于c類語言,屬于複制傳參。
語言
python
go語言
基礎變量傳參
傳值
數組
傳遞引用
對象
傳遞引用(arry,dict屬于對象)