一段代码清楚认识状态变量、局部变量
pragma solidity ^0.4.4;
contract Person {
int public _age;
string public _name;
function Person(int age,string name) {
_age = age;
_name = name;
}
function f(string name) {
var name1 = name;
...
}
}
在这段代码中,
_age,
_name就属于
状态变量,
Person(int age,string name)中的
age和
name,还有
f(string name)中的
name以及
f()函数中声明的
name1都默认属于
本地/局部变量。
值类型代码演示
pragma solidity ^0.4.4;
contract Person {
int public _age;
function Person(int age) {
_age = age;
}
function f() {
midifyAge(_age);
}
function midifyAge(int age) {
age = 100;
}
}
在这段代码中,在我们创建合约时,因为构造函数中需要传入一个参数
age,如下图所示,我传入的值是
29。

合约创建完后,我们很容易在界面中看到
_age的初始值为
29。

接下来我们切换到
f方法,然后点击执行,因为
_age是值类型,所以在函数传参或者将值类型的变量值赋值给一个新变量,当我们尝试修改新变量时,原来的
值类型变量值并不会发生任何变化,在本案例中,当我们调用
midifyAge(_age)代码时,我们可以理解成,创建了一个临时变量
age,并且将
_age的值传给了
age,因为是值传递,当我们尝试在
midifyAge函数中修改新变量
age的值时,原来的变量值
_age的值保持不变。


引用类型memory/storage
引用类型的变量有两种类型,分别是
memory和
storage。
memory(值传递)
pragma solidity ^0.4.4;
contract Person {
string public _name;
function Person() {
_name = "liyuechun";
}
function f() {
modifyName(_name);
}
function modifyName(string name) {
var name1 = name;
bytes(name1)[0] = 'L';
}
}
代码解析 上面的代码中:function modifyName(string name) {
var name1 = name;
bytes(name1)[0] = 'L';
}
等价于:function modifyName(string memory name) {
var name1 = name;
bytes(name1)[0] = 'L';
}
等价于:function modifyName(string memory name) {
string memory name1 = name;
bytes(name1)[0] = 'L';
}
等价于:function modifyName(string name) {
string memory name1 = name;
bytes(name1)[0] = 'L';
}
由上面几种写法,我们不难看出,当
引用类型作为函数参数时,它的类型默认为
memory,函数参数为
memory类型的变量给一个变量赋值时,这个变量的类型必须和函数参数类型一致,所以我们可以写成
string memory name1 = name;,或者
var name1 = name;,
var声明一个变量时,这个变量的类型最终由赋给它值的类型决定。
任何函数参数当它的类型为引用类型时,这个函数参数都默认为memory类型,memory类型的变量会临时拷贝一份值存储到内存中,当我们将这个参数值赋给一个新的变量,并尝试去修改这个新的变量的值时,最原始的变量的值并不会发生变化。 例如: 在本案例中,当创建合约时,
_name的值为
liyuechun,当我们调用
f()函数时,
f()函数中会将
_name的值赋给临时的
memory变量
name,换句话说,因为
name的类型为
memory,所以
name和
_name会分别指向不同的对象,当我们尝试去修改
name指针指向的值时,
_name所指向的内容不会发生变化。



storage(指针传递)
当函数参数为
memory类型时,相当于
值传递,而
storage类型的函数参数将是指针传递。 如果想要在
modifyName函数中通过传递过来的指针修改
_name的值,那么必须将函数参数的类型显示设置为
storage类型,
storage类型拷贝的不是值,而是
_name指针,当调用
modifyName(_name)函数时,相当于同时有
_name,
name,
name1三个指针同时指向同一个对象,我们可以通过三个指针中的任何一个指针修改他们共同指向的内容的值。
pragma solidity ^0.4.4;
contract Person {
string public _name;
function Person() {
_name = "liyuechun";
}
function f() {
modifyName(_name);
}
function modifyName(string storage name) {
var name1 = name;
bytes(name1)[0] = 'L';
}
}
备注:function modifyName(string storage name) {
var name1 = name;
bytes(name1)[0] = 'L';
}
等价于:
function modifyName(string storage name) {
string storage name1 = name;
bytes(name1)[0] = 'L';
}
接下来我们将上面的代码拷贝到Ethereum Wallet中,你会发现有一个地方会报错。如下图所示:
报错的内容为:
Location has to be memory for publicly visible
functions (remove the "storage" keyword).
function modifyName(string storage name) {
^
报错原因:因为函数默认为
public类型,但是当我们的函数参数如果为
storage类型时,函数的类型必须为
internal或者
private

完整无错误代码如下:
pragma solidity ^0.4.4;
contract Person {
string public _name;
function Person() {
_name = "liyuechun";
}
function f() {
modifyName(_name);
}
function modifyName(string storage name) internal {
var name1 = name;
bytes(name1)[0] = 'L';
}
}

