solidity 数组是否有弹出功能?
Is there a pop functionality for solidity arrays?
我已经使用 solidity 将数据推送到数组中。 pop 有类似的功能吗?
string[] myArray;
myArray.push("hello")
最好的解决方案是什么?如何在 solidity 中删除动态数组中的元素?
2019 年 2 月 19 日更新:正如 Joel 在下面指出的那样,pop
已添加到 built-in 数组支持中。参见 https://solidity.readthedocs.io/en/v0.5.4/types.html#array-members。在这里留下原始答案,以防其他人使用旧版本的 Solidity。
Solidity中没有pop函数。您可以考虑几个选项来维护阵列。
删除并留空
最简单的解决方案是 delete
特定索引处的元素:
string element = myArray[index];
delete myArray[index];
return element;
但是,这不会移动数组中的元素,并且会在数组中留下“字符串 0”的元素。要检查此元素,您可以使用
if(bytes(myArray[index]).length > 0) ...
交换和删除
如果您不关心数组中的顺序,可以将元素与数组中的最后一个元素交换,然后删除:
string element = myArray[index];
myArray[index] = myArray[myArray.length - 1];
delete myArray[myArray.length - 1];
myArray.length--;
return element;
使用 Shift 键删除
如果数组中的顺序很重要,您可以删除该元素,然后将所有剩余元素向左移动。
string element = myArray[index];
for (uint i = index; i < myArray.length - 1; i++) {
myArray[i] = myArray[i + 1];
}
delete myArray[myArray.length - 1];
myArray.length--;
return element;
请注意,这将是最昂贵的选项。如果你的数组很长,你的 gas 使用率会很高。
根据@Jedsada 的建议,这里有一个作为库的版本:
pragma solidity ^0.4.24;
library StackLib {
using StackLib for Stack;
struct Stack {
uint[] _items;
}
function pushElement(Stack storage self, uint element) internal returns (bool) {
self._items.push(element);
}
function popElement(Stack storage self) internal returns (uint) {
uint element = self.peek();
if (self.size() > 0)
delete self._items[self.size() - 1];
return element;
}
function peek(Stack storage self) internal returns (uint) {
uint value;
if (self.size() > 0)
value = self._items[self.size() - 1];
return value;
}
function size(Stack storage self) internal returns (uint8) {
return self.size();
}
}
示例用法(重要说明:您不能使用 popElement
和 return 客户端的值。该方法会更改状态,只能在事务中使用。):
contract Test {
using StackLib for StackLib.Stack;
StackLib.Stack numbers;
function add(uint v) public {
numbers.pushElement(v);
}
function doSomething() public {
for (uint8 i = 0; i < numbers.size(); i++) {
uint curNum = numbers.popElement();
// do something with curNum
}
}
}
附加说明:不幸的是,var
自 0.4.20 以来已被弃用,并且没有泛型的替代品。您必须针对特定类型进行自定义。
你可以试试...
pragma solidity ^0.4.17;
contract TestArray {
uint[] public items;
constructor () public {
items.push(1);
items.push(2);
items.push(3);
items.push(4);
}
function pushElement(uint value) public {
items.push(value);
}
function popElement() public returns (uint []){
delete items[items.length-1];
items.length--;
return items;
}
function getArrayLength() public view returns (uint) {
return items.length;
}
function getFirstElement() public view returns (uint) {
return items[0];
}
function getAllElement() public view returns (uint[]) {
return items;
}
}
是的,从 v0.5.0 (details here) 开始:
Dynamic storage arrays and bytes (not string) have a member function called pop that you can use to remove an element from the end of the array. This also implicitly calls :ref:delete on the removed element.
function deleteElement(uint _index) public returns(bool) {
if (_index < 0 || _index >= x.length) {
return false;
} else if(x.length == 1) {
x.pop();
return true;
} else if (_index == x.length - 1) {
x.pop();
return true;
} else {
for (uint i = _index; i < x.length - 1; i++) {
x[i] = x[i + 1];
}
x.pop();
return true;
}
}
我已经使用 solidity 将数据推送到数组中。 pop 有类似的功能吗?
string[] myArray;
myArray.push("hello")
最好的解决方案是什么?如何在 solidity 中删除动态数组中的元素?
2019 年 2 月 19 日更新:正如 Joel 在下面指出的那样,pop
已添加到 built-in 数组支持中。参见 https://solidity.readthedocs.io/en/v0.5.4/types.html#array-members。在这里留下原始答案,以防其他人使用旧版本的 Solidity。
Solidity中没有pop函数。您可以考虑几个选项来维护阵列。
删除并留空
最简单的解决方案是 delete
特定索引处的元素:
string element = myArray[index];
delete myArray[index];
return element;
但是,这不会移动数组中的元素,并且会在数组中留下“字符串 0”的元素。要检查此元素,您可以使用
if(bytes(myArray[index]).length > 0) ...
交换和删除
如果您不关心数组中的顺序,可以将元素与数组中的最后一个元素交换,然后删除:
string element = myArray[index];
myArray[index] = myArray[myArray.length - 1];
delete myArray[myArray.length - 1];
myArray.length--;
return element;
使用 Shift 键删除
如果数组中的顺序很重要,您可以删除该元素,然后将所有剩余元素向左移动。
string element = myArray[index];
for (uint i = index; i < myArray.length - 1; i++) {
myArray[i] = myArray[i + 1];
}
delete myArray[myArray.length - 1];
myArray.length--;
return element;
请注意,这将是最昂贵的选项。如果你的数组很长,你的 gas 使用率会很高。
根据@Jedsada 的建议,这里有一个作为库的版本:
pragma solidity ^0.4.24;
library StackLib {
using StackLib for Stack;
struct Stack {
uint[] _items;
}
function pushElement(Stack storage self, uint element) internal returns (bool) {
self._items.push(element);
}
function popElement(Stack storage self) internal returns (uint) {
uint element = self.peek();
if (self.size() > 0)
delete self._items[self.size() - 1];
return element;
}
function peek(Stack storage self) internal returns (uint) {
uint value;
if (self.size() > 0)
value = self._items[self.size() - 1];
return value;
}
function size(Stack storage self) internal returns (uint8) {
return self.size();
}
}
示例用法(重要说明:您不能使用 popElement
和 return 客户端的值。该方法会更改状态,只能在事务中使用。):
contract Test {
using StackLib for StackLib.Stack;
StackLib.Stack numbers;
function add(uint v) public {
numbers.pushElement(v);
}
function doSomething() public {
for (uint8 i = 0; i < numbers.size(); i++) {
uint curNum = numbers.popElement();
// do something with curNum
}
}
}
附加说明:不幸的是,var
自 0.4.20 以来已被弃用,并且没有泛型的替代品。您必须针对特定类型进行自定义。
你可以试试...
pragma solidity ^0.4.17;
contract TestArray {
uint[] public items;
constructor () public {
items.push(1);
items.push(2);
items.push(3);
items.push(4);
}
function pushElement(uint value) public {
items.push(value);
}
function popElement() public returns (uint []){
delete items[items.length-1];
items.length--;
return items;
}
function getArrayLength() public view returns (uint) {
return items.length;
}
function getFirstElement() public view returns (uint) {
return items[0];
}
function getAllElement() public view returns (uint[]) {
return items;
}
}
是的,从 v0.5.0 (details here) 开始:
Dynamic storage arrays and bytes (not string) have a member function called pop that you can use to remove an element from the end of the array. This also implicitly calls :ref:delete on the removed element.
function deleteElement(uint _index) public returns(bool) {
if (_index < 0 || _index >= x.length) {
return false;
} else if(x.length == 1) {
x.pop();
return true;
} else if (_index == x.length - 1) {
x.pop();
return true;
} else {
for (uint i = _index; i < x.length - 1; i++) {
x[i] = x[i + 1];
}
x.pop();
return true;
}
}