2016-11-03 5 views
0

На картинке ниже вы можете увидеть код, выполненный на игровой площадке, которая не чувствует себя хорошо. Но компилятор Swift полностью справляется с этим. По какой-то причине глубина погружения кортежа сводится к одному.Weird uncraping кортежей в Swift

Чтобы быть более выразительным:

  • Первая карта вызова вызывает ошибку компиляции. (Strange!)
  • Второй звонок в порядке. (Странно!)

Кто-нибудь знает это ошибка или особенность?

Playground example

+2

'(((что-то))))' идентично 'something', сравните http://stackoverflow.com/questions/24767681/single-element-parethesized-expressions-tuples-vs-common-use-us- из-круглых скобок. –

+0

@MartinR вы путаете математические выражения и кортежи. –

+1

@MartinR (комментарий не относится к этому вопросу) ... кроме игровой площадки, где 'a = 5' отображает значение' a' после присвоения в боковой панели, тогда как '(a = 5)' не будет;) – dfri

ответ

1

(Int, Int) является тип кортежа (где круглые скобки являются частью его типа), так же, как ((Int, Int)) имеет тот же тип кортежа, но завернутые в дополнительной пары (избыточных) скобках, так же, как (((Int, Int))) является тот же тип кортежа, что и два предыдущих, но завернутый в два набора (избыточных) скобок.

var a: (((Int, Int))) 
print(type(of: a)) // (Int, Int) 

Дополнительные скобки вводятся в действие только в том случае, если вы начинаете комбинировать различные типы на вложенном уровне, например.

var a: ((Int, Int), Int) 
print(type(of: a)) // ((Int, Int), Int)`. 

Теперь, почему первое закрытие карты не в состоянии, в то время как второй нет?

При использовании задней крышек, вы можете либо

  1. Использование стенографии имя аргумента ($0, ...), или
  2. использования явно названы (или явно имя-опущено, '_') параметры.

Оба ваших примеры пытаются использовать именованные параметры, но только второй пример следующим образом правила использования параметров имен, а именно: о том, что имена параметров должны быть поставлены (поставки параметра типа и закрытие возвращаемого типа не является обязательным, но в некоторых случаях необходимо из-за ограничений вывода типа компилятора).

Изучите следующие примеры:

/* all good */ 
arr.map { (a) in 
    2*a /* ^-- explicitly name parameter */ 
} 

// or 
arr.map { a in 
    2*a /* ^-- explicitly name parameter */ 
} 

/* additional parantheses: 
     error: unnamed parameters must be written with the empty name '_' 

    the closure now believes we want to supply parameter name as well as 
    an explicit type annotation for this parameter */ 
arr.map { ((a)) in 
    2*a /* ^-- compiler believes this is now a _type_, and prior to realizing 
       that it is not, prompts us for the error that we have not 
       supplied a parameter name/explicly omitted one with '_' */ 
} 

/* additional parantheses: 
     error: use of undeclared type 'a' */ 
arr.map { (_: (a)) in 
    1 /* ^-- type omitted: compiler now realize that 'a' is not a type */ 
} 

/* fixed: all good again! */ 
arr.map { (_: (Int)) in 
    1 
} 

В первом примере вы обернуть кортеж в попытке именования элементов кортежа (в .... in части закупоривающем) в paranthesis (так же, как показаны выше ошибки), что означает, что Swift считает, что это тип (тип (x, y)), и в этом случае компилятор требует включения имени внутреннего параметра или явно опускания (используя _). Только когда вы укажете имя параметра, компилятор поймет, что x и y являются недопустимыми.

В вашем втором примере вы просто напрямую связываете замыкания с двумя членами кортежа с именами внутренних параметров x и y, выбирая явно не вводить аннотирование этих параметров (что хорошо).

+1

Благодарим вас за подробный ответ. Я должен был напечатать тип '(((Int, Int)))' тоже :) –