【问题标题】:Type inference creating undesired constraint类型推断创建不希望的约束
【发布时间】:2012-07-28 00:54:57
【问题描述】:

由于我有大量的IDisposables 需要处理一段时间,因此我设置了一个一次性物品列表和一个传递函数,以将项目添加到其中作为副作用:

let mutable disposables = []
let (~-) (x:'a) = disposables <- x :: disposables; x

这样我就有希望做到这一点:

let thing1 = -new Form()
let thing2 = -new Control()

for i in disposables do i.Dispose()

问题在于 F# 自动将 'a 约束为 IDisposable,并带有警告消息:

这种构造导致代码比类型注释所指示的更通用。类型变量“a”已被限制为“IDisposable”类型。

那么operator ~-的返回类型就变成了IDisposable,这就破坏了函数的便利性。

有没有办法阻止 F# 创建这个约束?

【问题讨论】:

  • 如果disposablesIDisposable 的列表,那么x 除了IDisposable 本身还能是什么?在任何情况下,你都可以给disposables 一个显式类型,然后看看你会得到什么——我是一个Haskeller,所以这只是猜测。
  • let inline (~-) (x:'a) = disposables &lt;- x :: disposables; x 能解决这个问题吗?
  • @JohnPalmer 不,Local class bindings cannot be marked inline. Consider lifting the definition out of the class or else do not mark it as inline.
  • @JonPurdy 我需要返回的x 是我发送的类型,而不是IDisposable。在disposables 上注释类型似乎没有太大变化:(
  • 很多更好的方法来做到这一点!

标签: f# type-inference


【解决方案1】:

知道了!

答案是当我在函数中使用xIDisposable 时,而不是在函数的类型签名中:

let mutable disposables = []
let (~-) x = disposables <- (x :> IDisposable) :: disposables; x

【讨论】:

  • (upcast x) 读起来比 (x :&gt; IDisposable) IMO 好一点,但你需要给 disposables 一个明确的类型。
【解决方案2】:

您没有就您的代码征求一般性建议,但我觉得有必要指出一些奇怪之处。

首先,您几乎不必致电Dispose()use 是管理资源的标准方式。你可能应该这样做:

use thing1 = new Form()
use thing2 = new Control()

其次,为什么要将不可变数据结构分配给mutable 变量?如果您确信需要手动跟踪资源,请使用

let disposables = ResizeArray<IDisposable>()

最后,在定义一个在其自身范围之外改变变量的运算符之前,您应该仔细考虑一下。这对操作员来说是不寻常的行为(除非操作员的范围很窄)。

【讨论】:

  • 尽管我很想使用use,但我正在处理游戏代码,所以为了提高效率,我不可避免地必须使用 .NET Framework 的本机习惯用法,尤其是在为了避免过多地调用 GC。我经常使用类,因为闭包在每次调用时都在堆上分配。就使用列表而言,我不太介意开销,因为一次性用品大多是巨大的资源,无论如何我都不会创建很多 - 所以列表和 ResizeArray 之间没有任何实际区别。
猜你喜欢
  • 1970-01-01
  • 2021-06-23
  • 2020-07-30
  • 1970-01-01
  • 1970-01-01
  • 2017-11-03
  • 1970-01-01
  • 1970-01-01
  • 2016-10-28
相关资源
最近更新 更多