Storage與Memory
在 Solidity 中,有兩個地方可以存儲變量 —— storage
或 memory
Storage
變量是指永久存儲在區(qū)塊鏈中的變量叛拷。 Memory
變量則是臨時的,當外部函數(shù)對某合約調(diào)用完成時灯谣,內(nèi)存型變量即被移除。
大多數(shù)時候你都用不到這些關鍵字,默認情況下 Solidity 會自動處理它們汽久。 然而也有一些情況下,你需要手動聲明存儲類型踊餐,主要用于處理函數(shù)內(nèi)的 結(jié)構體
和 數(shù)組
時:
contract SandwichFactory {
struct Sandwich {
string name;
string status;
}
Sandwich[] sandwiches;
function eatSandwich(uint _index) public {
// Sandwich mySandwich = sandwiches[_index];
// ^ 看上去很直接景醇,不過 Solidity 將會給出警告
// 告訴你應該明確在這里定義 `storage` 或者 `memory`。
// 所以你應該明確定義 `storage`:
Sandwich storage mySandwich = sandwiches[_index];
// ...這樣 `mySandwich` 是指向 `sandwiches[_index]`的指針
// 在存儲里吝岭,另外...
mySandwich.status = "Eaten!";
// ...這將永久把 `sandwiches[_index]` 變?yōu)閰^(qū)塊鏈上的存儲
// 如果你只想要一個副本三痰,可以使用`memory`:
Sandwich memory anotherSandwich = sandwiches[_index + 1];
// ...這樣 `anotherSandwich` 就僅僅是一個內(nèi)存里的副本了
// 另外
anotherSandwich.status = "Eaten!";
// ...將僅僅修改臨時變量,對 `sandwiches[_index + 1]` 沒有任何影響
// 不過你可以這樣做:
sandwiches[_index + 1] = anotherSandwich;
// ...如果你想把副本的改動保存回區(qū)塊鏈存儲
}
}
函數(shù)可見性: internal 和 external
internal
和 private
類似窜管,不過散劫, 如果某個合約繼承自其父合約,這個合約即可以訪問父合約中定義的“內(nèi)部”函數(shù)幕帆。
external
與public
類似获搏,只不過這些函數(shù)只能在合約之外調(diào)用 - 它們不能被合約內(nèi)的其他函數(shù)調(diào)用。
contract Sandwich {
uint private sandwichesEaten = 0;
function eat() internal {
sandwichesEaten++;
}
}
contract BLT is Sandwich {
uint private baconSandwichesEaten = 0;
function eatWithBacon() public returns (string) {
baconSandwichesEaten++;
// 因為eat() 是internal 的失乾,所以我們能在這里調(diào)用
eat();
}
}
與其他合約的交互
如果我們的合約需要和區(qū)塊鏈上的其他的合約會話常熙,則需先定義一個 interface
(接口)。
假設在區(qū)塊鏈上有這么一個合約:
contract LuckyNumber {
mapping(address => uint) numbers;
function setNum(uint _num) public {
numbers[msg.sender] = _num;
}
function getNum(address _myAddress) public view returns (uint) {
return numbers[_myAddress];
}
}
現(xiàn)在假設我們有一個外部合約碱茁,使用 getNum 函數(shù)可讀取其中的數(shù)據(jù)裸卫。
首先,我們定義 LuckyNumber 合約的 interface :
contract NumberInterface {
function getNum(address _myAddress) public view returns (uint);
}
在我們的 app 代碼中使用這個接口纽竣,合約就知道其他合約的函數(shù)是怎樣的墓贿,應該如何調(diào)用,以及可期待什么類型的返回值蜓氨。
使用接口
上面的接口募壕,我們可以在合約中這樣使用:
contract MyContract {
address NumberInterfaceAddress = 0xab38...;
// ^ 這是FavoriteNumber合約在以太坊上的地址
NumberInterface numberContract = NumberInterface(NumberInterfaceAddress);
// 現(xiàn)在變量 `numberContract` 指向另一個合約對象
function someFunction() public {
// 現(xiàn)在我們可以調(diào)用在那個合約中聲明的 `getNum`函數(shù):
uint num = numberContract.getNum(msg.sender);
// ...在這兒使用 `num`變量做些什么
}
}
通過這種方式,只要將您合約的可見性設置為public
(公共)或external
(外部)语盈,它們就可以與以太坊區(qū)塊鏈上的任何其他合約進行交互舱馅。
處理多返回值
function multipleReturns() internal returns(uint a, uint b, uint c) {
return (1, 2, 3);
}
function processMultipleReturns() external {
uint a;
uint b;
uint c;
// 這樣來做批量賦值:
(a, b, c) = multipleReturns();
}
// 或者如果我們只想返回其中一個變量:
function getLastReturnValue() external {
uint c;
// 可以對其他字段留空:
(,,c) = multipleReturns();
}
if 語句
function eatBLT(string sandwich) public {
// 看清楚了,當我們比較字符串的時候刀荒,需要比較他們的 keccak256 哈希碼
if (keccak256(sandwich) == keccak256("BLT")) {
eat();
}
}