文档: https://solidity-by-example.org/
视频教程: https://www.youtube.com/watch?v=xv9OmztShIw&list=PLO5VPQH6OWdVQwpQfw9rZ67O6Pjfo6q-p
说明
看视频没注意有文档, 前面写了一篇好多废话, 之后结合文档+视频去做笔记和写代码, 做记录...
常量(constant)
常量是不能修改的变量。它们的值是硬编码的,使用常量可以节省gas成本。
不可变变量(imutable)
不可变变量就像常量。不可变变量的值可以在构造函数内部设置,但之后不能修改。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract ConstantsAndImutable {
// coding convention to uppercase constant variables
address public constant MY_ADDRESS = 0x777788889999AaAAbBbbCcccddDdeeeEfFFfCcCc;
uint public constant MY_UINT = 123;
// coding convention to uppercase constant variables
address public immutable MY_ADDRESS2;
uint public immutable MY_UINT2;
constructor(uint _myUint) {
MY_ADDRESS2 = msg.sender;
MY_UINT2 = _myUint;
}
}
注意这种带构造器的合约需要填入初始值才能部署, 不然会报错:
creation of Constants errored: Error encoding arguments: Error: invalid BigNumber string (argument="value", value="", code=INVALID_ARGUMENT, version=bignumber/5.7.0)
从显示来看的话没有太大区别:
对状态变量的读写
要编写或更新状态变量,需要发送一个交易(transaction)。
另一方面,可以免费读取状态变量,而无需支付任何交易费用。
实际上前面已经做过类似的操作了. 修改一下案例.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
contract StateVariable {
uint public stateval = 123;
function get() view external returns(uint) {
return stateval;
}
function set(uint myval) external {
stateval = myval;
}
}
如果是用的MetaMask
的话会对这个支付费用比较敏感. 每次执行都需要用户去确认交易. 而Remix vm
提供的测试号都是默认直接执行交易了.
问题: 函数也可以用public
修饰, 那么public
和external
是有什么区别?
货币单位ether和wei
交易(transaction)需要用ether支付。
类似于一美元等于100美分的方式,1个以太等于$10^{18}$ WEI。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract EtherUnits {
uint public oneWei = 1 wei;
// 1 wei is equal to 1
bool public isOneWei = 1 wei == 1; // true
uint public oneEther = 1 ether;
// 1 ether is equal to 10^18 wei
bool public isOneEther = 1 ether == 1e18; // true
}
gas fee (燃气费)
你需要支付多少以太币进行一笔交易?
你支付的以太币数量为 gas spent(已消耗的燃气)* gas price(每单位燃气愿意支付的以太币)
,其中:
gas
是计算的单位。gas spent
是交易中使用的总燃气费用。gas price
是你愿意为每单位燃气支付的以太币。
具有更高gas price
的交易在区块中具有更高的优先级。未使用的燃气将被退还。
燃气限制
对于你可以使用的燃气量有两个上限:gas limit
(你愿意在交易中使用的最大燃气量,由你设置)block gas limit
(区块中允许的最大燃气量,由网络设置)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
// 用死循环去测试gas的返还
contract Gas {
uint public i = 0;
// Using up all of the gas that you send causes your transaction to fail.
// State changes are undone.
// Gas spent are not refunded.
function forever() public {
// Here we run a loop until all of the gas are spent
// and the transaction fails
while (true) {
i += 1;
}
}
}
if/else, 三元运算符
跟Java和C一样的.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract IfElse {
function foo(uint x) public pure returns (uint) {
if (x < 10) {
return 0;
} else if (x < 20) {
return 1;
} else {
return 2;
}
}
function ternary(uint _x) public pure returns (uint) {
// if (_x < 10) {
// return 1;
// }
// return 2;
// shorthand way to write if / else statement
// the "?" operator is called the ternary operator
return _x < 10 ? 1 : 2;
}
}
for, while, do-while
循环结构也跟Java, C类似
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Loop {
function loop() public {
// for loop
for (uint i = 0; i < 10; i++) {
if (i == 3) {
// Skip to next iteration with continue
continue;
}
if (i == 5) {
// Exit loop with break
break;
}
}
// while loop
uint j;
while (j < 10) {
j++;
}
}
}
Mapping
使用语法(keyType => valueType)创建映射。
keyType
可以是任何内置值类型、字节、字符串或任何合约。valueType
可以是任何类型,包括另一个Mapping
或Array
。Mapping
是不可迭代的。
Mapping
貌似不能作为返回类型, 会报错:
TypeError: Data location must be "memory" or "calldata" for return parameter in function, but none was given.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8;
contract Mapping {
mapping (address => uint) public myMap; // 用于观察
// Mapping 总会返回值.
// If the value was never set, it will return the default value.
function get(address key) public view returns(uint) {
return myMap[key]; // 2885 gas
}
function set(address key, uint val) public {
myMap[key] = val; // 22854 gas
}
function remove(address key) public {
delete myMap[key]; // 5554 gas
}
}
contract NestedMapping {
mapping (address => mapping(uint => bool)) public nestedMap;
function get(address addr, uint _i) public view returns(bool){
return nestedMap[addr][_i]; // 3178 gas
}
function set(address addr, uint _i, bool _b) public {
nestedMap[addr][_i] = _b; // 25217 gas
}
function remove(address addr, uint _i) public {
delete nestedMap[addr][_i]; // 25060 gas
}
}
随便找个地址测着玩就行, 按照两个合约和上面提到的报错来看, 我们没法一次获取整个Mapping的值?
Array
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract Array {
// Several ways to initialize an array
uint[] public arr;
uint[] public arr2 = [1, 2, 3];
// Fixed sized array, all elements initialize to 0
uint[10] public myFixedSizeArr;
function get(uint i) public view returns (uint) {
return arr[i];
}
// Solidity can return the entire array.
// But this function should be avoided for
// arrays that can grow indefinitely in length.
function getArr() public view returns (uint[] memory) {
return arr;
}
function push(uint i) public {
// Append to array
// This will increase the array length by 1.
arr.push(i);
}
function pop() public {
// Remove last element from array
// This will decrease the array length by 1
arr.pop();
}
function getLength() public view returns (uint) {
return arr.length;
}
function remove(uint index) public {
// Delete does not change the array length.
// It resets the value at index to it's default value,
// in this case 0
delete arr[index];
}
function examples() external pure {
// create array in memory, only fixed size can be created
uint[] memory a = new uint[](5);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract ArrayRemoveByShifting {
// [1, 2, 3] -- remove(1) --> [1, 3, 3] --> [1, 3]
// [1, 2, 3, 4, 5, 6] -- remove(2) --> [1, 2, 4, 5, 6, 6] --> [1, 2, 4, 5, 6]
// [1, 2, 3, 4, 5, 6] -- remove(0) --> [2, 3, 4, 5, 6, 6] --> [2, 3, 4, 5, 6]
// [1] -- remove(0) --> [1] --> []
uint[] public arr;
function remove(uint _index) public {
require(_index < arr.length, "index out of bound");
for (uint i = _index; i < arr.length - 1; i++) {
arr[i] = arr[i + 1];
}
arr.pop();
}
function test() external {
arr = [1, 2, 3, 4, 5];
remove(2);
// [1, 2, 4, 5]
assert(arr[0] == 1);
assert(arr[1] == 2);
assert(arr[2] == 4);
assert(arr[3] == 5);
assert(arr.length == 4);
arr = [1];
remove(0);
// []
assert(arr.length == 0);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
contract ArrayReplaceFromEnd {
uint[] public arr;
// Deleting an element creates a gap in the array.
// One trick to keep the array compact is to
// move the last element into the place to delete.
function remove(uint index) public {
// Move the last element into the place to delete
arr[index] = arr[arr.length - 1];
// Remove the last element
arr.pop();
}
function test() public {
arr = [1, 2, 3, 4];
remove(1);
// [1, 4, 3]
assert(arr.length == 3);
assert(arr[0] == 1);
assert(arr[1] == 4);
assert(arr[2] == 3);
remove(2);
// [1, 4]
assert(arr.length == 2);
assert(arr[0] == 1);
assert(arr[1] == 4);
}
}
示例代码自己部署自己玩.
标签:基本,function,arr,return,Solidity,gas,uint,概念学习,public From: https://www.cnblogs.com/joey-redfield/p/17879571.html