Ссылаться на:Жаркая погода Таланты/гиды/волк…
Обзор языка разработки Dart
Эта статья познакомит вас с основными функциями языка программирования Dart, начиная с переменных и операторов и заканчивая использованием классов и библиотек, при условии, что у вас уже есть опыт программирования на других языках.
Вы можете проверить поОбзор библиотеки дартсУзнайте больше о базовой библиотеке Dart. Чтобы узнать больше о возможностях языка, см.Спецификация языка программирования Dart.
Памятка:
Вы можете испытать большинство языковых функций Dart через DartPad (выучить больше),Откройте Дартпад.
Эта страница включает несколько DartPads в качестве примеров,
Если вы видите только пустые поля (и ничего), см.Страница часто задаваемых вопросов о DartPad.
Простая программа Dart
В следующем коде приложения используются многие основные функции Dart:
// Define a function.
void printInteger(int aNumber) {
print('The number is $aNumber.'); // Print to console.
}
// This is where the app starts executing.
void main() {
var number = 42; // Declare and initialize a variable.
printInteger(number); // Call a function.
}
Вот фрагменты кода, используемые в вышеупомянутом приложении, которые применимы ко всем (или почти ко всем) приложениям Dart:
// This is a comment.
// 注释。
Однострочный оператор, начинающийся с двойной косой черты, называется однострочным комментарием. Dart также поддерживает многострочные комментарии и комментарии к документации. чекПримечанияПолучите больше информации об этом.
void
Специальный тип, представляющий значение, которое никогда не будет использоваться. Похожий наmain()
и printInteger()
функция , сvoid
Объявленный тип возвращаемого значения функции не возвращает значение.
int
Другой тип данных, представляющий целое число. Некоторые другие в дартевстроенный типвключают String
,List
и bool
.
42
Представляет числовой литерал. Числовой литерал является константой времени компиляции.
print()
Удобный способ отображения вывода информации.
'...'
(или "..."
)
Представляет строковый литерал.
$variableName
(или ${expression}
)
Представляет интерполяцию строк: переменную или выражение, содержащееся в строковом литерале. чекнитьПолучите больше информации об этом.
main()
специальный инеобходимыйФункция верхнего уровня, с которой всегда начинают выполняться приложения Dart. чекосновная функцияПолучите больше информации об этом.
var
Он используется для определения переменных.Определение переменных таким образом не требует указания типа переменной.
Памятка:
Код этого сайта следуетРуководство по стилю дартссоглашение в .
важные концепции
Когда вы изучаете язык Dart, вы должны помнить о следующих моментах:
- Все ссылки на переменныеобъект, каждый объект являетсясвоего родаэкземпляр . числа, функции и
null
являются объектами. Все классы наследуются отObject своего рода. - Хотя Dart является строго типизированным языком, указывать тип при объявлении переменной необязательно, поскольку Dart может делать вывод о типах. В приведенном выше коде переменная
number
Предполагается, что типint
тип. Если вы хотите явно объявить неопределенный тип, вы можетеиспользовать специальный типdynamic
. - Dart поддерживает дженерики, такие как
List<int>
(представляющий список объектов int) илиList<dynamic>
(представляющий собой набор списков, состоящих из объектов любого типа). - Dart поддерживает функции верхнего уровня, такие как
main
методы), но также поддерживает определение функций, принадлежащих классу или объекту (т.статический и метод экземпляра). Вы также можете определить функции внутри функций (вложенный или локальная функция). - Dart поддерживает верхний уровеньПеременнаяи определить переменные (статические и переменные экземпляра), принадлежащие классу или объекту. Переменные экземпляра иногда называют полями или свойствами.
- В Dart нет ничего похожего на Java
public
,protected
иprivate
Квалификатор доступа к члену. Если идентификатор начинается с символа подчеркивания (_), это означает, что идентификатор является частным в библиотеке. можно проконсультироватьсяБиблиотеки и видимостьПолучите больше информации об этом. - идентификаторМожет начинаться с буквы или символа подчеркивания (_), за которым может следовать комбинация символов и цифр.
- Дартсвыражение и утверждениеЕсть разница, у выражений есть значения, а у утверждений нет. НапримерУсловное выражение
expression condition ? expr1 : expr2
Бесконечное значениеexpr1
илиexpr2
. и оператор перехода if-elseпо сравнению с,if-else
Операторы ветвления не имеют значения. Оператор обычно содержит одно или несколько выражений, но выражение не может содержать только один оператор. - Инструменты Dart могут отображатьпредупреждать и ОшибкаДва типа вопросов. Предупреждения указывают на возможную проблему с кодом, но не препятствуют его запуску. Ошибки делятся на ошибки времени компиляции и ошибки времени выполнения; код ошибок времени компиляции не может быть запущен; ошибки времени выполнения возникают при запуске кодааномальный.
Памятка:
Если вам интересно, почему Dart использует символы подчеркивания, а не что-то вродеpublic
или private
в качестве модификатора см.Проблема SDK № 33383.
ключевые слова
В следующей таблице перечислены ключевые слова, используемые языком Dart.
abstract 2 | else | import 2 | super |
---|---|---|---|
as 2 | enum | in | switch |
assert | export 2 | interface 2 | sync 1 |
async 1 | extends | is | this |
await 3 | extension 2 | library 2 | throw |
break | external 2 | mixin 2 | true |
case | factory 2 | new | try |
catch | false | null | typedef 2 |
class | final | on 1 | var |
const | finally | operator 2 | void |
continue | for | part 2 | while |
covariant 2 | Function 2 | rethrow | with |
default | get 2 | return | yield 3 |
deferred 2 | hide 1 | set 2 | |
do | if | show 1 | |
dynamic 2 | implements 2 | static 2 |
Этих слов следует избегать в качестве идентификаторов. Однако при необходимости в качестве идентификаторов можно использовать слова с надстрочным индексом:
- с надстрочным индексом1Ключевое словоконтекстные ключевые слова, которые имеют смысл только в определенных сценариях, их можно использовать где угодно в качестве действительных идентификаторов.
- с надстрочным индексом2Ключевое слововстроенный идентификатор, что просто упрощает преобразование кода JavaScript в код Dart. Эти ключевые слова в большинстве случаев являются допустимыми идентификаторами, но их нельзя использовать в качестве имен классов или типов или в качестве префиксов импорта.
- с надстрочным индексом3Ключевое слово для Dart 1.0 было выпущено дляАсинхронная поддержка связанная информация. нельзя указать по ключевому слову
async
,async*
илиsync*
используется в теле метода, идентифицированногоawait
илиyield
в качестве идентификатора.
Другие ключевые слова без надстрочного индексазарезервированное слово, ни один из них не может использоваться в качестве идентификатора.
Переменная
Следующий пример кода создаст и инициализирует переменную:
var name = 'Bob';
Переменные хранят только ссылки на объекты. Это называется здесьname
Переменная хранитString
Ссылка на объект типа "Боб" является значением этого объекта.
name
Тип переменной выводится какString
, но вы можете указать для него тип. Если ссылка на объект не ограничена одним типом, она может бытьРекомендации по дизайнуобозначить его какObject
или dynamic
тип.
dynamic name = 'Bob';
В дополнение к этому вы также можете указать тип:
String name = 'Bob';
Памятка:
Эта статья следуетруководство по советам по стилюрекомендации в , черезvar
Объявите локальную переменную вместо использования указанного типа.
По умолчанию
В Dart неинициализированные переменные имеют значение инициализации по умолчанию:null
. Это верно даже для чисел, потому что в Dart все является объектом, и числа не являются исключением.
int lineCount;
assert(lineCount == null);
Памятка:
assert()
Вызовы будут игнорироваться в производственном коде. Во время разработки,assert(condition)
будет вУсловное суждениеВыбрасывает исключение, когда false. Для получения подробной информации см.Assert.
Окончательный и постоянный
Если вы не хотите изменять переменную, вы можете использовать ключевое словоfinal
или const
Модифицированные переменные, эти два ключевых слова можно заменитьvar
ключевое слово или перед определенным типом. Переменной final может быть присвоено значение только один раз; переменная const является константой времени компиляции (переменная const также является final). Конечные переменные верхнего уровня или конечные переменные класса инициализируются при первом использовании.
Памятка:
Переменные экземпляра могут бытьfinal
но неconst
Да, конечные переменные экземпляра должны быть инициализированы до начала конструктора, например, при объявлении переменной экземпляра или в качестве параметра конструктора, или путем помещения ее в конструкторсписок инициализациисередина.
В следующем примере мы создаем и устанавливаем две окончательные переменные:
final name = 'Bob'; // Without a type annotation
final String nickname = 'Bobby';
Вы не можете изменить значение конечной переменной:
name = 'Alice'; // Error: a final variable can only be set once.
использовать ключевые словаconst
Измененная переменная указывает, что переменнаяконстанты времени компиляции. Если вы используете const для изменения переменных в классе, вы должны добавить ключевое слово static, то естьstatic const
(Примечание переводчика: порядок нельзя изменить). При объявлении константной переменной вы можете назначить ее напрямую или использовать другие константные переменные для ее назначения:
const bar = 1000000; // 直接赋值 [Unit of pressure (dynes/cm2)]
const double atm = 1.01325 * bar; // 利用其它 const 变量赋值 (Standard atmosphere)
const
Ключевые слова можно использовать не только для определения констант, но и для созданияпостоянное значение, константное значение может быть присвоено любой переменной. Вы также можете объявить конструкторы как константы, объекты, созданные этим типом конструктора, неизменяемы.
var foo = const [];
final bar = const [];
const baz = []; // 相当于 `const []` (Equivalent to `const []`)
Ключевое слово можно опустить, если инициализатор используется для присвоения значения константе.const
, например константа вышеbaz
Присвоение опущеноconst
. Для получения подробной информации см.Не используйте избыточноconst
.
Значение переменных, не дополненных final или const, можно изменить, даже если эти переменные ранее ссылались на значение const.
foo = [1, 2, 3]; // foo 的值之前为 const [] (Was const [])
Значение константы не может быть изменено:
baz = [42]; // 报错:常量不可以被赋值。(Error: Constant variables can't be assigned a value.)
Вы можете использовать в константахПроверка типов и приведение (is
и as
),если в коллекции а также спред оператор (...
и ...?
):
const Object i = 3; // Where i is a const Object with an int value...
const list = [i as int]; // Use a typecast.
const map = {if (i is int) i: "int"}; // Use is and collection if.
const set = {if (list is List<int>) ...list}; // ...and a spread.
Памятка: Although a final
object cannot be modified, its fields can be changed. In comparison, a const
объект и его поля не могут быть изменены: ониimmutable.
можно проконсультироватьсяLists,Maps и ClassesУзнайте больше об использованииconst
Информация для создания постоянных значений.
встроенный тип
Язык Dart поддерживает следующие типы:
- numbers
- strings
- booleans
- списки (также известные как спискиarrays)
- sets
- maps
- руны (для представления символов Unicode в строках)
- symbols
Вышеупомянутые типы могут быть инициализированы напрямую с помощью литералов. Например 'This is a string'
это строковая буквальная,true
является логическим литералом.
Поскольку каждая ссылка на переменную в Dart указывает на объект (aсвоего родаэкземпляр), обычно вы также можете использоватьКонструктордля инициализации переменной. Некоторые встроенные типы имеют собственные конструкторы. Например, вы можете использоватьMap()
для создания объекта карты.
Numbers
Dart поддерживает два типа чисел:
Целочисленное значение, длина не может превышать 64 бита, а конкретный диапазон значений зависит от разных платформ. В DartVM его значение находится между -263 и 263-1. Dart, который компилируется в JavaScript, используетчисла JavaScript, который допускает значения в диапазоне от -253 до 253-1.
64-битное число двойной точности с плавающей запятой, соответствующее стандарту IEEE 754.
int
и double
обаnum
подкласс . num определяет некоторые основные операторы, такие как +, -, *, / и т. д., а также определяетabs()
,ceil()
и floor()
и другие методы (побитовые операторы, такие как >>, определены в int). Если num и его подклассы не соответствуют вашим требованиям, вы можете проверитьdart:mathAPI в библиотеке.
Целые числа — это числа без десятичной точки.Вот несколько примеров определения целочисленных литералов:
var x = 1;
var hex = 0xDEADBEEF;
Число является числом с плавающей запятой, если оно содержит десятичную точку. Вот несколько примеров определения литералов чисел с плавающей запятой:
var y = 1.1;
var exponents = 1.42e5;
При необходимости целочисленные литералы будут автоматически преобразованы в литералы с плавающей запятой:
double z = 1; // Equivalent to double z = 1.0.
Подсказки к версии:
До Dart 2.1 было ошибкой использовать целочисленные литералы в контексте чисел с плавающей запятой.
Вот как конвертировать между строками и числами:
// String -> int
var one = int.parse('1');
assert(one == 1);
// String -> double
var onePointOne = double.parse('1.1');
assert(onePointOne == 1.1);
// int -> String
String oneAsString = 1.toString();
assert(oneAsString == '1');
// double -> String
String piAsString = 3.14159.toStringAsFixed(2);
assert(piAsString == '3.14');
Целые числа поддерживают традиционные операции смещения, такие как сдвиг (>), побитовое И (&), побитовое ИЛИ (|), например:
assert((3 << 1) == 6); // 0011 << 1 == 0110
assert((3 >> 1) == 1); // 0011 >> 1 == 0001
assert((3 | 4) == 7); // 0011 | 0100 == 0111
Числовые литералы являются константами времени компиляции. Для многих арифметических выражений, пока их операнды являются константами, результат выражения также является константой времени компиляции.
const msPerSecond = 1000;
const secondsUntilRetry = 5;
const msUntilRetry = secondsUntilRetry * msPerSecond;
Strings
Строки Dart представляют собой последовательности символов в кодировке UTF-16. Строки можно создавать с помощью одинарных или двойных кавычек:
var s1 = 'Single quotes work well for string literals.';
var s2 = "Double quotes work just as well.";
var s3 = 'It\'s easy to escape the string delimiter.';
var s4 = "It's even easier to use the other delimiter.";
// 代码中文解释
var s1 = '使用单引号创建字符串字面量。';
var s2 = "双引号也可以用于创建字符串字面量。";
var s3 = '使用单引号创建字符串时可以使用斜杠来转义那些与单引号冲突的字符串:\'。';
var s4 = "而在双引号中则不需要使用转义与单引号冲突的字符串:'";
В строке начните с${
表达式
}
Форма использует выражение. Если выражение является идентификатором, вы можете опустить {}. Если результатом выражения является объект, Dart вызывает объектtoString
метод получения строки.
var s = 'string interpolation';
assert('Dart has $s, which is very handy.' ==
'Dart has string interpolation, ' +
'which is very handy.');
assert('That deserves all caps. ' +
'${s.toUpperCase()} is very handy!' ==
'That deserves all caps. ' +
'STRING INTERPOLATION is very handy!');
// 代码中文解释
var s = '字符串插值';
assert('Dart 有$s,使用起来非常方便。' == 'Dart 有字符串插值,使用起来非常方便。');
assert('使用${s.substring(3,5)}表达式也非常方便' == '使用插值表达式也非常方便。');
Памятка:
==
Оператор отвечает за оценку того, является ли содержимое двух объектов одинаковым.Если две строки содержат одну и ту же последовательность кодирования символов, они равны.
ты можешь использовать +
оператор или сопоставление нескольких строк для объединения строк:
var s1 = 'String '
'concatenation'
" works even over line breaks.";
assert(s1 ==
'String concatenation works even over '
'line breaks.');
var s2 = 'The + operator ' + 'works, as well.';
assert(s2 == 'The + operator works, as well.');
// 代码中文解释
var s1 = '可以拼接'
'字符串'
"即便它们不在同一行。";
assert(s1 == '可以拼接字符串即便它们不在同一行。');
var s2 = '使用加号 + 运算符' + '也可以达到相同的效果。';
assert(s2 == '使用加号 + 运算符也可以达到相同的效果。');
Многострочные строки также могут быть созданы с использованием трех одинарных или трех двойных кавычек:
var s1 = '''
你可以像这样创建多行字符串。
''';
var s2 = """这也是一个多行字符串。""";
добавить перед строкойr
Создайте «сырые» строки в качестве префиксов (т.е. строки, которые не будут обрабатываться (например, экранироваться) каким-либо образом):
var s = r'In a raw string, not even \n gets special treatment.';
// 代码中文解释
var s = r'在 raw 字符串中,转义字符串 \n 会直接输出 “\n” 而不是转义为换行。';
ты можешь проверитьРуны и кластеры графемПолучите дополнительную информацию о том, как представлять символы Юникода в строках.
Строковый литерал является константой времени компиляции, и пока он является константой времени компиляции, его можно использовать как выражение интерполяции для строкового литерала:
// 可以将下面三个常量作为字符串插值拼接到字符串字面量中。(These work in a const string.)
const aConstNum = 0;
const aConstBool = true;
const aConstString = 'a constant string';
// 而下面三个常量不能作为字符串插值拼接到字符串字面量。
var aNum = 0;
var aBool = true;
var aString = 'a string';
const aConstList = [1, 2, 3];
const validConstString = '$aConstNum $aConstBool $aConstString';
// const invalidConstString = '$aNum $aBool $aString $aConstList';
можно проконсультироватьсяСтроки и регулярные выраженияПолучите дополнительную информацию о том, как использовать строки.
Booleans
Дартс используетbool
Ключевое слово представляет логический тип, а логический тип имеет только два объекта.true
и false
, обе из которых являются константами времени компиляции.
Безопасность типов Dart не позволяет вам использовать что-то вродеif (nonbooleanValue)
или assert (nonbooleanValue)
Такой код проверяет логические значения. Вместо этого всегда следует явно проверять логические значения, например, в следующем коде:
// 检查是否为空字符串 (Check for an empty string).
var fullName = '';
assert(fullName.isEmpty);
// 检查是否小于等于零。
var hitPoints = 0;
assert(hitPoints <= 0);
// 检查是否为 null。
var unicorn;
assert(unicorn == null);
// 检查是否为 NaN。
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);
Lists
множество (Array) является наиболее распространенным типом коллекций почти во всех языках программирования, а в Dart массивы представленыListПредставление объекта. обычно называетсяList.
Литералы списков в Dart выглядят так же, как литералы массивов в JavaScript. Вот пример списка дротиков:
var list = [1, 2, 3];
Памятка:
Здесь Дарт делает вывод, чтоlist
имеет типList<int>
, если вы добавите в массив объект типа не-int, будет сообщено об ошибке. ты можешь читатьвывод типаПолучите больше информации об этом.
Вы можете добавить запятую после последнего элемента в типах коллекций Dart. Эта запятая не влияет на набор, но это хороший способ избежать ошибок "копировать-вставить".
var list = [
'Car',
'Boat',
'Plane',
];
Индекс нижнего индекса списка начинается с 0, нижний индекс первого элемента равен 0, а нижний индекс последнего элемента равенlist.length - 1
. Вы можете получить длину и элементы списка в Dart так же, как в JavaScript:
var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);
list[1] = 1;
assert(list[1] == 1);
Добавить перед литералом спискаconst
Ключевое слово создает константу времени компиляции:
var constantList = const [1, 2, 3];
// constantList[1] = 1; // This line will cause an error.
Дартс представлен в 2.3спред оператор(...
)и Ощущение пустого расширенного оператора(...?
), они обеспечивают удобный способ вставки нескольких элементов в коллекцию.
Например, вы можете использовать оператор спреда (...
) вставляет все элементы из одного списка в другой список:
var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);
Если правая часть оператора спреда может быть нулевой, вы можете использовать оператор спреда с поддержкой нуля (...?
), чтобы избежать исключения:
var list;
var list2 = [0, ...?list];
assert(list2.length == 1);
можно проконсультироватьсяраспространить предложение оператораПолучите дополнительную информацию о том, как использовать оператор спреда.
Дарт также представилесли в коллекции и в коллекциюоперации, при построении коллекции можно использовать условное суждение (if
) и цикл (for
).
В следующем примере используетсяесли в коллекциичтобы создать пример списка, который может содержать 3 или 4 элемента:
var nav = [
'Home',
'Furniture',
'Plants',
if (promoActive) 'Outlet'
];
Далее следует использоватьв коллекциюПример изменения элементов в списке и добавления их в другой список:
var listOfInts = [1, 2, 3];
var listOfStrings = [
'#0',
for (var i in listOfInts) '#$i'
];
assert(listOfStrings[1] == '#1');
ты можешь проверитьИспользование рекомендаций потока управления в коллекцияхПолучите более подробную информацию и примеры использования if и for с коллекциями.
В классе List есть много удобных методов для управления списками, вы можете обратиться кДженерики и собиратьПолучите больше информации об этом.
Sets
В Dart набор — это неупорядоченная коллекция определенного набора элементов. Dart поддерживает наборы с помощью заданных литералов иSetкласс обеспечивает.
Подсказки к версии:
Хотя набортипвсегда была основной функцией Dart, но SetЛитералы (литералы)Это в DART 2.2 на вечеринке.
Вот как использовать литерал Set для создания коллекции Set:
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
Памятка:
Вывод дротикаhalogens
переменная - этоSet<String>
Коллекция типов, будет выдано сообщение об ошибке, если в Set будет добавлен объект неверного типа. ты можешь проверитьвывод типаПолучить больше контента, связанного с ним.
можно использовать в{}
чтобы создать пустой набор, добавив перед ним параметр типа, или{}
Присвоить переменной типа Set:
var names = <String>{}; // 类型+{}的形式创建Set。
// Set<String> names = {}; // 声明类型变量的形式创建 Set (This works, too).
// var names = {}; // 这样的形式将创建一个 Map 而不是 Set (Creates a map, not a set.)
Установить или карту?Синтаксис литерала Map аналогичен синтаксису литерала Set. Из-за предыдущего синтаксиса литерала карты, поэтому{}
По умолчаниюMap
тип. Если ты забудешь{}
Для типа аннотации или присвоения переменной необъявленного типа Dart создаст типMap<dynamic, dynamic>
Объект.
использовать add()
метод илиaddAll()
Метод добавляет элемент в существующий набор:
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);
использовать .length
Вы можете получить количество элементов в наборе:
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);
assert(elements.length == 5);
может быть добавлен перед литералом Setconst
ключевое слово создает константу времени компиляции Set:
final constantSet = const {
'fluorine',
'chlorine',
'bromine',
'iodine',
'astatine',
};
// constantSet.add('helium'); // This line will cause an error.
Начиная с Dart 2.3, наборы могут поддерживать использование операторов спреда, таких как списки (...
и ...?
) и Коллекция операций If и Коллекция For. ты можешь проверитьОператор спреда списка и Оператор сбора списковПолучите больше информации об этом.
Вы также можете проверитьДженерики а также SetПолучите больше информации об этом.
Maps
В общем, карта — это объект, используемый для связывания ключей и значений. где и ключи, и значения могут быть объектами любого типа. каждыйключможет появиться только один раз, ноценностьМожно повторять несколько раз. Карта в Dart предоставляет литералы карты иMapВведите две формы карты.
Вот пара примеров создания карты с использованием литерала карты:
var gifts = {
// 键: 值
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};
var nobleGases = {
2: 'helium',
10: 'neon',
18: 'argon',
};
Памятка:
Дарт будетgifts
Тип переменной выводится какMap<String, String>
, в то время какnobleGases
Тип выводится какMap<int, String>
. Если вы добавите неверные значения типа к этим двум объектам Map, возникнет исключение времени выполнения. ты можешь читатьвывод типаПолучите больше информации об этом.
Вы также можете создать карту с помощью конструктора карты:
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';
Памятка: If you come from a language like C# or Java, you might expect to see new Map()
instead of just Map()
. In Dart, the new
keyword is optional. For details, see Using constructors.
Если вы раньше использовали такой язык, как C# или Java, возможно, вы захотите использоватьnew Map()
Создайте объект карты. Но в Дартеnew
Ключевые слова не являются обязательными. (Примечание переводчика: и не рекомендуется) Вы можете проверитьИспользование конструктораПолучите больше информации об этом.
Добавление пар ключ-значение к существующей карте аналогично операциям JavaScript:
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds'; // 添加键值对 (Add a key-value pair)
Получение значения из карты похоже на JavaScript.
var gifts = {'first': 'partridge'};
assert(gifts['first'] == 'partridge');
Возвращается нуль, если полученный ключ не существует на карте:
var gifts = {'first': 'partridge'};
assert(gifts['fifth'] == null);
использовать .length
Вы можете получить количество пар ключ-значение на карте:
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds';
assert(gifts.length == 2);
Добавить перед литералом Mapconst
ключевое слово может создать константу времени компиляции карты:
final constantMap = const {
2: 'helium',
10: 'neon',
18: 'argon',
};
// constantMap[2] = 'Helium'; // This line will cause an error.
Карта может поддерживать использование оператора распространения, такого как List (...
и ...?
) и if и для операций коллекций. ты можешь проверитьОператор спреда списка и Оператор сбора списковПолучите больше информации об этом.
Вы также можете проверитьДженерики а также MapsПолучите больше информации об этом.
Руны и кластеры графем
В Дарте,runesПредоставляет кодовые точки Unicode для строк. использовать сумка персонажейдля доступа или управления воспринимаемыми пользователем символами, также известными какКластеры графем Unicode (расширенные).
Кодировка Unicode определяет уникальное числовое значение для каждой буквы, цифры и символа. Поскольку строка в Dart представляет собой последовательность символов UTF-16, для представления 32-битных значений Unicode требуется специальный синтаксис.
Обычный способ представления символов Unicode — использование\uXXXX
, где XXXX — четырехзначное шестнадцатеричное число. Например, Unicode для символа сердца (♥)\u2665
. Шестнадцатеричные числа, не являющиеся четырьмя цифрами, должны быть заключены в фигурные скобки. Например, Unicode смеющегося смайлика (?) – это \u{1f600}
.
Если вам нужно прочитать и записать один символ Unicode, вы можете использовать символы, определенные в пакете символов.characters
добытчик. он вернетсяCharacters
объект в виде строки кластеров графем. Вот пример использования API символов:
import 'package:characters/characters.dart';
...
var hi = 'Hi ??';
print(hi);
print('The end of the string: ${hi.substring(hi.length - 1)}');
print('The last character: ${hi.characters.last}\n');
Вывод зависит от вашей среды и примерно похож на:
$ dart bin/main.dart
Hi ??
The end of the string: ???
The last character: ??
Дополнительные сведения об управлении строками с помощью пакета символов см. в разделе Пакет символовОбразец и Справочник по API.
Памятка:
Вы должны быть осторожны при использовании List для работы с Rune. В зависимости от языка, набора символов и т. д., с которыми вы работаете, могут возникнуть проблемы со строками. Для получения подробной информации см. вопрос в Stack Overflow: [Как мне перевернуть строку в Dart? ][Как перевернуть строку в Dart?].
Symbols
Символ представляет собой оператор или идентификатор, объявленный в Dart. Вам вряд ли когда-либо понадобятся символы, но они полезны для API, которые ссылаются на идентификаторы по имени, потому что после минимизации кода, хотя имена идентификаторов изменятся, их символы останутся прежними.
Вы можете использовать префикс идентификатора с#
префикс для получения символа:
#radix
#bar
Символьные литералы являются константами времени компиляции.
функция
Dart — настоящий объектно-ориентированный язык, поэтому даже функции являются объектами и имеют тип.Function, что означает, что функции могут быть назначены переменным или в качестве аргументов для других функций. Вы также можете вызвать экземпляр класса Dart как функцию. Для получения подробной информации см.вызываемый класс.
Вот пример определения функции:
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
В то время как эффективное руководство Dart рекомендуетОпределите тип возвращаемого значения в открытом API., но функция по-прежнему действительна, даже если она не определена:
isNoble(atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
Если тело функции содержит только одно выражение, вы можете использовать сокращенный синтаксис:
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
грамматика=> 表达式
Да { return 表达式; }
сокращение для ,=>
иногда называетсястрелкафункция.
Памятка:
Между => и ; может быть тольковыражениескорее, чемутверждение. Например, нельзя поставитьесли операторв нем, но можно поместитьусловное выражение.
параметр
Функции могут иметь аргументы двух форм:Обязательные параметры и необязательный параметр. Обязательные параметры определяются перед списком параметров, а необязательные параметры определяются после обязательных параметров. Необязательные параметры могут бытьназванный или Место расположения.
Памятка:
Некоторые API (особенноFlutterконструктор элемента управления) использует только именованные параметры, даже если параметр является обязательным. Дополнительную информацию см. в следующем разделе.
При передаче параметров функциям или определении параметров функции вы можете использовать [запятую в конце] [запятую в конце].
именованные параметры
Именованные параметры являются необязательными по умолчанию, если только они специально не отмечены как обязательные.
Когда вы вызываете функцию, вы можете использовать参数名: 参数值
указать именованные параметры в виде . Например:
enableFlags(bold: true, hidden: false);
When defining a function, use {参数1, 参数2, …}
to specify named parameters:
Определение функции с помощью{param1, param2, …}
указать именованные параметры:
/// 设置 [bold] 和 [hidden] 标识……
/// Sets the [bold] and [hidden] flags...
void enableFlags({bool bold, bool hidden}) {...}
Хотя именованные параметры относятся к типу необязательных параметров, вы все равно можете использовать@requiredаннотацию, чтобы идентифицировать именованный параметр как обязательный параметр, и в этом случае вызывающая сторона должна предоставить значение для параметра. Например:
const Scrollbar({Key key, @required Widget child})
Если звонящий хочет пройтиScrollbar
Конструктор для конструирует объект полосы прокрутки, не предоставляяchild
параметр, это вызовет ошибку компиляции.
@requiredАннотации определены вmetaпакет, вы можете импортировать его, импортировавpackage:meta/meta.dart
использование пакета.
необязательные позиционные аргументы
использовать []
Оберните последовательность аргументов как позиционные аргументы:
String say(String from, String msg, [String device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
Вот пример вызова вышеуказанной функции без необязательных аргументов:
assert(say('Bob', 'Howdy') == 'Bob says Howdy');
Вот пример вызова вышеуказанной функции с необязательными аргументами:
assert(say('Bob', 'Howdy', 'smoke signal') ==
'Bob says Howdy with a smoke signal');
Значение параметра по умолчанию
Можно использовать =
Определите значения по умолчанию для именованных и позиционных параметров функции.Значение по умолчанию должно быть константой времени компиляции.Если значение по умолчанию не указано, значением по умолчанию являетсяnull
.
Ниже приведен пример установки значения по умолчанию для необязательного параметра:
/// 设置 [bold] 和 [hidden] 标识……
/// Sets the [bold] and [hidden] flags ...
void enableFlags({bool bold = false, bool hidden = false}) {...}
// bold 的值将为 true;而 hidden 将为 false。
enableFlags(bold: true);
В более старых версиях кода Dart использовались двоеточия (:
) вместо=
установить значения по умолчанию для именованных параметров. Причина в том, что вначале именованные параметры поддерживали только:
. Однако эта поддержка сейчас устарела, поэтому мы рекомендуем вам толькоиспользовать =
указать значения по умолчанию.
Следующий пример покажет вам, как установить значения по умолчанию для позиционных параметров:
String say(String from, String msg,
[String device = 'carrier pigeon']) {
var result = '$from says $msg with a $device';
return result;
}
assert(say('Bob', 'Howdy') ==
'Bob says Howdy with a carrier pigeon');
Список или карта также могут использоваться в качестве значений по умолчанию. В следующем примере определяетсяdoStuff()
функцию , и дайте ей имяlist
и gifts
Параметр задает значение типа List и значение типа Map.
void doStuff(
{List<int> list = const [1, 2, 3],
Map<String, String> gifts = const {
'first': 'paper',
'second': 'cotton',
'third': 'leather'
}}) {
print('list: $list');
print('gifts: $gifts');
}
основная функция
Каждая программа Dart должна иметьmain()
Функция верхнего уровня используется как точка входа в программу.main()
Возвращаемое значение функции равноvoid
и естьList<String>
Необязательный параметр типа.
Ниже приведено веб-приложениеmain()
Пример функции:
void main() {
querySelector('#sample_text_id')
..text = 'Click me!'
..onClick.listen(reverseText);
}
Памятка:
в приведенном выше коде..
грамматика называетсякаскадные вызовы. Используйте каскадный доступ для выполнения нескольких операций над объектом.
Ниже показано использование доступа к командной строке с параметрамиmain()
Пример функции:
// 使用命令 dart args.dart 1 test 运行该应用
// Run the app like this: dart args.dart 1 test
void main(List<String> arguments) {
print(arguments);
assert(arguments.length == 2);
assert(int.parse(arguments[0]) == 1);
assert(arguments[1] == 'test');
}
Вы можете сделать это, используябиблиотека параметровдля определения и анализа аргументов командной строки.
Функции — это объекты первого класса.
Функция может быть передана в качестве аргумента другой функции. Например:
void printElement(int element) {
print(element);
}
var list = [1, 2, 3];
// 将 printElement 函数作为参数传递。
list.forEach(printElement);
Вы также можете назначить функцию переменной, например:
var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
assert(loudify('hello') == '!!! HELLO !!!');
В этом примере используется анонимная функция. В следующем разделе будет более подробное знакомство с ним.
анонимная функция
Большинство методов имеют такие имена, какmain()
или printElement()
. Вы можете создать метод без имени, назовите егоанонимная функция,Лямбда-выражения или Закрытие закрытия. Вы можете назначить анонимный метод переменной, а затем использовать его, например, добавить или удалить эту переменную в коллекцию.
Анонимные методы похожи на именованные, параметры могут быть определены в круглых скобках и разделены запятыми.
Содержимое следующих фигурных скобок является телом функции:
([[类型] 参数[, …]]) { 函数体; };
Следующий код определяет только один параметрitem
И анонимные методы без типов параметров. Эта функция вызывается для каждого элемента в списке, печатая строку позиции и значения элемента:
var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
Нажмите кнопку «Выполнить», чтобы выполнить код.
Если в теле функции есть только один оператор возврата, вы можете использовать сокращенную толстую стрелку. Вставьте следующий код в DartPad и нажмите кнопку «Выполнить», чтобы убедиться, что две функции совместимы.
list.forEach(
(item) => print('${list.indexOf(item)}: $item'));
лексический охват
Dart — это язык с лексической областью видимости. Область действия переменных определяется при написании кода. Доступ к переменным, определенным в фигурных скобках, можно получить только внутри фигурных скобок, как в Java.
Вот пример переменных в нескольких областях вложенной функции:
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);
}
}
}
Уведомление nestedFunction()
Функции могут обращаться ко всем переменным, включая переменные верхнего уровня.
Лексическое замыкание
ЗакрытиеТо есть объект-функция, даже если объект-функция вызывается за пределами своей исходной области, по-прежнему может обращаться к переменным в своей лексической области.
Функция может заключать в себе переменные, определенные в ее области. В следующем примере функцияmakeAdder()
захваченная переменнаяaddBy
. Всякий раз, когда функция возвращается, она может использовать захваченныйaddBy
Переменная.
/// 返回一个将 [addBy] 添加到该函数参数的函数。
/// Returns a function that adds [addBy] to the
/// function's argument.
Function makeAdder(int addBy) {
return (int i) => addBy + i;
}
void main() {
// 生成加 2 的函数。
var add2 = makeAdder(2);
// 生成加 4 的函数。
var add4 = makeAdder(4);
assert(add2(3) == 5);
assert(add4(3) == 7);
}
Тест на равенство функций
Ниже приведены примеры тестов на равенство функций верхнего уровня, статических методов и примеров методов:
void foo() {} // 定义顶层函数 (A top-level function)
class A {
static void bar() {} // 定义静态方法
void baz() {} // 定义实例方法
}
void main() {
var x;
// 比较顶层函数是否相等。
x = foo;
assert(foo == x);
// 比较静态方法是否相等。
x = A.bar;
assert(A.bar == x);
// 比较实例方法是否相等。
var v = A(); // A 的实例 #1
var w = A(); // A 的实例 #2
var y = w;
x = w.baz;
// 这两个闭包引用了相同的实例对象,因此它们相等。
assert(y.baz == x);
// 这两个闭包引用了不同的实例对象,因此它们不相等。
assert(v.baz != w.baz);
}
возвращаемое значение
Все функции имеют возвращаемые значения. Последняя строка функции, которая не отображает оператор возврата, по умолчанию выполняется.return null;
.
foo() {}
assert(foo() == null);
оператор
Dart поддерживает операторы, указанные в следующей таблице. Вы можете реализовать эти операторы какчлен класса.
описывать | оператор |
---|---|
унарный суффикс |
表达式++ 表达式-- () [] . ?.
|
унарный префикс |
-表达式 !表达式 ~表达式 ++表达式 --表达式
|
Умножение и деление |
* / % ~/
|
Сложение и вычитание |
+ -
|
битовая операция |
<< >> >>>
|
двоичный файл с | & |
бинарное исключающее ИЛИ | ^ |
двоичный или | | |
Отношения и тестирование типов |
>= > <= < as is is!
|
Определение эквивалентности |
== !=
|
логический и | && |
логический или | || |
Пустое суждение | ?? |
условное выражение | 表达式 1 ? 表达式 2 : 表达式 3 |
каскад | .. |
назначать |
= *= /= += -= &= ^= и т.д……
|
Пожалуйста, обрати внимание:
Приведенный выше приоритет оператора является копией поведения парсера Dart. Для более точного описания см.Спецификация языка Dartсинтаксис в .
После использования оператора выражение создается. Вот несколько примеров операторных выражений:
a++
a + b
a = b
a == b
c ? a : b
a is T
существуеттаблица оператора, Оператор упорядочил в соответствии с приоритетом, то есть первая строка с наивысшим приоритетом, последняя строка с наименьшим приоритетом, в то время как та же самая строка, крайняя левая с наивысшим приоритетом, крайняя правая имеет самый низкий приоритет. Например:%
приоритет оператора выше, чем==
,и ==
выше чем&&
. Согласно правилам приоритета, это означает, что следующие две строки кода выполняют один и тот же эффект:
// 括号提高了可读性。
// Parentheses improve readability.
if ((n % i == 0) && (d % i == 0)) ...
// 难以理解,但是与上面的代码效果一样。
if (n % i == 0 && d % i == 0) ...
Пожалуйста, обрати внимание:
Для операторов с двумя операндами левый операнд определяет функцию оператора. Например, для объектов Vector и Point выражениеaVector + aPoint
используется в операторе сложения, определенном в объекте Vector (+
).
арифметические операторы
Dart поддерживает распространенные арифметические операторы:
оператор | описывать |
---|---|
+ |
добавлять |
– |
уменьшать |
-表达式 |
Унарный отрицательный, также может использоваться как инверсия (изменение знака выражения) |
* |
брать |
/ |
Удалить |
~/ |
Разделить и округлить |
% |
по модулю |
Пример:
assert(2 + 3 == 5);
assert(2 - 3 == -1);
assert(2 * 3 == 6);
assert(5 / 2 == 2.5); // 结果是一个浮点数
assert(5 ~/ 2 == 2); // 结果是一个整数
assert(5 % 2 == 1); // 取余
assert('5/2 = ${5 ~/ 2} r ${5 % 2}' == '5/2 = 2 r 1');
Дарт также поддерживает операции по увеличению и уменьшению.
Operator++var
|
var = var + 1 (значение выраженияvar + 1 ) |
---|---|
var++ |
var = var + 1 (значение выраженияvar ) |
--var |
var = var – 1 (значение выраженияvar – 1 ) |
var-- |
var = var – 1 (значение выраженияvar ) |
Пример:
var a, b;
a = 0;
b = ++a; // 在 b 赋值前将 a 增加 1。
assert(a == b); // 1 == 1
a = 0;
b = a++; // 在 b 赋值后将 a 增加 1。
assert(a != b); // 1 != 0
a = 0;
b = --a; // 在 b 赋值前将 a 减少 1。
assert(a == b); // -1 == -1
a = 0;
b = a--; // 在 b 赋值后将 a 减少 1。
assert(a != b); // -1 != 0
оператор отношения
В следующей таблице перечислены реляционные операторы и их значения:
Operator==
|
равный |
---|---|
!= |
диапазон |
> |
больше, чем |
< |
меньше, чем |
>= |
больше или равно |
<= |
меньше или равно |
Чтобы определить, представляют ли два объекта x и y одно и то же, используйте==
Вот и все. (В редких случаях может потребоваться использованиеidentical()Функция, позволяющая определить, идентичны ли два объекта. ). Ниже==
Некоторые правила для операторов:
- Предположим, что есть переменныеx и y, и по крайней мере один из x и y равен нулю, тогда x == y вернет true тогда и только тогда, когда оба x и y равны null, в противном случае он вернет false, если только один из них равен null.
-
x.==(y)
вернет значение, здесь с y или без него, т. е. y является необязательным. то есть==
на самом деле является методом в x и может быть переопределен. Для получения подробной информации см.оператор перезаписи.
В следующем коде приведены примеры каждого реляционного оператора:
assert(2 == 2);
assert(2 != 3);
assert(3 > 2);
assert(2 < 3);
assert(3 >= 3);
assert(2 <= 3);
оператор оценки типа
as
,is
,is!
Операторы — это операторы, определяющие тип объекта во время выполнения.
Operator | Meaning |
---|---|
as |
преобразование типа (также используется для указанияпрефикс класса)) |
is |
Возвращает true, если объект имеет указанный тип |
is! |
Возвращает false, если объект имеет указанный тип |
если и только еслиobj
ДостигнутоT
Интерфейс,obj is T
Это правда. Например obj is Object
Всегда верно, потому что все классы являются подклассами Object.
Только если вы уверены, что объект относится к этому типу, вы можете использоватьas
Операторы могут преобразовывать объекты в определенный тип. Например:
(emp as Person).firstName = 'Bob';
Если вы не уверены, является ли тип объектаT
, пожалуйста, используйте перед преобразованиемis T
Тип проверки.
if (emp is Person) {
// 类型检查
emp.firstName = 'Bob';
}
ты можешь использовать as
оператор сокращенно:
(emp as Person).firstName = 'Bob';
Памятка:
Вышеуказанные два метода отличаются: еслиemp
имеет значение null или не относится к типу Person, первый метод вызовет исключение, а второй — нет.
оператор присваивания
можно использовать =
для присвоения значений, и вы также можете использовать??=
Чтобы присвоить значение для переменных значение NULL.
// 将 value 赋值给 a (Assign value to a)
a = value;
// 当且仅当 b 为 null 时才赋值
b ??= value;
рисунок +=
Такие операторы присваивания сочетают в себе арифметические операторы и операторы присваивания.
= |
–= |
/= |
%= |
>>= |
^= |
---|---|---|---|---|---|
+= |
*= |
~/= |
<<= |
&= |
|= |
В следующей таблице объясняется, как работает оператор совпадения:
Сцены | составная операция | эквивалентное выражение |
---|---|---|
Предположим, что есть операторop: | a op= b |
a = a op b |
Пример: | a += b |
a = a + b |
В следующем примере показано, как использовать операторы присваивания и составные операторы присваивания:
var a = 2; // 使用 = 赋值 (Assign using =)
a *= 3; // 赋值并做乘法运算 Assign and multiply: a = a * 3
assert(a == 6);
Логические операторы
Используя логические операторы, вы можете инвертировать или комбинировать логические выражения.
оператор | описывать |
---|---|
!表达式 |
Отменить результат выражения (т.е. true становится false, false становится true) |
|| |
логический или |
&& |
логический и |
Вот пример использования логических выражений:
if (!done && (col == 0 || col == 3)) {
// ...Do something...
}
Побитовые операторы и операторы сдвига
В Dart побитовые операторы работают с одним битом в двоичном формате, но только с целыми числами.
оператор | описывать |
---|---|
& |
побитовое И |
| |
побитовое ИЛИ |
^ |
Побитовое исключающее ИЛИ |
~表达式 |
Побитовая инверсия (т.е. «0» становится «1», а «1» становится «0») |
<< |
битовый сдвиг влево |
>> |
битовый сдвиг вправо |
Вот пример использования побитовых операторов и операторов сдвига:
final value = 0x22;
final bitmask = 0x0f;
assert((value & bitmask) == 0x02); // 按位与 (AND)
assert((value & ~bitmask) == 0x20); // 取反后按位与 (AND NOT)
assert((value | bitmask) == 0x2f); // 按位或 (OR)
assert((value ^ bitmask) == 0x2d); // 按位异或 (XOR)
assert((value << 4) == 0x220); // 位左移 (Shift left)
assert((value >> 4) == 0x02); // 位右移 (Shift right)
условное выражение
В Dart есть два специальных оператора, которые можно использовать вместоif-elseЗаявление:
condition ? expr1 : expr2
If condition is true, evaluates expr1 (and returns its value); otherwise, evaluates and returns the value of expr2.
条件 ? 表达式 1 : 表达式 2
: Если условие истинно, выполнить выражение 1 и вернуть результат выполнения, в противном случае выполнить выражение 2 и вернуть результат выполнения.
expr1 ?? expr2
If expr1 is non-null, returns its value; otherwise, evaluates and returns the value of expr2.
表达式 1 ?? 表达式 2
: возвращает значение выражения1, если оно не равно нулю, в противном случае выполняет выражение2 и возвращает его значение.
При определении назначений на основе логических выражений рассмотрите возможность использования?:
.
var visibility = isPublic ? 'public' : 'private';
Рассмотрите возможность использования, если назначение основано на проверке нулевого значения??
.
String playerName(String name) => name ?? 'Guest';
Приведенный выше пример также можно записать по крайней мере в двух разных формах, но он недостаточно лаконичен:
// 相对使用 ?: 运算符来说稍微长了点。(Slightly longer version uses ?: operator).
String playerName(String name) => name != null ? name : 'Guest';
// 如果使用 if-else 则更长。
String playerName(String name) {
if (name != null) {
return name;
} else {
return 'Guest';
}
}
Каскадный оператор (..)
Каскадный оператор (..
) позволяет последовательно вызывать переменные или методы нескольких объектов для одного и того же объекта.
Например следующий код:
querySelector('#confirm') // 获取对象 (Get an object).
..text = 'Confirm' // 使用对象的成员 (Use its members).
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
Первый способquerySelector
Возвращается объект Selector, а последующие каскадные операторы вызывают члены этого объекта Selector и игнорируют возвращаемое значение каждой операции.
Приведенный выше код эквивалентен:
var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));
Каскадные операторы могут быть вложенными, например:
final addressBook = (AddressBookBuilder()
..name = 'jenny'
..email = 'jenny@example.com'
..phone = (PhoneNumberBuilder()
..number = '415-555-0100'
..label = 'home')
.build())
.build();
Осторожно используйте каскадные операторы в функциях, возвращающих объекты. Например, следующий код неверен:
var sb = StringBuffer();
sb.write('foo')
..write('bar'); // 出错:void 对象中没有方法 write (Error: method 'write' isn't defined for 'void').
в приведенном выше кодеsb.write()
Метод возвращает void, а возвращаемое значение равноvoid
Метод не может использовать каскадный оператор.
Памятка:
строго говоря ..
Каскадирование — это не оператор, а специальный синтаксис Dart.
другие операторы
Большинство других операторов, уже использованных в других примерах:
оператор | название | описывать |
---|---|---|
() |
инструкции | Представляет вызов метода |
[] |
Список посещений | Доступ к элементу в определенной позиции в списке |
. |
посетить член | метод доступа к члену |
?. |
Участники с условным доступом | Аналогично описанному выше методу доступа к члену, но левый операнд не может иметь значение null, например foo?.bar, возвращает null, если foo имеет значение null, в противном случае возвращает bar |
больше о.
, ?.
и ..
Введение оператора, см.своего рода.
оператор управления потоком
Вы можете использовать следующий оператор для управления потоком выполнения кода Dart:
-
if
иelse
-
for
цикл -
while
иdo
-while
цикл -
break
иcontinue
-
switch
иcase
assert
использовать try-catch
и throw
Также может влиять на поток управления, подробности см.аномальныйчасть.
Если и еще
Дартс поддержкаif - else
предложение, гдеelse
является необязательным, как в примере ниже. Вы также можете обратиться кусловное выражение.
if (isRaining()) {
you.bringRainCoat();
} else if (isSnowing()) {
you.wearJacket();
} else {
car.putTopDown();
}
В отличие от JavaScript, условия в операторах if в Dart должны быть логическими, а не другими типами. Для получения подробной информации см.Логическое значение.
Для цикла
Вы можете использовать стандартныйfor
循环进行迭代。 Например:
var message = StringBuffer('Dart is fun');
for (var i = 0; i < 5; i++) {
message.write('!');
}
На языке дартс,for
Замыкание в цикле автоматически фиксирует циклзначение индексаЧтобы избежать некоторых распространенных ошибок в JavaScript. Предположим, у вас есть следующий код:
var callbacks = [];
for (var i = 0; i < 2; i++) {
callbacks.add(() => print(i));
}
callbacks.forEach((c) => c());
После того, как приведенный выше код будет выполнен, он выведет0
и 1
, но если тот же код выполнить в JavaScript, он выведет два2
.
Если объект, который нужно пройти, реализует интерфейс Iterable, вы можете использоватьforEach()метод, если вам не нужно использовать индекс, используйтеforEach
метод - очень хороший выбор:
candidates.forEach((candidate) => candidate.interview());
Классы, реализующие интерфейс Iterable, такие как List и Set, также поддерживаютfor-in
Форма повторять:
var collection = [1, 2, 3];
for (var x in collection) {
print(x); // 1 2 3
}
Пока и пока
while
Цикл будет оценивать условие перед выполнением тела цикла:
while (!isDone()) {
doSomething();
}
do-while
цикл будетСначала выполнить тело циклаУсловия переоценки:
do {
printLine();
} while (!atEndOfPage());
Прервать и продолжить
использовать break
Цикл может быть прерван:
while (true) {
if (shutDownRequested()) break;
processIncomingRequests();
}
использовать continue
Вы можете пропустить этот цикл и сразу перейти к следующему циклу:
for (int i = 0; i < candidates.length; i++) {
var candidate = candidates[i];
if (candidate.yearsExperience < 5) {
continue;
}
candidate.interview();
}
Если вы используете что-то вроде List или SetIterableобъект, вы можете переписать приведенный выше пример следующим образом:
candidates
.where((c) => c.yearsExperience >= 5)
.forEach((c) => c.interview());
Переключатель и чехол
Оператор Switch используется в Dart==
Чтобы сравнивать целые числа, строки или константы времени компиляции, два сравниваемых объекта должны быть одного типа и не могут быть подклассами или переопределены.==
оператор. тип перечисленияочень подходит дляSwitch
используется в заявлении.
Памятка:
Оператор Switch в Dart подходит только для ограниченного числа случаев, например, при использовании интерпретаторов и сканеров.
Каждый непустойcase
пункт должен иметьbreak
заявление или черезcontinue
,throw
или return
заканчиваться непустымcase
утверждение.
не соответствует ни одномуcase
В случае оператора он будет выполнятьсяdefault
Код в пункте:
var command = 'OPEN';
switch (command) {
case 'CLOSED':
executeClosed();
break;
case 'PENDING':
executePending();
break;
case 'APPROVED':
executeApproved();
break;
case 'DENIED':
executeDenied();
break;
case 'OPEN':
executeOpen();
break;
default:
executeUnknown();
}
В следующем примере игнорируетсяcase
оговоркаbreak
оператора, что приводит к ошибке:
var command = 'OPEN';
switch (command) {
case 'OPEN':
executeOpen();
// 错误: 没有 break
case 'CLOSED':
executeClosed();
break;
}
Однако Dart поддерживает пустыеcase
оператор, позволяющий выполнять его как сквозной.
var command = 'CLOSED';
switch (command) {
case 'CLOSED': // case 语句为空时的 fall-through 形式。
case 'NOW_CLOSED':
// case 条件值为 CLOSED 和 NOW_CLOSED 时均会执行该语句。
executeNowClosed();
break;
}
в непустомcase
Если вы хотите реализовать форму пропуска в операторе, вы можете использоватьcontinue
Оператор реализован с помощью метода label:
var command = 'CLOSED';
switch (command) {
case 'CLOSED':
executeClosed();
continue nowClosed;
// 继续执行标签为 nowClosed 的 case 子句。
nowClosed:
case 'NOW_CLOSED':
// case 条件值为 CLOSED 和 NOW_CLOSED 时均会执行该语句。
executeNowClosed();
break;
}
каждыйcase
предложения могут иметь локальные переменные и видны только внутри этого оператора case.
утверждение
Во время разработки его можно использовать, когда условное выражение ложно —assert(条件, 可选信息)
; — оператор для прерывания выполнения кода. Вы можете найти множество примеров использования assert в этой статье. Вот связанный пример:
// 确保变量值不为 null (Make sure the variable has a non-null value)
assert(text != null);
// 确保变量值小于 100。
assert(number < 100);
// 确保这是一个 https 地址。
assert(urlString.startsWith('https'));
assert
Второй параметр может добавить к нему строковое сообщение.
assert(urlString.startsWith('https'),
'URL ($urlString) should start with "https".');
assert
Первым аргументом может быть любое выражение, значение которого является логическим. Если выражение оценивается как истинное, утверждение выполняется успешно, и выполнение продолжается. Если выражение оценивается как ложное, утверждение терпит неудачу, вызываяAssertionErrorисключение.
Как судить, является ли утверждение действительным? Вступит ли в силу утверждение, зависит от используемых инструментов разработки и фреймворков:
- Трепетать вРежим отладкиэффективен, когда.
- Некоторые средства разработки, такие какdartdevcОбычно он действует по умолчанию.
- некоторые другие инструменты, такие какdart а также dart2jsДобавляя аргументы командной строки при запуске программ Dart
--enable-asserts
Сделайте так, чтобы утверждение вступило в силу.
В производственном коде утверждение игнорируется при передачеassert
Параметры не оцениваются.
аномальный
Код Dart может генерировать и перехватывать исключения. Исключения представляют собой некоторые неизвестные условия ошибки, которые, если их не поймать, будут выброшены, что приведет к прекращению выполнения кода, вызвавшего исключение.
В отличие от Java, все исключения в Dart являются непроверяемыми исключениями, методам не нужно объявлять, какие исключения будут генерироваться, и вам не нужно перехватывать какие-либо исключения.
Дарт предоставляетException и ErrorДва типа исключений и ряд их подклассов, вы также можете определить свои собственные типы исключений. Но в Dart любой ненулевой объект может быть выброшен как исключение и не ограничен типами Exception или Error.
Выбросить исключение
Далее речь идет о метании илипровоцироватьПример исключения:
throw FormatException('Expected at least 1 section');
Вы также можете бросать произвольные объекты:
throw 'Out of llamas!';
Памятка:
Хороший код обычно бросаетError или ExceptionТип исключения.
Поскольку создание исключения — это выражение, его можно использовать в операторах =>, а также в других местах, где используются выражения:
void distanceTo(Point other) => throw UnimplementedError();
поймать исключение
Перехват исключения предотвращает передачу исключения (за исключением повторной генерации исключения). Перехват исключения дает вам возможность его обработать:
try {
breedMoreLlamas();
} on OutOfLlamasException {
buyMoreLlamas();
}
Для кода, который может генерировать несколько типов исключений, вы также можете указать несколько операторов catch, каждый из которых соответствует типу исключения.Если в операторе catch не указан тип исключения, это означает, что может быть перехвачен любой тип исключения:
try {
breedMoreLlamas();
} on OutOfLlamasException {
// 指定异常
buyMoreLlamas();
} on Exception catch (e) {
// 其它类型的异常
print('Unknown exception: $e');
} catch (e) {
// // 不指定类型,处理其它全部
print('Something really unknown: $e');
}
Как показано в приведенном выше коде, вы можете использоватьon
или catch
чтобы поймать исключения, используйтеon
чтобы указать тип исключения, используйтеcatch
чтобы поймать объект исключения, можно использовать оба одновременно.
ты сможешьcatch
Метод задает два параметра, первый параметр — это выброшенный объект исключения, а второй параметр — информация о стеке.StackTraceОбъект:
try {
// ···
} on Exception catch (e) {
print('Exception details:\n $e');
} catch (e, s) {
print('Exception details:\n $e');
print('Stack trace:\n $s');
}
ключевое словоrethrow
Пойманное исключение может быть выброшено снова:
void misbehave() {
try {
dynamic foo = true;
print(foo++); // 运行时错误
} catch (e) {
print('misbehave() partially handled ${e.runtimeType}.');
rethrow; // 允许调用者查看异常。
}
}
void main() {
try {
misbehave();
} catch (e) {
print('main() finished handling ${e.runtimeType}.');
}
}
Finally
Независимо от того, брошено ли исключение,finally
оператор всегда выполняется, если не указаноcatch
оператор для перехвата исключения, исключение будет выполнено послеfinally
Выдает после утверждения:
try {
breedMoreLlamas();
} finally {
// 总是清理,即便抛出了异常。
cleanLlamaStalls();
}
finally
оператор появится при любом совпаденииcatch
Выполнить после оператора:
try {
breedMoreLlamas();
} catch (e) {
print('Error: $e'); // 先处理异常。
} finally {
cleanLlamaStalls(); // 然后清理。
}
Вы можете прочитать обзор основной библиотеки Dartаномальныйглаву для получения дополнительной информации.
своего рода
Dart – это объектно-ориентированный язык, поддерживающий механизм наследования на основе примесей. Все объекты являются экземплярами класса, и все классы наследуются от него.Object своего рода. наследование на основе примесейОзначает, что хотя каждый класс (кроме Object) имеет только один суперкласс, код одного класса можно повторно использовать в наследовании нескольких других классов. Метод расширенияэто способ добавления функциональности к классу без изменения класса или создания подклассов.
Используйте членов класса
объектычленпо функциям и данным (т.е.метод и переменная экземпляра)сочинение. методперечислитьЭто делается через объект, таким образом вы можете получить доступ к функциям и данным объекта.
использовать(.
) для доступа к переменной экземпляра или методу объекта:
var p = Point(2, 2);
// 获取 y 值
assert(p.y == 2);
// 调用变量 p 的 distanceTo() 方法。
double distance = p.distanceTo(Point(4, 4));
использовать ?.
заменять .
Можно избежать проблем, вызванных нулевым выражением слева:
// If p is non-null, set a variable equal to its y value.
var a = p?.y;
использовать конструктор
можно использовать Конструктордля создания объекта. Конструкторы могут быть названы как类名
или 类名 . 标识符
форма. Например, следующие коды используются соответственноPoint()
и Point.fromJson()
Два конструктора создаютPoint
Объект:
var p1 = Point(2, 2);
var p2 = Point.fromJson({'x': 1, 'y': 2});
Следующий код имеет тот же эффект, но перед именем конструктораnew
Ключевое слово является необязательным:
var p1 = new Point(2, 2);
var p2 = new Point.fromJson({'x': 1, 'y': 2});
Подсказки к версии:
Начиная с Дарта 2,new
Ключевое слово является необязательным.
Некоторые классы предоставляютпостоянный конструктор. Чтобы использовать постоянный конструктор, добавьте перед именем конструктораconst
ключевое слово для создания констант времени компиляции:
var p = const ImmutablePoint(2, 2);
Две константы времени компиляции, созданные с помощью одного и того же конструктора и с одинаковыми значениями параметров, являются одним и тем же объектом:
var a = const ImmutablePoint(1, 1);
var b = const ImmutablePoint(1, 1);
assert(identical(a, b)); // 它们是同一个实例 (They are the same instance!)
существует постоянный контекстВ сценариях можно опустить конструктор или литерал передconst
ключевое слово. Например, в следующем примере мы создаем постоянную карту:
// Lots of const keywords here.
// 这里有很多 const 关键字
const pointAndLine = const {
'point': const [const ImmutablePoint(0, 0)],
'line': const [const ImmutablePoint(1, 10), const ImmutablePoint(-2, 11)],
};
В зависимости от контекста вы можете просто оставить первыйconst
ключевое слово, все остальные опущены:
// Only one const, which establishes the constant context.
// 只需要一个 const 关键字,其它的则会隐式地根据上下文进行关联。
const pointAndLine = {
'point': [ImmutablePoint(0, 0)],
'line': [ImmutablePoint(1, 10), ImmutablePoint(-2, 11)],
};
Но если невозможно судить о том, можно ли его опустить по контекстуconst
, вы не можете опуститьconst
ключевое слово, иначенепостоянный объект Например:
var a = const ImmutablePoint(1, 1); // 创建一个常量 (Creates a constant)
var b = ImmutablePoint(1, 1); // 不会创建一个常量 (Does NOT create a constant)
assert(!identical(a, b)); // 这两变量并不相同 (NOT the same instance!)
Подсказки к версии:
Только с тех пор, как Dart 2 может опустить на основе контекстной оценкиconst
ключевое слово.
Получить тип объекта
Вы можете использовать объект ObjectruntimeType
свойство получает тип объекта во время выполнения, т.е.Typeэкземпляр .
print('The type of a is ${a.runtimeType}');
До сих пор мы видели, какиспользовать своего рода. Оставшаяся часть этого раздела покажет вам, каквыполнитькласс.
переменная экземпляра
Ниже приведен пример объявления переменной экземпляра:
class Point {
double x; // 声明 double 变量 x 并初始化为 null。
double y; // 声明 double 变量 y 并初始化为 null
double z = 0; // 声明 double 变量 z 并初始化为 0。
}
Все неинициализированные переменные экземпляра имеют значениеnull
.
Все переменные экземпляра неявно объявляютGetterметод, переменные экземпляра неконечных типов также неявно объявляютSetterметод. ты можешь проверитьГеттеры и сеттерыПолучите больше информации об этом.
class Point {
double x;
double y;
}
void main() {
var point = Point();
point.x = 4; // 使用 x 的 Setter 方法。
assert(point.x == 4); // 使用 x 的 Getter 方法。
assert(point.y == null); // 默认值为 null。
}
Если вы инициализируете переменную экземпляра при ее объявлении (а не в конструкторе или другом методе), то значение переменной экземпляра устанавливается при создании экземпляра объекта перед конструктором и его списком инициализаторов.
Конструктор
Объявление функции с тем же именем, что и класс, объявляет конструктор (дляименованный конструкторТакже могут быть добавлены дополнительные идентификаторы). Большинство форм конструкторов являются генеративными конструкторами, которые используются для создания экземпляра класса:
class Point {
double x, y;
Point(double x, double y) {
// 还会有更好的方式来实现此逻辑,敬请期待。
this.x = x;
this.y = y;
}
}
использовать this
Ключевое слово относится к текущему экземпляру.
Памятка:
Используйте тогда и только тогда, когда возникают конфликты именthis
Ключевое слово имеет смысл, иначе Dart его проигнорирует.this
ключевое слово.
Процесс назначения переменных экземпляра в конструкторе аналогичен для большинства языков программирования, но Dart предоставляет специальный синтаксический сахар, упрощающий этот шаг:
class Point {
double x, y;
// 在构造函数体执行前用于设置 x 和 y 的语法糖。
Point(this.x, this.y);
}
конструктор по умолчанию
Если вы не объявите конструктор, Dart автоматически сгенерирует конструктор без параметров, и этот конструктор вызовет конструктор без параметров своего суперкласса.
Конструкторы не наследуются
Подкласс не наследует конструктор суперкласса, если подкласс не объявляет конструктор, будет только конструктор по умолчанию без аргументов.
именованный конструктор
Более явное намерение можно выразить, объявив несколько именованных конструкторов для класса:
class Point {
double x, y;
Point(this.x, this.y);
// 命名式构造函数
Point.origin()
: x = 0,
y = 0;
}
Помните, что конструкторы не могут быть унаследованы, что означает, что подклассы не могут наследовать названный конструктор родительского класса. Если вы хотите предоставить названный конструктор в подклассе с тем же именем, что и называемый конструктор родительского класса, вам нужно явно объявлено в подклассах.
Вызов конструктора родительского класса не по умолчанию
По умолчанию конструктор подкласса вызывает анонимный конструктор суперкласса без аргументов, и вызов будет выполнен до того, как будет выполнен код тела функции конструктора подкласса, если конструктор подкласса также имеетсписок инициализации, то список инициализации будет выполнен перед вызовом конструктора родительского класса.В общем случае порядок вызова тройки следующий:
- список инициализации
- Конструктор без аргументов родительского класса
- конструктор текущего класса
Если родительский класс не имеет анонимного конструктора без параметров, то дочерний класс должен вызвать один из конструкторов родительского класса.Указание конструктора родительского класса для конструктора дочернего класса необходимо использовать только перед телом конструктора (:
) указано.
В следующем примере конструктор класса Employee вызывает именованный конструктор родительского класса Person. Нажмите кнопку «Выполнить», чтобы выполнить пример кода.
Поскольку параметр передается конструктору суперкласса до выполнения конструктора подкласса, параметр также может быть выражением, например функцией:
class Employee extends Person {
Employee() : super.fromJson(defaultData);
// ···
}
Пожалуйста, обрати внимание:
Аргументы, переданные конструктору родительского класса, не могут использоватьthis
ключевое слово, потому что на этом этапе передачи параметров конструктор подкласса не был выполнен, а объект экземпляра подкласса не был инициализирован, поэтому все члены экземпляра не могут быть доступны, но члены класса могут.
список инициализации
В дополнение к вызову конструктора родительского класса переменные экземпляра также могут быть инициализированы до выполнения тела конструктора. Разделите каждую переменную экземпляра запятой.
// Initializer list sets instance variables before
// the constructor body runs.
// 使用初始化列表在构造函数体执行前设置实例变量。
Point.fromJson(Map<String, double> json)
: x = json['x'],
y = json['y'] {
print('In Point.fromJson(): ($x, $y)');
}
Пожалуйста, обрати внимание:
выражение списка инициализаторов = оператор справа не может использоватьthis
ключевое слово.
В режиме разработки вы можете использовать в списке инициализацииassert
для проверки входных данных:
Point.withAssert(this.x, this.y) : assert(x >= 0) {
print('In Point.withAssert(): ($x, $y)');
}
Использовать настройки списка инициализацииfinal
Поля очень удобны, в следующем примере используется список инициализации для установки трехfinal
значение переменной. Нажмите кнопку «Выполнить», чтобы выполнить пример кода.
конструктор перенаправления
Иногда конструктор в классе используется только для вызова других конструкторов в классе.В этом случае конструктор не имеет тела функции, просто используйте (:) после сигнатуры функции, чтобы указать другие конструкторы, на которые необходимо перенаправить:
class Point {
double x, y;
// 该类的主构造函数。
Point(this.x, this.y);
// 委托实现给主构造函数。
Point.alongXAxis(double x) : this(x, 0);
}
постоянный конструктор
Если объекты, сгенерированные классом, являются неизменяемыми, вы можете сделать их константами времени компиляции при их создании. Вы можете добавить перед конструктором классаconst
ключевое слово и убедитесь, что все переменные экземпляраfinal
для достижения этой функции.
class ImmutablePoint {
static const ImmutablePoint origin = ImmutablePoint(0, 0);
final double x, y;
const ImmutablePoint(this.x, this.y);
}
Экземпляр, созданный конструктором констант, не всегда является константой.использовать конструкторглава.
завод конструктор
использовать factory
Ключевое слово, идентифицирующее конструктор класса, сделает этот конструктор конструктором фабрики, что будет означать, что новый объект экземпляра не всегда будет возвращаться, когда экземпляр класса создается с использованием этого конструктора. Например, конструктор фабрики может возвращать экземпляр из кэша или возвращать экземпляр подтипа.
В следующем примереLogger
Фабричный конструктор возвращает объект из кеша иLogger.fromJson
Конструктор фабрики инициализирует конечную переменную из объекта JSON.
class Logger {
final String name;
bool mute = false;
// _cache 变量是库私有的,因为在其名字前面有下划线。
static final Map<String, Logger> _cache =
<String, Logger>{};
factory Logger(String name) {
return _cache.putIfAbsent(
name, () => Logger._internal(name));
}
factory Logger.fromJson(Map<String, Object> json) {
return Logger(json['name'].toString());
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
Памятка:
Недоступно в заводском конструктореthis
.
Конструктор фабрики вызывается так же, как и любой другой конструктор:
var logger = Logger('UI');
logger.log('Button clicked');
var logMap = {'name': 'UI'};
var loggerJson = Logger.fromJson(logMap);
метод
Методы — это функции, обеспечивающие поведение объекта.
метод экземпляра
Метод экземпляра объекта может обращаться к переменным экземпляра иthis
. следующееdistanceTo()
Метод является примером метода экземпляра:
import 'dart:math';
class Point {
double x, y;
Point(this.x, this.y);
double distanceTo(Point other) {
var dx = x - other.x;
var dy = y - other.y;
return sqrt(dx * dx + dy * dy);
}
}
оператор
Примеры метода: оператор имеет специальное имя. Dart позволяет использовать следующие имена определенных операторов:
< |
+ |
| |
[] |
---|---|---|---|
> |
/ |
^ |
[]= |
<= |
~/ |
& |
~ |
>= |
* |
<< |
== |
– |
% |
>> |
Памятка:
Вы можете заметить некоторыеоператорне появляется в списке, т.е.!=
. Потому что они просто синтаксический сахар. выражениеe1 != e2
Просто !(e1 == e2)
Синтаксический сахар для .
Для представления оператора перезаписи мы используемoperator
отметка к отметке. Ниже переписано+
и -
Примеры операторов:
class Vector {
final int x, y;
Vector(this.x, this.y);
Vector operator +(Vector v) => Vector(x + v.x, y + v.y);
Vector operator -(Vector v) => Vector(x - v.x, y - v.y);
// Operator == and hashCode not shown.
// ···
}
void main() {
final v = Vector(2, 3);
final w = Vector(2, 2);
assert(v + w == Vector(4, 5));
assert(v - w == Vector(0, 1));
}
Геттеры и сеттеры
Getter и Setter представляют собой пару специальных методов, используемых для чтения и записи объектов объекта. Как уже упоминалось выше, каждое свойство объекта экземпляра имеет неявный метод Getter. Если это не окончательное свойство, также будет метод сеттера. Ты можешь использоватьget
и set
Ключевое слово добавляет методы Getter и Setter для дополнительных свойств:
class Rectangle {
double left, top, width, height;
Rectangle(this.left, this.top, this.width, this.height);
// 定义两个计算产生的属性:right 和 bottom。
double get right => left + width;
set right(double value) => left = value - width;
double get bottom => top + height;
set bottom(double value) => top = value - height;
}
void main() {
var rect = Rectangle(3, 4, 20, 15);
assert(rect.left == 3);
rect.right = 12;
assert(rect.left == -8);
}
Преимущество использования геттеров и сеттеров заключается в том, что вы можете сначала использовать свои переменные экземпляра, а затем через некоторое время обернуть их в методы без изменения кода, то есть сначала определить их, а затем изменить, не затрагивая исходную логику.
Памятка:
Такие операторы, как приращение (++), будут выполняться правильно независимо от того, определен ли метод Getter. Чтобы избежать некоторых ненужных исключений, оператор вызывает геттер только один раз и сохраняет его значение во временной переменной.
абстрактный метод
Методы экземпляра, методы Getter и Setter могут быть абстрактными. Определите метод интерфейса, не создавая конкретную реализацию, и позвольте классу, который его реализует, реализовать метод. Абстрактные методы могут существовать только вабстрактный класссередина.
Абстрактный метод можно объявить, используя точку с запятой (;) вместо тела метода:
abstract class Doer {
// 定义实例变量和方法等等……
void doSomething(); // 定义一个抽象方法。
}
class EffectiveDoer extends Doer {
void doSomething() {
// 提供一个实现,所以在这里该方法不再是抽象的……
}
}
абстрактный класс
использовать ключевые словаabstract
Идентификация класса позволяет классу бытьабстрактный класс, абстрактный класс не будет создан. Абстрактные классы часто используются для объявления методов интерфейса и иногда имеют конкретные реализации методов. Если вы хотите, чтобы абстрактный класс создавался одновременно, вы можете определить егозавод конструктор.
Абстрактные классы часто содержатабстрактный метод. Вот пример абстрактного класса, который объявляет абстрактные методы:
// This class is declared abstract and thus
// can't be instantiated.
// 该类被声明为抽象的,因此它不能被实例化。
abstract class AbstractContainer {
// 定义构造函数、字段、方法等……
void updateChildren(); // 抽象方法。
}
неявный интерфейс
Каждый класс неявно определяет и реализует интерфейс, который содержит все экземпляры-члены класса и другие интерфейсы, реализованные классом. Если вы хотите создать класс A, поддерживающий вызов API класса B, и не хотите наследовать от класса B, вы можете реализовать интерфейс класса B.
Класс может передать ключевое словоimplements
для реализации одного или нескольких интерфейсов и реализации API, определенного каждым интерфейсом:
// A person. The implicit interface contains greet().
// Person 类的隐式接口中包含 greet() 方法。
class Person {
// _name 变量同样包含在接口中,但它只是库内可见的。
final _name;
// 构造函数不在接口中。
Person(this._name);
// greet() 方法在接口中。
String greet(String who) => '你好,$who。我是$_name。';
}
// Person 接口的一个实现。
class Impostor implements Person {
get _name => '';
String greet(String who) => '你好$who。你知道我是谁吗?';
}
String greetBob(Person person) => person.greet('小芳');
void main() {
print(greetBob(Person('小芸')));
print(greetBob(Impostor()));
}
Если вам нужно реализовать несколько интерфейсов классов, вы можете разделить каждый класс интерфейса запятой:
class Point implements Comparable, Location {...}
расширить класс
использовать extends
ключевое слово для создания подкласса и может использоватьsuper
Ключевое слово относится к родительскому классу:
class Television {
void turnOn() {
_illuminateDisplay();
_activateIrSensor();
}
// ···
}
class SmartTelevision extends Television {
void turnOn() {
super.turnOn();
_bootNetworkInterface();
_initializeMemory();
_upgradeApps();
}
// ···
}
Переопределить членов класса
Подклассы могут переопределять методы экземпляров суперклассов (включаяоператор), методы Getter и Setter. ты можешь использовать @override
аннотация, указывающая, что вы переопределяете элемент:
class SmartTelevision extends Television {
@override
void turnOn() {...}
// ···
}
ты можешь использовать covariant
ключевое словочтобы сузить код, который соответствуетбезопасность типаТип параметра метода или переменной экземпляра .
Пожалуйста, обрати внимание:
Если переопределить==
оператор, должен также переопределить объектhashCode
Геттерный метод . ты можешь проверитьРеализовать ключи картыУзнайте больше о переписывании==
и hashCode
пример.
метод noSuchMethod
Запускается, если вызывается метод или переменная экземпляра, которые не существуют в объекте.noSuchMethod
метод, вы можете переопределитьnoSuchMethod
метод для отслеживания и регистрации этого поведения:
class A {
// 除非你重写 noSuchMethod,否则调用一个不存在的成员会导致 NoSuchMethodError。
@override
void noSuchMethod(Invocation invocation) {
print('你尝试使用一个不存在的成员:' +
'${invocation.memberName}');
}
}
Вы можете вызвать нереализованный метод, только если выполняется одно из следующих условий:
- Приемник статичен
dynamic
тип. - Получатель имеет статический тип, определяет нереализованный метод (абстрактный подойдет), а динамический тип получателя реализует
noSuchMethod
метод и конкретная реализация иObject
разница в .
ты можешь проверитьСпецификация переадресации noSuchMethodПолучите больше информации об этом.
метод расширения
Методы расширения — это способ добавления функциональности к существующей библиотеке. Возможно, вы использовали его, не зная, что это метод расширения. Например, при использовании автозавершения кода в среде IDE рекомендуется использовать методы расширения наряду с обычными методами.
ВотString
Пример использования метода расширения в , назовем егоparseInt()
, это вstring_apis.dart
Определено в:
import 'string_apis.dart';
...
print('42'.padLeft(5)); // Use a String method.
print('42'.parseInt()); // Use an extension method.
Дополнительные сведения об использовании и реализации методов расширения см.страница метода расширения.
тип перечисления
Тип перечисления — это особый тип, также известный какenumerations или enums, используемый для определения некоторого фиксированного числа постоянных значений.
Using enums
использовать перечисление
использовать ключевые словаenum
чтобы определить тип перечисления:
enum Color { red, green, blue }
Вы можете использовать при объявлении типа перечислениязамыкающая запятая.
Каждое значение перечисления имеетindex
Метод Getter переменной-члена, который возвращает значение позиции с индексом 0. Например, индекс первого значения перечисления равен 0, а индекс второго значения перечисления равен 1. И так далее.
assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);
Чтобы получить все значения перечисления, используйте класс перечисленияvalues
метод для получения списка, содержащего их:
List<Color> colors = Color.values;
assert(colors[2] == Color.blue);
ты сможешьоператор переключенияИспользуйте перечисления в , но следует отметить, что каждый случай значений перечисления должен быть обработан, то есть каждое значение перечисления должно быть предложением case, иначе появится предупреждение:
var aColor = Color.blue;
switch (aColor) {
case Color.red:
print('红如玫瑰!');
break;
case Color.green:
print('绿如草原!');
break;
default: // 没有该语句会出现警告。
print(aColor); // 'Color.blue'
}
Типы перечисления имеют следующие два ограничения:
- Перечисления не могут быть подклассами, вы не можете смешивать их и не можете реализовать перечисление.
- Класс перечисления не может быть создан явно.
ты можешь проверитьСпецификация языка программирования DartПолучите больше информации об этом.
Добавьте функциональность в класс с помощью Mixins
Mixin — это шаблон метода для повторного использования кода в классе при множественном наследовании.
использовать with
ключевое слово, за которым следует имя класса Mixin для использования шаблона Mixin:
class Musician extends Performer with Musical {
// ···
}
class Maestro extends Person
with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}
Чтобы реализовать Mixin, создайте класс, который наследуется от Object и не объявляет конструктор. Если вы не хотите, чтобы класс использовался как обычный класс, используйте ключевое словоmixin
альтернативаclass
. Например:
mixin Musical {
bool canPlayPiano = false;
bool canCompose = false;
bool canConduct = false;
void entertainMe() {
if (canPlayPiano) {
print('Playing piano');
} else if (canConduct) {
print('Waving hands');
} else {
print('Humming to self');
}
}
}
можно использовать ключевые словаon
Чтобы указать, какие классы могут использовать класс Mixin, например, есть класс Mixin A, но A может использоваться только классом B, вы можете определить A следующим образом:
class Musician {
// ...
}
mixin MusicalPerformer on Musician {
// ...
}
class SingerDancer extends Musician with MusicalPerformer {
// ...
}
In the preceding code, only classes that extend or implement the Musician
class can use the mixin MusicalPerformer
. Because SingerDancer
extends Musician
, SingerDancer
can mix in MusicalPerformer
.
Подсказки к версии:
mixin
Ключевое слово поддерживалось только в кавычках в Dart 2.1. Код из более ранних версий обычно используетabstract class
заменять. ты можешь проверитьЖурнал изменений Dart SDK и 2.1 спецификация миксинаПолучите больше информации об изменениях Mixin в версии 2.1.
переменные и методы класса
использовать ключевые словаstatic
Вы можете объявлять переменные класса или методы класса.
статическая переменная
Статические переменные (т. е. переменные класса) часто используются для объявления переменных состояния и констант, принадлежащих области видимости класса:
class Queue {
static const initialCapacity = 16;
// ···
}
void main() {
assert(Queue.initialCapacity == 16);
}
Статические переменные не инициализируются до тех пор, пока они не будут использованы впервые.
Памятка:
Код этой статьи соответствуетРуководство по рекомендациям по стилюсоглашения об именах в , использовать驼峰式大小写
назвать константу.
статический метод
Статические методы (то есть методы класса) не могут работать с экземплярами, поэтому не могут использоватьthis
. Но они могут обращаться к статическим переменным. Как показано в следующем примере, вы можете вызывать статические методы непосредственно в классе:
import 'dart:math';
class Point {
double x, y;
Point(this.x, this.y);
static double distanceBetween(Point a, Point b) {
var dx = a.x - b.x;
var dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
}
void main() {
var a = Point(2, 2);
var b = Point(4, 4);
var distance = Point.distanceBetween(a, b);
assert(2.8 < distance && distance < 2.9);
print(distance);
}
Памятка:
Для некоторых универсальных или часто используемых статических методов их следует определять как функции верхнего уровня, а не как статические методы.
Вы можете использовать статические методы как константы времени компиляции. Например, вы можете передать статический метод в качестве параметра конструктору констант.
Дженерики
Если вы посмотрите документацию по API для массивов, вы найдете массивыListФактический типList<E>
. Обозначение указывает, что массив представляет собойДженерики(или параметризованный тип)как правилоИспользуйте букву для представления параметров типа, таких как E, T, S, K, V и т. д.
Зачем использовать дженерики?
Обобщения часто используются в ситуациях, когда требуется безопасность типов, но они также могут быть полезны для выполнения кода:
- Правильное указание дженериков может улучшить генерацию кода.
- Использование дженериков может уменьшить дублирование кода.
Например, если вы хотите объявить массив, который может содержать только типы String, вы можете объявить массив какList<String>
(произносится как «список строк»), таким образом вы можете легко избежать многих проблем, вызванных помещением в массив переменных, не являющихся строками, а компилятор и другие люди, читающие код, могут легко обнаружить и локализовать проблему:
var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
names.add(42); // Error
Еще одна причина использовать дженерики — уменьшить дублирование кода. Обобщения позволяют использовать одно и то же объявление интерфейса между несколькими реализациями разных типов.Например, в следующем примере объявляется интерфейс для класса для кэширования объектов:
abstract class ObjectCache {
Object getByKey(String key);
void setByKey(String key, Object value);
}
Вскоре вы можете снова захотеть сделать кеш для объектов String, поэтому есть еще один класс для кеша String:
abstract class StringCache {
String getByKey(String key);
void setByKey(String key, String value);
}
Если через какое-то время вы захотите создать класс и для чисел, такого кода много...
В настоящее время вы можете рассмотреть возможность использования дженериков для объявления класса и позволить различным типам кешей реализовать класс для создания различных конкретных реализаций:
abstract class Cache<T> {
T getByKey(String key);
void setByKey(String key, T value);
}
В приведенном выше коде T является альтернативным типом. Он эквивалентен заполнителю типа, и разработчик указывает конкретный тип при вызове интерфейса.
Использование литералов коллекций
Литералы List, Set и Map также могут быть параметризованы. Чтобы определить параметризованный список, просто добавьте перед квадратными скобками<type>
; Чтобы определить параметризованную карту, просто добавьте перед фигурными скобками<keyType, valueType>
:
var names = <String>['小芸', '小芳', '小民'];
var uniqueNames = <String>{'小芸', '小芳', '小民'};
var pages = <String, String>{
'index.html': '主页',
'robots.txt': '网页机器人提示',
'humans.txt': '我们是人类,不是机器'
};
Используйте конструкторы с параметрами типа
Обобщения также можно использовать при вызове конструкторов, просто используйте угловые скобки после имени класса (<...>
) для переноса одного или нескольких типов:
var nameSet = Set<String>.from(names);
Следующий код создает объект Map с ключами типа Int и значениями типа View:
var views = Map<int, View>();
Общие коллекции и типы, которые они содержат
Общий тип Dart:затвердевший, что означает, что информация о типе сохраняется даже во время выполнения:
var names = List<String>();
names.addAll(['小芸', '小芳', '小民']);
print(names is List<String>); // true
Памятка:
В отличие от Java, дженерики в Java — это типы.стереть, что означает, что универсальный тип удаляется во время выполнения. В Java вы можете сказать, является ли объект списком, но вы не можете сказать, является ли объект списком.List<String>
.
Ограничить параметризованные типы
Иногда при использовании дженериков вам может понадобиться ограничить диапазон типов дженериков.В этом случае вы можете использоватьextends
Ключевые слова:
class Foo<T extends SomeBaseClass> {
// 具体实现……
String toString() => "'Foo<$T>' 的实例";
}
class Extender extends SomeBaseClass {...}
Затем вы можете использоватьSomeBaseClass
Или его подкласс в качестве общего параметра:
var someBaseClassFoo = Foo<SomeBaseClass>();
var extenderFoo = Foo<Extender>();
В настоящее время вы также можете указать универсальный тип без параметров.В этом случае тип универсального типа без параметровFoo<SomeBaseClass>
:
var foo = Foo();
print(foo); // 'Foo<SomeBaseClass>' 的实例 (Instance of 'Foo<SomeBaseClass>')
не будуSomeBaseClass
Тип в качестве универсального параметра приведет к ошибке компиляции:
var foo = Foo<Object>();
Используйте общие методы
Сначала Dart поддерживал только указание дженериков в объявлениях классов, но теперь дженерики также можно использовать в методах, называемыхобщий метод:
T first<T>(List<T> ts) {
// 处理一些初始化工作或错误检测……
T tmp = ts[0];
// 处理一些额外的检查……
return tmp;
}
методfirst<T>
ДженерикиT
Может использоваться в следующих местах:
- Тип возвращаемого значения функции (
T
). - тип параметра (
List<T>
). - тип локальной переменной (
T tmp
).
ты можешь проверитьИспользуйте общие функцииПолучите больше информации о дженериках.
Библиотеки и видимость
import
и library
Ключевые слова могут помочь вам создать модульную и совместно используемую кодовую базу. Кодовая база не только предоставляет API, но также действует как оболочка: элементы, начинающиеся с подчеркивания (_), видны только в кодовой базе.Каждая программа Dart — это библиотека, даже если ключевое слово не используетсяlibrary
указано.
Библиотека Dart может использоватьпакетный инструментдля публикации и развертывания.
использовать библиотеку
использовать import
чтобы указать пространство имен, чтобы другие библиотеки могли получить к нему доступ.
Например, вы можете импортировать кодовую базуdart:htmlЧтобы использовать связанные API в Dart Web:
import 'dart:html';
import
Единственным параметром является URI, используемый для указания кодовой базы, для встроенных библиотек Dart используйтеdart:xxxxxx
форма. Для других библиотек вы можете использовать путь файловой системы или начать сpackage:xxxxxx
форма.package:xxxxxx
Указанная библиотека предоставляется через диспетчер пакетов (например, инструмент pub):
import 'package:test/test.dart';
Памятка:
URIозначает универсальный идентификатор ресурса.
URL(унифицированный указатель ресурсов) — это общий URI.
Укажите префикс библиотеки
Если вы импортируете две кодовые базы с конфликтующими идентификаторами, вы можете указать префикс для одной из них. Например, если и в библиотеке1, и в библиотеке2 есть класс Element, то это можно сделать так:
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
// 使用 lib1 的 Element 类。
Element element1 = Element();
// 使用 lib2 的 Element 类。
lib2.Element element2 = lib2.Element();
часть библиотеки импорта
Если вы хотите использовать только часть кодовой базы, вы можете выборочно импортировать кодовую базу. Например:
// 只导入 lib1 中的 foo。(Import only foo).
import 'package:lib1/lib1.dart' show foo;
// 导入 lib2 中除了 foo 外的所有。
import 'package:lib2/lib2.dart' hide foo;
Ленивая загрузка библиотек
ленивая загрузка(также часто упоминается какленивая загрузка) позволяет приложению загружать базу кода, когда это необходимо. Ниже приведены сценарии, в которых может использоваться отложенная загрузка:
- Для того, чтобы сократить время инициализации приложения.
- Проводите A/B-тестирование, например, тестирование различных реализаций различных алгоритмов.
- Загружает редко используемые функции, такие как дополнительные экраны и диалоги.
В настоящее время только dart2js поддерживает ленивую загрузку.Flutter, Dart VM и DartDevc в настоящее время не поддерживают отложенную загрузку. ты можешь проверитьissue #33118 и issue #27776Получите больше информации об этом.
использовать deferred as
ключевое слово для определения кодовых баз, которые необходимо лениво загружать:
import 'package:greetings/hello.dart' deferred as hello;
Когда вам действительно нужно использовать API в библиотеке, сначала вызовите егоloadLibrary
Библиотека загрузки функций:
Future greet() async {
await hello.loadLibrary();
hello.printGreeting();
}
В предыдущем коде используйтеawait
Ключевое слово приостанавливает выполнение кода до загрузки библиотеки. больше оasync
и await
Для получения информации см.Асинхронная поддержка.
loadLibrary
Неважно, можно ли вызывать функцию несколько раз, кодовая база будет загружена только один раз.
При использовании отложенной загрузки следует помнить о нескольких вещах:
- Константы в кодовой базе с отложенной загрузкой необходимо импортировать, когда кодовая база загружена, и они не будут импортированы, когда она не загружена.
- Типы из лениво загружаемых библиотек нельзя использовать при импорте файлов. Если вам нужно использовать типы, подумайте о переносе типов интерфейса в другую библиотеку и сделайте так, чтобы обе библиотеки импортировали библиотеку интерфейса по отдельности.
- Dart будет неявно помещать
loadLibrary
метод импортирован для использованияdeferred as 命名空间
в классе .loadLibrary
Функция возвращаетFuture.
Библиотека реализации
чекСоздать зависимый пакет библиотекиДоступны советы по реализации пакетов библиотек, в том числе:
- Как организовать исходные файлы для библиотеки.
- как пользоваться
export
Заказ. - когда использовать
part
Заказ. - когда использовать
library
Заказ. - Как реализовать поддержку многоплатформенных библиотек с помощью команд импорта и экспорта.
Асинхронная поддержка
В кодовой базе Dart множество возвратовFuture или StreamОбъектные функции, эти функцииасинхронныйДа, они вернутся непосредственно перед завершением трудоемкой операции (например, ввода-вывода), не дожидаясь завершения трудоемкой операции.
async
и await
Ключевые слова используются для реализации асинхронного программирования и делают ваш код синхронным.
Работа с фьючерсами
Вы можете получить результат завершения исполнения Future двумя способами:
- использовать
async
иawait
; - Используйте Future API, см. конкретное описаниеОбзор библиотеки.
использовать async
и await
Код для асинхронен, но немного похож на синхронный код. Например, в приведенном ниже коде используетсяawait
Дождитесь результата выполнения асинхронной функции.
await lookUpVersion();
Должен использоваться с ключевым словом asyncасинхронная функцияиспользовать вawait
:
Future checkVersion() async {
var version = await lookUpVersion();
// 使用 version 继续处理逻辑
}
Памятка:
Хотя асинхронная функция может выполнять трудоемкие операции, она не ждет завершения этих трудоемких операций.await
выражение (строка кода) Возвращает объект Future, а затем ожидает продолжения выражения ожидания после реализации.
использовать try
,catch
а также finally
обращаться с использованиемawait
Исключение, вызванное:
try {
version = await lookUpVersion();
} catch (e) {
// 无法找到版本时做出的反应
}
Вы можете использовать несколько раз в асинхронных функцияхawait
ключевое слово. Например, следующий код ожидает результата функции три раза:
var entrypoint = await findEntrypoint();
var exitCode = await runExecutable(entrypoint, args);
await flushThenExit(exitCode);
await 表达式的返回值通常是一个 Future 对象;如果不是的话也会自动将其包裹在一个 Future 对象里。Future 对象代表一个“承诺”,await 表达式会阻塞直到需要的对象返回。
при использованииawait
вызвать ошибку компиляции, когдаawait
используется в асинхронной функции. Например, если вы хотите использовать в функции main()await
,Так main()
функция должна использоватьasync
Идентификатор ключевого слова.
Future main() async {
checkVersion();
print('在 Main 函数中执行:版本是 ${await lookUpVersion()}');
}
Асинхронная функция оператора
асинхронная функцияэто тело функции, заданноеasync
Функция, помеченная ключевым словом.
поставить ключевое словоasync
Добавьте к функции и верните объект Future. Предположим, есть следующий метод, который возвращает объект String:
String lookUpVersion() => '1.0.0';
Измените его на асинхронную функцию, которая возвращает Future:
Future<String> lookUpVersion() async => '1.0.0';
Обратите внимание, что телу функции не обязательно использовать Future API. Dart создает объекты Future, если это необходимо.
Если функция не возвращает допустимое значение, вам необходимо установить тип возвращаемого значенияFuture<void>
.
О будущем,async
и await
Для ознакомления с использованием вы можете обратиться к этой кодовой лаборатории:asynchronous programming codelab.
Обработка потоков
Если вы хотите получить значение из потока, у вас есть два варианта:
- использовать
async
ключевое слово иАсинхронный цикл(использоватьawait for
идентификатор ключевого слова). - Используйте потоковый API. Для получения подробной информации см.Обзор библиотеки.
Памятка:
в настоящее время используюawait for
ключевое слово, убедитесь, что оно делает логику кода более понятной и действительно требует ожидания выполнения всех результатов. Например, его обычно не следует использовать в прослушивателях событий пользовательского интерфейса.await for
ключевое слово, потому что поток событий, создаваемых фреймворками пользовательского интерфейса, бесконечен.
Определение асинхронного цикла с помощью await for выглядит следующим образом:
await for (varOrType identifier in expression) {
// 每当 Stream 发出一个值时会执行
}
表达式
должен иметь тип Stream. Последовательность выполнения следующая:
- Подождите, пока Stream вернет данные.
- Выполните тело цикла, используя данные, возвращенные Stream в 1.
- Повторяйте шаги 1 и 2, пока не будут возвращены данные потока.
использовать break
и return
Оператор может перестать получать данные Stream, тем самым разорвав цикл и отменив регистрацию прослушивания Stream.
Если вы столкнулись с ошибкой времени компиляции при реализации асинхронного цикла for, убедитесь, чтоawait for
в асинхронной функции.Например, чтобыmain()
Используйте асинхронный цикл for в функции,main()
Тело функции должно быть помечено какasync
:
Future main() async {
// ...
await for (var request in requestServer) {
handleRequest(request);
}
// ...
}
Вы можете обратиться к обзору библиотеки оdart:asyncдля получения дополнительной информации об асинхронном программировании.
Строитель
Когда вам нужно лениво сгенерировать последовательность значений, рассмотрите возможность использованиягенераторная функция. Dart имеет встроенную поддержку двух форм методов генератора:
Добавив к функцииsync*
ключевое слово и установите тип возвращаемого значения Iterable для реализацииСинхронизироватьгенераторная функция, используемая в функцииyield
оператор для передачи значений:
Iterable<int> naturalsTo(int n) sync* {
int k = 0;
while (k < n) yield k++;
}
выполнить асинхронныйФункции генератора аналогичны синхронизации, за исключением того, что ключевое словоasync*
И возвращаемое значение — Stream:
Stream<int> asynchronousNaturalsTo(int n) async* {
int k = 0;
while (k < n) yield k++;
}
Если генератор вызывается рекурсивно, используйтеyield*
Заявление улучшает производительность выполнения:
Iterable<int> naturalsDownFrom(int n) sync* {
if (n > 0) {
yield n;
yield* naturalsDownFrom(n - 1);
}
}
вызываемый класс
Реализуя классcall()
метод, который позволяет использовать экземпляр класса в режиме, подобном вызову функции.
В приведенном ниже примереWannabeFunction
Класс определяет функцию call(), функция принимает три строковых параметра, тело функции объединяет три строки, разделяет строки пробелами и добавляет восклицательный знак в конце. Нажмите кнопку «Выполнить», чтобы выполнить код.
карантинная область
Большинство компьютеров, даже на мобильных платформах, используют многоядерные процессоры. Чтобы эффективно использовать многоядерную производительность, разработчики обычно используют общую память, чтобы позволить потокам выполняться одновременно. Однако совместное использование данных несколькими потоками часто приводит к ряду потенциальных проблем и приводит к некорректной работе кода.
Чтобы решить проблему параллелизма, вызванную многопоточностью, Dart использует изоляты вместо потоков, и весь код Dart выполняется в одном потоке.isolate середина. Каждый изолят имеет свою собственную динамическую память, чтобы другие изоляты не могли получить доступ к его состоянию.
Для получения дополнительной информации вы можете обратиться к следующим документам:
- Асинхронное программирование Dart: карантины и цикл событий
- dart:изолировать Справочник по APIпредставилIsolate.spawn() и TransferableTypedDataиспользование
- Background parsing cookbook on the Flutter site
- О сайте FlutterФоновый разборПоваренная книга
определение типа
В языке Dart функции — это такие объекты, как String и Number, и вы можете использоватьопределение типа(или называетсяпсевдоним типа метода), чтобы назвать тип функции. При назначении функции этого типа функции переменной с помощью именования функций определение типа сохраняет связанную информацию о типе.
Например, следующий код не использует определения типов:
class SortedCollection {
Function compare;
SortedCollection(int f(Object a, Object b)) {
compare = f;
}
}
// 简单的不完整实现。
int sort(Object a, Object b) => 0;
void main() {
SortedCollection coll = SortedCollection(sort);
// 我们知道 compare 是一个函数类型的变量,但是具体是什么样的函数却不得而知。
assert(coll.compare is Function);
}
В приведенном выше коде, когда параметрf
назначить вcompare
, информация о типе функции теряется, здесьf
Тип этой функции(Object, Object) → int
(→ означает возврат), конечно, этот тип также является подклассом Function, но будетf
назначить вcompare
Задний,f
тип (Object, Object) → int
будет потерян. мы можем использоватьtypedef
Явно сохранить информацию о типе:
typedef Compare = int Function(Object a, Object b);
class SortedCollection {
Compare compare;
SortedCollection(this.compare);
}
// 简单的不完整实现。
int sort(Object a, Object b) => 0;
void main() {
SortedCollection coll = SortedCollection(sort);
assert(coll.compare is Function);
assert(coll.compare is Compare);
}
Памятка:
В настоящее время определения типов можно использовать только для типов функций, но это может измениться в будущем.
Поскольку определение типа — это всего лишь псевдоним, мы можем использовать его для определения метода любого типа функции:
typedef Compare<T> = int Function(T a, T b);
int sort(int a, int b) => a - b;
void main() {
assert(sort is Compare<int>); // True!
}
метаданные
Использование метаданных может добавить в код дополнительную информацию. Метаданные снабжены аннотациями@
начинается с , за которым следует константа времени компиляции (например,deprecated
) или вызвать конструктор констант.
В Dart есть две аннотации, которые можно использовать во всем коде:@deprecated
и @override
. ты можешь проверитьрасширить классполучить о@override
Примеры использования . Далее следует использовать@deprecated
Пример:
class Television {
/// _弃用: 使用 [turnOn] 替代_
@deprecated
void activate() {
turnOn();
}
/// 打开 TV 的电源。
void turnOn() {...}
}
Аннотации метаданных можно настраивать. В следующем примере определяется аннотация @todo с двумя параметрами:
library todo;
class Todo {
final String who;
final String what;
const Todo(this.who, this.what);
}
Пример использования аннотации @todo:
import 'todo.dart';
@Todo('seth', 'make this do something')
void doSomething() {
print('do something');
}
Метаданные можно использовать перед объявлением библиотеки, класса, определения типа, параметра типа, конструктора, фабрики, функции, поля, параметра или переменной, а также перед импортом или экспортом. Информацию о метаданных можно получить во время выполнения с помощью отражения.
Примечания
Dart поддерживает однострочные комментарии, многострочные комментарии и комментарии к документации.
однострочный комментарий
Однострочные комментарии начинаются с//
Начинать. все в//
и конец строки игнорируются компилятором.
void main() {
// TODO: refactor into an AbstractLlamaGreetingFactory?
print('Welcome to my Llama farm!');
}
многострочный комментарий
Многострочные комментарии начинаются с/*
начать с*/
конец. все в/*
и */
Содержимое между ними игнорируется компилятором (комментарии к документации не будут игнорироваться), а многострочные комментарии могут быть вложенными.
void main() {
/*
* This is a lot of work. Consider raising chickens.
Llama larry = Llama();
larry.feed();
larry.exercise();
larry.clean();
*/
}
Примечания к документации
Комментарии к документации могут быть многострочными или однострочными.///
или /**
Начинать. Использовать на последовательных строках///
Имеет тот же эффект, что и многострочный комментарий документа.
В комментариях к документации компилятор Dart игнорирует весь текст, если он не заключен в квадратные скобки. Используйте квадратные скобки для обозначения классов, методов, полей, переменных верхнего уровня, функций и параметров. Символы в круглых скобках разрешаются в лексическом домене документированного элемента программы.
Вот комментарий к документации, ссылающийся на другие классы и члены:
/// A domesticated South American camelid (Lama glama).
///
/// Andean cultures have used llamas as meat and pack
/// animals since pre-Hispanic times.
class Llama {
String name;
/// Feeds your llama [Food].
///
/// The typical llama eats one bale of hay per week.
void feed(Food food) {
// ...
}
/// Exercises your llama with an [activity] for
/// [timeLimit] minutes.
void exercise(Activity activity, int timeLimit) {
// ...
}
}
В сформированном документе[Food]
будет ссылкой на документацию API для класса Food.
Разбирайте код Dart и создавайте HTML-документы, вы можете использовать SDK вИнструмент для создания документацииПример создания документа см.Dart API documentationСоветы по структуре документа см. в документации:Guidelines for Dart Doc Comments..
Суммировать
На этой странице представлен обзор функций, обычно используемых в языке Dart. Есть еще много функций, которые еще предстоит реализовать, но мы надеемся, что они не нарушат существующий код. Для получения дополнительной информации см.Спецификация языка Dart и Эффективное руководство по языку Dart.
Чтобы узнать больше о базовой библиотеке Dart, см.Обзор базовой библиотеки Dart