如果 for 循环中的语句没有过滤掉 solidity 中的项目
If statement in for loop not filtering out items in solidity
// @param physicalAddress - the actual address of the home a host wants to list (not the ethereum address)
// @return _id - list of ids for homes
function listHomesByAddress(string _physicalAddress) public returns(uint [] _id ) {
uint [] results;
for(uint i = 0 ; i<homes.length; i++) {
if(keccak256(homes[i].physicalAddress) == keccak256(_physicalAddress) && homes[i].available == true) {
results.push(homes[i].id);
}
}
return results;
}
结果应该是与输入的物理地址匹配的 ID 列表,但它不会过滤,而是 returns 所有可用的房屋。
当我改为使用 String utils 时,没有任何变化。
完整代码如下:
pragma solidity ^0.4.0;
import "browser/StringUtils.sol";
// @title HomeListing
contract HomeListing {
struct Home {
uint id;
string physicalAddress;
bool available;
}
Home[] public homes;
mapping (address => Home) hostToHome;
event HomeEvent(uint _id);
event Test(uint length);
constructor() {
}
// @param physicalAddress - the actual address of the home a host wants to list (not the ethereum address)
function addHome(string _physicalAddress) public {
uint _id = uint(keccak256(_physicalAddress, msg.sender));
homes.push(Home(_id, _physicalAddress, true));
}
// @param physicalAddress - the actual address of the home a host wants to list (not the ethereum address)
// @return _id - list of ids for homes
function listHomesByAddress(string _physicalAddress) public returns(uint [] _id ) {
uint [] results;
for(uint i = 0 ; i<homes.length; i++) {
string location = homes[i].physicalAddress;
if(StringUtils.equal(location,_physicalAddress )) {
results.push(homes[i].id);
}
}
return results;
}
}
给您带来麻烦的部分是 uint[] results;
行。默认情况下,声明为局部变量的数组引用 storage
内存。来自 Solidity docs 的“什么是内存关键字”部分:
There are defaults for the storage location depending on which type of variable it concerns:
- state variables are always in storage
- function arguments are in memory by default
- local variables of struct, array or mapping type reference storage by default
- local variables of value type (i.e. neither array, nor struct nor mapping) are stored in the stack
结果是您引用了合同的第一个存储槽,恰好是 Home[] public homes
。这就是为什么要取回整个数组的原因。
要解决此问题,您需要使用 memory
数组。但是,您还有一个额外的问题,即您不能在 Solidity 中使用动态内存数组。解决方法是确定结果大小限制并静态声明数组。
示例(限制为 10 个结果):
function listHomesByAddress(string _physicalAddress) public view returns(uint[10]) {
uint [10] memory results;
uint j = 0;
for(uint i = 0 ; i<homes.length && j < 10; i++) {
if(keccak256(homes[i].physicalAddress) == keccak256(_physicalAddress) && homes[i].available == true) {
results[j++] = homes[i].id;
}
}
return results;
}
// @param physicalAddress - the actual address of the home a host wants to list (not the ethereum address)
// @return _id - list of ids for homes
function listHomesByAddress(string _physicalAddress) public returns(uint [] _id ) {
uint [] results;
for(uint i = 0 ; i<homes.length; i++) {
if(keccak256(homes[i].physicalAddress) == keccak256(_physicalAddress) && homes[i].available == true) {
results.push(homes[i].id);
}
}
return results;
}
结果应该是与输入的物理地址匹配的 ID 列表,但它不会过滤,而是 returns 所有可用的房屋。 当我改为使用 String utils 时,没有任何变化。
完整代码如下:
pragma solidity ^0.4.0;
import "browser/StringUtils.sol";
// @title HomeListing
contract HomeListing {
struct Home {
uint id;
string physicalAddress;
bool available;
}
Home[] public homes;
mapping (address => Home) hostToHome;
event HomeEvent(uint _id);
event Test(uint length);
constructor() {
}
// @param physicalAddress - the actual address of the home a host wants to list (not the ethereum address)
function addHome(string _physicalAddress) public {
uint _id = uint(keccak256(_physicalAddress, msg.sender));
homes.push(Home(_id, _physicalAddress, true));
}
// @param physicalAddress - the actual address of the home a host wants to list (not the ethereum address)
// @return _id - list of ids for homes
function listHomesByAddress(string _physicalAddress) public returns(uint [] _id ) {
uint [] results;
for(uint i = 0 ; i<homes.length; i++) {
string location = homes[i].physicalAddress;
if(StringUtils.equal(location,_physicalAddress )) {
results.push(homes[i].id);
}
}
return results;
}
}
给您带来麻烦的部分是 uint[] results;
行。默认情况下,声明为局部变量的数组引用 storage
内存。来自 Solidity docs 的“什么是内存关键字”部分:
There are defaults for the storage location depending on which type of variable it concerns:
- state variables are always in storage
- function arguments are in memory by default
- local variables of struct, array or mapping type reference storage by default
- local variables of value type (i.e. neither array, nor struct nor mapping) are stored in the stack
结果是您引用了合同的第一个存储槽,恰好是 Home[] public homes
。这就是为什么要取回整个数组的原因。
要解决此问题,您需要使用 memory
数组。但是,您还有一个额外的问题,即您不能在 Solidity 中使用动态内存数组。解决方法是确定结果大小限制并静态声明数组。
示例(限制为 10 个结果):
function listHomesByAddress(string _physicalAddress) public view returns(uint[10]) {
uint [10] memory results;
uint j = 0;
for(uint i = 0 ; i<homes.length && j < 10; i++) {
if(keccak256(homes[i].physicalAddress) == keccak256(_physicalAddress) && homes[i].available == true) {
results[j++] = homes[i].id;
}
}
return results;
}