我读了一些关于存储
、内存
和 View
、pure
的文档,但我不完全了解理解他们。我有以下代码:
contract {
struct Random {
uint32 state;
uint8 i;
}
function main() pure internal {
Random rand = Random(seed, 0);
...
}
function get_rand(Random rand, uint8 n) pure internal returns (uint16) {
assert(n <= 16)
while (true) {
if (rand.i >= 8) {
rand.state = xorshift32(rand.state);
rand.i = 0;
}
uint8 r = uint8(rand.state >> (rand.i << 4)) & 0x0f;
rand.i += 1;
if (r < n) {
return r;
}
}
}
}
我的问题是:
1) 我应该在 main
中为局部变量标记 storage
还是 memory
吗?我应该为 get_rand
中的参数标记什么?
2)突变会起作用吗?比如说,我读到纯函数无法更改状态变量,并且内存变量会被复制。将两者标记为存储
就足够了吗?如果 get_rand
改变了参数,我还应该声明 pure
吗?
谢谢
最佳答案
view
和 pure
是函数修饰符,描述该函数中的逻辑如何与合约状态交互。如果您的合约要从存储中读取,但不写入,则可以使用 view
(或 constant
完全相同)修饰符(请参阅 view functions documentation )。如果您不打算从合约状态读取或写入,并且您所做的一切仅适用于内存变量,那么它就是 pure function 。
Should I mark storage or memory for the local variable in main? And what should I mark for the argument in get_rand?
默认情况下,结构是 storage
变量,它将尝试将您的结构写入状态。这是你需要小心的地方,因为如果你在应该使用 storage
的地方使用 memory
变量,你实际上可以覆盖你的状态。示例:
contract C {
uint _var;
function f() public {
Random r;
...
}
}
在本例中,r
是未初始化的存储指针,这导致变量指向存储槽 0。当您在结构体中设置某个变量 ( r.state = 100;
) 时,它会将该值写入槽 0,覆盖 _var
处的值。
当您想要创建一个新结构体作为局部变量时,您需要使用 memory
修饰符,然后将其设置为状态变量(或将其添加到状态映射/数组)。当您想要将结构从映射/数组读取到局部变量中时,请使用 storage
。
根据您提供的示例,您希望将其设置为 memory
变量。 非常仔细阅读 Solidity 文档的 this section。
Will the mutation work? Say, I read that a pure function cannot change state variables, and memory variables are copied. Is marking both as storage enough? Should I still declare pure for get_rand if it changes its argument?
不,它不会改变您的契约(Contract)状态。虽然局部结构变量默认为 storage
,但函数参数默认始终为 memory
(即使是结构)。修改rand
内部的get_rand
不会修改任何状态。如果您将函数更改为访问状态,则会因 pure
修饰符而收到编译错误。
关于solidity - Solidity 中的状态变量是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49613580/