【问题标题】:Swift: seemingly not allowed to compare a String? with a String?Swift:貌似不允许比较字符串?用字符串?
【发布时间】:2016-07-08 14:37:47
【问题描述】:

我要求用户输入(这可行)并尝试输出不同的结果,具体取决于输入是nil、空字符串还是使用switch 子句的非空字符串(不起作用)。

第一次尝试让我出错,因为我正在尝试将可选字符串与非可选字符串进行比较:

import Foundation

print("Hi, please enter a text:")

let userInput = readLine(stripNewline: true)

switch userInput {
    case nil, "": // Error: (!) Expression pattern of type ‘String’ cannot match values of type ‘String?’
        print("You didn’t enter anything.")
    default:
        print("You entered: \(userInput)")
}

很公平,所以我创建了一个可选的空字符串来比较:

import Foundation

print("Hi, please enter a text:")

let userInput = readLine(stripNewline: true)
let emptyString: String? = "" // The new optional String

switch userInput {
    case nil, emptyString: // Error: (!) Expression pattern of type ‘String?’ cannot match values of type ‘String?’
        print("You didn’t enter anything.")
    default:
        print("You entered: \(userInput)")
}

所以这给了我一个错误,说我无法将“字符串?”与“字符串?”进行比较。

这是为什么呢?它们是否仍然不是同一类型?

PS。我觉得我在这里遗漏了一些基本的东西,例如Troy 指出的关于可选的不是“与相应的非可选类型相同的类型,但有可能没有值”(不是确切的报价,请参阅问题末尾的更新:What does an exclamation mark mean in the Swift language?)。但我一直无法连接最后的点,为什么这不行。

【问题讨论】:

    标签: swift switch-statement compare optional


    【解决方案1】:

    替换

    case `nil`, "":
    

    case nil, .Some(""):
    

    注意 optional 是一个具有两个可能值的枚举:.None.Some(value)

    关于String? 的第二个示例,请注意case 中的匹配是使用~= 运算符执行的,该运算符未为可选项定义。

    如果你定义:

    @warn_unused_result
    public func ~=<T: Equatable>(lhs: T?, rhs: T?) -> Bool {
        return lhs == rhs
    }
    

    您的两个示例都将开始工作(不推荐)。

    【讨论】:

    • 是的。 ~= 是为 Equatable 操作数定义的,但即使底层包装类型是可选项,也不能等同。 – ~= 也为 _OptionalNilComparisonType 操作数定义,这就是为什么 (as I assume) 模式 case nil: 有效。
    • 您还可以将模式.Some("")缩短为""?
    • 完全同意,尽管我认为这可能是 Swift 编译器中的一个错误,值得关注。与.Some(string) 匹配的模式有效但optionalString 无效的事实感觉像是一种无意的不一致。 (特别是因为 Swift 并没有真正将“模式匹配作为解构”范式归于 Scala 等。)
    • @MartinR 没错。我得出了同样的结论。我不确定这是否是错误。我可能缺少一个案例。
    【解决方案2】:

    您是否尝试将 userInput 文本作为字符串获取:

    let response = userInput ?? ""
    switch response {
        case "": 
            print("You didn’t enter anything.")
        default:
            print("You entered: \(response)")
    }
    

    那你肯定是同类型的String。

    我希望它有效

    【讨论】:

    • 我不允许将responsenil 进行比较,可能是因为respones 不再是可选的。我收到错误Expression pattern of type ‘_’ cannot match values of type ‘String’
    • 是的,抱歉,您可以将其与字符串表达式进行比较。那么即使你的值一开始是 nil ,它也会被转换为一个空字符串。这样您的打印信息就会出现
    • 但是,从等式中删除nil 应该可以工作(我只是不确定如何在运行程序时引发nil 事件),请参阅stackoverflow.com/questions/27439723/…。感谢您为我指明正确的方向!
    • @EliasMossholm:readLine 在文件结束条件下返回 nil。您可以通过在终端或调试器控制台中按 Control-D 来触发它。
    【解决方案3】:

    作为对现有良好答案的补充:而不是测试 针对nil 和空字符串,您可以反过来 并针对非零字符串进行测试(使用input? 模式)和 添加where 约束:

    switch userInput {
    case let input? where !input.isEmpty:
        print("You entered", input)
    default:
        print("You did not enter anything")
    }
    

    等价:

    if case let input? = userInput where !input.isEmpty {
        print("You entered", input)
    } else {
        print("You did not enter anything")
    }
    

    但是: readLine() 仅在文件末尾返回 nil 条件,这意味着不能再从标准中读取数据 输入。因此,终止 这种情况下的程序:

    guard let userInput = readLine(stripNewline: true) else {
        fatalError("Unexpected end-of-file")
    }
    // `userInput` is a (non-optional) String now
    
    if userInput.isEmpty {
        print("You did not enter anything")
    } else {
        print("You entered", userInput)
    }
    

    【讨论】:

    • 在这些情况下,文件结尾的情况何时会在现实生活中发生? (以便理解为什么终止程序是更好的选择。)
    • @EliasMossholm:例如,如果您的程序从文件 (myProg &lt; inputData) 中读取输入。一旦到达文件末尾,readLine() 就会返回 nil。因此,如果输入文件没有包含足够的数据供您的程序使用,则无法继续。 – 当您“直接”调用程序并输入 Control-D 时,也会发生同样的情况。这将关闭程序的标准输入,所有后续的 readLine() 调用都返回 nil。
    【解决方案4】:

    请参阅不言自明的示例...

    let txtArr: [String?] = [nil, "", "some text"]
    
    for txt in txtArr {
        switch txt {
        case nil:
            print("txt is nil")
        case let .Some(t) where t.isEmpty:
            print("txt is empty string")
        default:
            print("txt is \(txt)")
        }
    }
    

    代码打印

    txt is nil
    txt is empty string
    txt is Optional("some text")
    

    【讨论】:

      猜你喜欢
      • 2012-11-15
      • 1970-01-01
      • 1970-01-01
      • 2014-10-02
      • 1970-01-01
      • 2011-08-17
      • 2012-10-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多