zoukankan      html  css  js  c++  java
  • F#中的自定义隐式转换

    我们知道隐式变换在可控情况下会使代码变得简洁。熟悉C#的都知道C#中可以自定义隐式变换,例如

    public class A
    {
        private int data;
        
        public static implicit operator A(int i)
        {
            return new A{ data = i};
        }
    }

    众所周知,F#本身不会进行任何隐式变换。那F#中是否也可以自定义隐式变换呢?

    当然可以。通过定义自己的操作符即可实现。

    我们先定义一个转换操作符

    let inline (!>) (x:^a) : ^b = ((^a or ^b) : (static member op_Implicit : ^a -> ^b) x)

    先看操作符"!>"的签名:有一个类型为a的输入参数,输出参数类型为b。再看定义部分,则是一个类型约束,指示类型a或者b至少有一个类型包含指定签名的成员

    static member op_Implicit。然后接着是输入参数x。这些,就足够实现隐式转换。看一个例子

    let inline (!>) (x:^a) : ^b = ((^a or ^b) : (static member op_Implicit : ^a -> ^b) x)
    
    type A() = class end
    type B() = 
        static member op_Implicit(a:A) = B()
        member this.Add x y = x + y
    
    let show (b: B) = b.Add
    
    let res = show (!> A()) 1 2

    这段代码输入结果为3。

    我们将引入一个术语duck typing,它是有关动态类型的,对一个对象建立某种适用性以达到某些目的。我们知道在正常的类型中,对象的适用性是由对象的类型决定。在duck typing中,对象的适用性在某种意义上由方法和属性决定,而非对象的类型。

    在F#中,我们可以利用这种机制创建泛型函数,从而给我们编程带来很大的好处。例如以下例子中我们引入duck typing

    // Longhand
    let inline implicit< ^a,^b when ^a : (static member op_Implicit : ^b -> ^a)> arg =
      ( ^a : (static member op_Implicit : ^b -> ^a) arg)
      
    // Shorthand - let the compiler do the work
    let inline implicit arg =
      ( ^a : (static member op_Implicit : ^b -> ^a) arg)

    (代码参考http://weblogs.asp.net/podwysocki/f-duck-typing-and-structural-typing

    利用以上代码我们就可以重写!>操作符

    let (!>) : A -> B = implicit

    然后运行上面的最后一行代码

    let res = show (!> A()) 1 2

    可以获得同样的结果3

    当然,在F#中为了保证类型安全,不推荐使用这种自定义隐式变换特性。

     参考:Type Constraints

  • 相关阅读:
    特征方程
    鸽巢原理
    Python列表与字典
    布尔型
    python字符串
    Python小笔记
    IntelliJ 中Maven pom.xml依赖不生效解决
    IDEA创建servlet,篇末有找不到servlet报404的原因
    jQuery的ajax之验证用户名是否被注册
    jquery之Validata表单验证
  • 原文地址:https://www.cnblogs.com/sjjsxl/p/4990778.html
Copyright © 2011-2022 走看看