gpt4 book ai didi

generics - 在 F# 中实现通用接口(interface)的对象集合

转载 作者:行者123 更新时间:2023-12-02 22:08:51 25 4
gpt4 key购买 nike

假设我有以下代码:

type A =
abstract member hi: string

type B() =
interface A with
member self.hi: string = "Hello"

type C() =
interface A with
member self.hi: string = "Yo"

只要我显式指定接口(interface)类型,我就可以使 F# 的类型检查器满意 AB 类型的对象列表:

let l: A list = [ B(); C() ]

但是当通用参数出现时我有点困惑。例如,

type A<'T> =
abstract member thing: 'T

type B() =
interface A<int> with
member self.thing: int = 1

type C() =
interface A<string> with
member self.thing: string = "Yo"

我尝试使用类似的东西

let l: A<_> list = [B(); C()]

F# 似乎想固执地填写泛型类型参数:

error FS0001: The type 'C' is not compatible with the type 'A<int>'

请注意,我已在具有标准接口(interface)的 Java 和具有特征的 Scala 中使用了此模式,因此我很惊讶我无法在 F# 中执行此操作。我在这里缺少什么?

最佳答案

使用_在类型参数位置基本上告诉编译器“为我推断类型”。列表中第一个完全定义的类型是 A<int>所以_固定为int 。您需要自己提供所有列表元素的(最不常见的)父类(super class)型。由于 F# 不支持泛型中的接口(interface)协变,因此您在这里所能做的就是 obj :let l: obj list = [B(); C()]

请注意,这对于 C# 也是如此,因为差异仅对引用类型起作用:

interface IInvariant<T>
{
T Item { get; }
}

interface ICovariant<out T>
{
T Item { get; }
}

class Foo : IInvariant<int>, ICovariant<int>
{
public int Item { get; }
}

class Bar : IInvariant<string>, ICovariant<string>
{
public string Item { get; }
}

class Baz
{
static void Check()
{
var a = new IInvariant<object>[] { new Foo(), new Bar() };
// CS0266 Cannot implicitly convert type 'Foo' to 'C.IInvariant<object>'
// CS0266 Cannot implicitly convert type 'Bar' to 'C.IInvariant<object>'

var b = new ICovariant<object>[] { new Foo(), new Bar() };
// CS0266 Cannot implicitly convert type 'Foo' to 'C.ICovariant<object>'
}
}

在 F# 中,您可以创建一个可区分联合来捕获类型信息:

type InvariantWrapper =
| Integer of IInvariant<int>
| Stringy of IInvariant<string>

let c = [ Integer(Foo()); Stringy(Bar()) ]

关于generics - 在 F# 中实现通用接口(interface)的对象集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42308781/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com