Class F#模板中编译时可派生类型的使用
在下面的代码中,我想使用变量的类型实例化一个模板类,最终作为传递到函数中的泛型变量,但即使是这种更简单的形式也不起作用:Class F#模板中编译时可派生类型的使用,class,templates,generics,f#,Class,Templates,Generics,F#,在下面的代码中,我想使用变量的类型实例化一个模板类,最终作为传递到函数中的泛型变量,但即使是这种更简单的形式也不起作用: type saveXY<'a when 'a:comparison> (x:'a,y:'a) = member this.X = x member this.Y = y member this.lessThan () = this.X < this.Y [<EntryPoint>] let main argv =
type saveXY<'a when 'a:comparison> (x:'a,y:'a) =
member this.X = x
member this.Y = y
member this.lessThan () = this.X < this.Y
[<EntryPoint>]
let main argv =
let x1 = 3
let y1 = 7
let saver1 = new saveXY<int>(x1,y1) // Good
printfn "%A" (saver1.lessThan())
let x2 = 3.0
let y2 = 7.0
let saver2 = new saveXY<float>(x2,y2) // Good
printfn "%A" (saver2.lessThan())
let saver3 = new saveXY<x2.GetType()> (x2,y2) // No Good, see errors
0
如果删除saveXY
上的模板,则saver2
会出错,因为saver1
会导致saveXY
类参数被约束为int
我还尝试将x和y声明为简单的obj
,但这不起作用。我怀疑问题是这根本不可能,
也就是说,如果类参数类型是泛型的,则它们只派生一次(从第一次使用开始)。另一方面,也许我错过了什么
有没有一种方法可以将编译时可确定的基于变量的类型用作F#中的类型模板参数?是否有其他方法可以创建能够处理/存储泛型值的类型
更新:根据Lee的建议,如果您对类进行模板化,然后只需使用
来实例化该类,则此操作有效:
type saveXY<'a when 'a:comparison> (x:'a, y:'a) =
member this.X = x
member this.Y = y
member this.lessThan () = this.X < this.Y
[<EntryPoint>]
let main argv =
let x1 = 3
let y1 = 7
let saver3 = new saveXY<_> (x1,y1) // works, 'a is int
printfn "%A" (saver3.lessThan())
let x2 = 3.0
let y2 = 7.0
let saver3 = new saveXY<_> (x2,y2) // works, 'a is float
printfn "%A" (saver3.lessThan())
System.Console.ReadKey() |> ignore // wait for a key
0
键入saveXY(x:a,y:a)=
请记住这个。X=X
成员:this.Y=Y
成员this.lessThan()=this.X忽略//等待密钥
0
但是,为什么我需要像我上面建议的那样对类类型进行模板化呢?当我使用
时,编译器似乎无论如何都在推导类型,所以为什么我不能简单地使用(就像我使用函数一样):
type saveXY(x,y)=//x和y是泛型的,不是吗?它们只需要比较,是吗?
请记住这个。X=X
成员:this.Y=Y
成员this.lessThan()=this.X忽略//等待密钥
0
如果您只想让编译器推断您可以使用的泛型参数的类型:
let saver3 = new saveXY<_>(x2, y2)
如果您只想让编译器推断泛型参数的类型,可以使用:
let saver3 = new saveXY<_>(x2, y2)
F#没有任何内置方法来实例化运行时已知类型的泛型代码。您总是可以通过反射来实现这一点,但这并不是很有用——如果您使用反射来创建它,您实际上将无法对该值做很多事情
在本例中,您可以将LessThan
移动到单独的界面中:
type ILessThan =
abstract LessThan : unit -> bool
type SaveXY<'T when 'T:comparison> (x:'T,y:'T) =
member this.X = x
member this.Y = y
interface ILessThan with
member this.LessThan () =
printfn "Comparing values of type: %s" (typeof<'T>.Name)
this.X < this.Y
下面是一个如何工作的示例:
let lt = createSaveXY (typeof<float>) (box 3.0) (box 7.0)
lt.LessThan()
让lt=createSaveXY(typeof)(框3.0)(框7.0)
LessThan中尉()
但是正如我前面所说,这很少有用,也不是非常高效——所以,与其复制它,不如描述您试图解决的问题-可能有一个更好的解决方案。F#没有任何内置方法来实例化运行时已知类型的泛型代码。您总是可以通过反射来实现这一点,但这并不是很有用——如果您使用反射来创建它,您实际上将无法对该值做很多事情
在本例中,您可以将LessThan
移动到单独的界面中:
type ILessThan =
abstract LessThan : unit -> bool
type SaveXY<'T when 'T:comparison> (x:'T,y:'T) =
member this.X = x
member this.Y = y
interface ILessThan with
member this.LessThan () =
printfn "Comparing values of type: %s" (typeof<'T>.Name)
this.X < this.Y
下面是一个如何工作的示例:
let lt = createSaveXY (typeof<float>) (box 3.0) (box 7.0)
lt.LessThan()
让lt=createSaveXY(typeof)(框3.0)(框7.0)
LessThan中尉()
但正如我前面所说的,这很少有用,也不是非常高效-因此,与其复制它,不如尝试描述您试图解决的问题-可能有更好的解决方案。不,您不能像这样指定类型参数,尽管您已经静态地知道
x2
和y2
的类型,所以你的用例不清楚。不清楚你到底想做什么:你是想构建代码,用编译时未知的泛型参数来实例化你的类,还是只想说“不管x2是什么类型的,请使用它”,然后让编译器来解决它“无论x2是什么类型,请使用它“,让编译器解决它吗?案例-在上面的示例中,我希望使用浮点模板类型实例化saver3
,因为x2
是浮点。在实际代码中,x2将是泛型类型的函数参数,但如果函数是用不同的编译时类型实例化的,则不能像这样指定类型参数,尽管您已经静态地知道x2
和y2
的类型,所以你的用例不清楚。不清楚你到底想做什么:你是想构建代码,用编译时未知的泛型参数来实例化你的类,还是只想说“不管x2是什么类型的,请使用它”,然后让编译器来解决它“无论x2是什么类型,请使用它“,让编译器解决它吗?案例-在上面的示例中,我希望使用浮点模板类型实例化saver3
,因为x2
是浮点。在实际代码中,x2将是泛型类型的函数参数,但如果函数使用不同的编译时类型实例化,则第二种形式不起作用,但第一种形式起作用-请参见UPDATE@user1857742-您使用的是哪个版本的F#?第二种形式可能需要F#4I,我认为它的3.1—在Visual Studio 2013中,第二种形式不起作用,但第一种形式起作用—请参见UPDATE@user1857742-您使用的是哪个版本的F#?第二种形式可能需要F#4I,我想它的3.1版本-在Visual Studio 2013中,感谢您提供详细的答案-我不想重复
let lt = createSaveXY (typeof<float>) (box 3.0) (box 7.0)
lt.LessThan()