繁体   English   中英

是否有等效于在 F# 中创建 C# 隐式运算符的方法?

[英]Is there an equivalent to creating a C# implicit operator in F#?

在 C# 中,我可以将隐式运算符添加到类中,如下所示:

public class MyClass
{
    private int data;

    public static implicit operator MyClass(int i)
    {
        return new MyClass { data = i };
    }

    public static implicit operator MyClass(string s)
    {
        int result;

        if (int.TryParse(s, out result))
        {
            return new MyClass { data = result };
        }
        else
        {
            return new MyClass { data = 999 };
        }
    }

    public override string ToString()
    {
        return data.ToString();
    }
}

然后我可以将任何期望 MyClass 对象的函数传递给字符串或 int。 例如

public static string Get(MyClass c)
{
    return c.ToString();
}

static void Main(string[] args)
{
    string s1 = Get(21);
    string s2 = Get("hello");
    string s3 = Get("23");
}

有没有办法在 F# 中做到这一点?

正如其他人指出的那样,没有办法在 F# 中进行隐式转换。 但是,您始终可以创建自己的运算符,以使其更容易显式转换(并重用现有类已定义的任何 op_Implicit 定义):

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()

let myfn (b : B) = "result"

(* apply the implicit conversion to an A using our operator, then call the function *)
myfn (!> A())

隐式转换在类型安全和类型推断方面相当成问题,所以答案是:不,它实际上是一个有问题的特性。

不,那里没有。

在相关说明中,可以添加隐式或显式静态成员,以便 C# 可以使用它们。

type Country =
| NotSpecified
| England
| Wales
| Scotland
| NorthernIreland
 with static member op_Implicit(c:Country) = 
   match c with | NotSpecified    -> 0
                | England         -> 1
                | Wales           -> 2
                | Scotland        -> 3
                | NorthernIreland -> 4

例如,这允许 ac# 用户使用(int) Wales

从 F#6 开始,现在支持 op_Implicit,只要分辨率是类型导向且清晰的,例如

let x : System.Nullable<int> = 10 // valid in F#6

let doStuff (x:System.Nullable<int>) = ()
doStuff 10 // valid in F#6

type Foo() =
    static member X (x:System.Nullable<int>) = ()
Foo.X 10 // valid in F#6

请注意,前两个示例将给出一个可以关闭的警告 (FS3391)。

您可以像这样调用操作员:

let casted = TargetClass.op_Implicit sourceObject

感谢@isaac-abraham 和@kvb。 我压缩了他们的答案并使用操作要求的隐式构造函数构建了我的类型安全 ID:

type UserId =
  { id: string } // underlying, could be int or so as well
  static member op_Implicit(id:string) = { id = id }
  override r.ToString() = r.id

type ProductId =
  { id: string }
  static member op_Implicit(id:string) = { id = id }
  override r.ToString() = r.id

let id1 : UserId = "p1"
let id2 : UserId = "p1"
let id3 : UserId = "p2"
id1 = id2 // true
id1 = id3 // false
let pid1 : ProductId = "p1"
id1 = pid1 // type error, not comparable -> excellent, thats what this is for

使用记录可以实现结构平等,甚至可以进行比较:

id3 > id1 // true
id3 < id1 // false

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM