使用AutoOpen属性的推荐原则是什么?
(这个问题可能是继续when to use module function VS static function on similarly named type)
专家F#指出“当您定义ad hoc顶级运算符时,这可能很有用 和功能:“
所以这似乎可以减少代码组织中的模块角色,当你在技术上需要编写代码但从客户角度删除它的存在时。
还有别的吗? 你什么时候使用它?
答案 0 :(得分:38)
我认为AutoOpen
属性的主要用途是当您的库的用户打开命名空间时,您想要使一些自由绑定值可用。这是属性非常有用的地方,因为我认为库通常应该导出名称空间中的所有定义,但出于某些目的,您需要导出值并且不能在内部定义值命名空间。
以下是F# async extensions中定义计算构建器的示例,因此需要导出asyncSeq
值(但同时,所有功能都包含在命名空间中):
namespace FSharp.Async
type AsyncSeq<'T> = (* ... *)
type AsyncSeqBuilder() = (* ... *)
[<AutoOpen>]
module GlobalValues =
let asyncSeq = AsyncSeqBuilder()
图书馆的用户只需撰写open FSharp.Async
,他们就会看到asyncSeq
。我认为相同的模式用于各种数学库(您还希望导出简单命名的函数。)
对于模块(例如List
和Seq
),我认为大多数人不使用open
并通过模块名称访问这些功能(例如List.map
),所以虽然你可以将它用于嵌套模块,但我没有经常看到它。
答案 1 :(得分:20)
它可用于将模块组织成子模块,但在外部呈现统一/单模块视图:
module Outer =
[<AutoOpen>]
module Inner1 =
let f1() = ()
[<AutoOpen>]
module Inner2 =
let f2() = ()
open Outer
let x = f1()
let y = f2()
FParsec执行此操作:open FParsec
打开所有子模块(Primitives
,CharParsers
等。)
答案 2 :(得分:0)
聚会晚了一点,但是我想添加另一种用法。
我倾向于使用[<AutoOpen>]
在命名空间中公开类型。
// SlimSql\Types.fs
namespace SlimSql
[<AutoOpen>]
module Types =
type SqlOperation =
{
Statement : string
Parameters : SqlParam list
}
然后,我可以将函数附加到相同的类型名称,而不会出现名称已被使用的编译器错误。
// SlimSql\SqlOperation.fs
namespace SlimSql
module SqlOperation =
let merge (operations : SqlOperation list) : SqlOperation =
...
let wrapInTransaction operation =
...
然后,在消费代码中,所有内容都用相同的名称打包。因此,当用户在SqlOperation数据上查找行为时,他们自然可以通过键入SqlOperation.
来找到它,并且Intellisense会显示出来。在实践中,与使用List
之类的类型几乎相同。
open SlimSql
let operations =
[
sql "INSERT INTO ...." [ p "@Value" 123; ... ]
...
]
let writeOp =
operations
|> SqlOperation.merge
|> SqlOperation.wrapInTransaction
还可以自行打开SlimSql.Types模块,以仅访问与其他类型组成的类型。
我更喜欢这种解决方案,而不是使用静态成员来扩充类型。