Solidity中的表达式和控制结构(含实例)

116 阅读1分钟

嗨,读者朋友们!欢迎回到Solidity的世界。在这个博客中,我们将看到什么是Solidity中的表达式和控制结构。

Solidity中的表达式和控制结构是一个巨大的概念,我们今天将看到。

控制结构

大多数从大括号语言中知道的控制结构在Solidity中都是可用的。

有if、else、while、do、for、break、continue、return,具有C或JavaScript中已知的通常语义。

Solidity 也支持以try/catch-语句的形式处理异常,但只适用于外部函数调用和合约创建调用。

函数调用

内部函数调用

当前合约的函数可以被直接调用("内部")。也可以递归,正如在这个无厘头的例子中所看到的。

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

// This will report a warning
contract C {
    function example1(uint variable) public pure returns (uint ret) { return variable + example1(); }
    function example2() internal pure returns (uint ret) { return example2(7) + example1(); }
}

函数调用在EVM内部被转化为简单的跳转。

这表明当前的内存是不明确的,也就是说,将内存引用传递给内部调用的函数是非常有效的。只有同一合同实例的函数可以被内部调用。

你还是应该避免过度的递归,因为每个内部函数调用都会占用至少一个栈槽,而可用的栈槽只有1024个。

外部函数调用

函数的调用也可以使用this.example1(8);c.`example1`(2);符号,其中c 是一个合同实例,example1 是一个属于c 的函数。通过这两种方式调用函数example1 ,会导致它被 "外部 "调用,使用消息调用,而不是直接通过跳转调用。请注意,对this 的函数调用不能在构造函数中使用,因为实际的契约还没有被创建。

其他合约的函数必须被外部调用。对于外部调用,所有的函数参数都必须被复制到内存中。

当调用其他合同的函数时,你可以用特殊的选项{value: 10, gas: 10000} ,指定随调用发送的威或气的数量。请注意,我们不鼓励明确指定气体值,因为操作码的气体成本在未来可能会发生变化。你向合约发送的任何魏国都会被加入到该合约的总余额中。

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

contract InfoFeed {
    function info() public payable returns (uint ret) { return 42; }
}

contract Consumer {
    InfoFeed feed;
    function setFeed(InfoFeed addr) public { feed = addr; }
    function callFeed() public { feed.info{value: 10, gas: 800}(); }
}

你需要在info 函数中使用修饰符payable ,因为否则,value 选项将不可用。

由于EVM认为对一个不存在的合约的调用总是成功的,Solidity使用extcodesize 操作码来检查即将被调用的合约是否真的存在(它包含代码),如果不存在就会引起一个异常。如果返回数据将在调用后被解码,那么这个检查将被跳过,因此ABI解码器将捕捉到一个不存在的合同的情况。

请注意,在对地址而不是合同实例进行操作的低级调用中,不会进行这种检查。

如果被调用的合同本身抛出一个异常或失去气体,函数调用也会导致异常。

命名的调用和匿名的函数参数

函数调用的参数可以用名字给出,顺序不限,如果它们被括在{ } ,在下面的例子中可以看到。参数列表在名称上必须与函数声明中的参数列表相吻合,但可以是任意的顺序。

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

contract C {
    mapping(uint => uint) data;

    function f() public {
        set({value: 2, key: 3});
    }

    function set(uint key, uint value) public {
        data[key] = value;
    }

}

遗漏的函数参数名

不使用的参数(尤其是返回参数)的名称可以省略。这些参数将仍然存在于堆栈中,但它们是不可访问的。

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

contract C {
    // omitted name for parameter
    function func(uint var1, uint) public pure returns(uint) {
        return var1;
    }
}

谢谢你的阅读。这些是关于Solidity中表达式和控制结构的几个概念和示例代码。