比较重要的特性:
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
contract BasicTest {
uint myStoredData;
function myGet() public view returns (uint) {
return myStoredData;
}
function mySet(uint what) public {
myStoredData = what;
}
}
代码编译部署到区块链上之后,任何人只要知道了该合约的地址及函数签名,都可以修改myStoredData数据。比如,该合约地址为 0xaE036c65C649172b43ef7156b009c6221B596B8b 那么编写如下代码:
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
interface BasicTest {
function myGet() external view returns (uint);
function mySet(uint w) external;
}
contract Super {
BasicTest bt;
function setAddr(BasicTest addr) public {
bt = addr;
}
function test(uint w) public returns (uint) {
bt.mySet(w);
return bt.myGet();
}
}
输入参数为合约地址,执行setAddr;然后输入欲改值1356,就可以修改了。
布尔bool,整型int/uint,定长fixed/ufixed,地址address,定长字节数组,变长字节数组,枚举
需要说明的是:
function () {internal|external} [pure|constant|view|payable] [returns ()]
函数的可见性
可指定为external, public, internal, 或者private
对于public和private,相信学过其他高级语言的人都能明白:
函数的状态可变性
如果你试图在一个用view或者pure修饰的函数体内修改变量,或者在一个未使用payable修饰的函数体内发送ether,那么编译的时候,就会给出错误。
仅仅发生在一个合约内部。可以理解为“方法调用”。
外部函数调用使用消息机制实现。外部调用事件消息包括了发送者,接收者,内容,ether数量,以及gas。
一个合约调用其它合约的函数,只有通过外部函数调用的方式,没有其它方式。
调用一个public函数,分别使用内部调用和外部调用,对比一下:
内部调用
function g1(uint a) public returns(uint ret) {
return 44;
}
function y2() public returns(uint ret) {
uint a = g1(100);
for(uint i=0; i < 30; i++) {
g1(100);
}
return a;
}
外部调用
function g1(uint a) public returns(uint ret) {
return 44;
}
function y1() public returns(uint ret) {
uint a = this.g1(100);
for(uint i=0; i < 30; i++) {
this.g1(100);
}
return a;
}
可以看出,所消耗的gas差别很大。
进一步试验
contract FunctionTest{
uint public v1;
uint public v2;
function internalFunc() internal{
v1 = 10;
}
function externalFunc() external returns (uint res){
v2 = 20;
return v2;
}
function resetV2() public {
v2 = 0;
}
function callFunc() public {
//直接使用内部的方式调用
internalFunc(); //<--- 合约内部直接调用,正确
//不能在内部调用一个外部函数,会报编译错误。
//Error: Undeclared identifier.
//externalFunc(); //<--- 外部合约不可以调用
//不能通过`external`的方式调用一个`internal`
//Member "internalFunc" not found or not visible after argument-dependent lookup in contract FuntionTest
//this.internalFunc(); //<--- this.相当于外部调用
//使用`this`以`external`的方式调用一个外部函数
this.externalFunc();
}
}
// 合约的继承
contract Son is FunctionTest {
function callInternalFunc() public{
internalFunc(); // 可以继承父合约的内部方法
this.externalFunc();
}
}
contract FunctionTest1{
uint public v3;
function externalCall(FunctionTest ft) public {
//调用另一个合约的外部函数
v3 = ft.externalFunc();
//不能调用另一个合约的内部函数
//Error: Member "internalFunc" not found or not visible after argument-dependent lookup in contract FuntionTest
//ft.internalFunc();
}
function resetV3() public {
v3 = 0;
}
}
最后,再看一个发送ether的例子。可以指定gas。具体如何估算,留个悬念,请见下回分解吧。
function g(uint a) public payable returns(uint ret) {
return 44;
}
function y() public payable returns(uint ret) {
uint a = this.g{value:11,gas:5800}(100);
return a;
}
constructor() payable{} //必不可少
注意: payable关键字
页面更新:2024-03-10
本站资料均由网友自行发布提供,仅用于学习交流。如有版权问题,请与我联系,QQ:4156828
© CopyRight 2020-2024 All Rights Reserved. Powered By 71396.com 闽ICP备11008920号-4
闽公网安备35020302034903号