Switch 语句必须详尽 - Xcode 错误?
Posted
技术标签:
【中文标题】Switch 语句必须详尽 - Xcode 错误?【英文标题】:Switch Statement Must Be Exhaustive - Xcode bug? 【发布时间】:2017-06-23 05:20:13 【问题描述】:我对 Xcode 抛出的这个错误感到非常困惑。它说Switch statement must be exhaustive
。但是,我 100% 肯定我正在处理所有案件。
这是我的代码:
enum Search: Endpoint
case sets(query: String?, creator: String?, imagesOnly: Bool?, autocomplete: Bool?, modifiedSince: TimeInterval?, page: Int?, perPage: Int?)
case classes(query: String, page: Int?, perPage: Int?)
case universal(query: String, page: Int?, perPage: Int?)
public var baseURL: String return QuizletEndpoint.baseURL
public var version: Float return QuizletEndpoint.version
public var path: String
switch self // Switch must be exhaustive ERROR.
case .sets:
return "search/sets"
case .classes:
return "search/classes"
case .universal:
return "search/universal"
更新 #1
以下是关于我的协议Endpoint
的详细信息:
/// Represents an Endpoint for networking.
public protocol Endpoint: URLConvertible, URLRequestConvertible
/// The url without any parameters or paths.
var baseURL: String get
/// The version of the API.
var version: Float get
/// The path to the resource.
var path: String get
/// Any parameters to be encoded.
var params: Parameters get
public extension Endpoint
public func asURL() throws -> URL
let finalURL = try baseURL.asURL().appendingPathComponent("\(version)").appendingPathComponent(path)
return finalURL
func asURLRequest() throws -> URLRequest
let finalURL = try asURL()
let request = URLRequest(url: finalURL)
return try URLEncoding.default.encode(request, with: params)
更新 #2
好的,现在我几乎可以肯定这是一个 Xcode 错误。将default
子句添加到我的枚举会产生一个编译器警告,指出default
子句永远不会被执行,因此编译器有点同意default
子句是多余的:
public var path: String
switch self
case .sets:
return "search/sets"
case .classes:
return "search/classes"
case .universal:
return "search/universal"
default: return "" // WARNING: Default will never be executed.
我是疯了还是这是一个 Xcode 错误?我已经尝试清理构建文件夹,定期清理,多次重建,但我似乎无法让这个错误消失。我开始相信这是 Xcode 中的错误,因为我正在运行测试版,但我只想仔细检查并确保它不是我这边的错误。
【问题讨论】:
请张贴代码,而不是截图——最好是minimal reproducible example。 @MartinR 会更新我的问题 @LeoDabus 但我对所有情况都满意 您的代码为我编译(如果我删除未清除的原始类型“端点”) 这绝对是 Xcode 9 beta 2 的一个错误。在详尽性上正确检测到具有单个案例case a(String?, String?, Bool?, Int?, Int?, Int?)
的枚举上的开关,但不适用于 case a(String?, String?, Bool?, Bool?, Int?, Int?)
。它以某种方式取决于枚举案例的关联值的数量和类型。 Xcode 8.3.3 不会发生这种情况。
【参考方案1】:
有时 Swift 无法检测到所有可能的情况。
最好的办法是添加 default:
案例,然后添加 break
。
但是请注意,如果您从 enum
中删除 : Endpoint
类型,您的代码在 Xcode 8.3.3 中可以正常工作。那是什么类型的?
【讨论】:
是的,但我不想有不必要的代码。如上所示,我满足所有情况。 即使有关联的值,编译器通常也会检测 switch 语句是否详尽。你的说法总体上是不正确的。 是的,看起来是这样。一旦你删除: Endpoint
,复制和粘贴他的代码就可以了。所以看起来它与那种类型有关。在这里更新我的答案。【参考方案2】:
这样写就不会报错(Xcode 9 beta 2):
import Foundation
enum Search
case sets(query: String?, creator: String?, imagesOnly: Bool?, autocomplete: Bool?, modifiedSince: TimeInterval?, page: Int?, perPage: Int?)
case classes(query: String, page: Int?, perPage: Int?)
case universal(query: String, page: Int?, perPage: Int?)
public var baseURL: String return ""
public var version: Float return 0
public var path: String
switch self // Switch must be exhaustive ERROR.
case .sets(_, _, _, _, _, _, _):
return "search/sets"
case .classes(_, _, _):
return "search/classes"
case .universal(_, _, _):
return "search/universal"
如果我要做很多匹配,我通常更喜欢将关联的值包装在单独的结构中。这使得模式更简单,并且在更改关联值的性质时减少了工作量。因此:
enum Search
struct Sets
var query: String?
var creator: String?
var imagesOnly: Bool?
var autocomplete: Bool?
var modifiedSince: TimeInterval?
var page: Int?
var perPage: Int?
case sets(Sets)
struct Classes
var query: String
var page: Int?
var perPage: Int?
case classes(Classes)
struct Universal
var query: String
var page: Int?
var perPage: Int?
case universal(Universal)
public var baseURL: String return ""
public var version: Float return 0
public var path: String
switch self // Switch must be exhaustive ERROR.
case .sets(_):
return "search/sets"
case .classes(_):
return "search/classes"
case .universal(_):
return "search/universal"
【讨论】:
但是 OP 的代码(没有(_, ...)
模式)也不会产生错误 ...
是的,它为我修好了。我会在 3 分钟内将其标记为已接受(如果允许的话)。你知道为什么会这样吗?
当我将 OP 的代码放在 Xcode 8.3.3 操场上时,它不会出错,但是当我将它粘贴到 Xcode 9 beta 2 REPL 中时,它会出错。
@MartinR 即使我很难理解两者都不应该起作用吗?
@Harish 谢谢。所以这个答案可能应该更新清楚。【参考方案3】:
XCode 仅在您切换枚举时检查 switch 语句是否详尽。对于其他所有情况,它会检查是否存在默认语句,如果没有,则会发出警告。
为了编译器,你需要包含一个默认块,但没有任何事情要做,break 关键字就派上用场了:
public var path: String
switch self // Switch must be exhaustive ERROR.
case .sets:
return "search/sets"
case .classes:
return "search/classes"
case .universal:
return "search/universal"
default: break
【讨论】:
【参考方案4】:使用enum
类型时,切换块是详尽的。即使打开Bool
也需要除了true 和false 之外的默认块。所以可能编译器会引发
每个 switch 语句都必须是详尽的。也就是说,所有可能的 正在考虑的类型的值必须与以下之一匹配 切换案例。
正如@Dave Wood 所说,最好的办法是添加一个默认值:case 后跟 break
【讨论】:
但是,我的代码中也有其他枚举,它工作正常。我不明白为什么这个失败了。【参考方案5】:如果在 switch 语句中你负责返回 TableViewCell 或 CollectionViewCell 之类的东西,那么除了以下两个之外的所有解决方案都将失败:
-
使用 UITableViewCell() 或 UICollectionViewCell()。 “()”将实例化您需要返回的项目的空值版本。
写一个错误。在重构代码以添加另一种可能性而不增加 switch 语句的相应案例时,您可能会遇到此错误(从而使其不完整)。在这种情况下,您需要向未来的程序员写一封情书错误消息,以明确解释他们忘记了什么。
返回 UITableViewCell()
... 是使我摆脱此错误的代码,但如果您确实已经详尽无遗,则可能更适合编写错误代码。 fatalError() 可以解决问题。
【讨论】:
以上是关于Switch 语句必须详尽 - Xcode 错误?的主要内容,如果未能解决你的问题,请参考以下文章
Xcode 6.1 if/else/for/switch 语句不自动完成(仅限 Swift)