current position:Home>Eight skills of dart development

Eight skills of dart development

2021-08-27 07:48:57 Breeze_ Luckly

This is my participation 8 The fourth of the yuegengwen challenge 20 God , Check out the activity details :8 Yuegengwen challenge . For the Nuggets August is more challenging , Specially bring you what I summarized in the development dart Related skills , This is a # dart Developed 7 Tips The second season of

8. Use named constructors and initialization lists to get more ergonomic API.

Suppose you want to declare a class that represents a temperature value .

You can make your class API Explicitly support Two Two named constructors, Celsius and Fahrenheit :

class Temperature {
  Temperature.celsius(this.celsius);
  Temperature.fahrenheit(double fahrenheit)
    : celsius = (fahrenheit - 32) / 1.8;
  double celsius;
}
 Copy code 

This class only needs one Storage Variable to represent temperature , And use the initialization list to convert Fahrenheit temperature to Celsius temperature .

This means that you can declare the temperature value like this :

final temp1 = Temperature.celsius(30);
final temp2 = Temperature.fahrenheit(90);
 Copy code 

9. getter and setter

stay Temperature In the class above ,celsius Declared as a storage variable .

But users may prefer to be in Fahrenheit obtain or Set up temperature .

This can be used getter and setter Easy to finish , They allow you to define calculated variables . This is an updated course :

class Temperature {
  Temperature.celsius(this.celsius);
  Temperature.fahrenheit(double fahrenheit)
    : celsius = (fahrenheit - 32) / 1.8;
  double celsius;
  double get fahrenheit
    => celsius * 1.8 + 32;
  set fahrenheit(double fahrenheit)
    => celsius = (fahrenheit - 32) / 1.8;
}
 Copy code 

This makes it easy to get or set the temperature using degrees Fahrenheit or Celsius :

final temp1 = Temperature.celsius(30);
print(temp1.fahrenheit);
final temp2 = Temperature.fahrenheit(90);
temp2.celsius = 28;
 Copy code 

The bottom line : Use a named constructor 、getter and setter To improve the design of classes .

10. Use underscores on unused function arguments

stay Flutter in , We often use widgets with function parameters . A common example is ListView.builder

class MyListView extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemBuilder: (context, index) => ListTile(
        title: Text('all the same'),
      ),
      itemCount: 10,
    );
  }
}
 Copy code 

under these circumstances , We don't use (context, index) Parameters of itemBuilder. So we can replace them with underscores :

ListView.builder(
  itemBuilder: (_, __) => ListTile(
    title: Text('all the same'),
  ),
  itemCount: 10,
)
 Copy code 

Be careful : These two parameters are different (_ and __), Because they are Individual identifiers .

11. Need a class that can only be instantiated once ( Another example )? Use static instance variables with private constructors .

The most important feature of a singleton is that there can only be One its example . This is useful for modeling file systems and so on .

// file_system.dart
class FileSystem {
  FileSystem._();
  static final instance = FileSystem._();
}
 Copy code 

To be in Dart Create a singleton in , You can declare a named constructor and use _ The syntax makes it private .

then , You can use it to create a static final instance of the class .

therefore , Any code in other files can only pass through instance Variable to access this class :

// some_other_file.dart
final fs = FileSystem.instance;
// do something with fs
 Copy code 

Be careful : If you are not careful ,final May cause many problems . Before using them , Make sure you understand their shortcomings .

12. Need to collect unique set? Use collections instead of lists .

Dart The most commonly used collection type in is List.

But the list can have duplicate items , Sometimes it's not what we want :

const citiesList = [
  'London',
  'Paris',
  'Rome',
  'London',
];
 Copy code 

We can Set Use... When you need a unique set of values a ( Please note that Use final):

// set is final, compiles
final citiesSet = {
  'London',
  'Paris',
  'Rome',
  'London', // Two elements in a set literal shouldn't be equal
};
 Copy code 

The above code generates a warning , because London Included twice . If we try to be right constset Do the same thing , Will receive an error and our code will not compile :

// set is const, doesn't compile
const citiesSet = {
  'London',
  'Paris',
  'Rome',
  'London', // Two elements in a constant set literal can't be equal
};
 Copy code 

When we work with Taiwan , We can get useful API, Such as union,difference and intersection

citiesSet.union({'Delhi', 'Moscow'});
citiesSet.difference({'London', 'Madrid'});
citiesSet.intersection({'London', 'Berlin'});
 Copy code 

The bottom line : When you create a collection , Ask yourself if you want its project to be unique , And consider using a collection .

13. How to use try、on、catch、rethrow、finally

try also catch In use based on Future Of API Very ideal , If something goes wrong , these API Could throw an exception .

This is a complete example , Shows how to make the most of them :

Future<void> printWeather() async {
  try {
    final api = WeatherApiClient();
    final weather = await api.getWeather('London');
    print(weather);
  } on SocketException catch (_) {
    print('Could not fetch data. Check your connection.');
  } on WeatherApiException catch (e) {
    print(e.message);
  } catch (e, st) {
    print('Error: $e\nStack trace: $st');
    rethrow;
  } finally {
    print('Done');
  }
}
 Copy code 

Some precautions :

  • You can add multiple on Clause to handle different types of exceptions .
  • You can use fallback catch Clause to handle all exceptions that do not match any of the above types .
  • You can use rethrow Statement throws the current exception up the call stack , Keep stack trace at the same time .
  • You can use finally stay Future Run some code when you're done , Whether it succeeds or fails .

If you are using or designing something based on Future Of API, Be sure to handle exceptions as needed .

14. common Future Constructors

DartFuture Class with some convenient factory constructors :Future.delayed,Future.value and Future.error.

We can Future.delayed Used to create a Future Waiting for a certain delay . The second parameter is a ( Optional ) Anonymous functions , You can use it to complete a value or throw an error :

await Future.delayed(Duration(seconds: 2), () => 'Latte');
 Copy code 

But sometimes we want to create a Future Immediate :

await Future.value('Cappuccino');
await Future.error(Exception('Out of milk'));
 Copy code 

We can use Future.value A value to successfully complete , perhaps Future.error Complete with an error .

You can use these constructors to emulate data from Future Of API Response . This is useful when writing mock classes in your test code .

15. Universal flow constructor

Stream Class also comes with some convenient constructors . Here are the most common :

Stream.fromIterable([1, 2, 3]);
Stream.value(10);
Stream.empty();
Stream.error(Exception('something went wrong'));
Stream.fromFuture(Future.delayed(Duration(seconds: 1), () => 42));
Stream.periodic(Duration(seconds: 1), (index) => index);
 Copy code 
  • Used to select from the list of values Stream.fromIterable Create a Stream.
  • Use Stream.value, If you have only one value .
  • be used for Stream.empty Create an empty stream .
  • be used for Stream.error Create a stream with error values .
  • be used for Stream.fromFuture Create a stream that contains only one value , This value will be available at future completion .
  • be used for Stream.periodic Create a periodic flow of events . You can use a Appoint Duration Is the time interval between events , And specify an anonymous function to generate each value given its index in the stream .

16. Synchronous and asynchronous generators

stay Dart in , We can Sync The generator is defined as a return Function of Iterable

Iterable<int> count(int n) sync* {
  for (var i = 1; i <= n; i++) {
    yield i;
  }
}
 Copy code 

This use sync* grammar . Inside the function , We can “ Generate ” or yield Multiple values . These will Iterable Returns... When the function is complete .


On the other hand , asynchronous The generator is a return a Function of Stream

Stream<int> countStream(int n) async* {
  for (var i = 1; i <= n; i++) {
    yield i;
  }
}
 Copy code 

This uses this async* grammar . Inside the function , We can yield Take the same value as in the case of synchronization .

But if we want to , We can use await be based on Future Of API, Because this is a asynchronous generator :

Stream<int> countStream(int n) async* {
  for (var i = 1; i <= n; i++) {
    // dummy delay - this could be a network request
    await Future.delayed(Duration(seconds: 1));
    yield i;
  }
}
 Copy code 

copyright notice
author[Breeze_ Luckly],Please bring the original link to reprint, thank you.
https://en.qdmana.com/2021/08/20210827074852050e.html

Random recommended