为什么不上传在f# [英] Why isn't up-casting automatic in f#
问题描述
我在F#中实现了一个C#接口,看起来像:
I was implementing a C# interface in F# that looked something like:
public interface IThings
{
Stream ThingsInAStream()
}
我的实现看起来像:
My implementation looked something like:
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 IS / strong>一个流我知道我可以把它转换为流如:
I don't understand MemoryStream IS a Stream I know that I can cast it to as stream like:
ms :> Stream
同样适用于 [|string|]
和 IEnumerable< string>
它实现了接口,我可以显式转换它,但它不能自动工作。
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([|"";""|])
这也是自动转换!
推荐答案
尼古拉斯一般是对的。
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.)
其次,使用接口的事情变得困难。想象两个分支返回两个不同的类,它们都实现了接口 IA
和 IB
。编译器如何确定返回类型是 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< ; string>
,函数期望 seq< string>
。编译器知道什么upcast插入(因为它知道目标类型),所以它这样做。
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屋!