文章目录
Dart(一)库和可见性,常用集合简介
库和可见性
import
和 library
指令可以用来创建一个模块化的,可共享的代码库。
库不仅提供了 API ,而且对代码起到了封装的作用: 以下划线 (_) 开头的标识符仅在库内可见。
每个 Dart 应用程序都是一个库 ,虽然没有使用 library
指令。
使用库
//1
import 'dart:core';
//2
import 'package:test/test.dart';
//3
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
//4
import 'package:lib1/lib1.dart' show foo;
import 'package:lib2/lib2.dart' hide foo;
//5
import 'package:greetings/hello.dart' deferred as hello;
1、命名空间导入
通过
import
指定一个库命名空间中的内如如何在另一个库中使用。
2、系统路径或包管理器导入
import
参数只需要一个指向库的 URI。 对于内置库,URI 拥有自己特殊的dart:
方案。 对于其他的库,使用系统文件路径或者package:
方案 。package:
方案指定由包管理器(如 pub 工具)提供的库。
Although the lib graphic shows
lib/bar/b.dart
using a relative import (import '../foo/a.dart'
), it could instead use thepackage:
directive (import 'package:my_package/foo/a.dart'
).
3、指定库前缀
如果导入两个存在冲突标识符的库, 则可以为这两个库,或者其中一个指定前缀。
4、导入库的一部分
如果你只使用库的一部分功能,则可以选择需要导入的 内容。
5、延迟加载库
Deferred loading (也称之为 lazy loading) 可以让应用在需要的时候再加载库。 下面是一些使用延迟加载库的场景:
- 减少 APP 的启动时间。
- 执行 A/B 测试,例如 尝试各种算法的 不同实现。
- 加载很少使用的功能,例如可选的屏幕和对话框。
要延迟加载一个库,需要先使用
deferred as
来导入,当需要使用的时候,使用库标识符调用
loadLibrary()
函数来加载库:Future greet() async { await hello.loadLibrary(); hello.printGreeting(); }
在一个库上你可以多次调用
loadLibrary()
函数。但是该库只是载入一次。使用延迟加载库的时候,请注意以下问题:
- 延迟加载库的常量在导入的时候是不可用的。 只有当库加载完毕的时候,库中常量才可以使用。
- 在导入文件的时候无法使用延迟库中的类型。 如果你需要使用类型,则考虑把接口类型移动到另外一个库中, 让两个库都分别导入这个接口库。
- Dart 隐含的把
loadLibrary()
函数导入到使用deferred as *的命名空间*
中。loadLibrary()
方法返回一个 Future。
实现库
有关如何实现库包的建议,请参考 Create Library Packages
-
library
指定一个命名空间
库的拆分
有的时候一个库可能太大,不能方便的保存在一个文件当中。Dart允许我们把一个库拆分成一个或者多个较小的part组件。或者我们想让某一些库共享它们的私有对象的时候,我们需要使用part。
-
part、part of
dart中,通过使用part、part of、library来实现拆分库,这样,就可以将一个庞大的库拆分成各种小库,只要引用主库即可,用法如下:
导出库
-
export
当bot_toast库被页面A引用时,bot_toast库就会通过export将如下红色框选的dart库到处到使用bot_toast库的页面A中,相当于页面A自动导入了如下红色框选文件库。
区别
part与import有什么区别?
可见性: 如果说在A库中import了B库,A库对B库是不可见的,也就是说B库是无法知道A库的存在的。而part的作用是将一个库拆分成较小的组件。两个或多个part共同构成了一个库,它们彼此之间是知道互相的存在的。
作用域:import不会完全共享作用域,而part之间是完全共享的。如果说在A库中import了B库,B库import了C库,A库是没有办法直接使用C库的对象的。而B,C若是A的part,那么三者共享所有对象。并且包含所有导入。
常用集合(List、Set、Map)简介
-
内置类型,集合和其他核心功能。 该库会被自动导入到所有的 Dart 程序。
-
dart:core
隶属于sky_engine
-
List、Set、Map
Array 就是 List 对象, 通常称之为 List 。
Set 是一个元素唯一且无序的集合。
Map 是用来关联 keys 和 values 的对象。 keys 和 values 可以是任何类型的对象。在一个 Map 对象中一个 key 只能出现一次。 但是 value 可以出现多次。
初始化
通过直接赋值方式创建
///List
var list = [];
var list1 = [1, 2, 3];
var constantList = const [1, 2, 3];
///Set
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
var names = <String>{};
// Set<String> names = {}; // 这样也是可以的。
///Map
var gifts = {
// Key: Value
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};
var nobleGases = {
2: 'helium',
10: 'neon',
18: 'argon',
};
///?
var arg = {};
是 Set 还是 Map ?
Map 字面量语法同 Set 字面量语法非常相似。 因为先有的 Map 字母量语法,所以 {}
默认是 Map
类型。 如果忘记在 {}
上注释类型或赋值到一个未声明类型的变量上, 那么 Dart 会创建一个类型为 Map<dynamic, dynamic>
的对象。
通过构造函数方式创建
external关键字
看源码的时侯经常可以看到,
- Object类里有很多方法都是用external声明,并且这些方法没有具体实现;
- class不是abstract class,为什么方法可以不用实现呢?
这就是external的作用,external修饰的函数具有一种实现函数声明和实现体分离的特性。
简单来说,*external只声明方法,声明的方法需要由外部去实现*,通常是由底层sdk根据不同平台(vm、web等)实现;若外部没实现,则会返回null;
以List为例,对应的是**
sdk/sdk_nnbd/lib/_internal/vm/lib/array_patch.dart
**
Iterable
List,Set,Map
共同相关的抽象类Iterable
,都是通过Iterable
完成遍历及其他操作。
/// List
abstract class List<E> implements EfficientLengthIterable<E> {
}
/// Set
abstract class Set<E> extends EfficientLengthIterable<E> {
}
/**
* Marker interface for [Iterable] subclasses that have an efficient
* [length] implementation.
*/
abstract class EfficientLengthIterable<T> extends Iterable<T> {
const EfficientLengthIterable();
/**
* Returns the number of elements in the iterable.
*
* This is an efficient operation that doesn't require iterating through
* the elements.
*/
int get length;
}
///
/// Map
abstract class Map<K, V> {
Iterable<MapEntry<K, V>> get entries;
Iterable<K> get keys;
Iterable<V> get values;
}
/// Iterable
abstract class Iterable<E> {
/// Returns a new `Iterator` that allows iterating the elements of this
/// `Iterable`.
///
/// Iterable classes may specify the iteration order of their elements
/// (for example [List] always iterate in index order),
/// or they may leave it unspecified (for example a hash-based [Set]
/// may iterate in any order).
///
/// Each time `iterator` is read, it returns a new iterator,
/// which can be used to iterate through all the elements again.
/// The iterators of the same iterable can be stepped through independently,
/// but should return the same elements in the same order,
/// as long as the underlying collection isn't changed.
///
/// Modifying the collection may cause new iterators to produce
/// different elements, and may change the order of existing elements.
/// A [List] specifies its iteration order precisely,
/// so modifying the list changes the iteration order predictably.
/// A hash-based [Set] may change its iteration order completely
/// when adding a new element to the set.
///
/// Modifying the underlying collection after creating the new iterator
/// may cause an error the next time [Iterator.moveNext] is called
/// on that iterator.
/// Any *modifiable* iterable class should specify which operations will
/// break iteration.
Iterator<E> get iterator;
/// Returns a new lazy [Iterable] with elements that are created by
/// calling `f` on each element of this `Iterable` in iteration order.
///
/// This method returns a view of the mapped elements. As long as the
/// returned [Iterable] is not iterated over, the supplied function [f] will
/// not be invoked. The transformed elements will not be cached. Iterating
/// multiple times over the returned [Iterable] will invoke the supplied
/// function [f] multiple times on the same element.
///
/// Methods on the returned iterable are allowed to omit calling `f`
/// on any element where the result isn't needed.
/// For example, [elementAt] may call `f` only once.
Iterable<T> map<T>(T f(E e)) => MappedIterable<E, T>(this, f);
/// Returns a new lazy [Iterable] with all elements that satisfy the
/// predicate [test].
///
/// The matching elements have the same order in the returned iterable
/// as they have in [iterator].
///
/// This method returns a view of the mapped elements.
/// As long as the returned [Iterable] is not iterated over,
/// the supplied function [test] will not be invoked.
/// Iterating will not cache results, and thus iterating multiple times over
/// the returned [Iterable] may invoke the supplied
/// function [test] multiple times on the same element.
Iterable<E> where(bool test(E element)) => WhereIterable<E>(this, test);
/// Returns a new lazy [Iterable] with all elements that have type [T].
///
/// The matching elements have the same order in the returned iterable
/// as they have in [iterator].
///
/// This method returns a view of the mapped elements.
/// Iterating will not cache results, and thus iterating multiple times over
/// the returned [Iterable] may yield different results,
/// if the underlying elements change between iterations.
Iterable<T> whereType<T>() => WhereTypeIterable<T>(this);
/// Expands each element of this [Iterable] into zero or more elements.
///
/// The resulting Iterable runs through the elements returned
/// by [f] for each element of this, in iteration order.
///
/// The returned [Iterable] is lazy, and calls [f] for each element
/// of this every time it's iterated.
///
/// Example:
/// ```dart
/// var pairs = [[1, 2], [3, 4]];
/// var flattened = pairs.expand((pair) => pair).toList();
/// print(flattened); // => [1, 2, 3, 4];
///
/// var input = [1, 2, 3];
/// var duplicated = input.expand((i) => [i, i]).toList();
/// print(duplicated); // => [1, 1, 2, 2, 3, 3]
/// ```
Iterable<T> expand<T>(Iterable<T> f(E element)) =>
ExpandIterable<E, T>(this, f);
/// Whether the collection contains an element equal to [element].
///
/// This operation will check each element in order for being equal to
/// [element], unless it has a more efficient way to find an element
/// equal to [element].
///
/// The equality used to determine whether [element] is equal to an element of
/// the iterable defaults to the [Object.==] of the element.
///
/// Some types of iterable may have a different equality used for its elements.
/// For example, a [Set] may have a custom equality
/// (see [Set.identity]) that its `contains` uses.
/// Likewise the `Iterable` returned by a [Map.keys] call
/// should use the same equality that the `Map` uses for keys.
bool contains(Object? element) {
for (E e in this) {
if (e == element) return true;
}
return false;
}
/// Applies the function [f] to each element of this collection in iteration
/// order.
void forEach(void f(E element)) {
for (E element in this) f(element);
}
/// Reduces a collection to a single value by iteratively combining elements
/// of the collection using the provided function.
///
/// The iterable must have at least one element.
/// If it has only one element, that element is returned.
///
/// Otherwise this method starts with the first element from the iterator,
/// and then combines it with the remaining elements in iteration order,
/// as if by:
/// ```dart
/// E value = iterable.first;
/// iterable.skip(1).forEach((element) {
/// value = combine(value, element);
/// });
/// return value;
/// ```
/// Example of calculating the sum of an iterable:
/// ```dart
/// iterable.reduce((value, element) => value + element);
/// ```
E reduce(E combine(E value, E element)) {
Iterator<E> iterator = this.iterator;
if (!iterator.moveNext()) {
throw IterableElementError.noElement();
}
E value = iterator.current;
while (iterator.moveNext()) {
value = combine(value, iterator.current);
}
return value;
}
/// Reduces a collection to a single value by iteratively combining each
/// element of the collection with an existing value
///
/// Uses [initialValue] as the initial value,
/// then iterates through the elements and updates the value with
/// each element using the [combine] function, as if by:
/// ```dart
/// var value = initialValue;
/// for (E element in this) {
/// value = combine(value, element);
/// }
/// return value;
/// ```
/// Example of calculating the sum of an iterable:
/// ```dart
/// iterable.fold(0, (prev, element) => prev + element);
/// ```
T fold<T>(T initialValue, T combine(T previousValue, E element)) {
var value = initialValue;
for (E element in this) value = combine(value, element);
return value;
}
/// Checks whether every element of this iterable satisfies [test].
///
/// Checks every element in iteration order, and returns `false` if
/// any of them make [test] return `false`, otherwise returns `true`.
bool every(bool test(E element)) {
for (E element in this) {
if (!test(element)) return false;
}
return true;
}
/// Converts each element to a [String] and concatenates the strings.
///
/// Iterates through elements of this iterable,
/// converts each one to a [String] by calling [Object.toString],
/// and then concatenates the strings, with the
/// [separator] string interleaved between the elements.
String join([String separator = ""]) {
Iterator<E> iterator = this.iterator;
if (!iterator.moveNext()) return "";
StringBuffer buffer = StringBuffer();
if (separator == null || separator == "") {
do {
buffer.write(iterator.current.toString());
} while (iterator.moveNext());
} else {
buffer.write(iterator.current.toString());
while (iterator.moveNext()) {
buffer.write(separator);
buffer.write(iterator.current.toString());
}
}
return buffer.toString();
}
/// Checks whether any element of this iterable satisfies [test].
///
/// Checks every element in iteration order, and returns `true` if
/// any of them make [test] return `true`, otherwise returns false.
bool any(bool test(E element)) {
for (E element in this) {
if (test(element)) return true;
}
return false;
}
/// Creates a [List] containing the elements of this [Iterable].
///
/// The elements are in iteration order.
/// The list is fixed-length if [growable] is false.
List<E> toList({bool growable = true}) {
return List<E>.of(this, growable: growable);
}
/// Creates a [Set] containing the same elements as this iterable.
///
/// The set may contain fewer elements than the iterable,
/// if the iterable contains an element more than once,
/// or it contains one or more elements that are equal.
/// The order of the elements in the set is not guaranteed to be the same
/// as for the iterable.
Set<E> toSet() => Set<E>.of(this);
/// Returns the number of elements in [this].
///
/// Counting all elements may involve iterating through all elements and can
/// therefore be slow.
/// Some iterables have a more efficient way to find the number of elements.
int get length {
assert(this is! EfficientLengthIterable);
int count = 0;
Iterator it = iterator;
while (it.moveNext()) {
count++;
}
return count;
}
/// Returns `true` if there are no elements in this collection.
///
/// May be computed by checking if `iterator.moveNext()` returns `false`.
bool get isEmpty => !iterator.moveNext();
/// Returns true if there is at least one element in this collection.
///
/// May be computed by checking if `iterator.moveNext()` returns `true`.
bool get isNotEmpty => !isEmpty;
/// Returns a lazy iterable of the [count] first elements of this iterable.
///
/// The returned `Iterable` may contain fewer than `count` elements, if `this`
/// contains fewer than `count` elements.
///
/// The elements can be computed by stepping through [iterator] until [count]
/// elements have been seen.
///
/// The `count` must not be negative.
Iterable<E> take(int count) {
return TakeIterable<E>(this, count);
}
/// Returns a lazy iterable of the leading elements satisfying [test].
///
/// The filtering happens lazily. Every new iterator of the returned
/// iterable starts iterating over the elements of `this`.
///
/// The elements can be computed by stepping through [iterator] until an
/// element is found where `test(element)` is false. At that point,
/// the returned iterable stops (its `moveNext()` returns false).
Iterable<E> takeWhile(bool test(E value)) {
return TakeWhileIterable<E>(this, test);
}
/// Returns an [Iterable] that provides all but the first [count] elements.
///
/// When the returned iterable is iterated, it starts iterating over `this`,
/// first skipping past the initial [count] elements.
/// If `this` has fewer than `count` elements, then the resulting Iterable is
/// empty.
/// After that, the remaining elements are iterated in the same order as
/// in this iterable.
///
/// Some iterables may be able to find later elements without first iterating
/// through earlier elements, for example when iterating a [List].
/// Such iterables are allowed to ignore the initial skipped elements.
///
/// The [count] must not be negative.
Iterable<E> skip(int count) {
return SkipIterable<E>(this, count);
}
/// Returns an `Iterable` that skips leading elements while [test] is satisfied.
///
/// The filtering happens lazily. Every new [Iterator] of the returned
/// iterable iterates over all elements of `this`.
///
/// The returned iterable provides elements by iterating this iterable,
/// but skipping over all initial elements where `test(element)` returns
/// true. If all elements satisfy `test` the resulting iterable is empty,
/// otherwise it iterates the remaining elements in their original order,
/// starting with the first element for which `test(element)` returns `false`.
Iterable<E> skipWhile(bool test(E value)) {
return SkipWhileIterable<E>(this, test);
}
/// Returns the first element.
///
/// Throws a [StateError] if `this` is empty.
/// Otherwise returns the first element in the iteration order,
/// equivalent to `this.elementAt(0)`.
E get first {
Iterator<E> it = iterator;
if (!it.moveNext()) {
throw IterableElementError.noElement();
}
return it.current;
}
/// Returns the last element.
///
/// Throws a [StateError] if `this` is empty.
/// Otherwise may iterate through the elements and returns the last one
/// seen.
/// Some iterables may have more efficient ways to find the last element
/// (for example a list can directly access the last element,
/// without iterating through the previous ones).
E get last {
Iterator<E> it = iterator;
if (!it.moveNext()) {
throw IterableElementError.noElement();
}
E result;
do {
result = it.current;
} while (it.moveNext());
return result;
}
/// Checks that this iterable has only one element, and returns that element.
///
/// Throws a [StateError] if `this` is empty or has more than one element.
E get single {
Iterator<E> it = iterator;
if (!it.moveNext()) throw IterableElementError.noElement();
E result = it.current;
if (it.moveNext()) throw IterableElementError.tooMany();
return result;
}
/// Returns the first element that satisfies the given predicate [test].
///
/// Iterates through elements and returns the first to satisfy [test].
///
/// If no element satisfies [test], the result of invoking the [orElse]
/// function is returned.
/// If [orElse] is omitted, it defaults to throwing a [StateError].
E firstWhere(bool test(E element), {E orElse()?}) {
for (E element in this) {
if (test(element)) return element;
}
if (orElse != null) return orElse();
throw IterableElementError.noElement();
}
/// Returns the last element that satisfies the given predicate [test].
///
/// An iterable that can access its elements directly may check its
/// elements in any order (for example a list starts by checking the
/// last element and then moves towards the start of the list).
/// The default implementation iterates elements in iteration order,
/// checks `test(element)` for each,
/// and finally returns that last one that matched.
///
/// If no element satisfies [test], the result of invoking the [orElse]
/// function is returned.
/// If [orElse] is omitted, it defaults to throwing a [StateError].
E lastWhere(bool test(E element), {E orElse()?}) {
late E result;
bool foundMatching = false;
for (E element in this) {
if (test(element)) {
result = element;
foundMatching = true;
}
}
if (foundMatching) return result;
if (orElse != null) return orElse();
throw IterableElementError.noElement();
}
/// Returns the single element that satisfies [test].
///
/// Checks elements to see if `test(element)` returns true.
/// If exactly one element satisfies [test], that element is returned.
/// If more than one matching element is found, throws [StateError].
/// If no matching element is found, returns the result of [orElse].
/// If [orElse] is omitted, it defaults to throwing a [StateError].
E singleWhere(bool test(E element), {E orElse()?}) {
late E result;
bool foundMatching = false;
for (E element in this) {
if (test(element)) {
if (foundMatching) {
throw IterableElementError.tooMany();
}
result = element;
foundMatching = true;
}
}
if (foundMatching) return result;
if (orElse != null) return orElse();
throw IterableElementError.noElement();
}
/// Returns the [index]th element.
///
/// The [index] must be non-negative and less than [length].
/// Index zero represents the first element (so `iterable.elementAt(0)` is
/// equivalent to `iterable.first`).
///
/// May iterate through the elements in iteration order, ignoring the
/// first [index] elements and then returning the next.
/// Some iterables may have a more efficient way to find the element.
E elementAt(int index) {
RangeError.checkNotNegative(index, "index");
int elementIndex = 0;
for (E element in this) {
if (index == elementIndex) return element;
elementIndex++;
}
throw RangeError.index(index, this, "index", null, elementIndex);
}
/// Returns a string representation of (some of) the elements of `this`.
///
/// Elements are represented by their own `toString` results.
///
/// The default representation always contains the first three elements.
/// If there are less than a hundred elements in the iterable, it also
/// contains the last two elements.
///
/// If the resulting string isn't above 80 characters, more elements are
/// included from the start of the iterable.
///
/// The conversion may omit calling `toString` on some elements if they
/// are known to not occur in the output, and it may stop iterating after
/// a hundred elements.
String toString() => IterableBase.iterableToShortString(this, '(', ')');
}