【区块链安全 | 第二十六篇】表达式与控制结构(二)

在这里插入图片描述

表达式与控制结构

赋值

结构化赋值与返回多个值

Solidity 内部支持元组类型(tuple types),即由多个可能类型不同、数量在编译时为常数的对象组成的列表。元组可用于一次性返回多个值。这些返回值可以赋值给新声明的变量,也可以赋值给已有变量(或广义上的左值 LValues)。

元组在 Solidity 中并不是一种正式的类型,它们只能用于表达式的语法组合。

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;

contract C {
    uint index;

    function f() public pure returns (uint, bool, uint) {
        return (7, true, 2);
    }

    function g() public {
        // 用类型声明变量并从返回的元组中赋值,
        // 不需要指定所有元素(但数量必须一致)。
        (uint x, , uint y) = f();
        // 交换变量值的常见技巧 —— 不适用于非值类型的存储变量。
        (x, y) = (y, x);
        // 可以省略部分组件(也适用于变量声明)。
        (index, , ) = f(); // 设置 index 为 7
    }
}

不允许混合变量声明与非声明赋值,例如以下写法是无效的:(x, uint y) = (1, 2);

注意:当涉及引用类型时(如数组、结构体等),同时对多个变量赋值可能会出现意外的复制行为,需要小心使用。

数组和结构体的赋值复杂性

对于非值类型(如数组和结构体,包括 bytesstring),赋值语义更为复杂。

在下面这个例子中,对 g(x) 的调用对 x 无效,因为它在内存中创建了一个存储值的独立副本。然而,h(x) 可以成功修改 x,因为它传递的是引用而非副本。

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.4.22 <0.9.0;

contract C {
    uint[20] x;

    function f() public {
        g(x);
        h(x);
    }

    function g(uint[20] memory y) internal pure {
        y[2] = 3;
    }

    function h(uint[20] storage y) internal {
        y[3] = 4;
    }
}
  • g(x):传入的是 memory 类型的副本,对 y[2] 的修改不会影响到原始的 x
  • h(x):传入的是 storage 引用,对 y[3] 的修改将会直接改变合约状态变量 x[3]

这是 Solidity 中引用类型(如数组、结构体)赋值和传参行为的重要概念,memory 会复制,storage 会引用原始数据

作用域和声明

声明的变量将具有初始默认值,其字节表示为全零。变量的“默认值”是该类型的典型“零状态”。例如,bool 的默认值是 falseuintint 类型的默认值是 0。对于静态大小的数组和 bytes1bytes32,每个单独的元素将初始化为对应类型的默认值。对于动态大小的数组、bytesstring,默认值是空数组或空字符串。对于 enum 类型,默认值是它的第一个成员。

Solidity 中的作用域遵循 C99(以及许多其他语言)广泛使用的作用域规则:变量从其声明后的立即可见点开始,直到包含声明的最小 { } 块的结束。作为这一规则的例外,for 循环初始化部分声明的变量仅在 for 循环的结束之前可见。

类似参数的变量(函数参数、修饰符参数、catch 参数等)在后续的代码块中可见 —— 对于函数和修饰符参数,它们在函数体和修饰符体内可见;对于 catch 参数,它们在 catch 块内可见。

在代码块外声明的变量和其他项目,例如函数、合约、用户定义的类型等,即使在声明之前,也可以可见。这意味着我们可以在声明之前使用状态变量,并递归调用函数。

因此,以下示例将编译而不会产生警告,因为这两个变量具有相同的名称,但作用域是互不重叠的。

// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.5.0 <0.9.0;
contract C {
    function minimalScoping() pure public {
        {
            uint same;
            same = 1;
        }

        {
            uint same;
            same = 3;
       

猜你喜欢

转载自blog.csdn.net/2301_77485708/article/details/147034757