代码之家  ›  专栏  ›  技术社区  ›  Franco Tiveron

重载泛化

  •  0
  • Franco Tiveron  · 技术社区  · 7 年前

    给定类型

    type T = 
        static member OverloadedMethod(p:int) = ()
        static member OverloadedMethod(p:string) = ()
    

    //Case 1
    
    let inline call o = T.OverloadedMethod o //error
    
    call 3
    call "3"
    

    但是,尽管有内联的定义,这还是不起作用,编译器会抱怨

    错误FS0041方法“OverloadedMethod”的唯一重载无法 可能需要类型批注。候选:静态成员 T、 重载方法:p:int->单元,静态成员T。重载方法: p: 字符串->单位

    但是我们可以实现我们想要的,例如使用“操作符技巧”

    //Case 2
    
    type T2 =
    
        static member ($) (_:T2, p:int) = T.OverloadedMethod(p)
        static member ($) (_:T2, p:string) = T.OverloadedMethod(p)
    
    let inline call2 o = Unchecked.defaultof<T2> $ o
    
    call2 3
    call2 "3"
    

    有什么技术原因可以证明这种行为是正当的?我的猜测是,有一些折衷(可能与.NET互操作性有关),但找不到更多信息。

    编辑

    从这些帖子中,我把这作为一个理由:

    trait调用是F#编译器的特性,因此必须有两种不同的方法来编写简单调用和trait调用。对两者使用相同的语法是不方便的,因为这可能会让人困惑,有些用法可能会出现在一个简单的调用意外编译为trait调用的情况下”。

    让我们从另一个角度来思考这个问题:

    看看代码,编译器应该做的事情似乎很简单:

    (一) 是内联函数,因此请将编译推迟到使用站点

    2个)

    三) 叫“3” 就像前面用字符串代替int的情况一样

    (四) 调用3.0 错误,因为T.OverloadedMethod(float)不存在

    我真的很想看到一个代码示例,让编译器这样做将是一个问题,需要开发人员为trait调用编写额外的代码。

    在这里,我们面对的是一个看起来更好的案子。

    2 回复  |  直到 7 年前
        1
  •  1
  •   Jwosty    7 年前

    取舍源于这样一个事实:这是一个完全删除的编译器技巧。这意味着:

    1. 代码看不到(并利用)任何 call2 $ 方法重载。
    2. 有关的所有信息 呼叫2
    3. 它不会显示在调用堆栈中。这可能是件好事,也可能是件坏事——例如,在最新版本的F#编译器中,它们有选择地内联了某些要生成的函数 async stacktraces好一点。
    4. F#是在呼叫点烤的。如果您的调用代码是程序集A 呼叫2 来自程序集B,不能用新版本的 ;必须针对新程序集重新编译A。这可能是一个潜在的向后兼容性问题。

    Why is this F# code so slow? . 另一方面,我确信在某些情况下,它可能会导致活动的危害,或者只是导致IL代码膨胀。

        2
  •  1
  •   Gus    7 年前

    这种行为的原因是 T.OverloadedMethod o 在里面

    let inline call o = T.OverloadedMethod o
    

    不是一个特质召唤。这是相当简单的.NET重载,必须在调用站点解决,但由于函数类型并不意味着要解决哪个重载只是无法编译,因此需要此功能。

    let inline call (x:'U) : unit =
        let inline call (_: ^T, x: ^I) = ((^T or ^I) : (static member OverloadedMethod: _ -> _) x)
        call (Unchecked.defaultof<T>, x)
    

    通过自动推断这些约束,使用运算符可以节省许多击键,但正如您在问题中看到的,它需要在重载中包含一个伪参数。

    推荐文章