为什么 _initializing 和 isTopLevelCall 变量用于 Openzeppelin 的 Initializable 合约?

Why are _initializing and isTopLevelCall variables used in Initializable contract of Openzeppelin?

这是代理模式上下文中的抽象合约:

abstract contract Initializable {
    bool private _initialized;
    bool private _initializing;

    modifier initializer() {
        require(_initializing || !_initialized, "Initializable: contract is already initialized");

        bool isTopLevelCall = !_initializing;
        if (isTopLevelCall) {
            _initializing = true;
            _initialized = true;
        }

        _;

        if (isTopLevelCall) {
            _initializing = false;
        }
    }
}

contract UpgradebleTest1 is Initializable {
    uint public x;

    function initialize(uint _x) public initializer {
        x = _x;
    }
}

我不明白_initializing 和isTopLevelCall 的必要性。仅使用 _initialized 进行控制还不够吗?

谢谢,

_initializingisTopLevelCall 组合允许使用 initializer 修饰符进行链式调用:

contract UpgradebleTest1 is Initializable {
    uint public x;

    function initialize(uint _x) public initializer {
        internalInit(_x);
    }

    function internalInit(uint _x) internal initializer {
        x = _x;
    }
}

如果没有 _initializingisTopLevelCall 检查,initializer 修饰符将在第一次调用 (initialize()) 上传递,但在第二次调用 (internalInit()).

modifier initializer() {
    require(!_initialized, "Initializable: contract is already initialized");
    _initialized = true;
}
abstract contract Initializable {
        bool private _initialized;
    
        modifier initializer() {
            require(!_initialized, "Initializable: co...");
            _;
            _initialized = true;
        }
    }
    
contract UpgradebleTestParent is Initializable {
    uint public x;

    function initialize(uint _x) internal initializer {
        x = _x;
    }
}

contract UpgradebleTestMain is UpgradebleTestParent {
    function init(uint _x) public initializer {
        initialize(_x);
    }
}

如果和上面一样,会执行同样的逻辑,但是_initialized = true;会被不必要地执行两次,对吧?但是,它似乎比以前多一个变量和相关附加说明的便宜吗?不是吗?