Get started guide | Dart, check with you

It is planned to enter the Flutter pit recently, so it is recorded here and checked as soon as it is used;

Don't give advice, just do it,

A simple Dart program

main(){
  var number = "Hello World";
  printInteger(number);
}
//Define a function
printInteger(int aNumber){
  print('The number is $aNumber');
}

Important concepts

Learning Dart should be based on the following facts and concepts

  • Anything saved in a variable is an Object; All objects correspond to an instance of a class. Functions and null are objects. All objects are based on the Object class
  • Although Dart is strongly typed, Dart can infer the type. For example, the code variable number above is inferred as int type; If you want to make it clear that no type is required, Special type dynamic is required
  • Dart supports generics, such as list < int >, list < dynamic > (list of objects of any type)
  • Dart supports the top-level function main(). Similarly, the function is bound to a class or object (static function and instance function respectively). And support the creation of functions (nested or local functions) within functions.
  • Dart supports top-level variables
  • dart has no keywords public, protected and private. If_ At the beginning, it is private relative to the library
  • Ternary operator: condition? Expr1 : expr2
  • Type problem: warning and error. The warning indicates that the code may not work normally, but it will not block the execution of the program. The error may be a compilation or runtime error. The compilation error will prevent the execution of the code, and the runtime error will cause the code to throw an exception (#exception) during execution

keyword

abstract 2

dynamic 2

implements 2

show 1

as 2

else

import 2

static 2

assert

enum

in

super

async 1

export 2

interface 2

switch

await 3

extends

is

sync 1

break

external 2

library 2

this

case

factory 2

mixin 2

throw

catch

false

new

true

class

final

null

try

const

finally

on 1

typedef 2

continue

for

operator 2

var

covariant 2

Function 2

part 2

void

default

get 2

rethrow

while

deferred 2

hide 1

return

with

do

if

set 2

yield 3

These words should be avoided as identifiers

  • Words with 1 are contextual keywords that only have meaning in a specific location. They are valid identifiers everywhere
  • Those with 2 are built-in identifiers. These keywords are valid identifiers in most places and cannot be used for type names and import prefixes
  • With 3 is the update related to asynchronous support added after the release of Dart 1.0, which is used as the reserved word of restriction class.

variable

dynamic name = "345"; // name is inferred to be of type String
String name = "345";//Explicit declaration

Dynamic: this type has all possible attributes and methods. A variable modified by dynamic is equivalent to telling the system that I know what this type is. The type of data is not inferred at compile time after use, but at run time.

Default value

The default value of uninitialized variables is null, even for numeric types. Everything in Dart is an object

Final and Const

For variables that will never be modified during use, final or const can be used. The value of the final variable can only be set once, and the const variable is fixed at compile time.

Built in type

  • Number: there are two types: 1, int, and the integer value is not greater than 64 bits; Double double precision floating point number
  • String: Dart string is a set of UTF-16 unit sequences. The string is created by single quotation marks or double quotation marks

You can use + to connect strings into one; Use three or three double quotes to create a multiline string object

Using the prefix "r", you can create the "original raw string"

  • Boolean: true and false
  • List: (also known as Array)

var list = [1, 2, 3]; var list = [1, 2, 3]; assert(list.length == 3); assert(list[1] == 2);

list[1] = 1; assert(list[1] == 1);

Add const keyword before list to define compile time constants of list type

var constantList = const [1, 2, 3];

Map: used to associate key and value. Key can only appear once in the same map

var gifts = {
  // Key:    Value
  'first': 'partridge',
  'second': 'turtledoves',
  'fifth': 'golden rings'
};
  • Set: set is a unique set of elements
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
var names = <String>{};
// Set<String> names = {}; //  This is also possible.
// var names = {}; //  This creates a Map instead of a Set.
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);

var gifts = Map();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';

var nobleGases = Map();
nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';  
  • Rune: (used to represent Unicode characters in a string)

In Dart, Rune is used to represent UTF-32 encoded characters in a string

The common method of representing Unicode encoding is \ uXXXX, where XXXX is a 4-bit hexadecimal number. For example, a heart symbol( ♥) Yes. For special cases with non-4 values, put the coded value in braces. For example, emoji's smiling face is \ u{1f600}.

  • Symbol

The Symbol object represents the operator or identifier declared in the Dart program. You generally won't use it

Null-aware

Dart's null aware comes from the official version of Dart 1.12, and its existence is reasonable. Since there is such an operator, it shows that it saves our code to a certain extent

The whole operator is specially used to deal with null values. It will provide operations related to null pointers

a = b ?? c;

//If a is null, b is assigned to a
a ?? = b;

//When x is not nul, the fun function is called
a?.fun();

function

Dart is a real object-oriented language. Even the functions in dart are objects and have its type Function. This means that a Function can be assigned to a variable or passed as a parameter to other functions, or an instance of the dart class can be called as a method

isNoble(atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}
//If there is only one sentence, it can be written concisely
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;

=>* expr * syntax is {return *expr *;} Abbreviation for. = > Symbols are sometimes called arrow syntax. There can only be one expression after the arrow;

  • When calling an optional parameter to define a function, use {param1,param2,...}, Placed at the end of the parameter list to specify optional parameters, such as
const Scrollbar({Key key, @required Widget child,bool bold})

Use @ required to indicate that the parameter is a named parameter of the required nature.

  • Location optional parameters
String say(String from, String msg, [String device]) {
  var result = '$from says $msg';
  if (device != null) {
    result = '$result with a $device';
  }
  return result;
}

It is optional to mark parameters by placing them in []. Indicates that the parameter can not be transferred

  • Default parameter value
// The bold value is true; The hidden value is false
void abc(bool bold = false);

Accept a list and map and specify the default value of the parameter

  • main() function
void main(){
}
// Run the application like this: dart args dart 1 test
void main(List<String> arguments) {
  print(arguments);
}

The return value of main function is null, and the parameter is an optional list < string >

  • Anonymous function

Most functions have names, such as main(). dart can create functions without names. Such functions are called anonymous functions, sometimes called lambda or closure. Anonymous functions can be assigned to a variable. For example, an anonymous function can be added or deleted from a collection

main(){
  var list = [];
  list.add(1);
  list.add(2);
  list.add(3);
  list.add(4);
  
  list.forEach((num){
    print('Location: ${list.indexOf(num)} ;Value: $num');
  });
}

An anonymous function with no type parameter num is defined above. When the list is traversed, this function will be called every time and the value will be passed to the anonymous function.

If there is only one sentence, it can be written as follows:

list.forEach((num)=>print('Location: ${list.indexOf(num)} ;Value: $num'));
  • Assignment and transfer of functions
main(){
  //Assign anonymous functions to variables
  var one = (num)=>print(' Value: $num');
  one(10);
  
  //Assign ordinary functions to variables
  var two = abc;
  two(20);
  
  //Pass anonymous functions to normal functions
  abc2((str) => print("abc $str"));
}

void abc2(fun(String str)){
 fun("output------->");
}

void abc(num){
  print("Ha ha ha: $num");
}
  • Lexical scope

dart is a lexical scoped programming language.

In short, the scope of the variable has been determined when writing the code, and the visible scope of the variable is in curly brackets

bool topLevel = true;

void main() {
  var insideMain = true;

  void myFunction() {
    var insideFunction = true;

    void nestedFunction() {
      var insideNestedFunction = true;

      assert(topLevel);
      assert(insideMain);
      assert(insideFunction);
      assert(insideNestedFunction);
    }
  }
}

Internally, you can access all variables up to the variables in the top-level scope.

  • Lexical Closure

A closure is a function object. Even if the function is called outside its original scope, it can still access its variables in the lexical scope

///Returns a function. The returned function parameters are added to [addBy].
Function makeAdder(num addBy) {
  return (num i) => addBy + i;
}

void main() {
  // Create a function that adds 2.
  var add2 = makeAdder(2);

  // Create a function that adds 4.
  var add4 = makeAdder(4);

  assert(add2(3) == 5);
  assert(add4(3) == 7);
}
  • Test whether the functions are equal
void foo() {} // Top level function

class A {
  static void bar() {} // Static method
  void baz() {} // Example method
}

void main() {
  var x;

  // Compare top-level functions.
  x = foo;
  assert(foo == x);

  // Compare static methods.
  x = A.bar;
  assert(A.bar == x);

  // Compare the example method.
  var v = A(); // Instance 1 of A
  var w = A(); // Example 2 of A
  var y = w;
  x = w.baz;

  // The same instance (No. 2) referenced by two closures,
  // So they are equal.
  assert(y.baz == x);

  // Two closures refer to different instances,
  // So they are not equal.
  assert(v.baz != w.baz);
}
  • Return value

All functions will have a return value. If there is no clear return value, the function will be implicitly added return null; sentence

Extension function, attribute

extension StringExt on String {
  double toDouble() {
    return double.parse(this);
  }
  int toInt() {
    return int.parse(this);
  }
}

Object Extension:
extension ObjectExt on Object {
  bool isNullOrEmpty() {
    if (this is String)
      return (this as String).isEmpty;
    else if (this is Iterable) return (this as Iterable).isEmpty;
    return this == null;
  }
}

Generic extensions:
extension AllExt<T> on T {
  T apply(f(T e)) {
    f(this);
    return this;
  }

  R let<R>(R f(T e)) {
    return f(this);
  }
}

//Extended properties
extension SizeExtension on num {

  double get w => 10.0;

  double get h => 10.0;
}

operator

  • Dart defines the following operators:

Description

Operator

Unary suffix

*expr*++ *expr*-- () [] . ?.

Unary prefix

-*expr* !*expr* ~*expr* ++*expr* --*expr*

multiplicative

* / % ~/

additive

+ -

shift

<< >> >>>

bitwise AND

&

bitwise XOR

^

bitwise OR

|

relational and type test

>= > <= < as is is!

equality

== !=

logical AND

&&

logical OR

||

if null

??

conditional

*expr1* ? *expr2* : *expr3*

cascade

..

assignment

= *= /= += -= &= ^= etc.

In the above table, most operators can be overloaded

  • Conditional expression
*condition* ? *expr1* : *expr2*

If the condition is true, execute expr1 (and return its value): otherwise, execute and return the value of expr2.

*expr1* ?? *expr2*

If expr1 is non null, return the value of expr1; Otherwise, execute and return the value of expr2.

  • Level combined transport operator

The level transport operator can perform some operations on an object. In addition to calling the function, it can also access the field properties on the same object,

void main() {
  new A()
	  ..a1()
	  ..a2();
}
class A{
	void a1(){
		print('a1');
	}
	
	void a2(){
		print('a2');
	}
}
//a1  a2

Level transport operators can be nested

final addressBook = (AddressBookBuilder()
      ..name = 'jenny'
      ..email = 'jenny@example.com'
      ..phone = (PhoneNumberBuilder()
            ..number = '415-555-0100'
            ..label = 'home')
          .build())
    .build();

Control flow statement

  • if and else
  • for loops
for (var i = 0; i < 5; i++) {
  message.write('!');
}

You can also use forEach or for in

candidates.forEach((candidate) => candidate.interview());
var collection = [0, 1, 2];
for (var x in collection) {
  print(x); // 0 1 2
}
  • while and do-while loops
  • break and continue
  • switch and case

Similar to java, you can compare integers, strings, or compile time constants. The objects you compare are the same instance (and cannot be subclasses). You can also use switch statements for enumeration

  • assert

If the Boolean condition in assert is false, the normal program execution process will be interrupted

The assert statement is only valid in the development environment, but not in the production environment

abnormal

​ Dart can throw and catch exceptions. If it is not caught, it will throw exceptions and eventually cause the program to terminate

​ Unlike Java, all exceptions in Dart are non checking exceptions. Methods do not declare the exceptions they throw, nor do they require any exceptions to be caught

​ Dart provides Exception and Error types, as well as some subtypes. You can also customize Exception types. In addition, the dart program can throw any non null object, not just Exception and Error objects.

  • throw
throw FormatException('Expected at least 1 section');
  • Throw any object
void distanceTo(Point other) => throw UnimplementedError();
  • Throw an exception where an expression is used
void distanceTo(Point other) => throw UnimplementedError();
  • Catch

Catch exception

try {
  breedMoreLlamas();
} on OutOfLlamasException {
  // A special exception
  buyMoreLlamas();
} on Exception catch (e) {
  // Any other exceptions
  print('Unknown exception: $e');
} catch (e) {
  // No specified type, handle all exceptions
  print('Something really unknown: $e');
}

The catch function can specify 1 to 2 parameters. The first is the exception object and the second is the stack information (StackTrace object)

try {
  // ···
} on Exception catch (e) {
  print('Exception details:\n $e');
} catch (e, s) {
  print('Exception details:\n $e');
  print('Stack trace:\n $s');
}

If some exceptions need to be handled, you can use rethrow to re throw the exception

void misbehave() {
  try {
    dynamic foo = true;
    print(foo++); // Runtime error
  } catch (e) {
    print('misbehave() partially handled ${e.runtimeType}.');
    rethrow; // Allow callers to see the exception.
  }
}

void main() {
  try {
    misbehave();
  } catch (e) {
    print('main() finished handling ${e.runtimeType}.');
  }
}
  • finally

Finally will execute whether or not try to hold the exception. If the try fails, the corresponding catch will be executed first and finally

class

​ Dart is an object-oriented language based on class and mixin inheritance mechanism. Each object is an instance of a class, and all classes inherit from Object. . Mixin based inheritance means that each class (except Object) has only one superclass, and the code in one class can be reused in multiple other inherited classes.

  • create object
var p = Point(2, 2);

// Set a value for the variable y of the instance.
p.y = 3;

// Gets the value of the variable y.
assert(p.y == 3);

//If p is not empty, set y=8
p?.y = 8

// Call p's distanceTo() method.
num distance = p.distanceTo(Point(4, 4));

use?. Instead, You can avoid exceptions caused by the possibility that the left object may be null

  • Get object type

Using the runtimeType attribute of the object, you can get the type of the object at run time, and the runtimeType attribute returns one Type Object.

  • Instance variable
class Point {
  num x; // Declare the sample variable x, and the initial value is null.
  num y; // Declare the sample variable y, and the initial value is null.
  num z = 0; // Declare the sample variable z with an initial value of 0.
}

Uninitialized variable is null

All instance variables implicitly generate getter methods, and non final variables generate setter methods

  • Default construction

Dart provides a default construct when no construct is declared

  • Constructor is not inherited

Subclasses do not inherit the constructor of the parent class. If a subclass does not declare a constructor, it has only a default constructor (anonymous, no parameters).

  • Named constructor

Using named constructors, you can implement multiple constructors for a class, or you can use named constructors to more clearly indicate the function intention:

class Point {
  num x, y;

  Point(this.x, this.y);

  // Named constructor
  Point.origin() {
    x = 0;
    y = 0;
  }
}

Remember that constructors cannot be inherited, which means that the named constructor of the parent class will not be inherited by the child class. If you want to create a subclass using the named constructor defined in the parent class, you must implement the constructor in the subclass.

  • Call the default constructor of the parent class field

The execution sequence is as follows:

  1. initializer list
  2. superclass's no Arg constructor
  3. main class's no Arg constructor
class Person {
  String firstName;

  Person.fromJson(Map data) {
    print('in Person');
  }
}

class Employee extends Person {
  // Person does not have a default constructor;
  // you must call super.fromJson(data).
  Employee.fromJson(Map data) : super.fromJson(data) {
    print('in Employee');
  }
}

main() {
  var emp = new Employee.fromJson({});

  // Prints:
  // in Person
  // in Employee
  if (emp is Person) {
    // Type check
    emp.firstName = 'Bob';
  }
  (emp as Person).firstName = 'Bob';
}
  • Constant constructor

If your class and the created object will never change, you can create this constant instance at compile time, define the constant constructor, and ensure that all member variables are final.

var p = const ImmutablePoint(2, 2);

Add const before the constructor name to create a compile time constant

Note: constructing two identical compile time constants will result in one identical instance

const can be omitted in a constant context:

// There are many const keywords here.
const pointAndLine = const {
  'point': const [const ImmutablePoint(0, 0)],
  'line': const [const ImmutablePoint(1, 10), const ImmutablePoint(-2, 11)],
};
  // There is only one const, which establishes the constant context.
const pointAndLine = {
  'point': [ImmutablePoint(0, 0)],
  'line': [ImmutablePoint(1, 10), ImmutablePoint(-2, 11)],
};

In Dart2, the const keyword in a constant context can be omitted

class ImmutablePoint {
  static final ImmutablePoint origin =
      const ImmutablePoint(0, 0);

  final num x, y;

  const ImmutablePoint(this.x, this.y);
}
  • Factory constructor
class Logger {
  final String name;
  bool mute = false;

  // From named_ As you can see,
  // _ cache is a private property.
  static final Map<String, Logger> _cache =
      <String, Logger>{};

  factory Logger(String name) {
    if (_cache.containsKey(name)) {
      return _cache[name];
    } else {
      final logger = Logger._internal(name);
      _cache[name] = logger;
      return logger;
    }
  }

  Logger._internal(this.name);

  void log(String msg) {
    if (!mute) print(msg);
  }
}

In fact, it is a factory mode, such as the name of, and then get the corresponding instance

  • About others

Abstract classes and enumerations are not detailed. They are all basic operations, similar to java. If you don't understand, you can check it on the official website

Asynchronous operation

  • Future
void main() {
  print("start ----------->");
  print(getNetData());
  print("end -------------->");
}

String getNetData() {
  //It takes 3 seconds
  sleep(Duration(seconds: 3));
  return "network data ";
}
start ----------->F
//It takes three seconds to print as follows
 network data 
end -------------->

It can be seen that the main method is blocked directly, which makes the next code unable to continue to execute. This must be caused by the problem

Asynchronous network request

Future<String> getNetData() {
  return Future(() {
    sleep(Duration(seconds: 3));
    return "network data ";
  });
}
start ----------->
Instance of 'Future<String>'
end -------------->

Use the future object to place time-consuming operations in functions that pass in parameters

You can see that there is no blocking, but the returned result is an instance of future. Through future, time-consuming operations can be isolated without affecting the execution of the main thread.

Get future results

//When the future returned by getNetData has returned results, the function passed in then will be called automatically
//The function will be placed in the event loop and executed
getNetData().then((value) {
  print(value);
});
start ----------->
end -------------->
network data 

Exceptions during execution

getNetData().then((value) {
  //Support succeeded here
  print(value);
}).catchError((error) {
  //Execution failed here
  print(error);
});

Common methods

  • Future.whenComplete

Whether the implementation is successful or failed, it will come here

getNetData().then((value) {
  //Support succeeded here
  print(value);
}).catchError((error) {
  //Execution failed here
  print(error);
}).whenComplete(() => print("complete"));

It can be used to close the dialog box and other operations

  • Future. They chained call
//In them, you can continue to return the value, which will get the returned result in the next chained then call
getNetData().then((value) {
  //Support succeeded here
  print(value);
  return "data1";
}).then((value) {
  print(value);
  return "data2";
}).then((value) {
  print(value);
}).catchError((error) {
  //Execution failed here
  print(error);
}).whenComplete(() => print("complete"));
network data 
data1
data2
 complete
  • Future.wait

If you want to wait until multiple asynchronous tasks are completed before doing some operations, you can use future wait

Future.wait([getNetData(), getNetData(), getNetData()]).then((value) {
  value.forEach((element) {
    print(element);
  });
});

wait accepts an array of type future, and then will be executed only after the array's future is executed successfully

  • Future.delayed

The function is executed after a certain time delay

 Future.delayed(Duration(seconds: 3), () {
    return "3 Information after seconds";
  }).then((value) {
    print(value);
  });
  • async,await

async: used to indicate that the function is asynchronous. The defined function will return a Future object. You can use then to add a callback function

await: followed by a Future, which means waiting for the completion of the asynchronous task to be changed. It will not continue until the asynchronous task is completed. await must appear inside async

void main() {
  print("start ------
  ----->");

  getNetData().then((value) => print(value));

  print("end -------------->");
}

Future<String> getNetData() async {
  var result1 = await Future.delayed(Duration(seconds: 3), () {
    return "Network data 1";
  });
  var result2 = await Future.delayed(Duration(seconds: 3), () {
    return "Network data 2";
  });
  return result1 + "-----" + result2;
}
stay getNetData In, get the two results for splicing, and then return together
  
  The return value is wrapped in a Futter In, it can be used at the call them Get the results directly

---

> References: official documents, Flutter Actual combat,[Dart asynchronous](https://juejin.cn/post/6844903942795558919#heading-11)



## Now let's work together

> happy codeing

Added by jarow on Tue, 15 Feb 2022 04:41:21 +0200