F# F中具有通用度量单位结构的奇怪错误和其他奇怪行为#

F# F中具有通用度量单位结构的奇怪错误和其他奇怪行为#,f#,units-of-measurement,F#,Units Of Measurement,我有这种类型: type Vector3<[<Measure>]'u> = struct val x:float32<'u> val y:float32<'u> val z:float32<'u> end new(x, y, z) = { x = x; y = y; z = z } 给我一个错误: 错误1此表达式应为float32类型,但此处为float32类型

我有这种类型:

type Vector3<[<Measure>]'u> =
    struct
        val x:float32<'u>
        val y:float32<'u>
        val z:float32<'u>
    end

    new(x, y, z) = { x = x; y = y; z = z }
给我一个错误:

错误1此表达式应为float32类型,但此处为float32类型

只有在后续计算中使用此实例时,才会出现这种情况;否则,它会将
f
的类型正确解析为
Vector3
。给构造函数类型,如
Vector3(…)
似乎也解决了这个问题,这真的很奇怪


我做错了什么吗?

您需要为val字段指定默认值属性:

type Vector3<[<Measure>]'u> =
    struct
        [<DefaultValue(false)>] val mutable x:float32<'u>
        [<DefaultValue(false)>] val mutable y:float32<'u>
        [<DefaultValue(false)>] val mutable z:float32<'u>
    end
    member X.Init(x,y,z) = 
        X.x <- x
        X.y <- y
        X.z <- z
类型向量3
[]val可变y:float32
结束
成员X.Init(X,y,z)=
X.X
val y:32
新的(X,Y,Z)={X=X;Y=Y;Z=Z}
结束

您需要为val字段指定默认值属性:

type Vector3<[<Measure>]'u> =
    struct
        [<DefaultValue(false)>] val mutable x:float32<'u>
        [<DefaultValue(false)>] val mutable y:float32<'u>
        [<DefaultValue(false)>] val mutable z:float32<'u>
    end
    member X.Init(x,y,z) = 
        X.x <- x
        X.y <- y
        X.z <- z
类型向量3
[]val可变y:float32
结束
成员X.Init(X,y,z)=
X.X
val y:32
新的(X,Y,Z)={X=X;Y=Y;Z=Z}
结束

您的代码中的其他地方一定有问题。如果重置F#Interactive,打开一个新的空F#脚本文件并粘贴以下代码(然后在FSI中运行),那么一切对我来说都正常:

type Vector3<[<Measure>]'u> =
    struct
        val x:float32<'u>
        val y:float32<'u>
        val z:float32<'u>
    end
    new(x, y, z) = { x = x; y = y; z = z }

[<Measure>] type N    
let f = Vector3(0.f<N>, 0.f<N>, 0.f<N>) 

代码中的其他地方一定有问题。如果重置F#Interactive,打开一个新的空F#脚本文件并粘贴以下代码(然后在FSI中运行),那么一切对我来说都正常:

type Vector3<[<Measure>]'u> =
    struct
        val x:float32<'u>
        val y:float32<'u>
        val z:float32<'u>
    end
    new(x, y, z) = { x = x; y = y; z = z }

[<Measure>] type N    
let f = Vector3(0.f<N>, 0.f<N>, 0.f<N>) 


Bleh,现在它在构造函数中说“外部字段被赋予了值”。如果你不想可变,我想你可以使用记录类型。我很想使用记录,但它们会给垃圾收集器带来很大压力。@Ankur从概念上讲,是的,最好将结构视为“按值传递”,将类视为“按引用传递”,但当性能受到质疑时,内存分配细节相当重要。@Ankur我做到了——有了记录,我每秒可以管理大约1500000个粒子(每个粒子有一系列向量操作)。使用structs,我可以得到大约2100000。此外,使用引用类型而不是值类型的性能影响也是众所周知的问题。我不认为这很主观。Bleh,现在它在构造函数中说“外部字段被赋予了值”。如果你不想可变,我想你可以使用记录类型。我很想使用记录,但它们给垃圾收集器带来了很大的压力。@Ankur在概念上,是的,最好将结构看作是“传递值”类被视为“通过引用传递”,但当性能受到质疑时,内存分配细节相当重要。@Ankur我做到了——通过记录,我每秒可以管理大约1500000个粒子(每个粒子有一系列向量操作)。使用structs,我可以得到大约2100000。此外,使用引用类型而不是值类型的性能影响也是众所周知的问题。我不认为这很主观。你是如何定义N的?因为你上面所说的(将所有设置为0)对我来说都很好——或者问题出在你以后的计算中?@David N在
Microsoft.FSharp.Math.SI
下,我相信它在PowerPack中。使用记录格式时,计算工作正常。您如何定义N?因为你上面所说的(将所有设置为0)对我来说都很好——或者问题出在你以后的计算中?@David N在
Microsoft.FSharp.Math.SI
下,我相信它在PowerPack中。使用记录格式进行计算效果很好。您能否展开有关性能的讨论。我有点站在安克尔这边。我很确定,如果基准测试使用5-8个字段运行,structs方法将受到影响。如果XBox/Compact GC确实是目标平台,那么这一点就成立了。@David-我没有阅读Ankur回答下的全部讨论内容。性能始终取决于特定的场景-添加和删除
Struct
属性是最简单的方法:-)。一般来说,如果需要创建大量字段(尤其是存储在数组中的字段),结构可能更适合于少数字段。关于Ankur发布的链接(堆栈分配是一个实现细节)-如果类型是不可变的,那么它是在堆上还是在堆栈上分配并不重要。这很好,因为您可以编写代码,然后添加/remov
Struct
属性,看看什么工作得更好—它不影响行为,只影响性能。特别是对于数组,这确实很重要,因为结构数组可以作为单个连续内存块分配。@David主要规则是,如果结构需要装箱(即转换为
对象
),那么它会转换为类似于类的行为——因此它实际上比引用类型慢。这种情况不再经常发生,因为泛型可以缓解这种需求。此外,据说结构在32字节以下的性能最好——但我的经验是,即使在PC机上,它们也可以比类大一些,而且仍然比类快,因为它们不会给垃圾收集器带来太大的压力。你能进一步讨论Tomas的性能吗。我有点站在安克尔这边。我很确定,如果基准测试使用5-8个字段运行,structs方法将受到影响。如果XBox/Compact GC确实是目标平台,那么这一点就成立了。@David-我没有阅读Ankur回答下的全部讨论内容。性能始终取决于特定的场景-添加和删除
Struct
属性是最简单的方法:-)。一般来说,如果需要创建大量字段(尤其是存储在数组中的字段),结构可能更适合于少数字段。关于Ankur发布的链接(堆栈分配是一个实现细节)-如果类型是不可变的,则与
type Vector3<[<Measure>]'u> =
    struct
        val x:float32<'u>
        val y:float32<'u>
        val z:float32<'u>
    end
    new(x, y, z) = { x = x; y = y; z = z }

[<Measure>] type N    
let f = Vector3(0.f<N>, 0.f<N>, 0.f<N>) 
[<Struct>]
type Vector3<[<Measure>]'u>(x:float32<'u>, y:float32<'u>, z:float32<'u>) =
    member this.X = x    
    member this.Y = y
    member this.Z = z
    static member Empty : Vector3<'u> = Vector3(0.f<_>, 0.f<_>, 0.f<_>)

[<Measure>] type N

let f1 = Vector3<N>.Empty
let f2 = Vector3(0.f<N>, 0.f<N>, 0.f<N>) 
f1.X + f2.X