Flutter-Docs-Resources-Bootstrap into Dart - Notes

2023-05-16

Flutter-Docs-Resources-Bootstrap into Dart : https://docs.flutter.dev/resources/bootstrap-into-dart

Bootstrap into Dart

New to the Dart language? We compiled our favorite resources to help you quickly learn Dart. Many people have reported that Dart is easy and fun to learn. We hope these resources make Dart easy for you to learn, too.

exhaustive /ɪɡˈzɔːstɪv/ a详细的 inference /ˈɪnfərəns/ 推断 syntax /ˈsɪntæks/ 语法 syntactic /sɪnˈtæktɪk/ 语法的 shorthand /ˈʃɔːtˌhænd/ 速记法 handy /ˈhændɪ/ 有用的 terrestrial /təˈrɛstrɪəl/ a地球的 sound /saʊnd/ n声音a状态好的

$*variableName* (or ${*expression*}) is String interpolation: including a variable or expression’s string equivalent inside of a string literal.

Everything you can place in a variable is an object, and every object is an instance of a class. Even numbers, functions, and null are objects. With the exception of null (if you enable sound null safety), all objects inherit from the Object class.

Null safety was introduced in Dart 2.12. Using null safety requires a language version of at least 2.12.

If you enable null safety, variables can’t contain null unless you say they can. You can make a variable nullable by putting a question mark (?) at the end of its type.

In Dart 2.12 to 2.19, null safety is a configuration option in the pubspec. Null safety is not available in SDK versions prior to Dart 2.12.

To enable sound null safety, set the SDK constraint lower-bound to a language version of 2.12 or later. For example, your pubspec.yaml file might have the following constraints:

environment:
  sdk: '>=2.12.0 <3.0.0'

Dart supports top-level functions (such as main()), as well as functions tied to a class or object (static and instance methods, respectively). You can also create functions within functions (nested or local functions).

Similarly, Dart supports top-level variables, as well as variables tied to a class or object (static and instance variables). Instance variables are sometimes known as fields or properties.

Unlike Java, Dart doesn’t have the keywords public, protected, and private. If an identifier starts with an underscore (_), it’s private to its library. For details, see Libraries and visibility.

Uninitialized variables that have a nullable type have an initial value of null. (If you haven’t opted into null safety, then every variable has a nullable type.) Even variables with numeric types are initially null, because numbers—like everything else in Dart—are objects.

The first argument to assert can be any expression that resolves to a boolean value. If the expression’s value is true, the assertion succeeds and execution continues. If it’s false, the assertion fails and an exception (an AssertionError) is thrown.

In production code, assertions are ignored, and the arguments to assert aren’t evaluated.

You don’t have to initialize a local variable where it’s declared, but you do need to assign it a value before it’s used.

Top-level and class variables are lazily initialized; the initialization code runs the first time the variable is used.

Instance variables can be final but not const.

The const keyword isn’t just for declaring constant variables. You can also use it to create constant values, as well as to declare constructors that create constant values. Any variable can have a constant value.

You can omit const from the initializing expression of a const declaration, like for baz above. For details, see DON’T use const redundantly.

You can change the value of a non-final, non-const variable, even if it used to have a const value:

You can define constants that use type checks and casts (is and as), collection if, and spread operators (... and ...?):

Although a final object cannot be modified, its fields can be changed. In comparison, a const object and its fields cannot be changed: they’re immutable.

Some other types also have special roles in the Dart language:

  • Object: The superclass of all Dart classes except Null.
  • Enum: The superclass of all enums.
  • Future and Stream: Used in asynchrony support.
  • Iterable: Used in for-in loops and in synchronous generator functions.
  • Never: Indicates that an expression can never successfully finish evaluating. Most often used for functions that always throw an exception.
  • dynamic: Indicates that you want to disable static checking. Usually you should use Object or Object? instead.
  • void: Indicates that a value is never used. Often used as a return type.

The Object, Object?, Null, and Never classes have special roles in the class hierarchy, as described in the top-and-bottom section of Understanding null safety.

Dart supports the spread operator (...) and the null-aware spread operator (...?), which provide a concise way to insert multiple values into a collection.

For example, you can use the spread operator (...) to insert all the values of a list into another list

If the expression to the right of the spread operator might be null, you can avoid exceptions by using a null-aware spread operator (...?):

Dart also offers collection if and collection for, which you can use to build collections using conditionals (if) and repetition (for).

Set or map? The syntax for map literals is similar to that for set literals. Because map literals came first, {} defaults to the Map type. If you forget the type annotation on {} or the variable it’s assigned to, then Dart creates an object of type Map<dynamic, dynamic>.

Sets support spread operators (... and ...?) and collection if and for, just like lists do. For more information, see the list spread operator and list collection operator discussions.

Dart is a true object-oriented language, so even functions are objects and have a type, Function. This means that functions can be assigned to variables or passed as arguments to other functions. You can also call an instance of a Dart class as if it were a function. For details, see Callable classes.

The => *expr* syntax is a shorthand for { return *expr*; }. The => notation is sometimes referred to as arrow syntax.

Only an expression—not a statement—can appear between the arrow (=>) and the semicolon (😉. For example, you can’t put an if statement there, but you can use a conditional expression.

Dart has two operators that let you concisely evaluate expressions that might otherwise require if-else statements:

  • *condition* ? *expr1* : *expr2*

    If condition is true, evaluates expr1 (and returns its value); otherwise, evaluates and returns the value of expr2.

  • *expr1* ?? *expr2*

    If expr1 is non-null, returns its value; otherwise, evaluates and returns the value of expr2.

A function can have any number of required positional parameters. These can be followed either by named parameters or by optional positional parameters (but not both).

Some APIs—notably Flutter widget constructors—use only named parameters, even for parameters that are mandatory.

mandatory /ˈmændətərɪ/ a强制性的

Named parameters are optional unless they’re explicitly marked as required. When defining a function, use {*param1*, *param2*, …} to specify named parameters. If you don’t provide a default value or mark a named parameter as required, their types must be nullable as their default value will be null:

When calling a function, you can specify named arguments using *paramName*: *value*.

To define a default value for a named parameter besides null, use = to specify a default value. The specified value must be a compile-time constant.

If you instead want a named parameter to be mandatory, requiring callers to provide a value for the parameter, annotate them with required.

You might want to place positional arguments first, but Dart doesn’t require it. Dart allows named arguments to be placed anywhere in the argument list when it suits your API.

Optional positional parameters

Wrapping a set of function parameters in [] marks them as optional positional parameters. If you don’t provide a default value, their types must be nullable as their default value will be null.

To define a default value for an optional positional parameter besides null, use = to specify a default value. The specified value must be a compile-time constant.

Every app must have a top-level main() function, which serves as the entrypoint to the app. The main() function returns void and has an optional List<String> parameter for arguments.

You can pass a function as a parameter to another function. You can also assign a function to a variable.

Most functions are named, such as main() or printElement(). You can also create a nameless function called an anonymous function, or sometimes a lambda or closure. You might assign an anonymous function to a variable so that, for example, you can add or remove it from a collection.

An anonymous function looks similar to a named function—zero or more parameters, separated by commas and optional type annotations, between parentheses.

The code block that follows contains the function’s body:

([[Type] param1[,]]) {
  codeBlock;
};

The following example defines an anonymous function with an untyped parameter, item, and passes it to the map function. The function, invoked for each item in the list, converts each string to uppercase. Then in the anonymous function passed to forEach, each converted string is printed out alongside its length.

const list = ['apples', 'bananas', 'oranges'];
list.map((item) {
  return item.toUpperCase();
}).forEach((item) {
  print('$item: ${item.length}');
});
//APPLES: 6
//BANANAS: 7
//ORANGES: 7

Asynchrony support

Dart libraries are full of functions that return Future or Stream objects. These functions are asynchronous: they return after setting up a possibly time-consuming operation (such as I/O), without waiting for that operation to complete.

The async and await keywords support asynchronous programming, letting you write asynchronous code that looks similar to synchronous code.

Why asynchronous code matters

Asynchronous operations let your program complete work while waiting for another operation to finish. Here are some common asynchronous operations:

  • Fetching data over a network.
  • Writing to a database.
  • Reading data from a file.

Such asynchronous computations usually provide their result as a Future or, if the result has multiple parts, as a Stream. These computations introduce asynchrony into a program. To accommodate that initial asynchrony, other plain Dart functions also need to become asynchronous.

To interact with these asynchronous results, you can use the async and await keywords. Most asynchronous functions are just async Dart functions that depend, possibly deep down, on an inherently asynchronous computation.

A future (lower case “f”) is an instance of the Future (capitalized “F”) class. A future represents the result of an asynchronous operation, and can have two states: uncompleted or completed.

  • When a future’s operation finishes, the future completes with a value or with an error.

To define an async function, add async before the function body. The await keyword works only in async functions.

Now that you have an async function, you can use the await keyword to wait for a future to get the completed result of an asynchronous expression.

An async function runs synchronously until the first await keyword. This means that within an async function body, all synchronous code before the first await keyword executes immediately.

You can use await multiple times in an async function. For example, the following code waits three times for the results of functions:

Classes

Dart is an object-oriented language with classes and mixin-based inheritance. Every object is an instance of a class, and all classes except Null descend from Object. Mixin-based inheritance means that although every class (except for the top class, Object?) has exactly one superclass, a class body can be reused in multiple class hierarchies. Extension methods are a way to add functionality to a class without changing the class or creating a subclass.

You can create an object using a constructor. Constructor names can be either *ClassName* or *ClassName*.*identifier*. For example, the following code creates Point objects using the Point() and Point.fromJson() constructors.

Some classes provide constant constructors. To create a compile-time constant using a constant constructor, put the const keyword before the constructor name.

To get an object’s type at runtime, you can use the Object property runtimeType, which returns a Type object.

Use a named constructor to implement multiple constructors for a class or to provide extra clarity.

Remember that constructors are not inherited, which means that a superclass’s named constructor is not inherited by a subclass. If you want a subclass to be created with a named constructor defined in the superclass, you must implement that constructor in the subclass.

By default, a constructor in a subclass calls the superclass’s unnamed, no-argument constructor. The superclass’s constructor is called at the beginning of the constructor body.

If the superclass doesn’t have an unnamed, no-argument constructor, then you must manually call one of the constructors in the superclass. Specify the superclass constructor after a colon (:), just before the constructor body (if any).

To avoid having to manually pass each parameter into the super invocation of a constructor, you can use super-initializer parameters to forward parameters to the specified or default superclass constructor. This feature can’t be used with redirecting constructors. Super-initializer parameters have similar syntax and semantics to initializing formal parameters.

Sometimes a constructor’s only purpose is to redirect to another constructor in the same class. A redirecting constructor’s body is empty, with the constructor call (using this instead of the class name) appearing after a colon (😃.

If your class produces objects that never change, you can make these objects compile-time constants. To do this, define a const constructor and make sure that all instance variables are final.

Use the factory keyword when implementing a constructor that doesn’t always create a new instance of its class. For example, a factory constructor might return an instance from a cache, or it might return an instance of a subtype. Another use case for factory constructors is initializing a final variable using logic that can’t be handled in the initializer list.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Flutter-Docs-Resources-Bootstrap into Dart - Notes 的相关文章

随机推荐