本文讨论 Solidity 的类特性
本文讨论 Solidity 的类特性,Solidity 是以太坊区块链的默认智能合约语言。
在 Datona 实验室的 Solidity Smart-Data-Access-Contract(S-DAC)模板的开发和测试过程中,我们探索了使用类的技术,就像在传统的面向对象的编程(OOP)语言中一样。例如,我们希望能写出类似这样的代码:
import "ContractOwner.sol";
import "Partners.sol";
contract EasyShare ... {
ContractOwner contractOwner;
Partners partners;
...
function addPartner(...) public onlyContractOwner {
partners.add(...);
}
...
}
在这个例子中,ContractOwner
和 Partners
是我们想要使用的类。
一个类将相关的代码和数据封装在一个实体中。
关于这个的实现将在下面的例子中进一步探讨。
为什么在 Solidity 中使用类?
因为我们很习惯在 OOP 开发中使用类,并且想要继续以这种方式来开发,因为它很好用。
对于为什么要用 OOP 编程,其可能的原因有很多。参考wiki中的面向对象编程。
在 Solidity 中使用类有什么好处?
我们发现,OOP 是非常熟悉、自然的,通常可以减少错误率,便于独立测试,并能重用。
在 Solidity 中使用类的缺点是什么?
主要的缺点是可能会使我们不去完全使用 Solidity 的编程范式。
还有人担心,大量导入文件会成为维护的噩梦。
最后,Solidity 合约通常非常简单,而导入文件可能会增加不必要的复杂性、成本和文件管理。
尽管如此,我们认为值得探索各种可能性,即使只是为了拒绝它们。
Solidity 已经有很多与现代 OOP 语言非常不同的特性,如:合约、可支付账号(payable account);执行的 Gas 消耗;永久存储;全局执行等等。
然而,合约不是类,因为Solidity有函数调度程序和其他开销,调用其他合约的函数是非常昂贵的。我在另一篇文章中有提到过“Solidity 函数的 Gas 消耗 ”。
Solidity 提供了哪些功能来实现将代码和数据封装在类里呢?
下面我们将开始探讨:
1) 导入文件
2) 合约继承
3) 将库附加到结构体
在所有这些功能中,数据和函数都可以使用类似类的点符号。例如:myClass.myFunction(myArgument)
。在某些情况下,也可以不用指定类。
有一下几种情况,我们应该作为一个单独的实体文件保存,然后再导入它们,例如:
在 Solidity 中,合约有可能创建其他合约。除了为测试而创建的临时合约外,那些其他合约似乎很有可能是在不同的文件中被定义:
import "OtherContract.sol";
contract MyContract ... {
OtherContract otherContract;
constructor(...) public ... {
otherContract = new OtherContract(...);
}
...
}
在 Solidity 中,也可以继承合约。并且,除了为测试而创建的临时合约外,继承的合约似乎很有可能被重复使用,所以在一个单独的文件中定义很重要,在下面(2)会进一步探讨。
在 Solidity 中也可以创建库,库函数可以是外部或内部的。任何包含外部函数的库大概都是为了被其他合约重用,所以应该在一个独立的文件中定义。
import "SortLibray.sol";
contract MyContract ... {
MyStruct data;
...
function sortData(...) internal ... {
SortLibrary.sort(data);
}
...
}
包含内部函数的库将与合约的字节码一起被打包。这些将在(3)中讨论。
在 Solidity 中,有两种方式可以有效地提供类特性,一种是继承基础合约。
被继承的基础合约是一个普通合约,包含数据和可以作用于这些数据的函数,但通常是不完整的,或者说只是完整合约的一个片段。恰当的文件命名习惯是很有用,可以清楚知道哪些合约是作为可继承的基础合约。
我们还可以把继承当做对象组合来使用,这在下面的例子中会讲到。
这是另一种有效提供类特性的方式,这种方式是创建一个结构体并附加一个库,库中的函数接受该结构体。这就是将一个库附加到一个类型(通常是一个结构体)。
在希望使用该类的合约中,声明了结构体的变量,并可提供结构体作为参数来调用库函数。
Solidity 提供了一个编译器指令,以支持使用点符号调用库函数,这就是using for
( using library for struct)。这个功能也可以用于扩展标准类型,例如, using NumbersLib for uint
。
看看下面的例子。
我们用一个简单的合约来演示类特性技术。
这个版本的合约,使用一个叫做ContractOwner
的基础合约和一个叫做Partners
的组件类。
import "ContractOwner.sol";
import "Partners.sol";
co...
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!