# Data Structure 進階語法與資料結構教學程式碼共筆
## Array
```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.8.4;
contract Array {
uint256[] arr_1;
uint256[] arr_2 = [3,2,4];
uint256[5] arr_3;
uint256[][] array2D = [ [1,2,3], [4,5,6] ];
constructor(uint256 _dynamicArrayLength) {
arr_1 = new uint256[](_dynamicArrayLength);
}
function getValueOfIndex(uint256 _index) public view returns (uint256) {
return arr_2[_index];
}
function addToArray(uint256 _value) public {
arr_2.push(_value);
}
function valueCount() public view returns(uint256) {
return arr_3.length;
}
function dynamicValueCount() public view returns(uint256) {
return arr_1.length;
}
}
```
## Mapping
```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.8.4;
contract Mapping {
mapping(uint256 => address) public nfts;
uint256 counter = 0;
function ownerOf(uint256 _tokenId) public view returns (address) {
return nfts[_tokenId];
}
function mintNFT() public {
nfts[counter] = msg.sender;
counter++;
}
}
```
## Struct
```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.8.4;
contract Struct {
struct User {
address id;
string name;
}
User owner;
constructor() {
owner = User(msg.sender, "KryptoCamp");
}
function getOwnerAddress() public view returns (address) {
return owner.id;
}
function getOwnerName() public view returns (string memory) {
return owner.name;
}
}
```
## Enum
```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.8.4;
contract Enum {
enum Rarity {
original, // 0
rare, // 1
super_rare // 2
}
Rarity public rarity;
constructor() {
rarity = Rarity.original;
}
function makeSuperRare() public {
rarity = Rarity.super_rare;
}
function reset() public {
delete rarity;
}
}
```
## Returns
```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.8.4;
contract Returns {
uint256 public x;
uint256 public y;
uint256 public z;
function getTrue() public pure returns (bool) {
return true;
}
function multipleReturns() public view returns(uint256 a, uint256 b, uint256 c) {
return (1, 2, 3);
}
function processMultipleReturns() public view returns(uint256 x, uint256 y, uint256 z) {
(x,y,z) = multipleReturns();
}
function getLastReturnValue() public view returns(uint256 z) {
(,,z) = multipleReturns();
}
}
```
## Visibility Function
```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.8.4;
contract Visibility {
function coreFunction() [visibility] {
// do something...
}
}
```
## Visibility Function 02
```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.8.4;
contract Math {
function addOne(uint256 x) internal pure returns (uint256) {
return x + 1;
}
}
contract Visibility is Math {
function coreFunction() public pure returns (string memory) {
return "Hello World";
}
function calculate(uint256 y) public pure returns (uint256) {
return addOne(5) + y;
}
}
```
## State Mutability - 可變性
```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.8.4;
contract StateMutability {
function coreFunction() [visibility] [mutability] returns (bool) {
return true;
}
}
```
## Extends
```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.8.4;
contract Math {
function addOne(uint256 x) internal pure returns (uint256) {
return x + 1;
}
}
contract Visibility is Math {
function coreFunction() public pure returns (string memory) {
return "Hello World";
}
function calculate(uint256 y) public pure returns (uint256) {
return addOne(5) + y;
}
}
```
## For Loop
```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.8.4;
contract ForLoop {
uint256[] numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
function countEvenNumbers() public view returns (uint256) {
uint256 count = 0;
for (uint256 i = 0; i < numbers.length; i++) {
if (isEvenNumber(numbers[i])) {
count++;
}
}
return count;
}
function isEvenNumber(uint256 _number) public view returns (bool) {
return (_number % 2 == 0 ? true : false);
}
}
```
## While
```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.8.4;
contract While {
uint256[] numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
function countEvenNumbers() public view returns (uint256) {
uint256 count = 0;
uint256 i = 0;
while (i < numbers.length) {
if (isEvenNumber(numbers[i])) {
count++;
}
i++;
}
return count;
}
function isEvenNumber(uint256 _number) public view returns (bool) {
return (_number % 2 == 0 ? true : false);
}
}
```
## Modifier
```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity >= 0.8.4;
contract Modifier {
address owner;
uint256 amountPerAddress = 5;
constructor() {
owner = msg.sender;
}
modifier onlyOwner {
require(owner == msg.sender);
_;
}
modifier maxAmount(uint256 _amount) {
require(_amount < amountPerAddress);
_;
}
function importantFunction() public onlyOwner view returns (string memory) {
return "Hello you are owner!";
}
function updateAmountPerAddress(uint256 _amount) public onlyOwner {
amountPerAddress = _amount;
}
function buySomething(uint256 _amount) public maxAmount(_amount) view returns (string memory) {
return "Success!";
}
}
```
## Error
```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
/// Not enough funds for transfer. Requested `requested`,
/// but only `available` available.
error NotEnoughFunds();
contract OtherContract {
function wrongFunction() external {
revert();
}
}
contract ErrorControl {
mapping(address => uint) balances;
OtherContract public otherContract;
constructor() {
otherContract = new OtherContract();
}
function transferThrowError() public {
revert();
// throw;
}
function transferAssertError() public {
assert(false); // true
//.. ->> xx
//.. ->> xx
}
function transferRevertError() public {
revert NotEnoughFunds();
}
function requireRevertError() public {
require(true, "revert error!!!!!");
}
function tryCatchError() public returns (string memory) {
try otherContract.wrongFunction() {
} catch {
return "Something wrong!!";
}
}
}
```
## Event - 事件
```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
contract Event {
event MyPushLog(uint256 indexed);
function debugMode(uint256 _message) public {
emit MyPushLog(_message);
}
}
```
`前端測試鏈事件接收`
```javascript
import { ethers } from 'ethers'
const provider = new ethers.providers.JsonRpcProvider('使用 foundry anvil 啟動測試鏈')
const abi = ['event MyPushLog(uint256 indexed)']
const iface = new ethers.utils.Interface(abi)
const LogHash = ethers.utils.id('MyPushLog(uint256)')
const filter = {
address: '替換為部署合約網址',
topics: [LogHash],
}
provider.on(filter, async (result) => {
console.log('Log in:', result, '\r\n')
let events = iface.parseLog(result)
console.log('indexed:', events.args[0])
})
```
## Interface - 介面
```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
contract Counter {
uint256 public count;
function inc() external {
count += 1;
}
}
interface Counter {
function count() external view returns (uint256);
function inc() external;
}
contract Interface {
function incCounter(address _counter) external {
Counter(_counter).inc();
}
function getCount(address _counter) external view returns (uint256) {
return Counter(_counter).count();
}
}
```
作業:如何透過 modifier 讓外部合約無法操作 Counter 合約的 inc 功能。
`抽象合約`
```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
abstract contract Feline {
function utterance() public pure virtual returns (bytes32);
}
contract Cat is Feline {
function utterance() public pure override returns (bytes32) {
return "miaow";
}
}
```
## Receive
```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
contract Receive {
event ReceiveLog(string);
function buybool() public {
payable(接收方地址).transfer(1 ether);
}
receive() external payable {
emit ReceiveLog("[001]receive ether...");
}
fallback() external payable {}
}
```
## Fallback
```solidity!
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
contract Fallback {
event FallbackCall(string);
fallback() external payable {
emit FallbackCall("call me fallback!");
}
}
```
## Virtual, Override
```solidity!
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
contract Virtual {
uint256 public counter = 0;
function incCount() public virtual {
counter++;
}
}
contract Override is Virtual {
function incCount() public override {
counter += 2;
}
}
```
## Operator - 算術運算子
```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
contract Operator {
uint x = 10;
uint y = 5;
function add() public view returns (uint256) {
return x + y;
}
function sub() public view returns (uint256) {
return x - y;
}
function mul() public view returns (uint256) {
return x * y;
}
function div() public view returns (uint256) {
return x / y;
}
function mod() public view returns (uint256) {
return x % y;
}
function inc() public {
x++;
}
function dec() public {
y--;
}
}
```
## Operator - 關係運算子
```solidity
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
contract RelationalOperator {
function equal(uint256 left, uint256 right) public pure returns (bool) {
return left == right;
}
function notEqual(uint256 left, uint256 right) public pure returns (bool) {
return left != right;
}
function GT(uint256 left, uint256 right) public pure returns (bool) {
return left > right;
}
function LT(uint256 left, uint256 right) public pure returns (bool) {
return left < right;
}
function GTE(uint256 left, uint256 right) public pure returns (bool) {
return left >= right;
}
function LTE(uint256 left, uint256 right) public pure returns (bool) {
return left <= right;
}
}
```
## Storage, Memory, Calldata
```solidity!
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.4;
contract Storage {
struct Todo {
string title;
bool completed;
}
// struct, array, mapping
Todo[] public todos;
function addTodo(string memory _title) public {
todos.push(Todo({
title: _title,
completed: false
}));
}
function updateTodoFromStorage(uint256 _index, string memory _title) public {
_title = "eat breakfast";
Todo storage todo = todos[0];
todo.completed = true;
todo.title = _title;
}
function fakeUpdateTodoFromMemory(uint256 _index) public view returns (Todo memory) {
Todo memory todo = todos[_index];
todo.completed = true;
return todo;
}
function updateTodoFromCalldata(uint256 _index, string calldata _title) public {
Todo storage todo = todos[0];
todo.title = _title;
}
}
```