Beitrag
Teile dein Wissen.
Wie aktualisiere ich den Schlüssel eines Händlers in ObjectTable, wenn er sich in der Struktur ändert?
Hallo zusammen, ich fange gerade mit dem Schreiben intelligenter Verträge an und arbeite an meinem allerersten Projekt. Ich hätte gerne Hilfe bei einem Problem, bei dem ich nicht weiterkomme.
Bisher habe ich eine Merchant
Struktur erstellt, die so aussieht:
-id
: eine eindeutige Kennung (UID)
-owner
: die Adresse des Händlers
-key
: eine Zeichenfolge, die als eindeutiger Schlüssel verwendet wird
-balance
: ein u64, das ihr Gleichgewicht darstellt
Ich habe auch eine MerchantRegistry
Struktur erstellt, um alle Händler zu verwalten:
-id
: eine andere UID
-merchant_to_address
: und die ObjectTable<address, Merchant>
Zuordnung von Adressen zu Händlern
-merchant_to_key
: eine ObjectTable<String, Merchant>
Zuordnung von Schlüsseln zu Händlern
Ich möchte in der Lage sein, einen Händler entweder anhand seinerAdresseoder anhand seinesSchlüsselszu finden.
Merchant
Wenn ein Benutzer seinen Schlüssel innerhalb der merchant_to_key
Struktur aktualisiert, aktualisiert die Änderung nicht automatisch den Schlüssel in der Tabelle. Das bedeutet, dass der alte Schlüssel immer noch auf den Händler zeigt, was Dinge kaputt macht.
Ich habe versucht, den Eintrag aus der Tabelle zu entfernen und ihn mit dem neuen Schlüssel wieder einzufügen, aber ich stoße immer wieder auf Fehler wie:
„Werte ohne Drop-Funktion können nicht ignoriert werden“
Ich bin mir ziemlich sicher, dass dies ein Anfängerfehler ist, aber ich konnte nirgends eine klare Erklärung oder Lösung finden. Gibt es eine richtige Methode, um den Schlüssel sowohl in der Struktur als auch in der Lookup-Tabelle zu aktualisieren?
- Sui
- Move
Antworten
6In Sui Move sind Objekte standardmäßig „Ressourcen“, was bedeutet, dass sie nicht versehentlich dupliziert oder verworfen werden können. Dies wird durch ein Typsystem erzwungen, bei dem Strukturen entweder die Fähigkeit zum Ablegen haben (was bedeutet, dass sie verworfen werden können, wenn sie den Gültigkeitsbereich überschreiten) oder nicht.
Deine Merchant-Struktur verfügt wahrscheinlich nicht über die Drop-Fähigkeit, weil sie eine UID enthält. UIDs sind eindeutige Identifikatoren für Objekte auf Sui und sollen verhindern, dass diese Objekte versehentlich gelöscht oder dupliziert werden. Wenn ein Objekt eine UID enthält, kann sie normalerweise nicht gelöscht werden.
Wenn Sie versuchen, einen Eintrag aus einer ObjectTable zu entfernen, gibt die Funktion remove den Wert zurück (in diesem Fall das Merchant-Objekt). Wenn Sie diesen zurückgegebenen Wert keiner Variablen zuweisen oder ihn nicht an eine andere Funktion übergeben, die ihn verarbeitet, geht Move davon aus, dass Sie versuchen, ihn zu „ignorieren“ oder zu „löschen“. Da deine Händler-Struktur nicht über die Drop-Fähigkeit verfügt, ist diese Aktion verboten, was zu der Fehlermeldung „Werte ohne Drop-Fähigkeit können nicht ignoriert werden“ führt.
Das Kernproblem ist, dass das Ändern eines Felds in einem Objekt (wie merchant.key = new_key;) die Schlüssel in Ihrer ObjectTable nicht automatisch aktualisiert. Die ObjectTable speichert das Objekt basierend auf dem Schlüssel, mit dem es hinzugefügt wurde. Wenn sich also der interne Schlüssel ändert, kennt die Tabelle immer noch nur den alten Schlüssel.
module your_address::your_module_name {
use sui::object::{Self, UID};
use sui::tx_context::{Self, TxContext};
use sui::string::{String, utf8};
use sui::object_table::{Self, ObjectTable}; // Import ObjectTable
// Define your Merchant struct
public struct Merchant has key, store {
id: UID,
owner: address,
key: String, // This is the key you want to update
balance: u64,
}
// Define your MerchantRegistry struct
public struct MerchantRegistry has key, store {
id: UID,
merchant_to_address: ObjectTable<address, Merchant>, // Mapping addresses to merchants
merchant_to_key: ObjectTable<String, Merchant>, // Mapping keys to merchants
}
// You'll likely have an `init` function to create the registry
fun init(ctx: &mut TxContext) {
let registry = MerchantRegistry {
id: object::new(ctx),
merchant_to_address: object_table::new(ctx),
merchant_to_key: object_table::new(ctx),
};
// Transfer ownership of the registry, or make it shared if applicable
sui::transfer::transfer(registry, tx_context::sender(ctx));
}
// Function to add a new merchant (for context)
public entry fun add_merchant(
registry: &mut MerchantRegistry,
merchant_owner: address,
merchant_key: vector<u8>, // Using vector<u8> for input, convert to String
ctx: &mut TxContext
) {
let merchant = Merchant {
id: object::new(ctx),
owner: merchant_owner,
key: utf8(merchant_key),
balance: 0,
};
// Add to both tables
object_table::add(&mut registry.merchant_to_address, merchant_owner, object::share_object(merchant));
// You'll need to decide on a primary storage and potentially store references or IDs in other tables.
// For simplicity, let's assume `merchant_to_key` is the primary and `merchant_to_address` stores the object ID.
// If `Merchant` is a shared object, you can store it in multiple tables.
// Let's adjust the `Merchant` struct for clarity in this example.
// For simplicity and to avoid the "same object in multiple places" issue,
// it's often better to have one "primary" table that owns the object,
// and other tables store only the object's ID or a reference.
// If you truly need the Merchant object directly in both tables, the Merchant itself needs to be a SHARED object.
// Let's revise the example to make Merchant a shared object.
// REVISED MERCHANT STRUCT (if you want it in both tables directly):
// public struct Merchant has key { // No 'store' ability if it's shared directly
// id: UID,
// owner: address,
// key: String,
// balance: u64,
// }
// public entry fun add_merchant(...) {
// let merchant = Merchant { ... };
// object::share_object(merchant); // Make it shared
// object_table::add(&mut registry.merchant_to_address, merchant_owner, merchant);
// object_table::add(&mut registry.merchant_to_key, utf8(merchant_key), merchant);
// }
// This makes `Merchant` a shared object, which has different implications for ownership and mutability.
//***************Let's stick to the original assumption that Merchant is not shared,
//***************and therefore only one table directly owns the `Merchant` object.
//***************If you want to look up by address AND key, and only one table can own the object,
//***************then one table (e.g., merchant_to_address) stores the `Merchant` object,
//***************and the other (merchant_to_key) stores the `ID` of the Merchant.
// For this scenario, let's assume `merchant_to_address` owns the `Merchant` objects,
// and `merchant_to_key` will map a String key to the `ID` of the Merchant.
// New Merchant struct:
// public struct Merchant has key, store {
// id: UID,
// owner: address,
// key: String, // Stored inside the object
// balance: u64,
// }
// Updated MerchantRegistry:
// public struct MerchantRegistry has key, store {
// id: UID,
// merchant_to_address: ObjectTable<address, Merchant>, // Owners the Merchant object
// merchant_to_key: ObjectTable<String, object::ID>, // Maps key to Merchant's ID
// }
//****************Let's assume for the sake of the user's original question*****************
//****************that `ObjectTable<String, Merchant>` is intended to hold****************
//****************the actual Merchant object, which implies it's the primary****************
//****************owner or the `Merchant` is shared.
//****************If `Merchant` is not shared, only ONE `ObjectTable` can hold it.
//****************The error "Cannot ignore values without drop ability" confirms
//****************that the `Merchant` object itself is being handled.
// Assuming merchant_to_key is the primary table where the Merchant object resides:
object_table::add(&mut registry.merchant_to_key, utf8(merchant_key), merchant);
// If you still need lookup by address, you'd store the ID in merchant_to_address:
// object_table::add(&mut registry.merchant_to_address, merchant_owner, object::id(&merchant));
// This creates a circular dependency in a single transaction if you try to get ID *after* adding.
// Best practice is one table owning the object, others holding IDs.
// For the sake of directly answering the user's original question about `merchant_to_key`:
}
/// Entry function to update a merchant's key in the ObjectTable.
public entry fun update_merchant_key(
registry: &mut MerchantRegistry,
old_key: vector<u8>, // Input as vector<u8> for String conversion
new_key: vector<u8>, // Input as vector<u8> for String conversion
ctx: &mut TxContext // TxContext is often needed for object::new or other operations
) {
// Convert input vectors to Sui Strings
let old_key_str = utf8(old_key);
let new_key_str = utf8(new_key);
// 1. Remove the merchant using the old key.
// This returns the 'Merchant' object. Since Merchant does not have 'drop',
// we *must* bind it to a variable.
let mut merchant = object_table::remove(&mut registry.merchant_to_key, old_key_str);
// 2. Update the 'key' field inside the retrieved Merchant struct.
merchant.key = new_key_str;
// 3. Re-insert the updated Merchant object into the table with the new key.
// This will create a new entry in the ObjectTable.
object_table::add(&mut registry.merchant_to_key, new_key_str, merchant);
// If you also had a `merchant_to_address` table mapping to `object::ID`,
// and the `owner` of the merchant might also change, you'd need to update that as well.
// For example:
// let old_address = merchant.owner; // Assuming merchant.owner is still the original owner
// if (old_address != new_owner_address) { // If owner changes
// let merchant_id = object_table::remove(&mut registry.merchant_to_address, old_address);
// // merchant.owner = new_owner_address; // Update owner in the struct if needed
// object_table::add(&mut registry.merchant_to_address, new_owner_address, merchant_id);
// }
}
// You might also want a function to get a merchant by key for testing
public fun get_merchant_by_key(
registry: &MerchantRegistry,
key: vector<u8>
): &Merchant {
object_table::borrow(®istry.merchant_to_key, utf8(key))
}
}
In Sui Move können Sie nicht einfach den Schlüssel eines Objekts in einer Tabelle ändern oder Objekte direkt löschen/ersetzen, ohne dass dies richtig gehandhabt wird. Wenn Sie das Schlüsselfeld in Ihrer Merchant-Struktur ändern, wird die Tabelle merchant_to_key nicht automatisch aktualisiert. Dadurch zeigt Ihr alter Schlüssel immer noch auf das Objekt, während der neue Schlüssel überhaupt keine Assoziation hat.
Der Fehler „Werte ohne Drop-Fähigkeit können nicht ignoriert werden“ tritt auf, weil Ihre Merchant-Struktur wahrscheinlich nicht über die Drop-Fähigkeit verfügt (was bei Strukturen, die eine UID enthalten, häufig der Fall ist). Das bedeutet, dass Sie das Objekt nicht einfach aus der Tabelle entfernen und verwerfen können. Sie müssen das zurückgegebene Objekt explizit speichern und wiederverwenden.
Um den Schlüssel eines Händlers korrekt zu aktualisieren, müssen Sie den alten Eintrag manuell entfernen, die Merchant-Struktur mit dem neuen Schlüssel aktualisieren und ihn dann wieder in die Tabelle einfügen. So können Sie das innerhalb einer Transaktion tun:
public entry fun update_merchant_key(
registry: &mut MerchantRegistry,
old_key: String,
new_key: String
) {
// 1. Remove the merchant using the old key and store the returned object.
let merchant = object_table::remove(&mut registry.merchant_to_key, old_key);
// 2. Update the key field inside the struct.
merchant.key = new_key;
// 3. Re-insert the merchant into the table with the updated (new) key.
object_table::add(&mut registry.merchant_to_key, new_key, merchant);
}```
Dieser Ansatz stellt sicher, dass Sie das Merchant-Objekt sicher extrahieren, seinen Schlüssel ändern und es dann mit dem neuen Schlüssel wieder in die ObjectTable einfügen.
Diese Methode respektiert die Besitzregeln von Move und verhindert den versehentlichen Verlust oder das „Auslaufen“ von Ressourcen. Dies ist besonders wichtig, wenn es sich um Typen handelt, denen die Fähigkeit fehlt, sie fallen zu lassen.
Um den Schlüssel eines Händlers in ObjectTable zu aktualisieren, müssen Sie manuell:
entfernen Sie das Merchant-Objekt mit dem old_key.
Aktualisieren Sie das Schlüsselfeld in der Merchant-Struktur, die Sie gerade abgerufen haben, und fügen Sie das geänderte Merchant-Objekt mithilfe von new_key wieder in die ObjectTable ein.
public entry fun update_merchant_key(
registry: &mut MerchantRegistry,
old_key: String,
new_key: String
) {
let mut merchant = object_table::remove(&mut registry.merchant_to_key, old_key); // 1. Remove and capture
merchant.key = new_key; // 2. Update the struct
object_table::add(&mut registry.merchant_to_key, new_key, merchant); // 3. Re-insert
}
Wenn du versuchst, den Schlüssel eines Händlers in einer ObjectTable zu aktualisieren<String, Merchant> und dabei auf Fehler wie „Werte ohne Drop-Fähigkeit können nicht ignoriert werden“ stoßen, besteht das Problem darin, dass du in Sui Move nicht einfach Objekte im Speicher löschen oder ersetzen kannst, ohne explizit den Besitz und Typen zu behandeln, denen die Drop-Funktion fehlt. Wenn Sie den Schlüssel in Ihrer Merchant-Struktur ändern, wird die Tabelle merchant_to_key dadurch nicht automatisch aktualisiert. Am Ende zeigt also der alte Schlüssel immer noch auf das Objekt, während der neue Schlüssel überhaupt nicht verknüpft ist.
Wenn du versuchst, das key
in a eines Händlers zu aktualisieren ObjectTable<String, Merchant>
und dabei auf Fehler wie „Werte ohne Drop-Fähigkeit können nicht ignoriert werden“ stoßen, besteht das Problem darin, dass du in Sui Move Objekte im Speicher nicht einfach löschen oder ersetzen kannst, ohne explizit den Besitz und Typen zu behandeln, denen die drop
Fähigkeit fehlt. Wenn Sie den Schlüssel in Ihrer Merchant
Struktur ändern, wird die merchant_to_key
Tabelle dadurch nicht automatisch aktualisiert. Am Ende zeigt der alte Schlüssel immer noch auf das Objekt, während der neue Schlüssel überhaupt nicht verknüpft ist.
Um dies zu beheben, müssen Sieden alten Eintragmanuell entfernen**, die Struktur aktualisieren und sie dannmit dem neuen Schlüssel wieder einfügen. Da die Merchant
Struktur jedoch nicht über diese drop
Fähigkeit verfügt, können Sie sie nicht einfach entfernen und das Ergebnis ignorieren — Sie müssen das zurückgegebene Objekt speichern und wiederverwenden. So können Sie das innerhalb einer Transaktion richtig machen:
public entry fun update_merchant_key(
registry: &mut MerchantRegistry,
old_key: String,
new_key: String
) {
// Remove the merchant using the old key and store the returned object
let merchant = object_table::remove(&mut registry.merchant_to_key, old_key);
// Update the key field inside the struct
merchant.key = new_key;
// Re-insert into the table with the updated key
object_table::add(&mut registry.merchant_to_key, new_key, merchant);
}
Auf diese Weise können Sie den Händler sicher extrahieren, ändern und mit dem neuen Schlüssel wieder einfügen — und das alles unter Beachtung der Eigentumsregeln von Move.
Denken Sie daran, dass dies notwendig ist, da Move so konzipiert ist, dass verhindert wird, dass Ressourcen versehentlich herunterfallen oder verloren gehen. Wenn deine Merchant
Struktur nicht über diese drop
Fähigkeit verfügt (was häufig der Fall ist, wenn sie eine enthältUID
), musst du sie immer explizit behandeln.
Um eine klarere Vorstellung davon zu bekommen, wie das ObjectTable
funktioniert und wie man sicher mit Eigentum umgeht, schaut euch die offizielle Dokumentation hier an: https://docs.sui.io/build/move/object-tables.
Weißt du die Antwort?
Bitte melde dich an und teile sie.
Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.
Verdiene deinen Anteil an 1000 Sui
Sammle Reputationspunkte und erhalte Belohnungen für deine Hilfe beim Wachstum der Sui-Community.

- ... SUISuiLover+1211
- ... SUI0xduckmove+1207
- ... SUIThorfin+1204
- ... SUIharry phan+849
- ... SUIOwen+689
- ... SUIMeaning.Sui+675
- ... SUItheking+587
- Warum benötigt BCS eine genaue Feldreihenfolge für die Deserialisierung, wenn Move-Strukturen benannte Felder haben?53
- Fehler bei der Überprüfung mehrerer Quellen“ in den Veröffentlichungen des Sui Move-Moduls — Automatisierte Fehlerbehebung43
- Sui-Transaktion schlägt fehl: Objekte sind für eine andere Transaktion reserviert25
- Wie interagieren Fähigkeitsbeschränkungen mit dynamischen Feldern in heterogenen Sammlungen?05