Roblox GuidebookWissensbibliothek
Deutsch ⌄

Entwicklung / ROBLOX

Inventarkopie in Luau: warum Änderungen trotz table.clone das Original erreichen

Vergleiche Zuweisung, flache Kopie und getrennt kopierte Einträge an einem kleinen erfundenen Inventar. Ein überprüftes Beispiel zeigt unabhängiges Bearbeiten bei unveränderter Ausgangsmenge und die Grenzen seines zweistufigen Datenmodells.

Aktualisiert:

Lege das gewünschte Entwurfsverhalten fest #

Stell dir ein Lehrinventar mit zwei Materialien vor: copper hat count=3 und wood hat count=1. Du möchtest einen Bearbeitungsentwurf öffnen und dessen Kupfermenge auf 9 setzen, während die Originaldaten 3 behalten. Zwei Werte müssen gleichzeitig geprüft werden; eine Beschriftung auf einer einzigen Anzeige reicht nicht. Notiere zuerst das erwartete Paar original=3 und draft=9. Wähle danach die Kopiermethode, die genau diese Trennung gewährleisten soll.

Materialien und Felder label und equipped sind für die Übung erfunden. Es handelt sich um gewöhnliche Tabellen im Speicher, nicht um ein echtes Roblox-Spielerinventar. Wir haben die eigenständige Logik in Luau überprüft, ohne GUI, Server, RemoteEvent oder Speicherstände anzuschließen. Diese Grenze ermöglicht eine ehrliche Aussage zum Beispiel statt eines fertigen Gegenstandssystems. Ein erfolgreicher Kopiertest beweist deshalb keine Ressourcenausgabe in einer veröffentlichten Experience.

Unterscheide neuen Namen und neue Tabelle #

Mit draft=original erhält dieselbe Tabelle einen zweiten Namen. Das offizielle Handbuch beschreibt Tabellen als referenzierte Werte; gewöhnliche Zuweisung erzeugt keinen unabhängigen Schnappschuss. Eine Änderung an draft.copper.count ist dann auch durch original.copper.count zu sehen. Das Problem ist keine Textdarstellung. Beide Variablen führen zu denselben Daten, sodass die gewünschte Trennung bereits fehlt, bevor eine Benutzeroberfläche beteiligt ist oder jemand eine Anzeige sieht.

Erstelle für die erste Prüfung einen frischen Datensatz und setze die Menge über den zweiten Namen auf 7. In unserem eigenständigen Test ist alias==source wahr, und source.copper.count wird 7. Das ist ein überprüftes Beispiel eines gemeinsamen Objekts. Nenne es nicht Kopie, nur weil der Variablenname anders ist. Erzeuge vor der nächsten Prüfung einen neuen Satz mit Menge 3, damit eine vorherige Änderung den Vergleich nicht verfälscht.

Verstehe die Grenze von table.clone #

table.clone erzeugt eine neue äußere Tabelle, kopiert deren Inhalte jedoch flach. War ein Wert selbst eine Tabelle, bleibt der Verweis auf sie gemeinsam. Deshalb kann draft~=original wahr sein, während gleichzeitig draft.copper==original.copper gilt. Das ist kein Widerspruch: Die äußeren Container unterscheiden sich, aber ein verschachtelter Eintrag ist gemeinsam. Ein Mengeneditor muss die Tiefe prüfen, auf der seine Änderung stattfindet, statt einen anderen äußeren Verweis als vollständige Unabhängigkeit zu betrachten.

In der zweiten eigenständigen Prüfung ändern wir die verschachtelte Menge über eine flache Kopie auf 8; die Originalmenge wird ebenfalls 8. Entfernen wir dagegen wood aus der äußeren Kopie, bleibt wood im Ausgangscontainer vorhanden. Die Handlungen betreffen verschiedene Ebenen und ergeben verschiedene Resultate. Fasse das nicht pauschal als Kopieren funktioniert oder funktioniert nicht zusammen. Nenne Feld und Ebene und bewahre beide Beobachtungen, statt das unbequeme Ergebnis auszulassen.

VerfahrenGemeinsamer copper-Eintrag?
ZuweisungJa
table.cloneJa
Einträge kopiertNein

Vergleiche Verweise und Werte getrennt #

Der Wert count beantwortet die Frage nach der gespeicherten Menge. Ein Tabellenvergleich mit == prüft im Beispiel die gemeinsame Identität. Gleiche Zahlen beweisen keine Unabhängigkeit. Zwei verschiedene Einträge können beide 3 enthalten, solange noch nichts geändert wurde. Prüfe deshalb zuerst die Verweisstruktur, dann die Handlung und beide Ergebniswerte. Andernfalls bleibt eine unerwünschte gemeinsame Referenz bis zum tatsächlichen Bearbeiten unsichtbar, wenn bereits Originaldaten verändert wurden.

Führe ein kurzes Protokoll: äußere Tabellen verschieden, copper-Einträge verschieden, Entwurfsänderung lässt den Ausgangswert unverändert. Ergänze für die Gegenrichtung eine Änderung von wood im Original und vergleiche den Entwurf. Beidseitige Prüfung hilft, wenn sich ein Objekt während der Bearbeitung eines anderen aktualisiert. Unser Test führt diese Vergleiche aus, misst aber kein gleichzeitiges Netzwerkverhalten und beweist nicht, dass sämtliche möglichen Konflikte einer Experience beseitigt sind.

Von Daten zum EntwurfBild in voller Größe öffnen ↗
Eigenes Diagramm des begrenzten zweistufigen Helfers.

Kopiere Einträge für eine ausdrücklich definierte Datenform #

Unsere eigene Funktion copyInventoryDraft unterstützt ein Wörterbuch mit nicht leeren Zeichenfolgen als Gegenstandskennungen. Jeder Wert ist ein einfacher Tabelleneintrag; benannte Felder enthalten ausschließlich Zeichenfolgen, Zahlen oder boolesche Werte. Die Funktion kopiert zuerst den äußeren Container und danach jeden Eintrag gesondert. Für diese Form bleiben Menge, Beschriftung und equipped=false als Werte erhalten, während die Eintragstabellen ihre Identität nicht mehr mit dem Original teilen.

Der Vertrag ist absichtlich begrenzt. Metatabellen, eine verschachtelte metadata-Tabelle, Funktionen und numerische Feldschlüssel liegen außerhalb und werden ausdrücklich abgelehnt. Das ist keine allgemeine tiefe Kopie beliebiger Daten. Die Begrenzung macht das Beispiel verständlich und prüfbar, ohne Zyklusbehandlung oder Erhalt komplexer Verweisgraphen zu versprechen. Beschreibe eine andere Projektstruktur zuerst und lege deren Kopierregeln fest, statt Prüfungen nur für einen erfolgreichen Start zu entfernen.

-- Teaching model only: string item IDs -> plain records -> scalar fields.
-- This is not a universal deep-copy function or a server validation layer.
local function copyInventoryDraft(original)
    assert(type(original) == "table", "Expected an inventory table")
    assert(getmetatable(original) == nil, "Root metatables are outside this model")
    local draft = table.clone(original)
    for id, record in pairs(original) do
        assert(type(id) == "string" and id ~= "", "Expected a nonempty item ID")
        assert(type(record) == "table", "Expected an item record")
        assert(getmetatable(record) == nil, "Record metatables are outside this model")
        for field, value in pairs(record) do
            assert(type(field) == "string", "Expected named record fields")
            local valueType = type(value)
            assert(valueType == "string" or valueType == "number" or valueType == "boolean",
                "Only scalar record fields are supported")
        end
        draft[id] = table.clone(record)
    end
    return draft
end

return copyInventoryDraft

Starte das kleine Anwendungsbeispiel #

Speichere für eigenständiges Luau den Helfer als table-copy-example.luau und das Anwendungsbeispiel als table-copy-usage.luau im gleichen Ordner. Die zweite Datei erhält die Funktion über require mit relativem Pfad, erstellt zwei Lehreinträge und setzt draft.copper.count auf 9. Genau diese Ausführung wurde überprüft. Beim Übertragen auf ein Roblox-ModuleScript musst du Modulzugriff und Umgebung getrennt anpassen; die Datei mit relativem Pfad ist keine vollständige Studio-Einrichtung.

Die überprüfte Ausgabe lautet GUIDEBOOK_TABLE_COPY_USAGE original=3 draft=9. Assertions vergleichen zusätzlich beide Mengen und erhalten equipped=false. Im Artikel stehen der vollständige begrenzte Helfer und seine kurze Anwendung. Beide zeichnen keine Oberfläche und vergeben keine Gegenstände. Weicht deine Ausgabe ab, prüfe gestartete Datei, Herkunft des Helfers und eine mögliche frühere Änderung der Ausgangsdaten. Bewahre diesen Kontext, statt einer vertrauten Ausgabebezeichnung allein zu vertrauen.

local copyInventoryDraft = require("./table-copy-example")
local original = {
    copper = {count = 3, label = "Copper", equipped = false},
    wood = {count = 1, label = "Wood", equipped = true},
}
local draft = copyInventoryDraft(original)
draft.copper.count = 9
assert(original.copper.count == 3)
assert(draft.copper.count == 9)
assert(draft.copper.equipped == false)
print("GUIDEBOOK_TABLE_COPY_USAGE original=" .. original.copper.count .. " draft=" .. draft.copper.count)

Prüfe Änderungen von beiden Seiten #

Nach getrenntem Kopieren der Einträge lässt die Bearbeitung der Kupfermenge im Entwurf den Originalwert 3 unverändert. Ändern wir danach wood im Original, bleibt der vorherige wood-Wert im Entwurf erhalten. Auch äußeres Einfügen und Entfernen im Entwurf fügt keine Originaleinträge ein und entfernt keine. Diese Beobachtungen gelten für die geprüfte Datenform. Sie sind aussagekräftiger als eine Erfolgsmeldung zum Funktionsaufruf, die über unabhängiges späteres Bearbeiten nichts sagt.

Verweisen zwei Ausgangskennungen auf einen Eintrag, erstellt der Helfer für jede Kennung eine eigene Kopie. Unser Test bestätigt verschiedene neue Einträge und unabhängige Änderungen. Die ursprüngliche gemeinsame Beziehung wird also nicht erhalten. Das ist eine gewollte Eigenschaft dieses Helfers. Ein Projekt, in dem der gemeinsame Eintrag eine Bedeutung hat, benötigt eine andere Regel. Beschreibe das Ergebnis nicht als genaue Kopie jedes möglichen Objektgraphen oder jeder Identitätsbeziehung.

Überprüftes ErgebnisBild in voller Größe öffnen ↗
Eigenständiges Luau-Ergebnis;kein echtes Spielinventar.

Verwechsle freeze nicht mit tiefer Unabhängigkeit #

Die offizielle Bibliothek erklärt, dass table.freeze die übergebene Tabelle an Ort und Stelle verändert und verschachtelte Werte nicht automatisch einfriert. Unser Test friert das äußere Inventar ein und prüft, dass copper darin weiterhin veränderbar ist. Eine Änderung von count bleibt möglich. Ein unveränderlicher äußerer Container beweist deshalb weder Bearbeitungsschutz aller enthaltenen Daten noch deren Trennung von anderen Verweisen. Dafür sind jeweils genauere Beobachtungen erforderlich.

table.clone einer eingefrorenen Tabelle liefert eine nicht eingefrorene äußere Kopie, während der verschachtelte Eintrag beim flachen Kopieren weiterhin gemeinsam ist. Das prüfen wir separat und erzeugen anschließend unabhängige Einträge mit dem begrenzten Helfer. Verwende eine einzige frozen-Markierung nicht als Beweis sämtlicher Ergebniseigenschaften. Entscheide zuerst zwischen Kopieren, gemeinsamen Verweisen und Änderungsverbot. Das sind unterschiedliche Anforderungen, die durch unterschiedliche Handlungen überprüft werden müssen.

Bewahre die Grenze der eigenständigen Prüfung #

Die Prüfungen betreffen Zuweisung, flache Kopie, Unabhängigkeit zweistufiger Einträge, false, leeres Wörterbuch, gemeinsame Ausgangseinträge und ausdrücklich nicht unterstützte Formen. Das Verhalten eines eingefrorenen äußeren Containers wurde gesondert untersucht. Übertrage diese Ergebnisse nicht auf jede rekursive Struktur: Der Helfer implementiert keinen solchen Graphdurchlauf. Die Ablehnung eines tieferen Eintrags gehört zu seinem Vertrag und ist kein allgemeiner Luau- oder Roblox-Fehler oder Nachweis einer universellen Kopierbibliothek.

Kopieren im Speicher bestätigt keine Spielerberechtigung zur Änderung eines echten Inventars und ersetzt keine Serverprüfung. Es speichert auch keinen Fortschritt zwischen Sitzungen. Eine Oberfläche benötigt eigene Prüfungen für Aktualisierung, Verwerfen eines Entwurfs und neue Daten; Speicherung benötigt ein separates Verfahren. Das wurde hier nicht durchgeführt. Gib diese Grenzen zusammen mit der überprüften Ausgabe an andere Entwickler weiter, damit der Helfer nicht als fertiges Spielsystem missverstanden wird.

FallErgebnis
Entwurf ändernOriginal bleibt3
Original ändernEntwurf unverändert
Tieferes ObjektVertrag lehnt ab
GUI und SpeicherständeNoch nicht geprüft

Wähle Kopieren für eine konkrete Handlung #

Das Abschlussprotokoll soll kopierte Ebene, weiterhin gemeinsame Verweise und tatsächlich isolierte Änderungen benennen. Für unsere Übung passt original=3 und draft=9 zur vorgesehenen Bearbeitungsaufgabe. Brauchst du dagegen nur eine neue Liste von Verweisen auf vorhandene Objekte, kann flaches Kopieren beabsichtigt sein. Formuliere Handlung und erwartete Wirkung vor der Auswahl eines Verfahrens, statt für jede Datenmenge automatisch das komplizierteste Kopieren einzusetzen.

Die eigenen Einträge, der Helfer und die Prüfungen stehen zum Lernen und Anpassen bereit. Bewahre Datenform und Grenzen dabei; ein neues verschachteltes Feld verlangt eine Vertragsprüfung und passende neue Tests. Versprich keine Beschleunigung, Speicherersparnis oder Reparatur eines echten Inventars ohne Messung und Integrationsprüfung. Prüfe aktuelle Regeln von table.clone und table.freeze anhand offizieller Quellen und bestätige Aussagen über eine bestimmte Umsetzung durch tatsächliches Ausführen.

Originalquellen

Luau — Standard Library
Roblox Creator Hub — Tables