尝试在 Swift 中实现 ?.let 模式,有可能吗?

Tra*_*ggs 0 kotlin swift

我一直在 Swift 和 Kotlin 之间来回移植代码。受到这个答案的启发,我一直在使用Swift?.let { } ?: run {}来替代我使用的许多地方。if let ... { } else {}

不过,我真的很喜欢 Kotlin 表达式。在我看来,它比关键字特定的if let混合物更通用。因此,为了平等起见——或者至少为了通过尝试愚蠢的实验来学习——我想我应该尝试let在 Swift 中实现这个构造。

因为let是 Swift 中的关键字,所以我立即发现我需要添加反引号,或者使用不同的名称,例如cull. 这导致了这个无法编译的代码:

extension Any {
    func cull<R>(block:(Self) -> R) -> R {
        return block(self)
    }
}
Run Code Online (Sandbox Code Playgroud)

考虑到我的学徒水平,可能存在很多问题。但最重要的是,我被告知我无法扩展 Any(此处有更详细的解释)。

所以Any不能被扩展。我可以使用任何其他语言构造来实现它,以便我可以实现类似 Kotlin 的东西吗let?基本上:

<expression>.foo { <expressionResult> in ... }
Run Code Online (Sandbox Code Playgroud)

作为一个奖励/旁白问题,我认为即使有一种方法(我确实希望有这样我可以学习),它也不会相同,因为 Kotlin 可以用于控制流,因为我可以做来自 Kotlin 的非本地返回,但不是来自 Swift 闭包。这也正确吗?

澄清

let基本上,我可以为指定类型实现 Kotlin模式:

protocol Cullable {}

extension Cullable {
    func cull<R>(_ block:(Self) -> R) -> R {
        return block(self)
    }
}

extension Int:Cullable { }

42.cull { thing in print(thing) } // this will print 42
Run Code Online (Sandbox Code Playgroud)

这如我所愿。但我不想扩展系统中的每一个非名义类型才能使其工作。我只是想以某种方式在全球范围内定义它。如果可能的话。

Swe*_*per 5

其实我觉得这样的方法已经存在了Optional。虽然这只是针对可选的,但至少它解决了你缺少?.let. 该方法称为map.

let optional: String? = "hello"
optional.map { print($0) } // prints hello
// note how I did not unwrap the optional. I called "map" directly on the optional, not the wrapped "String".
Run Code Online (Sandbox Code Playgroud)

您可以将map值 to 转换为另一个值,或者Void,就像我上面所做的那样。

我认为不可能对let所有事情都有方法。

flatMap如果你想在闭包内返回一个可选值,也可以使用。

是的,在了解了 Kotlin 中“非本地返回”的含义之后,我认为您不能在 Swift 中做同样的事情。那些花括号的东西是“闭包”。它们是“封闭的”,所以你不能将return周围的封闭物放在内部封闭物中。