Can flutter add to an unmodifiable list?

Løsning af 'Unmodifiable List' Fejl i Flutter

25/07/2002

Rating: 4.93 (9156 votes)

En af de mest almindelige, men frustrerende fejl, som både nye og erfarne Flutter-udviklere støder på, er Unsupported operation: Cannot add to an unmodifiable list. Denne fejl opstår typisk, når man forsøger at tilføje et element til en liste, især i forbindelse med state management-løsninger som Cubit eller BLoC. Selvom Dart-lister som udgangspunkt er designet til at være foranderlige og kunne vokse, er der specifikke scenarier, hvor de bliver 'låst'. Denne artikel vil dykke ned i årsagerne til denne fejl, præsentere klare og effektive løsninger, og give en dybere forståelse for uforanderlighed (immutability) i Dart og Flutter.

Can flutter add to an unmodifiable list?
Flutter: Unsupported operation: Can not add to an unmodifiable list. The other day I was working with Cubit and adding item to a List. Dart List is growable and modifiable by nature In our example we will be using a List. This List takes custom objects of Person type. This object just basic information about a Person.
Indholdsfortegnelse

Forståelse af Problemet: Hvad er en Uforanderlig Liste?

I Dart er en standard List en dynamisk samling, hvilket betyder, at du kan tilføje, fjerne og ændre elementer efter dens oprettelse. Problemet opstår med introduktionen af nøgleordet const. Når du erklærer en liste (eller ethvert andet objekt) med const, fortæller du Dart-kompileren, at denne værdi er en kompileringstidskonstant. Det betyder, at den oprettes én gang under kompileringen og aldrig kan ændres under kørslen af programmet. Dette er en kraftfuld funktion for optimering og for at sikre, at visse data forbliver konstante.

Lad os se på et typisk eksempel inden for state management, hvor fejlen ofte opstår. Forestil dig en state-klasse, der holder styr på en liste af personer:

class PersonStates { List<Person> people; PersonStates({ this.people = const <Person>[] }); PersonStates copyWith({List<Person>? people}) { return PersonStates( people: people ?? this.people, ); } }

Her initialiseres people-listen med const <Person>[]. Dette skaber en tom, uforanderlig liste som standardværdi. Når din Cubit eller BLoC senere forsøger at tage denne liste og tilføje en ny person til den, opstår konflikten. Du forsøger at udføre en operation (tilføje et element) på en datastruktur, der er eksplicit defineret som uforanderlig.

Fejlanalyse: Et Praktisk Eksempel med Cubit

For at illustrere problemet yderligere, lad os se på en Cubit-klasse, der forsøger at opdatere vores PersonStates:

class PersonCubit extends Cubit<PersonStates> { PersonCubit(): super(PersonStates()); void addPerson(Person newPerson) { // Her opstår fejlen! var currentPeople = state.people; currentPeople.add(newPerson); // Kaster 'Unsupported operation' emit(state.copyWith(people: currentPeople)); } }

Når addPerson kaldes, hentes state.people. Da den oprindelige tilstand blev skabt med en const tom liste, er currentPeople en reference til denne uforanderlige liste. Kaldet til currentPeople.add(newPerson) er derfor et forsøg på at ændre det uforanderlige, hvilket resulterer i den velkendte fejlmeddelelse.

How do I add dependencies to my Dart / flutter project?
Easily add dependencies to your Dart / Flutter project. Pubspec Assist is a Visual Studio Code extension that allows you to easily add dependencies to your Dart and Flutter project's pubspec.yaml, all without leaving your editor. 6. Material Theme Icon 7. Vscode icons Bring icons to your Visual Studio Code 8. Error Lens Features 9. Dart-import

Effektive Løsninger til Håndtering af Uforanderlige Lister

Heldigvis findes der flere strategier til at løse dette problem. Valget af løsning afhænger af din specifikke situation og kodearkitektur. De to mest almindelige metoder er at skabe en modificerbar kopi af listen eller at fjerne const-modifikatoren og håndtere de potentielle konsekvenser.

Løsning 1: Den Foretrukne Metode - Brug af .toList()

Den reneste og ofte sikreste løsning er at oprette en ny, modificerbar kopi af listen, før du forsøger at ændre den. Dette gøres nemt med .toList() metoden. Denne metode tager den eksisterende liste (uanset om den er foranderlig eller ej) og returnerer en helt ny List, der er fuldt modificerbar.

Lad os rette vores Cubit-metode med denne tilgang:

void addPerson(Person newPerson) { // Opret en ny, modificerbar kopi af listen var newPeopleList = state.people.toList(); // Tilføj det nye element til kopien newPeopleList.add(newPerson); // Emitter en ny state med den opdaterede liste emit(state.copyWith(people: newPeopleList)); }

Denne tilgang respekterer princippet om uforanderlighed i state management. Den oprindelige state ændres ikke. I stedet skabes en ny liste, og en helt ny state-objekt udsendes (emitteres) med denne nye liste. Dette er forudsigeligt og forhindrer uønskede bivirkninger.

Løsning 2: Fjernelse af `const` og Håndtering af Nullability

En alternativ løsning er at fjerne const-modifikatoren fra initialiseringen i din state-klasse. Dette gør listen modificerbar fra starten.

Can Flutter import Dart HTML?
Currently, you cannot import dart:html in Flutter applications by default, but it's needed for the web platform (e.g. localStorage). In some cases, Dart HTML can be importedin a package, but the dart analyzer may throw errors.
class PersonStates { // Nu nullable for at undgå initialiseringsfejl List<Person>? people; PersonStates({this.people}); // ... copyWith metode }

Denne ændring introducerer dog en ny udfordring: `null safety`. Hvis listen ikke initialiseres i konstruktøren, vil den være `null`, når du først forsøger at tilgå den. Dette vil føre til en `null check used on a null value` fejl. For at løse dette skal du sikre, at listen altid er initialiseret, før den bruges. Dette kan gøres med en separat initialiseringsmetode i din Cubit:

class PersonCubit extends Cubit<PersonStates> { PersonCubit(): super(PersonStates(people: [])); // Initialiser med en tom, modificerbar liste void addPerson(Person newPerson) { // ... nu virker det, men kræver omhyggelig initialisering } }

Selvom denne metode virker, kræver den mere omhyggelig håndtering af din state's livscyklus for at undgå `null`-fejl. Derfor er .toList()-metoden generelt at foretrække for sin enkelhed og sikkerhed.

Sammenligning af Løsninger

KriterieLøsning A: Brug .toList()Løsning B: Fjern const
ImplementeringLokal ændring i metoden, der opdaterer listen.Kræver ændringer i state-klassen og muligvis i initialiseringslogikken.
BivirkningerMinimale. Overholder principperne for uforanderlig state.Risiko for nullable-fejl, hvis ikke håndteret korrekt. Kan gøre state-objekter foranderlige.
AnbefalingAnbefales i de fleste tilfælde, især inden for state management.Kan overvejes i simplere scenarier, hvor state ikke deles bredt.

Bonus: Effektiv Iteration over Lister i Dart

Når du arbejder med lister, er det også vigtigt at vide, hvordan man effektivt kan gennemløbe dem. Her er en oversigt over de mest almindelige metoder til iteration i Dart.

`for`-løkke med Indeks

Den klassiske `for`-løkke giver dig adgang til både elementet og dets indeks, hvilket er nyttigt i mange situationer.

List<String> frugter = ["Æble", "Banan", "Appelsin"]; for (var i = 0; i < frugter.length; i++) { print("Frugt på indeks $i er ${frugter[i]}"); }

`for-in`-løkke

Hvis du ikke har brug for indekset og blot ønsker at behandle hvert element, er `for-in`-løkken mere læsbar og koncis.

Can I add a path to dart SDK in flutter?
update, yes you can manually add a path to the dart-sdk in flutter and get access to dart from the command line ! The Dart's SDK is located at /flutter/bin/cache/dart-sdk However, If Android Studio's flutter plugin is installed, the plugin needs to be told where flutter's SDK is located.
List<String> frugter = ["Æble", "Banan", "Appelsin"]; for (var frugt in frugter) { print("Frugt: $frugt"); }

`forEach`-metoden

For en mere funktionel tilgang kan du bruge `forEach`, som tager en funktion, der udføres for hvert element i listen.

List<String> navne = ["Peter", "Mette", "Lars"]; navne.forEach((navn) => print("Hej, $navn"));

Relaterede Udfordringer: Afhængigheder og Platformspecifik Kode

I et større Flutter-projekt vil du også støde på andre udfordringer relateret til kodestruktur og vedligeholdelse. For eksempel er korrekt håndtering af afhængigheder i `pubspec.yaml`-filen afgørende. Værktøjer som `Pubspec Assist` til VS Code kan automatisere processen med at tilføje nye pakker og spare dig for tid. Derudover kan du møde udfordringer med platformspecifik kode. For eksempel er import af `dart:html` nødvendigt for web-specifikke funktioner som `localStorage`, men det vil give fejl i en mobil-app. Dette kræver betingede importer eller arkitektoniske mønstre for at adskille web-kode fra mobil-kode.

Ofte Stillede Spørgsmål (FAQ)

Hvorfor får jeg "Cannot add to an unmodifiable list" fejlen?
Du får denne fejl, fordi du forsøger at tilføje, fjerne eller ændre et element i en liste, der er blevet erklæret som en `const`. Dette gør listen uforanderlig, og den kan ikke ændres efter oprettelsen.

Hvad er den bedste måde at løse det på?
I de fleste tilfælde, især når du arbejder med state management, er den bedste løsning at oprette en modificerbar kopi af listen ved hjælp af metoden `.toList()`. Dette bevarer din oprindelige state uændret og forhindrer uønskede bivirkninger.

How to iterate over a list in flutter or dart?
To access list items in Flutter or dart, we can use the index of the item. But if you want to iterate over the list, you can use the code examples explained in this article. We will use multiple methods in this post to iterate over a List in Dart or Flutter. Lists are a mutable collection in Dart. You can add or remove data to a Dart List.

Er det en dårlig praksis at bruge `const` på lister?
Nej, tværtimod. At bruge `const` er en god praksis for ydeevne og for at skabe forudsigelig og sikker kode ved at sikre uforanderlighed. Nøglen er at forstå, hvornår du har en `const`-liste, og hvordan du korrekt opretter en modificerbar kopi, når du har brug for at foretage ændringer.

Hvilken loop-metode er bedst til at iterere over en liste i Dart?
Det afhænger af dit behov. `for-in` er ofte den mest læsbare til simpel iteration. Den traditionelle `for`-løkke er nødvendig, hvis du har brug for elementets indeks. `forEach` tilbyder en kompakt, funktionel syntaks, som mange udviklere foretrækker.

Konklusion

Fejlen "Cannot add to an unmodifiable list" er mere end bare en irriterende stopklods; den er en vigtig læringsmulighed om et centralt koncept i moderne programmering: uforanderlighed. Ved at forstå, hvordan `const` påvirker dine datastrukturer, og ved at mestre teknikker som `.toList()` til at skabe sikre opdateringer, kan du skrive mere robust, forudsigelig og vedligeholdelsesvenlig Flutter-kode. At håndtere denne fejl korrekt er et afgørende skridt på vejen mod at blive en mere kompetent og effektiv Flutter-udvikler.

Hvis du vil læse andre artikler, der ligner Løsning af 'Unmodifiable List' Fejl i Flutter, kan du besøge kategorien Sundhed.

Go up