接口

Solidity 中,接口、抽象合约、与合约的抽象程度大致如下:

接口仅定义了需要实现的外部接口函数。抽象合约、具体合约可以实现接口。抽象合约中可能还存在未具体实现的虚函数,或者待决定的构造函数参数等。

具体合约可以继承于抽象合约。当具体合约继承于抽象合约时,必须实现抽象合约中未实现的虚函数,或者确定抽象合约中未确定的构造函数参数。

接口声明

接口与抽象合约或者具体合约不同,它不能实现任何函数,并且:

  1. 它是最抽象的最高层,接口可以继承其他接口,但是不能继承其他合约(无论是抽象合约还是具体合约)
  2. 对于函数,接口仅能声明未实现的外部(external)函数接口
  3. 接口类似于程序之间的协议,它只能被合约实现,而不能被具体实例化,因此无 constructor
  4. 同3,不能声明状态变量
  5. 同3,不能声明函数修饰符
  6. 可以声明结构体、枚举,因为在定义的接口中,可能会使用到这些结构体、枚举
Interfaces.sol
运行
复制
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.1 <0.9.0;

/// @title 打招呼接口
interface SayHi {

    // 可以声明枚举
    enum Language {
        English,
        Chinese,
        French,
        German
    }

    // 可以声明结构体
    struct Contry {
        string name;
        Language lang;
    }

    // 声明外部接口函数,默认为 virtual 函数,virtual 关键字可省略
    function sayHi() external virtual returns (string memory);
}

接口中的函数默认且必须为虚函数,virtual 关键字可以省略。

接口实现

使用 is 关键字,来标识某个合约实现了某个接口:

InterfacesImpl.sol
运行
复制
// 实现接口 SayHi
contract Friend is SayHi {
    function sayHi() external pure returns (string memory) {
        return "Hi";
    }
}

接口继承

接口可以继承另一个接口:

InterfacesImpl.sol
运行
复制
// 接口继承接口 SayHi
interface People is SayHi {

}

一个接口同样可以继承多个接口:

InterfacesImpl.sol
运行
复制
// 继承多个接口
interface SayHi1 {
    function sayHi() external returns (string memory);
}

interface SayHi2 {
    function sayHi() external returns (string memory);
}

interface People2 is SayHi1, SayHi2 {
    function sayHi() external override(SayHi1, SayHi2) returns (string memory);
}

当多个父接口具有相同签名及返回类型的函数时,需要显式地使用 override 关键字,重新声明该外部接口。