2015-06-14 4 views
3

Я новичок в Дарте и просто изучаю основы.Проверка, если дополнительный параметр указан в Dart

The Dart-Homepage показывает следующее:

It turns out that Dart does indeed have a way to ask if an optional parameter was provided when the method was called. Just use the question mark parameter syntax.

Here is an example:

void alignDingleArm(num axis, [num rotations]) { 
    if (?rotations) { 
    // the parameter was really used 
    } 
} 

Так что я написал простой сценарий тестирования для обучения:

import 'dart:html'; 

void main() { 

    String showLine(String string, {String printBefore : "Line: ", String printAfter}){ 
    // check, if parameter was set manually: 
    if(?printBefore){ 
     // check, if parameter was set to null 
     if(printBefore == null){ 
     printBefore = ""; 
     } 
    } 
    String line = printBefore + string + printAfter; 
    output.appendText(line); 
    output.appendHtml("<br />\n"); 
    return line; 
    } 

    showLine("Hallo Welt!",printBefore: null); 

} 

дротик-редактор уже отмечает вопросительный как Error:

Multiple markers at this line 
- Unexpected token '?' 
- Conditions must have a static type of 
'bool' 

При запуске сценария в Dartium JS-Console показывает следующее Ошибка:

Internal error: 'http://localhost:8081/main.dart': error: line 7 pos 8: unexpected token '?' 
if(?printBefore){ 
^

Я знаю, что было бы достаточно, чтобы проверить, если printBefore имеет нулевое значение, но я хочу, чтобы выучить язык.

Кто-нибудь знает причину этой проблемы? Как проверить, установлен ли параметр вручную?

ответ

4

Эта функция существовала в какой-то момент разработки Дарта, но она была удалена снова, потому что это вызвало больше осложнений, чем устранение, без решения проблемы, которая на самом деле нуждалась в решении - пересылка параметров по умолчанию.

Если у вас есть функция foo([x = 42]) и вы хотите функцию, чтобы направить на него, bar([x]) => f(x);, то, так как foo может на самом деле сказать, если x передается или нет, вы на самом деле в конечном итоге написание bar([x]) => ?x ? foo(x) : foo();. Это было хуже чем вы должны были сделать без оператора ?_.

Идеи возникли из-за наличия bar([x]) => foo(?:x) или чего-то, что было поставлено на x, если бы оно присутствовало, а не если оно отсутствовало (я больше не помню фактический предложенный синтаксис), но это быстро стало сложным, fx конвертировало именованные аргументы в позиционные - bar({x,y}) => foo(?:x, ?:y); - что если y был предоставлен и x не было. Это было действительно просто плохое решение для проблемы с саморазрушением.

Итак, функция ?x была откинута назад. Все необязательные параметры имеют значение по умолчанию, которое передается, если в вызове нет соответствующего аргумента. Если вы хотите перенаправить необязательный параметр, вам нужно знать значение по умолчанию для функции, к которой вы пересылаете.

Для большинства аргументов функции объявленное значение по умолчанию: null, с внутренним оператором if (arg == null) arg = defaultValue;, чтобы исправить его. Это означает, что значение null может быть отправлено напрямую без какой-либо путаницы.

Некоторые аргументы имеют значение по умолчанию null. Это в основном логические аргументы, но есть и другие случаи. Я рекомендую использовать null для всех, кроме названных логических параметров (потому что они действительно должны быть с именем больше, чем они должны быть необязательными).По крайней мере, если нет веских оснований не делать этого - чтобы гарантировать, что все подклассы будут иметь одинаковое значение по умолчанию для параметра метода (который может быть веской причиной или нет и должен использоваться судебно).

Если у вас есть необязательный параметр, который также может принимать null в качестве значения ... рассмотрите, действительно ли он должен быть факультативным, или вам просто нужна другая функция с еще одним аргументом. Или, может быть, вы можете ввести другое значение «отсутствующего аргумента» по умолчанию. Пример:

abstract class C { foo([D something]); } 
class _DMarker implements D { const _DMarker(); } 
class _ActualC { 
    foo([D something = const _DMarker()]) { 
    if (something == const _DMarker()) { 
     // No argument passed, because user cannot create a _DMarker. 
    } else { 
     // Argument passed, may be null. 
    } 
    } 
} 

Это большое обходное решение и вряд ли стоит того. В общем, просто используйте null в качестве значения по умолчанию, это проще.

+0

К сожалению, это не позволяет реализовать метод 'copyWith', когда он действителен для свойства, которое должно быть установлено в' null'. Один из них вынужден использовать оператор 'null'-coalescing, поэтому передача в' null' для этого свойства вместо этого игнорирует его и использует существующее значение, отличное от 'null'. –

+0

Да, это неудачный побочный эффект. Если все значения действительны, вы не можете отличить фактическое значение «null» от пропущенного значения. В этом случае вам может понадобиться ввести класс частного маркера и использовать экземпляры этого аргумента по умолчанию, тогда вы знаете, что клиент не может передать экземпляр этого класса, поэтому значение по умолчанию отличается от любого значения клиента. Если ваши аргументы напечатаны, вам может понадобиться один класс для каждого типа (вы можете сделать 'class _XMarker extends _Marker реализует Foo' для значения по умолчанию параметра' Foo'). Если тип 'int', вы застряли :( – lrn

0

Была найдена поддержка проверки того, был ли опциональный параметр на самом деле поставщиком в ранние даты Дарта (до 1.0), но был удален, поскольку он вызывает некоторые проблемы.

+0

Зачем вам нужны разные типы «null». В чем смысл фактического знания, установлено ли значение или нет? – Robert

+1

The? оператор не работал с переадресацией вызовов. То есть, пересылка вызова с необязательными аргументами требует экспоненциального (в количестве аргументов) количества кода. –