当前位置:网站首页>First try dart, notes

First try dart, notes

2022-07-19 15:15:00 Humanoid bug maker 9527

Declaration of variables

1. var

Be similar to JavaScript Medium var, It can accept any type of variable , But the biggest difference is Dart in var Once the variable is assigned , The type will be determined , You can't change the type , Such as :

var t = "hi world";
//  The following code is in dart China will report an error , Because of the variable t The type of has been determined to be String,
//  Once the type is determined, it cannot be changed .
t = 1000;

The above code is in JavaScript There is no problem , Front end developers need to pay attention to , The difference is because Dart It's a strongly typed language in itself , Any variable has a definite type , stay Dart in , When used var After declaring a variable ,Dart At compile time, we will infer the type of the first assigned data , After compilation, its type has been determined , and JavaScript Is a purely weakly typed scripting language ,var It's just the way variables are declared .

2. dynamic and Object

Object yes Dart The root base class of all objects , That is to say Dart All types in are Object Subclasses of ( Include Function and Null), So any kind of data can be assigned to Object Declared object . dynamic And Object Declared variables can be assigned to any object , And the type of assignment can be changed later , This sum var Is different , Such as :

dynamic t;
Object x;
t = "hi world";
x = 'Hello Object';
// There is no problem with the following code 
t = 1000;
x = 1000;

dynamic And Object The difference is dynamic The declared object compiler provides all possible combinations , and Object Declared objects can only use Object Properties and methods of , Otherwise, the compiler will report an error , Such as :

dynamic a;
 Object b = "";
 main() {
    
   a = "";
   printLengths();
 }   

 printLengths() {
    
   //  normal 
print(a.length);
   //  Report errors  The getter 'length' is not defined for the class 'Object'
   print(b.length);
 }

dynamic We need to pay more attention when using it , It's easy to introduce a runtime error , For example, the following code will not report an error when compiling , An error will be reported during operation :

print(a.xx); // a Is string , No, "xx" attribute , No errors will be reported at compile time , The runtime will report an error 

3. final and const

If you never plan to change a variable , So use final or const, No var, It's not a type either . One final Variable can only be set once , The difference is :const Variable is a compile time constant ( Directly replace with constant value at compile time ),final Variables are initialized the first time they are used . By final perhaps const Decorated variable , Variable types can be omitted , Such as :

// It can be omitted String This type declaration 
final str = "hi world";
//final String str = "hi world"; 
const str1 = "hi world";
//const String str1 = "hi world";

4. Air safety (null-safety)

Dart Everything in is the object , This means that if we define a number , If we use it before initializing it , If there is no inspection mechanism , You can't report a mistake , such as :

test() {
    
  int i; 
  print(i*8);
}

stay Dart Before introducing empty security , The above code will not report an error before execution , But it will trigger a runtime error , as a result of i The value of is null . But now there is free safety , When defining variables, we can specify whether the variables are nullable or not .

int i = 8; // The default value is not null , Must be initialized at definition time .
int? j; //  Defined as nullable type , For nullable variables , We must judge the space before using .

// If we expect that the variable cannot be empty , But its initial value cannot be determined when defining , I can add late keyword ,
// Indicates that it will be initialized later , But before using it formally, you must ensure that it has been initialized , Otherwise, an error will be reported

late int k;
k=9;

If a variable is defined as nullable , In some cases, even if we assign a value to it , But the preprocessor may still not recognize , At this time, we will explicitly ( By adding a ”!“ Symbol ) Tell the preprocessor that it is no longer null 了 , such as :

class Test{
    
  int? i;
  Function? fun;
  say(){
    
    if(i!=null) {
    
      print(i! * 8); // Because the sentence has been empty , So I can walk here  i  It must not be null, If there is no explicit declaration , be  IDE  Will report a mistake 
    }
    if(fun!=null){
    
      fun!(); //  ditto 
    }
  }
}

If the function variable in the above can be null , You can use syntax sugar when calling :

fun?.call() // fun  If it is not empty, it will be called 

function

Dart Is a real object-oriented language , So even functions are objects , And there's a type Function. This means that functions can be assigned to variables or passed as arguments to other functions , This is a typical feature of functional programming .

1. Function declaration

bool isNoble(int atomicNumber) {
    
  return _nobleGases[atomicNumber] != null;
}

Dart Function declaration if the return value type is not explicitly declared, it defaults to dynamic Handle , Be careful , Function return value has no type inference :

typedef bool CALLBACK();

// Do not specify return type , The default is dynamic, No bool
isNoble(int atomicNumber) {
    
  return _nobleGases[atomicNumber] != null;
}

void test(CALLBACK cb){
    
   print(cb()); 
}
// Report errors ,isNoble No bool type 
test(isNoble);

For functions that contain only one expression , You can use shorthand syntax :

bool isNoble (int atomicNumber)=> true ;   

2. Function as variable

var say = (str){
    
  print(str);
};
say("hi world");
#3.  Function passed as parameter 
void execute(var callback) {
    
    callback();
}
execute(() => print("xxx"))

(1) Optional position parameters

Wrapping a set of function parameters , use [] Marked as an optional positional parameter , And put it at the end of the parameter list :

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

Here's an example of calling this function without optional arguments :

say('Bob', 'Howdy'); // The result is : Bob says Howdy

Here is an example of calling this function with the third parameter :

say('Bob', 'Howdy', 'smoke signal'); // The result is :Bob says Howdy with a smoke signal

(2) Optional named parameters

When defining a function , Use {param1, param2, …}, At the end of the parameter list , Used to specify named parameters . for example :

// Set up [bold] and [hidden] sign 
void enableFlags({
    bool bold, bool hidden}) {
    
    // ... 
}

When you call a function , You can use the specified named parameter . for example :paramName: value

enableFlags(bold: true, hidden: false);

Optional named parameters in Flutter It's used a lot in . Be careful , You can't use optional positional parameters and optional named parameters at the same time .

mixin

Dart Multiple inheritance is not supported , But it supports mixin, simply mixin Sure “ Combine ” Multiple classes , Let's use an example to understand .

Define a Person class , Realize eating 、 speak 、 Walk and write code , At the same time define a Dog class , Realize eating 、 And walking function :

class Person {
    
  say() {
    
    print('say');
  }
}

mixin Eat {
    
  eat() {
    
    print('eat');
  }
}

mixin Walk {
    
  walk() {
    
    print('walk');
  }
}

mixin Code {
    
  code() {
    
    print('key');
  }
}

class Dog with Eat, Walk{
    }
class Man extends Person with Eat, Walk, Code{
    }

We defined several mixin, And then through with Keywords combine them into different classes . There is one caveat : If more than one mixin There is a method with the same name in ,with when , The last one will be used by default mixin Of ,mixin In the method, you can use super Before keyword call mixin Or methods in a class . We only introduce mixin The most basic feature , About mixin For more detailed content, readers can baidu by themselves .

Asynchronous Support

Dart Class libraries have a lot of returns Future perhaps Stream Object function . These functions are called asynchronous functions : They only return after setting up some time-consuming operations , Such as IO operation . Instead of waiting for the operation to complete .

async and await Keywords support asynchronous programming , Allows you to write asynchronous code much like synchronous code .

1. Future

Future And JavaScript Medium Promise Very similar , Represents the final completion of an asynchronous operation ( Or failure ) And the expression of its result value . Simply speaking , It's used to handle asynchronous operations , If the asynchronous processing is successful, the successful operation will be executed , If the asynchronous processing fails, catch the error or stop the subsequent operation . One Future Only one result , Or success , Or failure .

Because of its many functions , Here we only introduce its common API And characteristics . also , please remember ,Future All of the API The return value of is still a Future object , So it's very convenient to chain call .

(1)Future.then
For the convenience of the example , In this case we use Future.delayed Created a delayed task ( The actual scene would be a real time-consuming task , For example, a network request ), namely 2 The result string is returned in seconds "hi world!", And then we were in then Receive asynchronous results and print the results , The code is as follows :

Future.delayed(Duration(seconds: 2),(){
    
   return "hi world!";
}).then((data){
    
   print(data);
});

(2)Future.catchError
If an error occurs in an asynchronous task , We can do it in catchError Error caught in , Let's change the above example to :

Future.delayed(Duration(seconds: 2),(){
    
   //return "hi world!";
   throw AssertionError("Error");  
}).then((data){
    
   // Successful execution will come here  
   print("success");
}).catchError((e){
    
   // Execution failure will come here  
   print(e);
});

In this example , We threw an exception in an asynchronous task ,then The callback function for will not be executed , In its place catchError The callback function will be called ; however , It's not just catchError Callback to catch errors ,then Method also has an optional parameter onError, We can also use it to catch exceptions :

Future.delayed(Duration(seconds: 2), () {
    
	//return "hi world!";
	throw AssertionError("Error");
}).then((data) {
    
	print("success");
}, onError: (e) {
    
	print(e);
});

(3)Future.whenComplete
Sometimes , We will come across a scenario where we need to do something no matter whether the asynchronous task is successful or failed , For example, the load dialog box pops up before the network request , Close the dialog at the end of the request . This scenario , There are two ways , The first is in the then or catch Close the dialog box in , The second is to use Future Of whenComplete Callback , Let's change the above example :

Future.delayed(Duration(seconds: 2),(){
    
   //return "hi world!";
   throw AssertionError("Error");
}).then((data){
    
   // Successful execution will come here  
   print(data);
}).catchError((e){
    
   // Execution failure will come here  
   print(e);
}).whenComplete((){
    
   // Success or failure will come here 
});

(4)Future.wait
Sometimes , We need to wait for multiple asynchronous tasks to be executed before doing some operations , For example, we have an interface , You need to get data from two network interfaces first , After success , We need to process the data of the two interfaces before displaying it to UI On the interface , What to do ? The answer is Future.wait, It accepts a Future Array parameters , Only all in the array Future After all of them are successfully executed , Will trigger then The successful callback of , As long as there is one Future Execution failure , An error callback is triggered . below , We simulate Future.delayed To simulate two asynchronous tasks of data acquisition , When both asynchronous tasks succeed , Print the results of two asynchronous tasks , The code is as follows :

Future.wait([
  // 2 Seconds to return results  
  Future.delayed(Duration(seconds: 2), () {
    
    return "hello";
  }),
  // 4 Seconds to return results  
  Future.delayed(Duration(seconds: 4), () {
    
    return " world";
  })
]).then((results){
    
  print(results[0]+results[1]);
}).catchError((e){
    
  print(e);
});

Execute the code above ,4 In seconds, you'll see in the console “hello world”.

2. async/await

Dart Medium async/await and JavaScript Medium async/await The function is the same : Asynchronous task serialization . If you already know JavaScript Medium async/await Usage of , You can skip this section .

(1) Back to hell (Callback Hell)
If there's a lot of asynchronous logic in the code , And when a large number of asynchronous tasks depend on the results of other asynchronous tasks , It's bound to happen Future.then Callback in the set of callbacks . for instance , For example, there is a requirement scenario where users log in first , After successful login, you will get the user ID, And then through the user ID, Then ask for the user's personal information , After obtaining the user's personal information , For ease of use , We need to cache it on the local file system , The code is as follows :

// First, define each asynchronous task separately 
Future<String> login(String userName, String pwd){
    
	...
    // The user login 
};
Future<String> getUserInfo(String id){
    
	...
    // Get user information  
};
Future saveUserInfo(String userInfo){
    
	...
	//  Save user information  
}; 

Next , Perform the entire task flow :

login("alice","******").then((id){
    
 // Log in successfully and pass ,id Get user information  
 getUserInfo(id).then((userInfo){
    
    // Get user information and save  
    saveUserInfo(userInfo).then((){
    
       // Save user information , Next, do something else 
        ...
    });
  });
})

You can feel it , If there are a lot of asynchronous dependencies in the business logic , There will be the above situation that callback is nested in callback , Too much nesting will lead to a decrease in code readability and an increase in error rate , And it's very difficult to maintain , The question is figuratively called Back to hell (Callback Hell). Back to hell before JavaScript It's very prominent , It's also JavaScript Make complaints about the most points , But as the ECMAScript After the standard is released , This problem has been solved very well , And the two great artifact to solve hell is ECMAScript6 Introduced Promise, as well as ECMAScript7 Introduced in async/await. And in the Dart It's almost completely translational in JavaScript The two of them :Future amount to Promise, and async/await I didn't even change my name . Let's take a look at passing Future and async/await How to eliminate the nesting problem in the above example .

(2) Eliminate callback hell
There are two main ways to eliminate callback hell :

One 、 Use Future eliminate Callback Hell

login("alice","******").then((id){
    
  	return getUserInfo(id);
}).then((userInfo){
    
    return saveUserInfo(userInfo);
}).then((e){
    
   // Perform the next operation  
}).catchError((e){
    
  // Error handling  
  print(e);
});

As mentioned above , “Future All of the API The return value of is still a Future object , So it's very convenient to chain call ” , If in then It's a Future Words , The future Will execute , At the end of execution, the following then Callback , So down in turn , It avoids layers of nesting .

Two 、 Use async/await eliminate callback hell

adopt Future Call back and return Future Although it can avoid layer by layer nesting , But there is still a layer of callback , Is there a way to perform asynchronous tasks like writing synchronous code without using callbacks ? The answer is yes , This is about using async/await 了 , Let's take a look at the code first , And then explain , The code is as follows :

task() async {
    
   try{
    
    String id = await login("alice","******");
    String userInfo = await getUserInfo(id);
    await saveUserInfo(userInfo);
    // Perform the next operation  
   } catch(e){
    
    // Error handling  
    print(e);   
   }  
}

async Used to indicate that a function is asynchronous , The defined function will return a Future object , have access to then Method to add a callback function .

await There's a Future, Indicates waiting for the asynchronous task to complete , Only after asynchronous completion can we go down ;await Must appear in async Internal function .

You can see , We go through async/await An asynchronous flow is represented by synchronous code .

Actually , Whether in the JavaScript still Dart in ,async/await It's just a grammar candy , The compiler or interpreter will eventually turn it into a Promise(Future) The call chain of .

Stream

Stream It is also used to receive asynchronous event data , and Future The difference is , It can receive the results of multiple asynchronous operations ( Success or failure ). in other words , When performing asynchronous tasks , You can pass result data or error exceptions by triggering success or failure events multiple times . Stream It is often used in asynchronous task scenarios that can read data multiple times , Such as Internet content download 、 Document reading and writing, etc . for instance :

Stream.fromFutures([
  // 1 Seconds to return results 
  Future.delayed(Duration(seconds: 1), () {
    
    return "hello 1";
  }),
  //  Throw an exception 
  Future.delayed(Duration(seconds: 2),(){
    
    throw AssertionError("Error");
  }),
  // 3 Seconds to return results 
  Future.delayed(Duration(seconds: 3), () {
    
    return "hello 3";
  })
]).listen((data){
    
   print(data);
}, onError: (e){
    
   print(e.message);
},onDone: (){
    

});

The above code in turn will output :

I/flutter (17666): hello 1
I/flutter (17666): Error
I/flutter (17666): hello 3

The code is simple , I won't go into that .

Thinking questions : since Stream Can receive multiple events , Can it work Stream To implement a subscriber mode event bus ?

Dart and Java And JavaScript contrast

The reason will be Dart And Java and JavaScript contrast , Because , They are typical representatives of strongly typed languages and weakly typed languages respectively , also Dart A lot of places in grammar are also used for reference Java and JavaScript.

1. Dart vs Java

Objectively speaking ,Dart Grammatically, it's better than Java More expressive ; stay VM level ,Dart VM In memory recovery and throughput are repeatedly optimized .
It is worth noting that Dart stay Flutter It is already possible to GC Achieve 10ms within , therefore Dart and Java comparison , The decisive factor won't be performance .
And at the grammatical level ,Dart than Java More expressive , most important of all Dart Support for functional programming is much better than Java

2. Dart vs JavaScript

JavaScript The weak type of has been caught short , therefore TypeScript Even Facebook Of Flow There is a market .
JavaScript It is undoubtedly the best scripting language for dynamic support , For example JavaScript in , You can dynamically extend attributes to any object at any time , For Mastery JavaScript From the top of the world , This is undoubtedly a sharp sword .
however , Everything has two sides ,JavaScript The powerful dynamic feature is also a double-edged sword , You can often hear another voice , Think JavaScript It's a terrible dynamic , Being too flexible makes the code hard to anticipate , There is no way to limit changes that are not expected .
After all, some people are always worried about the code they or others write , They want to be able to make the code controllable , And expect to have a static type checking system to help reduce errors .
Because of this , stay Flutter in ,Dart Almost abandoned the dynamic nature of scripting languages , If reflection is not supported 、 It also does not support dynamic function creation . also Dart from 2.0 Start to force type checking (Strong Mode), The original inspection mode (checked mode) And optional types (optional type) Will fade out , So in terms of type security ,Dart and TypeScript、CoffeeScript It's almost the same , So from the dynamic point of view alone ,Dart There's no obvious advantage , But taken together ,Dart It can be used for server script 、APP Development 、Web Development , That's an advantage !

Notes from Flutter Chinese net

原网站

版权声明
本文为[Humanoid bug maker 9527]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/200/202207172242364989.html