preface
By the end of this chapter you will know:
- What is air safety
- Principles of air safety
- How do I enable air security
- The type of air safety
- Empty assertion operator
- Newest modifier
Video tutorial
Empty safety video tutorial address
Introduction to Air Safety
Null-safe Type System was introduced in Dart 2.12. If null-safe is enabled, types in code cannot be null by default, meaning that values cannot be null unless the type is declared nullable.
Air security is highly recommended by the government, and now many popular third-party libraries all support air security, so air security is the knowledge we must master.
Principles of air safety
- ** Default non-nullable: ** Unless you explicitly declare a variable to be nullable, it must be of a non-null type.
- ** Progressive migration: ** Freedom to choose when and how much code will be migrated, as well as the ability to use mixed-mode empty security, using both air-safe and non-air-safe code in a project.
- ** Completely reliable: ** all the benefits of code soundness – fewer bugs, smaller binaries, and faster execution.
Enabling air Security
Air safety is available in Dart 2.12 and Flutter 2.0 and can be enabled by specifying Dart SDK version 2.12
environment:
sdk: "> = 2.12.0 < 3.0.0"
Copy the code
Air safety type
Null security is divided into null and non-null. Null means that variables and parameters can be passed null, while non-null variables and parameters must not be null. In the following code demonstration, we use dart 2.12 to enable null security
- An error is reported when the variable is null
- An error is reported when passing parameters as empty
- The method must return parameters if it needs to, or compile an error
Variables can be null and cannot be null
Declare an empty variable
Here I declare a string attribute named name, but I don’t assign a value, so the memory address for name is an empty string.
String name;
Copy the code
Error message
It prompts that non-null variables must be initialized
Indicates that variables can be null
We can add one after Stirng, okay? “, which means that the name variable can be null, and we don’t get an error when we use the name property, but we get an error when we use the name property, and it says String, okay? Cannot be assigned to a String as follows:
Empty assertion operator
We got an error when we used the name attribute above. We could have used the empty assertion operator instead! Dart does not report errors at compile time. This symbol should not be used in projects unless you know explicitly that it is not null, because our name property is still null, so you will get an error like this at runtime:
======== Exception caught by widgets library =======================================================
The following _CastError was thrown building MyHomePage(dirty, state: _MyHomePageState#5824d):
Null check operator used on a null value
The relevant error-causing widget was:
MyHomePage MyHomePage:file:///Users/jm/Desktop/Work/Git/my_project/flutter_null_safety/lib/main.dart:29:13
When the exception was thrown, this was the stack:
..........
(package:flutter/src/rendering/binding.dart:319:5)
#123 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1143:15)
#124 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1080:9)
#125 SchedulerBinding.scheduleWarmUpFrame.<anonymous closure> (package:flutter/src/scheduler/binding.dart:863:7)
(elided 4 frames from class _RawReceivePortImpl.class _Timer.and dart:async-patch) = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =Copy the code
Parameter can be null and non – null use comparison
Declare a method that requires passing parameters
In the following code, we define a string with the optional parameter name. In the null-safe mechanism, we must ensure that the passed parameter cannot be empty, so we will receive the following error:
_upperCase({String name}) {
setState(() {
value.toUpperCase();
});
}
floatingActionButton: FloatingActionButton(
onPressed: _upperCase(),
child: Icon(Icons.add),
),
Copy the code
Error message
It prompts that the parameter name cannot be of type NULL, but is implicitly converted to NULL. There are two possible solutions to this problem
The solution
First: Add default values to optional parameters
_upperCase({String name = "Jimi"}) {
setState(() {
name.toUpperCase();
});
}
Copy the code
Second: Add required to the optional parameter
_upperCase({required String name}) {
setState(() {
name.toUpperCase();
});
}
Copy the code
If you add required to the optional parameter, name must be passed. If you add required to the optional parameter, name must be passed. If you add required to the optional parameter, name must be passed.
floatingActionButton: FloatingActionButton( onPressed: _upperCase(name: name!) , child: Icon(Icons.add), ),Copy the code
Here we use name! We said above that this is an empty assertion operator, which is used only if you know that the variable will have a value, so we will continue to optimize and declare name as a variable with a value as follows:
String name = "Jimi";
floatingActionButton: FloatingActionButton(
onPressed: _upperCase(name: name),
child: Icon(Icons.add),
),
Copy the code
The return value of a method can be null versus non-null
Declare a method that needs to return a value
Here I declare a method to convert name to uppercase. This code will not report errors until we introduce null security, but after we introduce null security you will receive the following error:
String name = "Jimi";
String _upperCaseName(String name) {
}
Copy the code
Error message
It indicates that the return type may be a type that cannot be NULL, and you can try adding a return or throw statement at the end.
The solution
First: Add a return statement
String _upperCaseName(String name) {
return name.toUpperCase();
}
Copy the code
Second: add a throw statement
String _upperCaseName(String name) {
throw "no return";
}
Copy the code
Custom class fields can be null and cannot be null using contrast
Declare a User class
We often use custom classes in the development process, and the attributes in the custom class are not assigned to the first value, so if we introduce null safety, we will get an error, as shown in the following:
class User {
String name;
int age;
setName(String name) {
this.name = name;
}
getName() {
return this.name;
}
setAge(int age) {
this.age = age;
}
getAge() {
return this.age; }}Copy the code
An error prompt
It tells you that name and age must have an initial value or be marked late.
The solution
The first is to declare that a variable can be null
We declare variables nullable, and we use the null assertion operator! But it also implies that NULL is a useful value for a field, which is the opposite, so it’s not recommended. Let’s look at the second solution, the late modifier.
String? name;
int? age;
Copy the code
The second type: late modifier
Since late involves a lot of content, we will take a chapter to explain it.
Newest modifier
The late modifier is used to constrain variables at run time rather than compile time, which means that late is equivalent to when a constraint is enforced on a variable.
For example, the name field decorated with late in this example is not necessarily initialized; each time it is read, a runtime check is inserted to ensure that it has been assigned. If no value is assigned, an exception is thrown, so adding String to the variable says, “My value is definitely a String,” and adding the late modifier means, “EVERY time I run it, I check to see if it’s true.”
When using the late modifier, the following is summarized:
- Don’t assign a value to the variable
- Assign the variable later
- Variables are assigned before being used
- If no value is assigned before use, an error will be reported
late String name;
late int age;
Copy the code
The late modifier loads lazily
Lazy loading is also known as lazy initialization. When you modify a variable with late, it will be delayed until the field is first accessed, rather than initialized when the constructor is instantiated. And the initialization content of the instance field is not accessible to this because the new instance object cannot be accessed until all the initialization methods are complete. With late, however, you can access this, call methods, and access instance fields.
Do not use the late modifier
The name attribute calls getUserName() directly. Finally, when we instantiate a User object and get the value of name, let’s look at the console output:
void main() {
print("Call constructor");
var user = User();
print("Get value");
print("The value obtained is:${user.getName()}");
}
class User {
String name = getUserName();
setName(String name) {
this.name = name;
}
getName() {
return this.name; }}String getUserName() {
print("Return user name");
return "Jimi";
}
Copy the code
Console output
Constructor flutter: returns the user's name. Flutter: gets the value. Flutter: gets the valueCopy the code
Use the late modifier
The code is the same as above, except for the late modifier at the definition field. Let’s look at the console output:
void main() {
print("Call constructor");
var user = User();
print("Get value");
print("The value obtained is:${user.getName()}");
}
class User {
late String name = getUserName();
setName(String name) {
this.name = name;
}
getName() {
return this.name; }}String getUserName() {
print("Return user name");
return "Jimi";
}
Copy the code
Console output
Constructor flutter: gets the value. Flutter: returns the user's name. Flutter: gets the value JimiCopy the code
We can obviously see that the second and third lines are reversed, and without the late modifier (i.e., no lazy loading), we call the fetch method directly when we instantiate the constructor. After the late modifier is added, the fetch will only be performed when the field is used.
conclusion
The introduction of empty security has made my code more reliable
- They all have to be nonempty in terms of type, but you can add them
?
Becomes nullable, using the null assertion operator!
Use. - All optional parameters must be non-null and usable
required
To build a non-optional named parameter. List
Classes are no longer allowed to contain uninitialized elements.late
Modifiers are checked at run time and can use non-null types andfinal
It also provides support for lazy initialization of fields.