Wie lese ich ein Array innerhalb einer Struktur?

Als Teil der Lernsolidität und Smart-Contract-Entwicklung entwickle ich ein einfaches Teileverwaltungs-/Verfolgungssystem. Ich habe eine Struktur und eine Zuordnung für eine Liste von Teilen als solche:

struct Part {
   uint pNumber;
   string pName;
   string pDesc;
   string pManuf;
   string[] owners;
}
mapping(uint => Part) public part_store;
uint public partsCount;

Ich füge der Zuordnung neue Teile mit der folgenden Methode hinzu:

function createPart (string _pName, string _pDesc, string _pManuf) public {
        partsCount++;
        part_store[partsCount].pNumber = partsCount;
        part_store[partsCount].pName = _pName;
        part_store[partsCount].pDesc = _pDesc;
        part_store[partsCount].pManuf = _pManuf; 
        part_store[partsCount].owners.push(_pManuf);

        /* Trigger event */
        emit partCreatedEvent(partsCount);
    }

Alles wird fehlerfrei kompiliert und ich kann diese Transaktion über Truffle einreichen. Ich erhalte eine Transaktions-ID, wenn ich neue Teile erstelle.

Jetzt versuche ich, die Daten innerhalb des Teils zu lesen, aber ich sehe das Array nicht, in das ich die Daten verschoben habe. Es scheint, dass die letzten Daten im Objekt der Hersteller sind. Aber es zeigt nicht, dass ich den Originalhersteller als Besitzer dieses Teils gedrängt habe.

> contract.part_store(1)
Result:
[ BigNumber { s: 1, e: 0, c: [1] },
   'part name',
   'part desc',
   'part Manuf' ]
>

Habe ich das Array nicht richtig definiert und Daten dorthin geschoben? Wie kann ich die Daten in diesem Array lesen? Ich brauche ein Array, weil dies eine einfache Möglichkeit ist, Eigentümer für die Teile zu speichern, da sich Eigentümer ändern können (dh einen neuen Eigentümer definieren, indem ein neuer Eigentümer für das bestimmte Teil in das Array verschoben wird).

Danke an alle.

BEARBEITEN : Es scheint, dass ich publicden Wert lesen kann, wenn ich ein Array außerhalb einer Struktur und definiere:

string[] public test1;
string[] test2;
function writeElem() public {
   test1.push("t1");
   test2.push("t2");
}

Ergebnisse:

> contract.writeElem()
...tx: 0x88...
...txHas: 0x88...
> contract.test1(0)
't1'
> contract.test2(0)
TypeError: app.test2 is not a function
> contract.test2
undefined

Ich glaube nicht, dass ich Variablen in struct public oder private definieren kann, also kann ich diese Daten vielleicht deshalb nicht lesen? Könnte es etwas mit Datenzugriff für Arrays in Solidity sein?

Antworten (2)

Was passiert ist, dass der "kostenlose" Getter, den Sie verwenden, den indizierten Wert nicht unterstützt, also lässt er ihn einfach weg. Der "kostenlose" Getter aus dem public mappingist ungefähr

function part_store(uint index) public view returns(uint, string, string, string) {
  Part storage p = part_store[index];
  return (p.pNumber, p.pName, p.pDesc, p.pManu);
}

Sie müssen eine Funktion erstellen, um die fehlenden Informationen abzurufen. Sie haben Spielraum. Sie könnten einfach mit dem weitermachen, was ich begonnen habe, und das Array hinzufügen, aber ich bin kein großer Fan davon, aufgrund von Skalierungsproblemen und Benzinkosten.

Sie könnten stattdessen

function getProductOwnerCount(uint part) public view returns(uint) { 
  return prod_store[part].owners.length; 
}

function getProductOwnerAtIndex(uint part, uint index) public view returns(address) { 
  return prod_store[part].owners[index]; 
}

Mit diesen beiden Funktionen kann jeder Beobachter die Array-Länge festlegen (damit er nicht am Ende vorbeiläuft) und die Zeile abrufen, an der er interessiert ist. Oder der Client kann alle Zeilen durchlaufen, um sie alle zu erhalten. Es ist erwähnenswert, dass Clients möglicherweise bereits über die meisten Eigentümer Bescheid wissen, wenn sie Ereignisprotokolle beobachtet haben und jedes Mal, wenn ein Eigentümer hinzugefügt wurde (sollte), Ereignisse ausgegeben wurden.

Ich hoffe es hilft.

Danke für deinen Kommentar. Ähnliches habe ich auch schon versucht getProductOwnerAtIndex. Das Array speichert jedoch eine Zeichenfolgenliste mit Namen anstelle von Adressen. In diesem Fall wird es sagen ...returns(string)und nicht adressieren. Wenn ich das versuche, bekomme ichTypeError: Data location must be "memory" for return parameter in function, but none was given.
Ich habe nur meine eigene Frage beantwortet. Sie können Zeichenfolgen zurückgeben, solange Sie das memorySchlüsselwort als solches verwenden ...returns(string memory) {. Machen Sie dasselbe für String-Arrays, müssen aber auch definieren pragma experimental ABIEncoderV2;, um dies tun zu können. Danke, dass du mich in die richtige Richtung weist.
Rechts. Neues Compiler-Ding.

Konnte eine Antwort auf meine Frage finden. Sie können Zeichenfolgen zurückgeben, solange Sie das memorySchlüsselwort verwenden.

function getProductOwner() public view returns(string memory) {
    return part_store[1].owners[0];
}

Machen Sie dasselbe für String-Arrays, aber Sie müssen auch eine neue Pragma-Definition oben auf der Quellseite hinzufügen, um dies tun zu können. Sie erhalten Warnungen, aber keine Fehler. Ich nehme an, dass dies daran liegt, dass es sich um eine neue Funktion handelt, die schließlich in Solidity voll funktionsfähig sein wird.

pragma experimental ABIEncoderV2;

function getProductOwners() public view returns(string[] memory) {
    return part_store[1].owners;
}

Hier ist der Test, den ich in Remix durchgeführt habe.Geben Sie hier die Bildbeschreibung ein