库函数定义
- 使用 library关键字定义库合约
- 不能继承别的合约,只能实现接口
- 不能有构造函数、成员变量、修饰器
总的来说,库合约就是纯粹的方法集。使用using for将方法附加在一个数据类型上。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// 定义一个库
library SafeMath {
function add(uint x, uint y) internal pure returns (uint) {
uint z = x + y;
require(z >= x, "uint overflow");
return z;
}
}
// 使用库的合约
contract TestSafeMath {
using SafeMath for uint;
uint public result;
function add(uint x, uint y) public {
result = x.add(y);
}
}
库合约中的public与internal
public或external库合约是通常通过delegatecall调用的,但是调用的参数约束和内部调用相同
对于 internal 库函数:它们会被编译器内联到调用它们的合约的字节码中。这意味着没有单独的函数调用,而是直接在合约代码内执行。
如果有public就需要单独部署
无论技术的实现方式如何,库函数调用时合约内部调用,上下文不变化
更新知识
b-->up:东风草绿
- 库的internal是inline到调用者代码中了
- 库的public方法是library单独部署为合约,然后用delegatecall调用。所以,如果library有public方法,则必然是要单独部署的(Linked Library)。如果全是internal方法,则可以不部署(Embedded Library)
- 当library因为有public而单独部署时,与proxy pattern相比照,都是利用另一个合约承载逻辑,但方式不用,一个利用存储布局,一个直接传递storage引用,上下文变量都保持在调用者一边。(调用者以delegatecall调用,由于library没有成员,被调用者只操作传入的参数,因此delegatecall不是像proxy pattern中的那样通过兼容存储布局利用另一合约逻辑的作用,而是通过操作storage属性的参数利用另一合约的逻辑)。
- library的public,external函数传入storage参数,从这一点来看,说它是普通合约并不准确。
- 调用者对单独部署的library的引用是在编译时完成,不是运行时,无法实现动态升级(是要故意为升级制造困难吗?)
- internal: 对调用者可见,并且内联编译;private:library内部用,对library使用者不可见(仅从可见性解释上,library类似超类)。public:对library使用者可见,但是合约要单独部署
- 交易属性:解释为对storage类型参数的操作,而不是成员;或者解释为对调用者成员变量的操作;两者等价