Xcode显示不必要的语法错误

时间:2019-02-14 07:33:31

标签: ios swift enums

我有一个带有值的枚举:

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 :(得分:2)

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]解释为[Types]

第二个问题是,由于您是在一行中执行此操作,因此(的结束处需要额外的括号)map,因为Swift不喜欢{之后的多个if。在不弄清楚括号的情况下,它将把{闭包中的第一个map解释为if then 块的开始。

所以:

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约定是,以{em>大写字母开头classstructenum类型名称,并启动变量,方法和枚举小写字母的值。

因此您的enum可以写为:

enum Types {
    case a, b, c, d
}

答案 1 :(得分:1)

一种解决方案是使枚举实现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
    }
}

答案 2 :(得分:1)

第二行中的问题是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) {

}

答案 3 :(得分:0)

  

闭包中不包含匿名闭包参数

之所以发生此错误,是因为您不能在if语句的情况下使用结尾块语法。当编译器看到括号{时,它假定在if条件为true时,它已经找到要执行的块。 $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
}

在操场上编译并运行良好。