#dart
Вопрос:
Есть ли какая-либо разница между использованием неявного приведения для приведения в dart и ключевым словом «as»? Приведут ли они к той же (или аналогичной) ошибке во время выполнения, если тип не соответствует ожиданиям?
Например:
dynamic foo = "blah";
String boo = foo; // is this
String boo2 = foo as String; // the same as this?
Ответ №1:
Нет. И да. TL;DR: Не беспокойтесь о разнице, просто делайте то, что читается лучше всего.
Если ваша программа верна, и слепки будут успешными, то вряд ли будет какая-то разница.
При выводе типов String boo = foo;
будет выводиться тип foo
с контекстным типом String
. Если результирующий статический тип foo
then оказывается dynamic
, то это подразумевает неявное понижение от dynamic
до `Строки.
Для String boo = foo as String;
статического типа foo
выводится без типа контекста. Независимо от того, каков результирующий статический тип, он будет приведен String
во время выполнения.
Вы можете увидеть разницу между этими двумя, если у вас есть более сложное выражение, чем просто переменная foo
:
T first<T extends dynamic>(List<T> list) => list.first;
String boo = first([1]); // <- compile-time error
String boo2 = first([1]) as String;
В этом примере вы получаете ошибку во время компиляции в boo
строке, потому что компилятор знает, что список должен быть a List<String>
. В boo2
строке нет ошибки , потому что список должен быть только a List<dynamic>
, и все, что first
возвращается, затем динамически преобразуется String
.
Более надуманным примером может быть:
T firstOrDefault<T extends dynamic>(List<T> list) {
if (list.isEmpty) {
// Invent some default values for known types.
if (null is T) return null as T;
if (0 is T) return 0 as T;
if (0.0 is T) return 0.0 as T;
if ("" is T) return "" as T;
if (false is T) return false as T;
throw UnsupportedError("No default value for the needed type");
}
return list.first;
}
String boo = firstOrDefault([]); // <- returns "", with null safety.
String boo2 = firstOrDefault([]) as String; // <- returns null, throws.
(Выполнение такого рода специализации параметров типа не является рекомендуемым стилем программирования. Он слишком хрупок именно потому, что на него могут непредсказуемым образом повлиять тонкие изменения статических типов.).
Игнорируя вывод и статическую проверку, во время выполнения нет большой разницы. Если foo
это просто простое выражение со статическим типом dynamic
, то язык требует, чтобы String
в обеих ситуациях он был понижен.
Тем не менее, веб-компилятор Dart2JS может включать необоснованные оптимизации, которые в основном полностью исключают неявные сокращения (поскольку «оптимизация» предполагает, что они были бы успешными), и продолжать работу с потенциально неверными значениями, передаваемыми по типу. По этой причине некоторые люди (в основном те, кто программирует для Интернета) могут предпочесть использовать неявные сокращения по сравнению с явными сокращениями.
Dart с нулевой безопасностью имеет только неявные исходы из dynamic
. Вы всегда можете принудительно удалить неявное понижение из любого типа, выполнив:
String boo3 = foo as dynamic;
Это as dynamic
свободное приведение, оно не влияет во время выполнения (оно не может завершиться ошибкой, и компилятор это знает), поэтому все, что оно делает,-это изменяет статический тип выражения … к чему-то, что вводит неявное понижение, которое компилятор dart2js затем (необоснованно) также проигнорирует.
(Используйте с осторожностью, как и во всем, что связано dynamic
с этим . Кроме того, анализатор может предупредить о «ненужном повышении».)