Как Js .cast () выполняет проверку типов? - PullRequest
1 голос
/ 26 мая 2020

Я использую GWT 2.9 с element2-1.0.0-RC1.

Следующий код генерирует ClassCastException во время выполнения:

DocumentRange documentRange = Js.cast(DomGlobal.document); // Fails
Range range = documentRange.createRange(); // Never reaches here

Когда я перехожу на использование Js.uncheckedCast(), он завершается успешно:

DocumentRange documentRange = Js.uncheckedCast(DomGlobal.document);
Range range = documentRange.createRange(); // Works

документация для Js.uncheckedCast() говорит:

«Вы всегда должны предпочесть регулярное приведение по сравнению с этим (если вы не знаете, что делаете!)»

Я не знаю, зачем мне это нужно, поэтому нервничаю. Может ли кто-нибудь объяснить, как Js.cast() выполняет проверку типов и почему мне нужно использовать Js.uncheckedCast() в этом случае?

1 Ответ

5 голосов
/ 26 мая 2020

Js.cast() - это способ немного обмануть и сделать что-то, что язык Java не разрешает, но может быть законным. Игнорируя «как это на самом деле работает», идея состоит в том, что теперь вы можете избавиться от проблем, при которых Java будет жаловаться, даже если окажется, что это git.

Примером может быть a java.lang.Double или double и хотите рассматривать его как JsNumber, чтобы вы могли вызвать для него toPrecision (2). Поскольку java.lang.Double является окончательным, приведение к несвязанному типу незаконно, но Java не знает, что в GWT Double на самом деле просто js Number. Итак, вместо этого вы можете выполнить приведение с помощью Js.cast(). Компилятор вставит туда проверку типа среды выполнения, проверяя во время выполнения, что ваш номер на самом деле является экземпляром JS Number.

Другим примером может быть попытка расширить некоторый собственный тип, предоставляемый elemental2, либо для реализации обходной путь для отсутствующей функции, или сделать что-то, специфичное для браузера c. Ваш новый класс может не расширять существующий класс - с точки зрения JS это нормально, вы просто описываете API, который, как вы знаете, будет существовать во время выполнения. Таким образом, нам нужно избегать языковой проверки Java «имеет ли это приведение вообще смысла?» И просто сказать компилятору, чтобы он попробовал это.

С другой стороны, вы можете «l * 1054» * "компилятору с Js.uncheckedCast(). Это используется в тех случаях, когда вы даже просите среду выполнения пропустить проверку и просто делать вид, что она сработает. Это может позволить вам делать странные вещи, например обрабатывать строки как массивы или решать кросс-фреймовые проблемы. Проверка времени выполнения не будет произведена, поэтому вместо правильного ClassCastException вы можете просто получить TypeError, если метод / свойство отсутствует.


В elemental2-dom 1.0.0-RC1 есть класс с именем DocumentRange, но на самом деле это не имеет никакого смысла - он объявлен как класс, что означает, что его можно проверить по типу в JS, но браузер spe c говорит, что это должен быть «интерфейс» (что в JS -land означает, что это просто описание типа, а не что-то, что вы можете проверить). https://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level2 -DocumentRange-method-createRange

Эта ошибка унаследована от компилятора закрытия, который утверждает, что у него есть конструктор: https://github.com/google/closure-compiler/blob/6a418aa/externs/browser/w3c_range.js#L241 -L251

Исправление предназначено для того, чтобы компилятор closure называл это интерфейсом, и чтобы вы могли его использовать в новом выпуске elemental2.


Есть два обходных пути. можно сделать здесь. Первый - обмануть с Js.uncheckedCast(DomGlobal.document) и сказать: «Да, я знаю, что Document не instanceof DocumentRange, но это потому, что такого класса как DocumentRange не существует, так что просто представьте, что это сработало, чтобы я мог позвонить createRange() на нем ». Это то, что вы уже делаете - он скрывает факт наличия ошибки, но в конце концов работает.

«Правильный» ответ - объявить свой собственный DocumentRange и выполнить Js.cast() вместо этого. Это по-прежнему мерзко - вы должны поддерживать свой новый интерфейс, пока закрытие не будет исправлено, а затем будет выпущен elemental2, а затем вы должны не забыть очистить его.

В этом случае я бы посоветовал солгать GWT и использование Js.uncheckedCast() - здесь есть только один метод, и вряд ли он существенно изменится.

...