Foreword
In the past year or so, I have been exposed to some languages that are unfamiliar to me, mainly Python
and Go
. During this period, in order to quickly realize the needs, I just followed the example. Lao’s code; I didn’t delve into some details and principles.
Take parameter passing as an example. The implementation details of each language are different, but there are similarities; it is easy for many novices to be confused when they get started, leading to some low-level mistakes.
Java
Basic type transfer
Let’s take Java
, which I am most familiar with, as an example. I believe no one can write such code:
@Test public void testBasic() { int a = 10; modifyBasic(a); System.out.println(String.format("Final result main a==%s", a)); } private void modifyBasic(int aa) { System.out.println(String.format("aa==%s", aa)); aa = 20; System.out.println(String.format("After modification aa==%s", aa)); }
Output results:
Before modification aa==10
After modification aa==20
Final result main a==10
However, judging from the purpose of this code, it should be to modify the value of a
. Intuitively, it is understandable if the modification is successful.
The fundamental reason why the results are not in line with expectations is the misunderstanding of parameter value passing and reference passing.
Before this, let’s clarify the difference between passing by value and passing by reference:
Here we first draw the conclusion that Java
uses value transfer; this can also explain why the above example did not successfully modify the original data.
Refer to the picture below for better understanding:
When a function call occurs, a
passes itself into the modifyBasic
method, copies its own value and assigns it to a new variableaa
As you can see from the picture, there is no relationship between the two variables a
and aa
, so for aa
Modifications will not affect a
.
It’s a bit like I gave an apple to my wife, and she peeled it; but the one in my hand didn’t change, because she just took an identical apple from the dinner plate and peeled it.
If I want her apple, I can only ask her to give me the peeled apple; it is similar to the return value of the method.
a = modifyBasic(a);
Reference type transfer
Let’s take a look at the transfer of reference types:
private class Car{ private String name; public Car(String name) { this.name = name; } @Override public String toString() { return "Car{" + "name='" + name + '\'' + '}'; } } @Test public void test01(){ Car car1 = new Car("benz"); modifyCar1(car1); System.out.println(String.format("Final result main car1==%s", car1)); } private void modifyCar1(Car car){ System.out.println(String.format("before modification car==%s", car)); car.name = "bwm"; System.out.println(String.format("after modification car==%s", car)); }
In this example, a car1
of benz
is first created, and then modified to bmw
through a method. The original car1
Will it be affected?
Before modification car==Car{name='benz'} After modification car==Car{name='bwm'} Final result main car1==Car{name='bwm'}
The results may be contrary to some people’s expectations, but can such modifications affect the original data? Isn’t this inconsistent with passing by value
? It seems like this is passing by reference
, right?
Don’t worry, everyone will understand after analyzing the picture below:
In the test01
method we create an object of car1
, which is stored in the heap memory. Assume that the memory address is 0x1102
. So the variable car1
applies this memory address.
When we call the modifyCar1
method, a variable car
will be created in the method stack. The next point is:
This car
variable is copied from the original input parameter car1
, so the heap memory corresponding to it is still 0x1102
;
So when we modify the data through the car
variable, we essentially modify the data in the same heap memory. Therefore, car1
that originally referenced this memory address can also see the corresponding changes.
This may be a bit confusing to understand, but we just need to remember one thing:
When passing reference type data, what is passed is not the reference itself, but the value; it is just that the value
is the memory address.
Because the same memory address is passed, the operation of the data will still affect the outside world.
So in the same way, a code similar to thisUse your own judgment)
Python
In Python
, whether a variable is mutable is an important factor affecting parameter passing:
As shown in the figure above, bool int float
these immutable types cannot modify the original data during parameter passing.
if __name__ == '__main__': x = 1 modify(x) print('final x={}'.format(x)) def modify(val): val = 2 Final x=1
The principle is similar to that in Java Go
, which is based on value passing and will not be repeated here.
Here we focus on the process of variable data types in parameter passing:
if __name__ == '__main__': x = [1] modify(x) print('final x={}'.format(x)) def modify(val): val.append(2) Final x=[1, 2]
The final data is affected, so does that mean this is pass by reference? Let’s try another example:
if __name__ == '__main__': x = [1] modify(x) print('final x={}'.format(x)) def modify(val): val = [1, 2, 3] Final x=[1]
Obviously this is not a reference pass. If it is a reference pass, the final x
should be equal to [1, 2,3]
.
Judging from the results, this transfer process is very similar to the pointer transfer in Go
. What val
gets is also the memory address of the x
parameter. Copy; they all point to the same memory address.
So the modification of this data essentially changes the same data, but once it is reassigned, a new memory will be created and the original data will not be affected.
Similar to the image above in Java
.
So to summarize:
- For immutable data: When passing parameters, values are passed, and modifications to parameters will not affect the original data.
- For variable data: what is passed is a copy of the memory address, and the operation of the parameters will affect the original data.
So these three are all passed by value. Is there any language that passes by reference?
Of course, C++
supports passing by reference:
#include using namespace std; classBox { public: double len; }; void modify(Box& b); int main() { Box b1; b1.len=100; cout <<"The value of b1 before calling:" <<b1.len <<endl; modify(b1); cout <<"After the call, the value of b1:" <<b1.len <<endl; return 0; } void modify(Box& b) { b.len=10.0; Box b2; b2.len = 999; b = b2; return; } Before the call, the value of b1: 100 After the call, the value of b1: 999
You can see that assigning the new object b2
to the input parameter b
will affect the original data.
Summary
In fact, if you look at these languages, you will find that they have many similarities, so usually we can quickly learn other languages after mastering one language.
But it is often the basics among these that are most overlooked. I hope that everyone can take these basic knowledge into consideration when coding in daily life. If you think more about it, you will definitely write more beautiful code (bugs).
This concludes this article on the analysis of parameter passing principles in multiple languages (java, go, python, c++). For more information on the principles of parameter passing in Java, please search previous articles or continue browsing below. Related articles I hope you will support me in the future!