1
enum SolarSystemPlanet: String, CaseIterable {
    case mercury, venus, earth, mars, jupiter, saturn, uranus, neptune

    func toRawValue(_ value: SolarSystemPlanet) -> PlanetName {
        value.rawValue
    }
}

使用上面的枚举,获取行星名称数组的一种方法是调用

SolarSystemPlanet.allCases.map { $0.rawValue }

但 Swift 支持一等函数,将函数视为“一等公民”,这允许我们像调用任何其他对象或值一样调用函数。

所以通过这个得到一个名字数组会很好

SolarSystemPlanet.allCases.map(.toRawValue)

但是,编译器似乎需要更多上下文。它无法map在编译时推断类型,所以我做了

SolarSystemPlanet.allCases.map(SolarSystemPlanet.toRawValue)

编译器停止抱怨,但我没有得到一个字符串数组。上面的行返回一个类型的值[(SolarSystemPlanet) -> String]

如果我将以上内容打印出来,而不是得到

["mercury", "venus", "earth", "mars", "jupiter", "saturn", "uranus", "neptune"]

我有

[(Function), (Function), (Function), (Function), (Function), (Function), (Function), (Function)]

如果我强制返回类型是[String]这样的

var planets: [String] = SolarSystemPlanet.allCases.map(SolarSystemPlanet.toRawValue)

Xcode 会抱怨[(SolarSystemPlanet) -> String]无法转换为[String]

毕竟有可能实现我想要做的事情吗?我错过了什么或做错了什么?

如果不可能,我也非常感谢一些关于原因的解释。

感谢您花时间阅读我的问题!


编辑感谢@sweeper的回答。

对于那些感兴趣的人,我进一步确保每个 String 枚举都有toRawValue

extension RawRepresentable where RawValue == String {
    static func toRawValue(_ value: Self) -> PlanetName {
        value.rawValue
    }
}

注意:这是 Swift 5.1.3

4

1 回答 1

1

请注意,toRawValue它不需要是实例方法。它可以是静态的:

static func toRawValue(_ value: SolarSystemPlanet) -> PlanetName {
    value.rawValue
}

现在您可以将SolarSystemPlanet.toRawValue其用作map.

或者,在这种情况下,您也可以使用keypath\.rawValue作为参数map

SolarSystemPlanet.allCases.map(\.rawValue)

这是 Swift 5.2 的一个新特性。

编辑:解释为什么实例方法不起作用

在 Swift 中,当从静态上下文访问时,具有签名的类型上的实例方法将成为T具有签名(U) -> R的静态方法(T) -> ((U) -> R)。实例方法需要一个封闭类型的实例才能调用,对吧?因此,当您将其传递 a 时T,它会(U) -> R返回原始实例函数。

因此,非静态的类型SolarSystemPlanet.toRawValue

(SolarSystemPlanet) -> ((SolarSystemPlanet) -> String)

这解释了为什么在map应用之后,数组变成了[(SolarSystemPlanet) -> String].

于 2020-03-28T12:35:11.563 回答