在此 OpenZeppelin ERC20 实现中声明一个额外的局部变量的目的是什么?

What is the purpose of declaring an extra local variable in this OpenZeppelin ERC20 implementation?

从使用solidity ^0.8.0的Openzeppelin的ERC20实现来看,_transfer函数是这样的:

function _transfer(address sender, address recipient, uint256 amount) internal virtual {
        require(sender != address(0), "ERC20: transfer from the zero address");
        require(recipient != address(0), "ERC20: transfer to the zero address");

        _beforeTokenTransfer(sender, recipient, amount);

        uint256 senderBalance = _balances[sender];
        require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
        _balances[sender] = senderBalance - amount;
        _balances[recipient] += amount;

        emit Transfer(sender, recipient, amount);
    }

写有没有特殊用途

uint256 senderBalance = _balances[sender];
require(senderBalance >= amount, "ERC20: transfer amount exceeds balance");
_balances[sender] = senderBalance - amount;

而不是简单地

require(_balances[sender]>= amount, "ERC20: transfer amount exceeds balance");
_balances[sender] -= amount;

?

pull request comment that contains this commit 添加 senderBalance:

The addition of revert messages back into the 0.8 branch (#2491) generated double reading of some storage slot. This PR remove the double sload, which reduces gas costs of running the affected function.

所以这是因为降低了 gas 使用量。

“一次从存储读取,一次从内存读取”比“两次从存储读取”消耗更少的 gas。