【问题标题】:Swift compiler hangs! Is it a bug?Swift 编译器挂起!它是一个错误吗?
【发布时间】:2015-01-31 10:17:40
【问题描述】:

有一次,当我在处理一个 Swift 项目时,Xcode 卡住了状态栏中的“正在编译 Swift 源代码”消息。不管我等了多久,编译都没有完成。我回滚了我最近的更改,并很快意识到让编译器感到困惑的是一个非常简单的枚举构造。下面是一个说明问题的 Playground 示例。

创建一个新的 Playground 并粘贴此代码。你看到任何输出了吗?

// Playground - noun: a place where people can play

import UIKit

enum FastingType: Int {
    case NoFast=0, Vegetarian, FishAllowed, FastFree, Cheesefare
}

class Fasting
{
    var allowedFood = [
        .NoFast:        ["meat", "fish", "milk", "egg", "cupcake"],
        .Vegetarian:    ["vegetables", "bread", "nuts"],
        .FishAllowed:   ["fish", "vegetables", "bread", "nuts"],
        .FastFree:      ["cupcake", "meat", "fish", "cheese"],
        .Cheesefare:    ["cheese", "cupcake", "milk", "egg"]
    ]

    func getAllowedFood(type: FastingType) -> [String] {
        return allowedFood[type]
    }
}


var fasting = Fasting()
println(fasting.getAllowedFood(.Vegetarian))
println("Hello world")

在我的机器上,忙碌指示灯一直在旋转,并且没有消息。我在 Xcode 6.1 (6A1052c) 和 Xcode 6.2-beta (6C86e) 上都试过这个。

这看起来像 Swift 编译器中的错误吗?还是我的代码有问题?

更新:

一些人注意到我忘记了getAllowedFood 函数中的返回类型。但是,仅此修复程序并不能解决问题。编译器仍然挂起。

在 cmets 中提出了一种解决方法:

Swift 似乎无法解释您的字典。给字典一个明确的类型来“帮助”编译器通常是个好主意。

以下添加“取消冻结”编译器:

var allowedFood: [FastingType: [String]]

【问题讨论】:

  • 永远不要在操场上测试。 (我知道这就是 Apple 所说的,但不要这样做。)如果您只是在真正的应用程序而不是操场上执行所有这些操作,编译器会为您提供明确的错误消息。
  • 哦,还有一条建议。当然,Swift 或 Cocoa 中可能存在错误,但除非你首先了解当出现问题时,是 做错了,否则你不会学习编程。
  • 如果我做错了什么,编译器应该显示错误信息,而不是无限循环!
  • Matt 的建议是务实的,但是是的,编译应该本质上是确定性的,并且永远不要无限循环,即使在操场上也是如此。

标签: xcode swift ios8


【解决方案1】:

是的,这可以被认为是一个编译器错误。编译器无法确定字典中键的类型。可以通过为字典指定显式类型或确保使用 FastingType.NoFast 完全指定第一个值来消除无限循环行为。

试试这个:

enum FastingType: Int {
    case NoFast=0, Vegetarian, FishAllowed, FastFree, Cheesefare
}

class Fasting
{
    var allowedFood:[FastingType: [String]] = [
        .NoFast:        ["meat", "fish", "milk", "egg", "cupcake"],
        .Vegetarian:    ["vegetables", "bread", "nuts"],
        .FishAllowed:   ["fish", "vegetables", "bread", "nuts"],
        .FastFree:      ["cupcake", "meat", "fish", "cheese"],
        .Cheesefare:    ["cheese", "cupcake", "milk", "egg"]
    ]

    func getAllowedFood(type: FastingType) -> [String] {
        return allowedFood[type]!
    }
}

变化:

  1. allowedFood 类型 [FastingType: [String]] 以便它可以解释您的枚举值。
  2. getAllowedFood() 一个返回类型。
  3. 解开字典查找,因为它们总是返回可选项。

或者,您可以将getAllowedFood() 改为return allowedFood[type] ?? [],如果您的字典不详尽,这样会更安全。

【讨论】:

  • 或者您可以在 getAllowedFood 中使用 switch 语句来避免 !
  • 感谢“修复”我的代码。不过,我打算问一个不同的问题:为什么原始代码使编译器无限循环?
  • 我猜你绝对可以称之为错误。斯威夫特似乎很难解释你的字典。为字典提供显式类型以“帮助”编译器通常是个好主意。
  • 请注意,只需将 .NoFast 更改为 FastingType.NoFast 即可停止无限循环行为,因为它假定所有其他键也必须为 FastingType
  • 谢谢,vacawama!我将您的答案标记为解决方案:-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-31
  • 1970-01-01
  • 2022-01-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多