If-Anweisung in for-Schleife filtert keine Elemente heraus

 // @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;

    }

Das Ergebnis soll eine Liste von IDs sein, die mit der eingegebenen physischen Adresse übereinstimmen, aber es filtert nicht durch, sondern gibt alle verfügbaren Häuser zurück. Wenn ich zur Verwendung von String utils wechsle, ändert sich nichts.

Hier ist der ganze Code:

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;

    }
}
Entscheide dich - willst du returns(uint [] _id )oder return results???
Ein Problem, das Sie haben, ist, dass Sie nie initialisieren, uint [] resultssodass es anfängt, auf den Speichersteckplatz 0 zu zeigen, der zu gehört Home[] public homes. Ein weiteres Problem ist, dass listHomesByAddresses nicht als constantoder gekennzeichnet ist viewund Ihren Vertragsspeicher ändert.

Antworten (1)

Ihr Problem mit der listHomesByAddressFunktion besteht darin, dass Sie versuchen, ein dynamisches Array im Speicher zu instanziieren, was unmöglich ist .

Da Sie nicht im Voraus wissen, wie groß ein Array Sie benötigen, müssen Sie es entweder zuerst zählen (was bedeutet, dass es zweimal geloopt wird, was verschwenderisch und teuer in Bezug auf Gas ist) oder ein Array im Lager verwenden. Wenn ein Array im Speicher verwendet wird, kostet es jedoch Gas, es anschließend zu leeren, was ebenfalls verschwenderisch ist.

Sie könnten stattdessen ein öffentliches Speicherarray verwenden, um IDs hineinzukopieren, und dabei die Anzahl der gefundenen Einträge zählen. Sie können diesen Zähler dann als Index des letzten relevanten Eintrags im Ergebnisarray verwenden. Jetzt kennen wir die Länge des Arrays im Speicher, die wir benötigen, und wir können fortfahren und das endgültige Array mit den IDs über eine getArrayFunktion erstellen:

uint[] public results;

function listHomesByAddress(string _physicalAddress) public returns(uint) {
    uint counter = 0;
    for(uint i = 0; i < homes.length; i++) {
        string location = homes[i].physicalAddress;
        if(StringUtils.equal(location, _physicalAddress)) {
            counter++;
            results[i] = homes[i].id;
        }
    }
    return getArray(counter);
}

function getArray(uint _length) public returns (uint[]) {
    uint[] memory arr = new uint[](_length);
    for (uint i = 0; i < _length; i++) {
        arr[i] = results[i];
    }
    return arr;
}

Wenn das Array nicht für einen Smart Contract benötigt wird, sondern für eine Front-End-DApp, können Sie einfach den Zähler zurückgeben und das Front-End kann damit das Ergebnis-Array durchlaufen, um stattdessen die richtigen IDs zu sammeln.