2.4.1 Layout of a Solidity Source File

Layout of a Solidity Source File

本文档翻译自 Solidity docs。

源文件可以包含任意数量的 contract定义,import 指令和 pragma 指令。

Pragmas

pragma 关键字可用于启用某些编译器功能或检查。 pragma指令始终是源文件的本地指令,因此如果要在所有项目中启用它,则必须将pragma添加到所有文件中。如果 import 另一个文件,该文件中的pragma将不会自动应用于导入文件。

Version Pragma

源文件可以(并且应该)使用所谓的版本编译指示进行注释,以拒绝使用可能引入不兼容更改的未来编译器版本进行编译。我们尝试将这些更改保持在绝对最小值,尤其是以语义变化也需要更改语法的方式引入更改,但这当然不总是可行的。因此,至少对于包含重大更改的版本来读取更改日志总是一个好主意,这些版本将始终具有 0.x.0x.0.0 形式的版本。

版本编译指示使用如下:

pragma solidity ^0.4.0;

这样的源文件不会使用早于版本0.4.0的编译器进行编译,并且它也不能在从版本0.5.0开始的编译器上工作(通过使用 ^ 添加第二个条件)。这背后的想法是在版本 0.5.0 之前不会有任何重大更改,因此我们始终可以确保我们的代码将按照我们的预期方式进行编译。我们没有修复编译器的确切版本,因此仍然可以使用bugfix版本。

可以为编译器版本指定更复杂的规则,表达式遵循 npm 使用的表达式。

Note

使用版本编译指示不会更改编译器的版本。它也不会启用或禁用编译器的功能。它只是指示编译器检查其版本是否与pragma所需的版本匹配。如果不匹配,编译器将发出错误。

Experimental Pragma

第二个pragma是实验性的pragma。它可用于启用默认情况下尚未启用的编译器或语言的功能。目前支持以下实验编译指示:

ABIEncoderV2

新的ABI编码器能够对任意嵌套的数组和结构进行编码和解码。它产生的优化代码不太理想(这部分代码的优化器仍在开发中)并且没有像旧编码器那样接收到太多的测试。您可以使用 pragma experimental ABIEncoderV2; 激活它。

SMTChecker

构建Solidity编译器时必须启用此组件,因此它不适用于所有Solidity二进制文件。构建说明解释了如何激活此选项。它在大多数版本中为Ubuntu PPA版本激活,但不适用于solc-js,Docker镜像,Windows二进制文件或静态构建的Linux二进制文件。

如果您使用 pragma experimental SMTChecker;,那么您将获得通过查询SMT求解器获得的其他安全警告。该组件尚不支持Solidity语言的所有功能,可能会输出许多警告。如果报告不支持的功能,分析可能不完整。

Importing other Source Files

Syntax and Semantics

Solidity支持与JavaScript中可用的导入语句非常相似的语句(来自ES6),尽管Solidity不知道“默认导出”的概念。

在全局级别,您可以使用以下形式的import语句:

import "filename";

此语句将所有全局符号从“filename”(以及在那里导入的符号)导入当前全局范围(与ES6不同,但向后兼容Solidity)。建议不要使用这种简单的形式,因为它会以不可预测的方式污染命名空间:如果在“filename”中添加新的顶级项,它们将自动出现在所有从“filename”导入的文件中。最好明确导入特定符号。

以下示例创建一个新的全局符号 symbolName,其成员是 “filename” 中的所有全局符号。

import * as symbolName from "filename";

如果存在命名冲突,您还可以在导入时重命名符号。此代码创建新的全局符号 aliassymbol2,它们分别从 “filename” 中引用 symbol1symbol2

import {symbol1 as alias, symbol2} from "filename";

另一种语法不是ES6的一部分,但可能很方便:

import "filename" as symbolName;

等价于 import * as symbolName from "filename";

Note

如果使用 import “filename.sol” 作为 moduleName;,则从 “filename.sol” 中作为 moduleName.C 访问名为 C 的合约,而不是直接使用 C.

Paths

在上面,filename 始终被视为带 / 作为目录分隔符的路径。. 作为当前和 .. 作为父目录。什么时候 ... 后跟一个字符,除了 /,它不被视为当前或父目录。所有路径名都被视为绝对路径,除非它们以当前路径 . 开头,或者父目录 ..

要从与当前文件相同的目录导入文件 x,请使用 import "./x" as x;。如果使用 import "x" as x; 相反,可能引用不同的文件(在全局 “include director” 中)。

这取决于编译器(见下文)如何实际解析路径。通常,目录层次结构不需要严格映射到本地文件系统,它也可以映射到通过发现的资源,例如 ipfs,http或git。

Note

始终使用 `import "./filename.sol";` 之类的相对导入;并避免在路径说明符中使用 `..`。在后一种情况下,最好使用全局路径并设置重映射,如下所述。

Use in Actual Compilers

调用编译器时,您可以指定如何发现路径的第一个元素以及路径前缀重映射。例如,您可以设置重映射,以便从您的本地目录 /usr/local/dapp-bin/library 中实际读取从虚拟目录 github.com/ethereum/dapp-bin/library 导入的所有内容。如果应用多个重映射,则首先尝试具有最长密钥的那个。不允许使用空前缀。重映射可以取决于上下文,允许您配置要导入的包,例如,同名库的不同版本。

solc:

对于solc(命令行编译器),您将这些路径重映射提供为 context:prefix=target arguments,其中 context:= target 部分都是可选的(在这种情况下,target 默认为 prefix)。编译常规文件的所有重映射值(包括它们的依赖关系)。

这种机制是向后兼容的(只要没有文件名包含 =:),因此不会发生重大变化。导入以 prefix 开头的文件的 context 目录中或下面的所有文件都通过将 prefix 替换为 target 来重定向。

例如,如果将 github.com/ethereum/dapp-bin/ 本地克隆到 /usr/local/dapp-bin,则可以在源文件中使用以下内容:

import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol" as it_mapping;

然后运行编译器:

solc github.com/ethereum/dapp-bin/=/usr/local/dapp-bin/ source.sol

作为一个更复杂的示例,假设您依赖于使用您签出到 /usr/local/dapp-bin_old 的旧版dapp-bin的模块,那么您可以运行:

solc module1:github.com/ethereum/dapp-bin/=/usr/local/dapp-bin/ \
     module2:github.com/ethereum/dapp-bin/=/usr/local/dapp-bin_old/ \
     source.sol

这意味着 module2 中的所有导入都指向旧版本,但 module1 中的导入指向新版本。

Note

`solc` 只允许您包含某些目录中的文件。它们必须位于其中一个显式指定的源文件的目录(或子目录)中,或者位于重映射目标的目录(或子目录)中。如果要允许直接绝对包含,请添加重映射 `/=/`。

如果存在多个导致有效文件的重映射,则选择具有最长公共前缀的重映射。

Remix:

Remix 为GitHub提供自动重映射,并通过网络自动检索文件。您可以导入上面的可迭代映射,例如

::

import "github.com/ethereum/dapp-bin/library/iterable_mapping.sol" as it_mapping;

Remix可能会在将来添加其他源代码提供程序。

Comments

可以使用单行注释 (//) 和多行注释 (/.../)。

// This is a single-line comment.

/*
This is a
multi-line comment.
*/

Note

单行注释由utf8编码中的任何unicode行终止符(LF,VF,FF,CR,NEL,LS或PS)终止。注释后终结符仍然是源代码的一部分,因此如果它不是ascii符号(这些是NEL,LS和PS),则会导致解析器错误。

此外,还有另一种称为natspec注释的注释,其文档尚未编写。它们使用三斜杠 (///) 或双星号块 (/** ... */) 编写,它们应直接在函数声明或语句之上使用。您可以在这些注释中使用 Doxygen样式 的标记来记录函数,注释形式验证的条件,并提供在用户尝试调用函数时向用户显示的确认文本。

在下面的示例中,我们记录了合约的标题,两个函数参数的说明和两个返回变量。

pragma solidity >=0.4.0 <0.6.0;

/** @title Shape calculator. */
contract ShapeCalculator {
    /** @dev Calculates a rectangle's surface and perimeter.
      * @param w Width of the rectangle.
      * @param h Height of the rectangle.
      * @return s The calculated surface.
      * @return p The calculated perimeter.
      */
    function rectangle(uint w, uint h) public pure returns (uint s, uint p) {
        s = w * h;
        p = 2 * (w + h);
    }
}

项目源代码

项目源代码会逐步上传到 Github,地址为 https://github.com/windstamp/dapp。

Contributor

  1. Windstamp, https://github.com/windstamp

Reference

  1. https://solidity.readthedocs.io/en/v0.5.0/
  2. https://solidity-cn.readthedocs.io/zh/develop/
  3. https://solidity.readthedocs.io/en/latest/layout-of-source-files.html
  4. https://docs.npmjs.com/misc/semver
  5. https://remix.ethereum.org/#optimize=false
  6. https://en.wikipedia.org/wiki/Doxygen

你可能感兴趣的:(2.4.1 Layout of a Solidity Source File)