Cos'è la Nullability in Dart (non annullabile per impostazione predefinita)?


27

Ho sentito parlare della nuova funzionalità del linguaggio di sicurezza null di Dart, attualmente l' esperimento " non nullable ". Dovrebbe essere introdotto come non annullabile per impostazione predefinita .

Le specifiche delle funzionalità sono disponibili qui e il problema di lingua GitHub qui .

Come funziona e dove posso provarlo?

Risposte:


49

Non annullabile (per impostazione predefinita)

L' esperimento non annullabile (per impostazione predefinita) è attualmente disponibile su nullsafety.dartpad.dev .
Tieni presente che puoi leggere le specifiche complete qui e la roadmap completa qui .


Cosa significa non annullabile per impostazione predefinita?

void main() {
  String word;
  print(word); // illegal

  word = 'Hello, ';
  print(word); // legal
}

Come puoi vedere sopra, una variabile essendo nulla per impostazione predefinita significa che ogni variabile dichiarata normalmente non può essere null. Di conseguenza, qualsiasi operazione che accede alla variabile prima che sia stata assegnata è illegale.
Inoltre, nullnon è consentita l' assegnazione a una variabile non nullable:

void main() {
  String word;

  word = null; // forbidden
  world = 'World!'; // allowed
}

In che modo mi aiuta?

Se una variabile è non annullabile , puoi essere sicuro che non lo sia mai null. Per questo motivo, non è mai necessario verificarlo in anticipo.

int number = 4;

void main() {
  if (number == null) return; // redundant

  int sum = number + 2; // allowed because number is also non-nullable
}

Ricorda

I campi dell'istanza nelle classi devono essere inizializzati se non sono annullabili:

class Foo {
  String word; // forbidden

  String sentence = 'Hello, World!'; // allowed
}

Vedi latesotto per modificare questo comportamento.

Tipi nullabili ( ?)

È possibile utilizzare i tipi nullable aggiungendo un punto interrogativo ?a un tipo variabile:

class Foo {
  String word; // forbidden

  String? sentence; // allowed
}

Non è necessario inizializzare una variabile nullable prima di poter essere utilizzata. È inizializzato come nullpredefinito:

void main() {
  String? word;

  print(word); // prints null
}

!

L'aggiunta !a qualsiasi variabile egenererà un errore di runtime se eè nullo e in caso contrario lo convertirà in un valore non annullabilev .

void main() {
  int? e = 5;
  int v = e!; // v is non-nullable; would throw an error if e were null

  String? word;
  print(word!); // throws runtime error if word is null

  print(null!); // throws runtime error
}

late

La parola chiave latepuò essere utilizzata per contrassegnare le variabili che verranno inizializzate in un secondo momento , cioè non quando vengono dichiarate ma quando vi si accede. Ciò significa anche che possiamo avere campi di istanza non annullabili che vengono inizializzati in seguito:

class ExampleState extends State {
  late String word; // non-nullable

  @override
  void initState() {
    super.initState();

    // print(word) here would throw a runtime error
    word = 'Hello';
  }
}

L'accesso wordprima che sia inizializzato genererà un errore di runtime.

late final

Le variabili finali ora possono anche essere contrassegnate in ritardo:

late final int x = heavyComputation();

Qui heavyComputationverrà chiamato solo una volta effettuato l' xaccesso. Inoltre, puoi anche dichiarare a late finalsenza un inizializzatore, che è lo stesso di avere solo una latevariabile, ma può essere assegnato solo una volta.

late final int x;
// w/e
x = 5; // allowed
x = 6; // forbidden

Nota che ora verranno valutate tutte le variabili di livello superiore o statiche con un inizializzatore late, indipendentemente dal fatto che lo siano final.

required

Precedentemente un'annotazione ( @required), ora integrata come modificatore. Consente di contrassegnare qualsiasi parametro denominato (per funzioni o classi) come required, il che li rende non annullabili:

void allowed({required String word}) => null;

Ciò significa anche che se un parametro deve essere non annullabile , deve essere contrassegnato come requiredo avere un valore predefinito:

void allowed({String word = 'World'}) => null;

void forbidden({int x}) // compile-time error because x can be null (unassigned)
    =>
    null;

Qualsiasi altro parametro denominato deve essere nullable :

void baz({int? x}) => null;

?[]

L' ?[]operatore nullo è stato aggiunto per l'operatore indice []:

void main() {
  List<int>? list = [1, 2, 3];

  int? x = list?[0]; // 1
}

Vedi anche questo articolo sulla decisione di sintassi .

?..

L'operatore a cascata ha ora anche un nuovo operatore di nulla consapevoli: ?...

Fa sì che le seguenti operazioni in cascata vengano eseguite solo se il destinatario non è nullo . Pertanto, ?..deve essere il primo operatore a cascata in una sequenza a cascata:

void main() {
  Path? path;

  // Will not do anything if path is null.
  path
    ?..moveTo(3, 4)
    ..lineTo(4, 3);

  // This is a noop.
  (null as List)
    ?..add(4)
    ..add(2)
    ..add(0);
}

Never

Per evitare confusione: questo non è qualcosa di cui gli sviluppatori devono preoccuparsi. Voglio menzionarlo per completezza.

Neversarà un tipo come quello precedentemente esistente Null( nonnull ) definito in dart:core. Entrambe queste classi non possono essere estese, implementate o mescolate, quindi non sono pensate per essere utilizzate.

In sostanza, Neversignifica che nessun tipo è consentito e di per Neversé non può essere istanziato.
Nient'altro che Neverin una List<Never>soddisfa il vincolo di tipo generico dell'elenco, il che significa che deve essere vuoto . List<Null>, tuttavia, può contenere null:

// Only valid state: []
final neverList = <Never>[
  // Any value but Never here will be an error.
  5, // error
  null, // error

  Never, // not a value (compile-time error)
];

// Can contain null: [null]
final nullList = <Null>[
  // Any value but Null will be an error.
  5, // error
  null, // allowed

  Never, // not a value (compile-time error)
  Null, // not a value (compile-time error)
];

Esempio: il compilatore inferirà List<Never>per un vuoto const List<T> .
Nevernon dovrebbe essere utilizzato dai programmatori per quanto mi riguarda.


5
Puoi dare alcuni scenari dove Neverpuò essere utilizzato?
Ramses Aldama,

2
In realtà abbiamo deciso di utilizzare "? []" Per l'operatore di indice con riconoscimento null anziché "?. []". Quest'ultimo è un po 'più complesso dal punto di vista grammaticale, ma è ciò che gli utenti vogliono.
munifico

@RamsesAldama Ho aggiunto qualcosa. Le specifiche a cui ho collegato menzionano di più.
creativecreatorormaybenot

@munificent Le specifiche e l'esperimento sono ancora obsoleti; grazie per aver sottolineato.
creativecreatorormaybenot

1
Va notato che late finalsu un membro o una variabile di istanza controlla solo in fase di esecuzione. Non è possibile verificarlo in fase di sviluppo o di compilazione a causa del problema di arresto. Quindi non otterrai aiuto IDE con esso.
Graham
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.