5月29日 22:35
What are the differences between view, pure, and payable function modifiers in Solidity?
In Solidity, view, pure, and payable are three important function modifiers that define the behavioral characteristics and constraints of functions.
1. View Modifier
Definition: Declares that the function will not modify the contract's state variables but can read the state.
Characteristics:
- Can read state variables (storage)
- Cannot modify state variables
- Cannot send ETH
- Does not consume Gas (when called externally)
soliditycontract ViewExample { uint256 public storedData = 100; // view function can read state function getData() public view returns (uint256) { return storedData; // read state variable } // Error: view function cannot modify state function setData(uint256 _data) public view { // storedData = _data; // compilation error! } }
2. Pure Modifier
Definition: Declares that the function neither reads nor modifies contract state, relying only on input parameters.
Characteristics:
- Cannot read state variables
- Cannot modify state variables
- Cannot access global variables like
msg.sender,msg.value - Does not consume Gas (when called externally)
soliditycontract PureExample { uint256 public constant VALUE = 100; // pure function only depends on input parameters function add(uint256 a, uint256 b) public pure returns (uint256) { return a + b; } // pure function can read constants function getConstant() public pure returns (uint256) { return VALUE; // constants don't count as state reads } // Error: pure function cannot read state variables function getData() public pure returns (uint256) { // return storedData; // compilation error! } }
3. Payable Modifier
Definition: Allows the function to receive ETH (Ether).
Characteristics:
- Can receive ETH transfers
- Can read and modify state (default behavior)
- Can access
msg.valueto get transfer amount - Consumes Gas
soliditycontract PayableExample { mapping(address => uint256) public balances; // payable function can receive ETH function deposit() public payable { require(msg.value > 0, "Must send ETH"); balances[msg.sender] += msg.value; } // query contract balance function getBalance() public view returns (uint256) { return address(this).balance; } // withdraw ETH function withdraw(uint256 amount) public { require(balances[msg.sender] >= amount, "Insufficient balance"); balances[msg.sender] -= amount; payable(msg.sender).transfer(amount); } }
Modifier Comparison Table
| Feature | view | pure | payable |
|---|---|---|---|
| Read state | ✅ | ❌ | ✅ |
| Modify state | ❌ | ❌ | ✅ |
| Receive ETH | ❌ | ❌ | ✅ |
| Access msg.value | ❌ | ❌ | ✅ |
| Gas consumption (external call) | None | None | Yes |
| Use cases | Data queries | Pure calculations | Fund operations |
Combined Usage
Some modifiers can be combined:
soliditycontract CombinedExample { // payable + view cannot be combined because view doesn't consume Gas while payable needs to handle transfers // can define ETH receiving functions receive() external payable {} fallback() external payable {} // calculation functions use pure function calculateFee(uint256 amount) public pure returns (uint256) { return amount * 5 / 100; // 5% fee } // query functions use view function getContractBalance() public view returns (uint256) { return address(this).balance; } }
Practical Application Example
soliditycontract Bank { mapping(address => uint256) private balances; uint256 public totalDeposits; // payable: receive deposits function deposit() public payable { balances[msg.sender] += msg.value; totalDeposits += msg.value; } // view: query balance function getBalance(address user) public view returns (uint256) { return balances[user]; } // pure: calculate interest function calculateInterest(uint256 principal, uint256 rate) public pure returns (uint256) { return principal * rate / 100; } // payable + other operations function withdraw() public payable { uint256 amount = balances[msg.sender]; require(amount > 0, "No balance"); balances[msg.sender] = 0; totalDeposits -= amount; payable(msg.sender).transfer(amount); } }
Best Practices
- Prefer pure: If a function doesn't need to read state, using pure can save Gas
- Explicitly use view: For read-only operations, explicitly mark view to improve code readability
- Use payable carefully: Ensure payable functions have appropriate access controls and amount validation
- Avoid abuse: Don't misuse these modifiers for Gas optimization, which may lead to security issues