为什么在 f# 中不能自动向上转换 [英] Why isn't up-casting automatic in f#

查看:12
本文介绍了为什么在 f# 中不能自动向上转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 F# 中实现了一个 C# 接口,看起来像:

I was implementing a C# interface in F# that looked something like:

public interface IThings
{
    Stream ThingsInAStream()
}

我的实现看起来像:

type FSharpThings() = 
    interface IThings with
       member this.ThingsInAStream() = 
           let ms = new MemoryStream()
           // add things to stream
           ms

现在我收到消息:

The expression was expected to have type 
  Stream
but here has type
  MemoryStream

我不理解 MemoryStream 一个我知道我可以将它转换为流的流:

I don't understand MemoryStream IS a Stream I know that I can cast it to as stream like:

ms :> Stream

同样适用于 [|"string"|]IEnumerable 它实现了接口,我可以显式地转换为它,但它不能自动工作.

Same goes for [|"string"|] and IEnumerable<string> it implements the interface and I can explicitly cast to it BUT it doesn't work automatically.

为什么这样做?

let things:(IEnumerable<'a> -> 'a) = (fun f -> f.First())

let thing= things([|"";""|])

这也是自动上传!

推荐答案

我认为 Nicolas 的回答总体上是正确的.允许在语言中无处不在自动向上转换会导致类型推断问题.

I think the answer from Nicolas is generally right. Allowing automatic up-casting everywhere in the language would cause problems for type inference.

原则上,编译器可以尝试寻找不同分支中返回的类型的公共基类型,但这并不像听起来那么容易:

In principle, the compiler could try looking for a common base type of the types returned in different branches, but this is not as easy as it sounds:

  • 首先,它应该返回最具体的类型还是其他类型?(编译器可以找到最具体的,但也许您实际上想要返回比从您的代码推断出的更一般的东西 - 因此明确指定是有用的.)

  • First, should it return the most specific type or some other type? (The compiler could find the most specific, but perhaps you actually want to return something a bit more general than what could be inferred from your code - so specifying that explicitly is useful.)

其次,接口变得困难.想象一下,两个分支返回两个不同的类,它们都实现了接口IAIB.编译器如何决定返回类型应该是IA 还是IB,或者obj?(这是一个大问题,因为它会显着影响代码的使用方式!)有关详细信息,请参阅此代码段.

Second, things get difficult with interfaces. Imagine that two branches return two different classes both implementing interfaces IA and IB. How does the compiler decide whether the return type should be IA or IB, or perhaps obj? (This is a big problem, because it significantly affects how the code can be used!) See this snippet for more details.

但是,有一个地方这不是问题并且 F# 编译器允许这样做.也就是说,当将参数传递给函数或方法时——在这种情况下,编译器知道所需的类型是什么,因此它只需要检查是否允许向上转换;它不需要推断要插入什么向上转换.因此,类型推断不受影响,因此编译器可以插入向上转换.这就是以下工作的原因:

However, there is one place where this is not a problem and F# compiler allows it. That is, when passing argument to a function or a method - in this case, the compiler knows what the desired type is and so it only needs to check that the upcast is allowed; it does not need to infer what upcast to insert. As a result, the type inference is not affected and so the compiler can insert an upcast. That is why the following works:

// The example from the question
let first (items:seq<'a>) = items |> Seq.head
let thing = first [|"";""|]

// Even simpler example - passing string as object
let foo (a:obj) = a 
foo "123"

这里,参数是array,函数需要seq.编译器知道要插入什么向上转换(因为它知道目标类型),因此它会这样做.

Here, the argument is array<string> and the function expects seq<string>. The compiler knows what upcast to insert (because it knows the target type) and so it does that.

这篇关于为什么在 f# 中不能自动向上转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆