Solidity 编程语言:合约结构、类型与修饰符

FreeGuideOnline 最新 2026-06-15

Solidity 编程语言基础:合约结构、类型与修饰符

Solidity 是以太坊智能合约的主流开发语言,属于静态类型、面向合约的高级语言。本教程将从零讲解合约的基本结构、核心类型系统以及函数与变量的修饰符,帮助初学者快速上手编写安全的智能合约。

合约结构

一个 .sol 文件通常由许可证标识版本声明导入语句合约定义组成。

最小合约骨架

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract HelloWorld {
    string public greeting = "Hello, World!";
}
  • SPDX-License-Identifier:声明代码许可,推荐 MIT。
  • pragma solidity ^0.8.20:指定编译器版本,^ 表示兼容 0.8.20 及以上但不包含 0.9.0。
  • contract 关键字定义合约,类似面向对象中的类。合约内部可以包含状态变量函数事件修饰符结构体枚举等。

导入与继承

import "./Other.sol";
import {Symbol} from "./Lib.sol";

contract Child is Parent {
    // 可多重继承
}
  • 使用 import 引入外部文件或合约。
  • 通过 is 关键字实现继承,支持多重继承,顺序影响方法解析。

类型系统

Solidity 的类型分为值类型引用类型。值类型在赋值或传参时直接拷贝数据;引用类型需要留意数据位置(memorystoragecalldata)。

值类型

布尔型

bool public isReady = true;

支持 !&&||==!= 运算。

整数

int8   smallInt;        // 有符号 8 位
uint256 bigNumber;      // 无符号 256 位(默认)
  • uint 默认为 uint256int 默认为 int256
  • 遵循位数递增步长 8 ,范围 uint8uint256
  • 运算包括 +-*/%**,0.8 起自动检查溢出。

定长浮点数(极少使用)

Solidity 支持 fixed / ufixed,但尚未完全实现,主流合约中几乎不用。

地址类型

address wallet = 0xAb5...;
address payable payee = payable(0xAb5...);
  • address:普通地址,存储 20 字节的以太坊地址。
  • address payable:可接收以太币,含 transfersend 方法。
  • 常用成员:.balance 查询余额,.call 进行低级调用。

合约类型

将合约名称当作类型,可以传递合约实例。

OtherContract public other;

定长字节数组

bytes32 public hash;
bytes1   b = 0x12;

bytes1bytes32,按位存储,有 .length 属性。

枚举

enum Status { Pending, Shipped, Delivered }
Status public current;

可与 uint 相互转换,默认值 0 对应第一个成员。

引用类型

引用类型需显式声明数据位置:storage(链上持久存储)、memory(函数内临时内存)、calldata(只读调用数据,节省 gas)。

数组

uint[] public fixedSize;             // 动态数组
uint[5] memory arr;                  // 定长数组
  • 支持 pushpoplength 修改长度(仅 storage 态可变长数组)。
  • 内存中数组需提前分配大小,new uint[](3)

结构体

struct Product {
    uint  id;
    string name;
    bool  inStock;
}
Product public item;

提供构造函数式初始化:Product(1, "book", true) 或键值对 Product({id: 1, name: "book", inStock: true})

映射(Mapping)

mapping(address => uint) public balances;
mapping(address => mapping(uint => bool)) public nested;
  • 键类型允许值类型、bytesstring、合约,不可为映射、数组、结构体。
  • storage 可用,不支持遍历,也不存在长度概念。

字符串与动态字节数组

string public name = "Alice";
bytes public data = "0xabcd";
  • string 用于 UTF-8 文本,与 bytes 一样动态大小。
  • string 不支持直接通过索引获取字符,需转为 bytes(s)

修饰符

修饰符用于改变函数或变量的行为,包括可见性状态可变性自定义逻辑等。

可见性修饰符

函数可见性

  • public:内外均可调用。
  • private:仅当前合约内可调用。
  • internal:当前合约及继承合约可调用。
  • external:仅从外部调用(内部调用需写 this.f(),消耗 gas 更高)。

状态变量的可见性除 external 外均可使用。public 变量会自动生成同名 getter 函数。

uint public total;        // 自动生成 total() 查询函数
uint private secret;

状态可变性修饰符

这些修饰符声明函数是否会读取或修改链上状态。

  • view:只读状态,不修改任何状态变量。
  • pure:既不读取也不修改状态,仅依赖输入参数计算。
  • 无修饰符(默认):可读可写状态。
  • payable:允许函数接收以太币,没有该修饰符的函数调用时携带 value 会失败。
function getBalance() public view returns (uint) {
    return address(this).balance;
}

function add(uint x, uint y) public pure returns (uint) {
    return x + y;
}

function deposit() public payable {
    // 可以接收 ETH
}

自定义修饰符

开发者可定义修饰符实现对前置条件、权限等的复用。

modifier onlyOwner {
    require(msg.sender == owner, "Not owner");
    _;  // 继续执行函数体
}

function withdraw() public onlyOwner {
    // 提款逻辑
}

_ 代表插入被修饰函数的主体。如需参数化:modifier fee(uint amount) { require(msg.value >= amount); _; }

其他重要修饰符与关键字

针对状态变量的修饰符

  • constant:用于编译期常量,不占用存储槽(如 uint constant DAY = 24 hours;)。
  • immutable:部署时赋值一次,之后不可变,存储方式更省 gas。
address public immutable creator;
constructor() { creator = msg.sender; }

继承相关修饰符

  • virtual:声明函数或函数修饰符可被子合约重写。
  • override:子合约重写父合约函数时使用。
contract Base {
    function foo() public virtual returns (string memory) {
        return "base";
    }
}

contract Child is Base {
    function foo() public pure override returns (string memory) {
        return "child";
    }
}

重写多个父合约函数时写作 override(Base1, Base2)

修饰符的执行顺序

自定义修饰符可组合使用,执行顺序为从右向左(或按声明顺序由外至内),_ 之前为前置,_ 之后为后置逻辑。

modifier A { _; }
modifier B { _; }

function f() A B { ... }
// 执行顺序:A的前置 → B的前置 → 函数体 → B的后置 → A的后置

综合示例

以下合约汇总基本结构、常见类型与修饰符用法:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

contract Store {
    address public immutable owner;
    mapping(uint => Item) public items;
    uint public itemCount;

    struct Item {
        string name;
        uint price;   // wei
        bool available;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "Unauthorized");
        _;
    }

    constructor() {
        owner = msg.sender;
    }

    function addItem(string calldata _name, uint _price) external onlyOwner {
        items[itemCount] = Item(_name, _price, true);
        itemCount++;
    }

    function buyItem(uint _id) external payable {
        Item storage item = items[_id];
        require(item.available, "Sold out");
        require(msg.value >= item.price, "Insufficient payment");
        item.available = false;
        // 实际项目中转移资金给卖家等
    }

    function getItem(uint _id) external view returns (string memory, uint, bool) {
        Item storage item = items[_id];
        return (item.name, item.price, item.available);
    }
}

该示例展示了:immutable 不可变变量、mapping 映射、struct 结构体、自定义修饰符 onlyOwnerexternalview 函数、以及 storage 引用的使用。


通过掌握合约结构、Solidity 的类型划分以及各类修饰符的含义,你已经具备编写基本智能合约的能力。后续学习可深入异常处理、事件、库合约以及更高级的设计模式。