Apa itu Nullability di Dart (Non-nullable secara default)?

27

Saya telah mendengar tentang fitur bahasa null keselamatan Dart baru, saat ini percobaan " 'tidak dapat dibatalkan' ". Seharusnya memperkenalkan non-nullable secara default .

Spesifikasi fitur dapat ditemukan di sini dan masalah bahasa GitHub di sini .

Bagaimana cara kerjanya dan di mana saya bisa mencobanya?

creativecreatorormaybenot
sumber

Jawaban:

49

Non-nullable (secara default)

Eksperimen yang tidak dapat dibatalkan (secara default) saat ini dapat ditemukan di nullsafety.dartpad.dev .
Ingatlah bahwa Anda dapat membaca spesifikasi lengkap di sini dan peta jalan lengkap di sini .


Apa yang dimaksud dengan non-nullable secara default?

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

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

Seperti yang Anda lihat di atas, variabel yang tidak dapat dibatalkan secara default berarti bahwa setiap variabel yang dideklarasikan secara normal tidak dapat null. Akibatnya, setiap operasi yang mengakses variabel sebelum ditugaskan adalah ilegal.
Selain itu, penetapan nullke variabel yang tidak dapat dibatalkan juga tidak diizinkan:

void main() {
  String word;

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

Bagaimana ini membantu saya?

Jika suatu variabel tidak dapat dibatalkan , Anda dapat memastikan bahwa itu tidak pernah null. Karena itu, Anda tidak perlu memeriksanya sebelumnya.

int number = 4;

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

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

Ingat

Bidang instance dalam kelas harus diinisialisasi jika tidak dapat dibatalkan:

class Foo {
  String word; // forbidden

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

Lihat di latebawah untuk mengubah perilaku ini.

Jenis tidak dapat dihapus ( ?)

Anda dapat menggunakan jenis yang dapat dibatalkan dengan menambahkan tanda tanya ?ke jenis variabel:

class Foo {
  String word; // forbidden

  String? sentence; // allowed
}

Sebuah nullable variabel tidak perlu diinisialisasi sebelum dapat digunakan. Ini diinisialisasi sebagai nulldefault:

void main() {
  String? word;

  print(word); // prints null
}

!

Menambahkan !untuk setiap variabel eakan melempar kesalahan runtime jika enull dan sebaliknya mengubahnya menjadi non-nullable nilai v.

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

Kata kunci latedapat digunakan untuk menandai variabel yang akan diinisialisasi nanti , yaitu tidak ketika mereka dideklarasikan tetapi ketika mereka diakses. Ini juga berarti bahwa kita dapat memiliki bidang instance yang tidak dapat dibatalkan yang diinisialisasi nanti:

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

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

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

Mengakses wordsebelum diinisialisasi akan menimbulkan kesalahan runtime.

late final

Variabel akhir sekarang juga dapat ditandai terlambat:

late final int x = heavyComputation();

Di sini heavyComputationhanya akan disebut sekali xdiakses. Selain itu, Anda juga dapat mendeklarasikan late finaltanpa penginisialisasi, yang sama dengan hanya memiliki latevariabel, tetapi hanya dapat ditugaskan satu kali.

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

Perhatikan bahwa semua variabel tingkat atas atau statis dengan penginisialisasi sekarang akan dievaluasi late, tidak peduli apakah itu variabel final.

required

Dahulu anotasi ( @required), sekarang sudah ada sebagai modifier. Ini memungkinkan untuk menandai parameter apa pun yang dinamai (untuk fungsi atau kelas) sebagai required, yang membuatnya tidak dapat dibatalkan:

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

Ini juga berarti bahwa jika suatu parameter tidak dapat dibatalkan , parameter tersebut harus ditandai sebagai requiredatau memiliki nilai default:

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

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

Parameter bernama lainnya harus nullable :

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

?[]

Operator nol sadar ?[]telah ditambahkan untuk operator indeks []:

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

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

Lihat juga artikel ini tentang keputusan sintaksis .

?..

Operator cascade kini juga memiliki operator menyadari nol baru: ?...

Ini menyebabkan operasi kaskade berikut hanya dijalankan jika penerima tidak nol . Oleh karena itu, ?..harus menjadi operator kaskade pertama dalam urutan kaskade:

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

Untuk menghindari kebingungan: ini bukan sesuatu yang harus dikhawatirkan oleh pengembang. Saya ingin menyebutkannya demi kelengkapan.

Neverakan menjadi tipe seperti yang sudah ada sebelumnya Null( tidaknull ) didefinisikan dalam dart:core. Kedua kelas ini tidak dapat diperpanjang, diimplementasikan, atau dicampur, sehingga tidak dimaksudkan untuk digunakan.

Pada dasarnya, Neverberarti tidak ada tipe yang diizinkan dan Neveritu sendiri tidak dapat dipakai.
Tidak ada Neveryang List<Never>memuaskan batasan tipe generik dari daftar, yang berarti harus kosong . List<Null>Namun, dapat mengandung 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)
];

Contoh: kompiler akan menyimpulkan List<Never>untuk kosong const List<T> .
Nevertidak seharusnya digunakan oleh programmer sejauh yang saya ketahui.

creativecreatorormaybenot
sumber
5
Bisakah Anda memberikan beberapa skenario di mana Neverdapat digunakan?
Ramses Aldama
2
Kami sebenarnya telah memutuskan untuk menggunakan "? []" Untuk operator indeks nol-sadar alih-alih "?. []". Yang terakhir ini sedikit lebih rumit secara tata bahasa, tetapi itulah yang diinginkan pengguna.
munificent
@RamsesAldama Saya telah menambahkan sesuatu. Spesifikasi yang saya tautkan lebih banyak menyebutkan.
creativecreatorormaybenot
@munificent Spek dan eksperimen masih ketinggalan zaman; terima kasih telah menunjukkan.
creativecreatorormaybenot
1
Harus ditunjukkan bahwa late finalpada variabel anggota atau instance hanya memeriksa saat runtime. Tidak mungkin memeriksa itu pada waktu pengembangan atau waktu kompilasi karena masalah penghentian. Jadi Anda tidak akan mendapatkan bantuan IDE dengan itu.
Graham