- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我正在寻找一种方法来用 中的 functional 对应项替换 if let
(或 guard let
)测试 swift 。我只是找不到办法去做,也许这是不可能的,但我对此很好奇。
所以我有这段代码:
struct Example {
var first: String? = "First"
var second: String? = "Second"
var concat: String? {
guard let first = first, let second = second else {
return nil
}
return first + second
}
}
var example = Example()
example.concat // FirstSecond
example.first = nil
example.concat // nil
我想要的是 concat
变量是 nil
如果 first 或 second 中的任何一个是 nil
。这就是上面的代码所做的。我在考虑如何让它功能性 *rainbows*。
我想到了这个,但我并不满意,因为我的 flatMap
需要显式参数名称,我想知道是否有更简洁的解决方案(暗示 map 链接或类似的东西):
struct Example {
var first: String? = "First"
var second: String? = "Second"
var concat: String? {
return first.flatMap { f in second.map { s in f + s } }
}
}
var example = Example()
example.concat // FirstSecond
example.first = nil
example.concat // nil
我考虑过元组,但它总是意味着使用像 Array
这样的中间类型,我觉得这不是很干净。
编辑 1: 最后,请考虑到此示例使用的是 String
,但我想找到一个适用于任何 Optional 的解决方案
类型。
我的理想解决方案是这样的:
var concat: String? {
return (first, second).map { $0 + $1 }
}
但这是不可能的,因为我们不能为元组定义函数。
编辑 2: 我得到的最接近(从我的理想解决方案)的代码是定义一个全局函数(不是很干净),如下所示:
func opMap<T>(_ tuple: (T?, T?), transform: (T,T) -> T?) -> T? {
guard let one = tuple.0, let two = tuple.1 else { return nil }
return transform(one, two)
}
var concat: String? {
return opMap((first, second)) { $0 + $1 }
}
另一个限制出现在这里,我只能使用成对的值。我的理想解决方案也适用于任意数量的值。
编辑 3:正如@Hamish 在评论中提出的那样,这是一种使用可选
扩展来解决问题的有趣方法:
extension Optional {
func map(with: Wrapped?, transform: (Wrapped, Wrapped) -> Wrapped?) -> Wrapped? {
guard case .some(let first) = self, let second = with else { return nil }
return transform(first, second)
}
}
var concat: String? {
return first.map(with: second) { $0 + $1 }
}
编辑 4:(是的,我喜欢编辑)@Martin R 提出了对以前解决方案的改进,它更接近我想要的(因为我们有独立的第一、第二和结果类型) ,见下文:
extension Optional {
func map<T, S>(with: T?, transform: (Wrapped, T) -> S?) -> S? {
guard case .some(let first) = self, let second = with else { return nil }
return transform(first, second)
}
}
上次编辑正确:我强烈建议您查看@Rob Napier 的回答及其评论,其中对我要实现的目标提出了很多要点。
最佳答案
虽然我认为原始代码是非常好的 Swift,以及你应该使用的东西(并且它没有任何功能),但你为此所需的 FP 工具在 Haskell 中称为 sequence
。您在这里构建的是一个 monad(我知道“monad”总是令人困惑的对话的开始,但这正是您正在构建的)。您需要一个表达式,如果所有元素都有值,则表达式有值,但如果任何元素没有值,则表达式没有值。这正是 monad 非常常用的用途。
那么让我们构建序列
。不幸的是,这与 Swift 的 sequence
冲突,但我真的不建议为此目的使用此工具。 if-let
是 Swift 中更强大的 monad;事实上,它非常接近 Haskell 的 do-notation。
// I'd never build `sequence` this way. I'd build it with a for-loop in Swift, but
// to stay super functional...
func sequence<T>(_ elements: [T?]) -> [T]? {
let result = elements.flatMap{$0}
return result.count == elements.count ? result : nil
}
好的,我们要用它做什么?好吧,这一切都非常笼统(就像好的 FP 一样)。它应该对两个元素和一百个元素同样有效。所以数组正是工具。 reduce
让我们把一个数组变成一个值:
var concat: String? {
return sequence([first, second])?.reduce("", +)
}
关于swift - 在单个功能指令中用两个值替换 `if/guard let`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43762627/
//Version A: var let = true; console.log(let);//true //Version B: let let = 0; //syntax Error: let i
//Version A: var let = true; console.log(let);//true //Version B: let let = 0; //syntax Error: let i
我在看a talk on JSON hijacking不到 2 分钟,已经有我不熟悉的 JavaScript。 let:let{let:[x=1]}=[alert(1)] 它似乎在 Edge 上工作并
(let ((x 2) (y 3) (let ((x 7) (z (+ x y))) (* z x))) 使用上面的代码,为什么答案是 35,而不是 70?在第二个 let
我正在编写一个以间隔作为参数并返回百分比错误的函数,但我坚持使用 let 或 let*。这是代码: 嵌套的 let 版本: (define (percent interval) (let (sta
我一直在阅读有关 Swift 中的Optional 的内容,并且看到过一些示例,其中 if let 用于检查Optional 是否包含值,如果包含值,则使用展开的值执行某些操作. 但是,我发现在 Sw
我正在尝试实现 local search algorithm进行优化。我是 Lisp 的新手,所以这是我想出的代码(注意 FORMATs): (defun local-search (solution
我一直在阅读有关 Swift 中的 Optionals 的文章,并且我看到了一些示例,其中 if let 用于检查 Optional 是否包含一个值,如果它包含 - 对未包装的值执行一些操作. 但是,
let () = Random.self_init();; let _ = Random.self_init ();; │- : unit = () 似乎“让()”什么也没返回? 真挚地! 最佳答案
有没有办法避免接下来的构造?一种在不向代码添加意图的情况下检查 null 的方法?我的意思是像 if (variableOne == null) return 但采用酷炫的 koltin 风格? va
什么时候使用 if-let 而不是 let 会使代码看起来更好以及对性能有影响吗? 最佳答案 我猜if-let当您想在代码的“then”部分引用 if 条件的值时,应该使用: 即而不是 (let [r
我有这些功能: (def i (atom {})) ;incremented/calculated file stats (defn updatei [n fic fos] (swap! i co
这个问题已经有答案了: Confused by the difference between let and let* in Scheme (2 个回答) 已关闭10 年前。 let、let* 和 l
因此,在 objective-c 、C/C++、.NET 以及我使用过的几乎所有其他语言中,您可以声明可以包含以前常量的常量,例如 #define PI 3.14159 #define HALFPI
在 Common Lisp 中,let 使用列表进行绑定(bind),即: (let ((var1 1) (var2 2)) ...) 虽然 Clojure 使用向量代替: (let
看下面两个使用相同代码的场景: 使用 IF LET: public func peripheral(_ peripheral: CBPeripheral, didDiscoverServices er
这个问题在这里已经有了答案: Differences between "static var" and "var" in Swift (3 个答案) 关闭 5 年前。 class Foo {
我脑海中的例子是:什么更好? 示例 1: (define (foo x) ... (values a b c)) (let-values (((a b c) (foo 42))) .
考虑以下宏: (defmacro somemacro [] (list 'let ['somevar "Value"] 'somevar)) 展开它会产生以下结果: (macroexpand
可以来给我解释一下为什么必须使用 let !而不是在这种情况下让?只有当我包含 ! 时,测试才会通过。我以为我明白 let 会在该块中的每个“it”语句之前自动执行,但显然情况并非如此。 descri
我是一名优秀的程序员,十分优秀!