我遇到了需要传递给Function
对象的JQueryAnimationOptions
类型。我通常会将lambda传递给回调,但这些似乎是不兼容。我查看了我在FunScript仓库中找到的每个样本。并找不到任何解决方法。
当用作返回语句Function
时,它还说Error: Invalid use of interface type
实际上是一个接口(用于什么?)。
那么如何使用此Function
类型传递回调参数?
代码:
[<FunScript.JS>]
module Main
open FunScript
open FunScript.TypeScript
let sayHelloFrom (name:string) =
Globals.window.alert("Hello, " + name)
let jQuery (selector:string) = Globals.jQuery.Invoke selector
let main() =
let options = createEmpty<JQueryAnimationOptions>()
options.duration <- 3000
options.complete <- (fun _ -> sayHelloFrom("F#"))
let properties = createEmpty<Object>()
properties.Item("opacity") <- 1
let mainContent = jQuery "#mainContent"
mainContent.animate(properties, options) |> ignore
mainContent.click(fun e -> sayHelloFrom("F#") :> obj)
答案 0 :(得分:2)
在F#和C#之间传递lambda时,这或多或少都有所作为。在F#中,函数可以被curry,而在C#(和JavaScript)中则不能。因此,当您需要将F#中的lambda发送到C#时,您需要先将其转换。在F#中,这是通过像这样包装lambda来完成的:
open System.Linq
open System.Collections.Generic
let ar = [|1;2;3|]
let f = fun (x: int) (y: int) -> x + y
let acc = ar.Aggregate( System.Func<int,int,int>(f) )
实际上,F#编译器可以在大多数时候推断出类型,因此您只需要编写:System.Func<_,_,_>(f)
。此外,当将F#lambda传递给期望C#lambda的方法时,编译器会自动为您进行包装。然后前面的例子变成:
let ar = [|1;2;3|]
let acc = ar.Aggregate( fun x y -> x + y )
(当然,在这种情况下,最好使用惯用的Array.reduce。这只是一个人为的例子。)
使用FunScript与JS交互时,这种方法完全相同。你唯一需要注意的是F#lambdas如何被翻译成JS。为了允许currying,具有两个或更多参数(如fun x y -> x + y
)的lambda变为:
function (x) {
return function (y) {
return x + y;
}
}
这可能是一个问题,因为本机JS会期望以下签名:function (x, y)
。在这种情况下,你需要用System.Func<_,_,_>()
包装lambda,就像在与C#交互时一样(如果你将lambda传递给方法,请记住这是自动完成的。)
但是,只有一个参数的lambda不会出现任何问题:fun x -> x*x
变为function (x) { return x*x; }
。在这种情况下,您不需要包装它们(无论如何都不会这样做)并且只需在必要时使用unbox
来安抚F#编译器就足够了。请注意,FunScript编译器会忽略最终JS代码中的unbox
,因此在运行时根本不会进行类型检查。
我希望解释清楚。如果不是,请添加评论,我将编辑答案。
答案 1 :(得分:0)
没关系,我找到了解决方案,我必须unbox
lambda:
options.complete <- unbox<Function> (fun _ -> sayHelloFrom("F#"))