Xcode, показывающий нежелательные синтаксические ошибки - PullRequest
0 голосов
/ 14 февраля 2019

У меня есть перечисление со значениями:

enum Types {
  case A
  case B
  case C
  case D
}

var tableViewDataSource: [Types] = [.A, .B, .C, .D]

Я хочу реализовать следующие условия:

let pickerSelectingFields: [Types] = [.A, .B, .C, .D]
    let indexes = pickerSelectingFields.map { tableViewDataSource.firstIndex(of: $0) }

    if indexes.contains(textField.tag) {
    // Working
    }

Когда я пытаюсь сделать все в одной строке, какниже это показывает ошибку:

Анонимный аргумент закрытия не содержится в замыкании

Код ниже:

if ([.A, .B, .C, .D] as? [Types]).map { tableViewDataSource.firstIndex(of: $0) }
                                 .contains(textField.tag)

Что я здесь не так делаю

Ответы [ 4 ]

0 голосов
/ 14 февраля 2019

Анонимный аргумент замыкания, не содержащийся в замыкании

Эта ошибка возникает из-за того, что вы не можете использовать синтаксис завершающего блока в условии оператора if.Когда компилятор видит открывающую фигурную скобку {, он предполагает, что обнаружил, что блок должен быть выполнен, когда условие if выполнено.$0 не имеет смысла в этом контексте.

Чтобы исправить это, вы должны использовать синтаксис без конечного блока, т.е. поставить скобки для вызова функции map.

if ([.A, .B, .C, .D] as? [Types]).map ({ tableViewDataSource.firstIndex(of: $0)}).contains(textField.tag)
//                                    ^- here                                   ^-- and here                            
{
    // Do stuff
}

Это оставит вас с этой ошибкой:

тип выражения неоднозначен без дополнительного контекста

Это из-за as?.Поместив туда знак вопроса, вы сообщаете компилятору, что не уверены, что массив можно преобразовать в массив Types, и поэтому он предполагает, что у него недостаточно информации для вывода типа.Уберите знак вопроса, и компилятор знает, что это должен быть массив Types, и поэтому может правильно определить тип выражения.

Фактически, если у вас есть только одно перечисление с этими членами, выможет оказаться, что вам не нужен актерский состав:

if [.A, .B, .C, .D].map ({ tableViewDataSource.firstIndex(of: $0) }).contains(1)
{
    // do something
}

компилируется и отлично работает на детской площадке.

0 голосов
/ 14 февраля 2019

Проблема во второй строке - неявный тип, который не может определить компилятор Swift.Короче говоря, выполнение ([.A, .B, .C, .D] as? [Types]) ничего хорошего не дает, вам нужно быть явным в каждом типе: ([Types.A, Types.B, Types.C, Types.D]).Теперь компилятор Swift может интерпретировать это как [Types].

. В первом примере он вам не нужен, потому что вы использовали явный тип:

let pickerSelectingFields: [Types] = [.A, .B, .C, .D]

.делая это неявно:

let pickerSelectingFields: = [.A, .B, .C, .D]

И вы можете снова исправить это, дав подсказку компилятору:

let pickerSelectingFields: = [Types.A, Types.B, Types.C, Types.D]

Это может быть немного сложно объяснить / понять, но я надеюсь, что это прояснитнесколько вещей.

Также отсутствует скобка, поэтому окончательный результат должен быть:

if (([Types.A, Types.B, Types.C, Types.D]).map { tableViewDataSource.firstIndex(of: $0) }).contains(textField.tag) {

}
0 голосов
/ 14 февраля 2019
if ([.A, .B, .C, .D] as? [Types]).map { tableViewDataSource.firstIndex(of: $0) }
                             .contains(textField.tag)

Что я здесь не так делаю?

Есть две проблемы.

Сначала вы использовали as? вместо as.Когда вы используете условное приведение as?, результат будет [Types]?: необязательный [Types].Затем Swift использует опциональную версию map, и вы в основном движетесь в неверном направлении.

Вам нужно было использовать as [Types], потому что вы просто приказываете Swift интерпретировать [.A, .B, .C, .D] as [Types].

Вторая проблема заключается в том, что, поскольку вы делаете это в одной строке, вам нужно несколько дополнительных скобок (, ) вокруг замыкания для map, потому что Swiftне любит множественные { после if.Без уточняющих паренов он будет интерпретировать первый {, который принадлежит замыканию для map, как начало , а затем блока для if.

Итак:

if ([.A, .B, .C, .D] as [Types]).map({ tableViewDataSource.firstIndex(of: $0) }).contains(textField.tag) {
    // do something
}

будет работать.

Вы также можете просто явно ввести одну из записей массива, и Swift интерпретирует весь массив как [Types] следующим образом:

if [Types.A, .B, .C, .D].map({ tableViewDataSource.firstIndex(of: $0) }).contains(textField.tag) {
    // do something
}

Примечание:

Обычное соглашение Swift - начинать имена типов class, struct и enum с заглавными буквами и для запуска переменных, методов и значений перечисления с строчными буквами.

Таким образом, ваш enum может быть записан как:

enum Types {
    case a, b, c, d
}
0 голосов
/ 14 февраля 2019

Одно решение состоит в том, чтобы сделать перечисление реализующим CaseIterable

enum Types: CaseIterable {
  case A 
  case B 
  case C 
  case D 
}

Затем вы можете проверить наличие тега в массиве следующим образом:

if textField.tag >= 0 && textField.tag < Types.allCases.count { //maybe not needed
    if tableViewDataSource.contains(Types.allCases[textField.tag]) {
         //do stuff
    }
}

Другой вариант -сделать перечисление типа Int

enum Types: Int{
  case A = 1
  case B 
  case C 
  case D 
}

, а затем проверить непосредственно с помощью тега

if let type = Types(rawValue: textField.tag) {
    if tableViewDataSource.contains(type) {
        //do stuff
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...