[英]Return from FOR … IN in extension recursive method (F#)?
我是 F# 的新手。 无法处理语法。 我需要将递归扩展方法从 C # 转换为 F #。 但无论我做什么,编译器都不喜欢我的代码。
这是我的方法:
public static class ViewExtensions
{
public static UIView FindFirstResponder(this UIView view)
{
if (view.IsFirstResponder)
{
return view;
}
foreach (UIView subView in view.Subviews)
{
var firstResponder = subView.FindFirstResponder();
if (firstResponder != null)
return firstResponder;
}
return null;
}
}
我试过这样的事情:
type UIKit.UIView with
member this.FindFirstResponder() =
let mutable firstResponder = null
if (this.IsFirstResponder) then this
else
for subView in this.Subviews do
firstResponder <- subView.FindFirstResponder()
但这显然是不正确的,编译器不会跳过这一点。 任何人都可以帮忙吗?
F# 没有提前返回(这是 C# 中的return
关键字正在做的事情)。 F# 中的每个表达式都必须从上到下进行全面评估,并且不能在中间中断。 来自类似 C 的语言可能会让人感觉很奇怪,但它实际上是一个特性,相信我。 它导致更易于理解、更易于维护的代码。
F# 中 model 迭代的自然方式是递归。 只要不进行递归调用,它就可以在任何步骤轻松中断。 但是您不必在每种情况下都使用裸递归,因为对于许多常见的用例,已经有库函数(它们本身是基于递归或其他此类函数构建的)。
在这种特殊情况下,感兴趣的 function 是Seq.tryPick
。 它采用序列和另一个 function,它返回一个option
- Some
或None
。 然后Seq.tryPick
将返回它遇到的第一个Some
,如果序列中没有Some
,则返回None
。 要将可为空的 .NET 值转换为option
,请使用Option.ofObj
,转换回使用Option.toObj
。
type UIKit.UIView with
member this.FindFirstResponder() =
if this.IsFirstResponder then this
else
this.Subviews
|> Seq.tryPick (fun v -> v.FindFirstResponder() |> Option.ofObj)
|> Option.toObj
如果您必须与 C# 交互,这或多或少是您能做的最好的事情。 互操作总是有点难看。 但是,如果您不再需要 C#,我建议将IsFirstResponder
、 Subviews
和FindFirstResponder
从方法和属性转换为独立函数,并使FindFirstResponder
返回一个option
(这是在 F# 中处理可选值的标准方法)。
然后 function 变得更漂亮了一点:
let findFirstResponder view =
if isFirstResponder view then Some view
else view |> subViews |> Seq.tryPick findFirstResponder
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.