Web3 / Solidity 智能合约基础 #2

继续上一篇的内容,这次来看看合约的更多语法以及如何引入其他合约进行交互。

构造函数

和其他面向对象语言一样,Solidity 中也有构造函数。

constructor({[参数类型] [参数名], ...}) {}

例如:

address public immutable contractOwner;
constructor() {
    contractOwner = msg.sender;
}

这样就可以在这个合约对象被实例化之后给 contractOwner 指定一个值,这里的值就是创建此合约的发送者地址。

合约交互

在这之前,先用之前学过的知识对 SimpleStorage 改造一下:

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

struct People {
    string name;
    address peopleAddress;
    uint256 favoriteNumber;
}

contract SimpleStorage {
    address public immutable contractOwner;

    constructor() {
        contractOwner = msg.sender;
    }

    mapping(string => People) public nameToPeople;

    function addPeople(string calldata name) public {
        nameToPeople[name] = People(name, msg.sender, 0);
    }

    function getPeople(string calldata name) public view returns (People memory) {
        return nameToPeople[name];
    }

    function setFavoriteNumber(string calldata name, uint256 number) public {
        People storage p = nameToPeople[name];
        p.favoriteNumber = number;
    }

    function removePeople(string calldata name) public {
        nameToPeople[name] = People("", 0x0000000000000000000000000000000000000000, 0);
    }
}

这里定义了一个 People 名字对 People 对象的映射,下面是对这个映射的简单增删改查函数。

注意这个 People 结构被放在了合约外部,因为其他合约也可能用到这个结构。

引入合约

使用 import 关键字引入其他合约,例如 import "./path/to/contract/xxx.sol"

接下来创建一个新文件:SimpleStorageFactory.sol,然后引入刚才的 SimpleStorage 合约。

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

import "./SimpleStorage.sol";

contract SimpleStorageFactory {
    SimpleStorage[] private storages;
}

实例化合约

使用 new 关键字来实例化一个合约,和 Java 是一样的。

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

import "./SimpleStorage.sol";

contract SimpleStorageFactory {
    SimpleStorage[] private storages;

    function createNewStorage() public {
        storages.push(new SimpleStorage());
    }
}

这样就完成了一个创建合约的函数,这个合约被保存在 storages 数组内。

与合约交互

现在 storages 储存了许多合约,下面就需要对不同的合约进行不同的操作了。

和其他面向对象语言一样,直接 对象.函数() 调用对应方法即可。

下面来完成这个 SimpleStorageFactory 合约:

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

import "./SimpleStorage.sol";

contract SimpleStorageFactory {
    SimpleStorage[] private storages;

    function createNewStorage() public {
        storages.push(new SimpleStorage());
    }

    function addPeople(uint index, string calldata name, uint256 defaultNumber) public {
        SimpleStorage s = storages[index];
        s.addPeople(name);
        if (defaultNumber != 0) {
            s.setFavoriteNumber(name, defaultNumber);
        }
    }

    function getPeople(uint index, string calldata name) public view returns (People memory) {
        return storages[index].getPeople(name);
    }

    function removePeople(uint index, string calldata name) public {
         SimpleStorage s = storages[index];
         s.removePeople(name);
    }
}

继承与重写

继承和重写是面向对象中的两个很重要的概念,Solidity 也同样支持这样的操作。

继承

在 Solidity 中,使用 is 关键字来继承其他合约。

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

import "./SimpleStorageExt.sol";

contract ExtraStorage is SimpleStorage {
    
}

这样就完成了 ExtraStorage 对 SimpleStorage 的继承。

重写

一般情况下,父合约的函数是不允许被子合约重写的。

contract ExtraStorage is SimpleStorage {
    function addPeople(string calldata name) public {
        nameToPeople[name] = People(name, msg.sender, 0);
    }
}

这一段代码编译无法通过,错误信息:Overriding function is missing “override” specifier.solidity(9456)

在 Solidity 中,用 virtual 关键字将某个函数标记为可重载,子合约可以用 override 关键字进行重写。

现在回到 SimpleStorage 中,找到这个函数,并且加上 virtual 关键字:

contract SimpleStorage {
    // ...
    function addPeople(string calldata name) public virtual {
        nameToPeople[name] = People(name, msg.sender, 0);
    }
    // ...
}

现在再给子合约的对应函数加上 override 关键字即可:

contract ExtraStorage is SimpleStorage {
    function addPeople(string calldata name) public override {
        nameToPeople[name] = People(name, msg.sender, 0);
    }
}

字符串拼接

在 Solidity 中,字符串拼接不能直接使用 + 连接,而是需要自己实现一个方法来完成这个操作。

字符串的本质就是一串字节,也就是字节数组,只要把两个字节数组拼接成一个新的字节数组,再重新转换成 string 就好了。

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

import "./SimpleStorageExt.sol";

contract ExtraStorage is SimpleStorage {
    function addPeople(string calldata name) public override {
        string memory tName = combine("Prefix_", name);
        nameToPeople[name] = People(tName, msg.sender, 0);
    }

     function combine(string memory s1, string memory s2) public pure returns (string memory) {
        bytes memory s1bytes =  bytes(s1);
        bytes memory s2bytes =  bytes(s2);

        bytes memory result = new bytes(s1bytes.length + s2bytes.length);

        uint256 k = 0;
        for (uint256 i = 0; i < s1bytes.length; i++) {
            result[k++] = s1bytes[i];
        }
        for (uint256 i = 0; i < s2bytes.length; i++) {
            result[k++] = s2bytes[i];
        }
        return string(result);
    }
}

接下来继续完善一下上面的重写函数,这个子合约需要在添加 People 时给 People 的名字加上一个前缀。

contract ExtraStorage is SimpleStorage {
    function addPeople(string calldata name) public override {
        string memory tName = combine("Prefix_", name);
        nameToPeople[tName] = People(tName, msg.sender, 0);
    }
    // ...
}

结束语

本期介绍了合约的构造函数与实例化以及继承重写,还有字符串拼接的方法。

下一期将会再次对合约的其他内容进行补充,如有错误欢迎指出。

未经允许禁止转载本站内容,经允许转载后请严格遵守CC-BY-NC-ND知识共享协议4.0,代码部分则采用GPL v3.0协议
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇