几个知识点
msg是内部变量,不能使用
函数的参数变量,不需要存储,因此可以指定类型之后,添加```memory```关键词
如果函数返回内部变量,只读,可以使用关键词```view```
返回变量的关键词是```returns```,而不是```return```
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.4;
contract Hello {
string public name;
function setName(string memory name_) public{
name = name_;
}
function getName() public view returns (string memory){
return name;
}
}
使用msg的时候,出现如下的编译警告
Warning: This declaration shadows a builtin symbol.
--> contracts/lesson/lesson-1-hello.sol:7:5:
|
7 | string public msg;
| ^^^^^^^^^^^^^^^^^
以太坊中单位的对应关系
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.4;
contract EthUint {
uint public oneWei = 1 wei;
uint public oneGwei = 1 gwei;
uint public oneEth = 1 ether;
function testOneWei() public view returns (bool) {
return oneWei == 1;
}
function testOneGgei() public view returns (bool) {
return oneGwei == 1 * 10**9;
}
function testOneEth() public view returns (bool) {
return oneEth == 1 * 10**18;
}
}
也可以参考网站:https://eth-converter.com/

函数的可见性严格排序
// private internal external public
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.4;
// private internal external public
contract funVisibility {
uint age;
function funPublic() public view returns (uint){
return age;
}
function funExternal() external view returns (uint){
return age;
}
function funInternal() internal view returns (uint){
return age;
}
function funPrivate() private view returns (uint){
return age;
}
function testFun() public view returns(uint) {
// return funPublic(); // ok
// return funExternal(); // not ok
// return funInternal(); // ok
return funPrivate(); // ok
}
}
contract subFunVisibility is funVisibility{
function testParentFun() public view returns(uint) {
// return funPublic(); // ok
// return funExternal(); // not ok
// return funInternal(); // ok
// return funPrivate(); // not ok
}
}
扩展阅读:https://tsaiyee.com/blog/2018/01/07/solidity-external-public-best-practices/ 【Solidity中的external与public使用最佳实践】
继承知识点
继承的语法是子类 is 父类
如果需要重写父类函数,父类定义需要使用virtual,子类需要使用pure override
如果父类构造函数有参数,子类定义的时候,也需要为父类指定构造函数的参数
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.4;
// private internal external public
contract Parent {
uint age;
constructor(uint age_){
age = age_;
}
function getAge() public view returns (uint){
return age;
}
function getDesc() public view virtual returns (string memory){
return "Parent";
}
}
contract Son is Parent(55){
// can call getAage fun
function getDesc() public pure override(Parent) returns (string memory){
return "Son";
}
}
扩展阅读:https://medium.com/taipei-ethereum-meetup/solidity-weekly-11-70c5208a3bf1 【pure 跟 view 的区别】
更正確的講,如果一個 function 不會改變到合約的 state,就可以加 modifier constant 在 returns 前面,因此在 web3.js 就可以用 call() 來呼叫該 function, 而不需要用 sendTransaction() 來呼叫。
到了 solc 0.4.17, 更把 constant 細分為 view 或 pure 兩種,只是程度上的不同。
view 一般來說,就用來取代 constant, 跟 compiler 説,該 function 不會對 storage state 有任何變動。(但會進行讀取, 所以 constant 改名為 view,更為恰當)
string greeting;
function SayHello() public view returns(string says) {
return greeting;
}
pure 定義該 function 連讀 storage state 都沒有。有人舉了一個誇張的例子如下:(它跟合約的所有 states 都無關, 可以加 modifier pure)
function returnTrue() public pure returns(bool response) {
return true;
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.4;
// private internal external public
contract A {
uint age;
constructor(uint age_){
age = age_;
}
function getAge() public view returns (uint){
return age;
}
}
contract B {
string name;
constructor(string memory name_){
name = name_;
}
function getNmae() public view returns (string memory){
return name;
}
}
contract C is A, B{
constructor()A(10) B ("hello"){
}
}
contract D is A, B{
constructor(uint age_, string memory name)A(age_) B (name){
}
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.4;
contract Event {
event Log(address sender, string msg );
function trancfer() public{
emit Log(msg.sender, "This is 1 mag");
emit Log(msg.sender, "This is 2 mag");
emit Log(msg.sender, "This is 3 mag");
}
}
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.4;
contract Hello {
event Log(address, uint);
function getGasInfo() public view returns(uint, uint){
return (tx.gasprice, block.gaslimit);
}
function getMagInfo () public payable {
emit Log(msg.sender, msg.value);
}
}
参数尽量提前检查,多执行代码,会增加gas费
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.4;
contract ErrorHandle {
int public balance = 0;
function add(int trans_num) public{
require(trans_num >= 0, "The trans num should big than 0");
// int old_balance = balance;
balance += trans_num;
//assert(balance >= old_balance);
// if(balance < old_balance){
// revert("error");
// }
}
}
需要注意的是,array的del函数并没有删除数据,只是把数据进行了清空
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.4;
// array
// push pop del length
contract Array {
uint[] public array1;
uint[3] public array2;
uint [] public arrar3 = [1,2,3];
function push(uint val) public{
array1.push(val);
}
function pop() public{
array1.pop();
}
function length() public view returns(uint){
return array1.length;
}
function del(uint index) public{
// param check
delete array1[index];
}
function test() public{
array1.push(1);
array1.push(2);
array1.push(3);
array1.push(4);
assert(length() == 4);
pop();
assert(length() == 3);
assert(array1[2] == 3);
del(2);
assert(length() == 3);
assert(array1[2] == 0);
}
}
需要注意的是
map的del函数,也只是把数据清空而不会把数据真正的删除
map没有遍历函数,如果希望遍历,可以添加一个辅助的数组
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.4;
contract Map {
mapping(address => uint) public MyMap;
function setMap(address add_, uint num) public{
MyMap[add_] = num;
}
function delMap(address addr_) public{
delete MyMap[addr_];
}
function getlMap(address addr_) public view returns (uint){
return MyMap[addr_];
}
}
注意事项
外部string参数使用memory修饰,int、bool等类型无需
内部结构体需要使用storage修饰
// SPDX-License-Identifier: GPL-3.0
pragma solidity 0.8.4;
contract Struct {
struct Todo{
string task;
bool complete;
}
Todo [] public todo_list;
function add(string memory _task) public {
// Todo memory todo = Todo(_task, false);
// Todo memory todo = Todo({
// task: _task,
// complete : false
// });
Todo memory todo;
todo.task = _task;
todo.complete = false;
todo_list.push(todo);
}
function get(uint index) public view returns (Todo memory){
return todo_list[index];
}
function getEle(uint index) public view returns (string memory, bool){
Todo storage todo = todo_list[index];
return (todo.task, todo.complete);
}
}

