F# 如何实现单例模式(语法)

F# 如何实现单例模式(语法),f#,singleton,F#,Singleton,我有一个从外部源刷新的数据缓存,我想限制我对应用程序内部的缓存(只读)的访问。我不希望每次需要访问数据源时都刷新数据源(例如,在实例化时,获取我需要的所有数据,因为有相当多的数据保持最新) 但是空值的缺乏让我陷入了一个循环。我想我可以使用一个选项类型等,但它是一个循环扔我 type MySingleton = [<DefaultValue>] static val mutable private instance: MySingleton opti

我有一个从外部源刷新的数据缓存,我想限制我对应用程序内部的缓存(只读)的访问。我不希望每次需要访问数据源时都刷新数据源(例如,在实例化时,获取我需要的所有数据,因为有相当多的数据保持最新)

但是空值的缺乏让我陷入了一个循环。我想我可以使用一个选项类型等,但它是一个循环扔我

type MySingleton = 

        [<DefaultValue>]
        static val mutable private instance: MySingleton option

        static member GetInstance() = 
            match instance with
                 | Some(i) -> i
                 | None -> 
                            *MySingleton.instance = new MySingleton()
                            MySingleton.instance*
type MySingleton=
[]
静态val可变私有实例:MySingleton选项
静态成员GetInstance()=
匹配实例
|一些(i)->i
|无->
*MySingleton.instance=new MySingleton()
MySingleton.instance*
根据编译器的说法,这种逻辑是错误的

       if Helper.notExists MySingleton.instance then
            MySingleton.instance <- Some(new MySingleton())        
       MySingleton.instance 
如果Helper.note存在MySingleton.instance,则
MySingleton.instance.NET4.0和F#都有
惰性
,所以我认为您需要

module MySingleton =
    let private x = Lazy.Create(fun() -> 42)
    let GetInstance() = x.Value
(其中,
42
可能是一个
newwhatevertype()
或任何昂贵的初始化)


(解说:现在是2010年,很少需要显式地处理同步原语;语言和库封装了所有常见模式。)

Brian提到的
惰性类型是一个很好的起点。它允许您确保在需要该值时运行计算,并保证线程安全,这意味着计算只运行一次(尽管在某些情况下,您也可以使用来指定多个线程可以开始初始化缓存,并且只使用第一个结果)

但是,您可能还需要一种机制来将缓存标记为无效(例如,在指定的时间之后)并强制重新初始化缓存。请注意,这并不是真正的单例模式。无论如何,您仍然可以使用
Lazy
以线程安全的方式执行此操作,但您需要像这样构造代码:

module Cache = 
  // returns a lazy value that initializes the cache when 
  // accessed for the first time (safely)
  let private createCacheInitialization() = 
    lazy( // some code to calculate cache 
          cache )
  // current cache represented as lazy value
  let mutable private currentCache = createCacheInitialization()

  // Returns the current cache
  let GetCache() = currentCache.Value
  // Reset - cache will be re-initialized next time it is accessed
  // (this doesn't actually initialize a cache - just creates a lazy value)
  let Reset() = currentCache <- createCacheInitialization()
模块缓存=
//返回一个惰性值,该值在
//首次访问(安全)
让private createCacheInitialization()=
lazy(//一些用于计算缓存的代码
缓存)
//当前缓存表示为延迟值
让可变私有currentCache=createCacheInitialization()
//返回当前缓存
让GetCache()=currentCache.Value
//重置-缓存将在下次访问时重新初始化
//(这实际上并没有初始化缓存-只是创建了一个延迟值)
让Reset()=currentCache问题是如何实现单例模式,而不是如何实现延迟加载模式。单个线程可以通过几种方式安全地实现,例如:

// Standard approach in F# 2.0: using an implicit constructor.
type Singleton private() =
    static let instance = new Singleton()
    static member Instance = instance

// Abbreviated approach in F# 3.0: using an implicit constructor with auto property.
type Singleton private() =
    static member val Instance = Singleton()

// Alternative example: When you have to use an explicit ctor,
// and also want to check instanciation upon each access of the property.

/// This type is intended for private use within Singleton only.
type private SyncRoot = class end

type Singleton =
    [<DefaultValue>]
    static val mutable private instance: Singleton

    private new() = { }

    static member Instance = 
        lock typeof<SyncRoot> (fun() ->
            if box Singleton.instance = null then
                Singleton.instance <- Singleton())
        Singleton.instance    
//F#2.0中的标准方法:使用隐式构造函数。
类型Singleton private()=
静态let实例=新单例()
静态成员实例=实例
//F#3.0中的简化方法:使用具有auto属性的隐式构造函数。
类型Singleton private()=
静态成员val Instance=Singleton()
//另一个示例:当您必须使用显式ctor时,
//并且还希望在每次访问属性时检查实例。
///此类型仅用于Singleton中的私人使用。
类型private SyncRoot=类结束
类型单态=
[]
静态val可变私有实例:Singleton
private new()={}
静态成员实例=
锁定类型(fun()->
如果box Singleton.instance=null,则

Singleton.instance很抱歉重新提出一个老问题,我只想指出,有些人可能试图在公共属性中公开
instance
,在这种情况下,下面的代码可能会很有用:

// private constructor, just as any OO singleton
type public MyType private() =
  inherit SomeParent()

  static let mutable instance = lazy(new MyType())

  // Get the instance of the type
  static member Instance with get() = instance.Value

这次是认真的评论。为了确保你在正确的事情上寻求帮助,singleton是一个特殊的精心编制的类,你可以尝试创建任意多的实例,但在第一个实例之后,每次你都会得到第一个实例。因此,如果你尝试创建一个singleton数组,你只会得到一个相同对象的数组通过阅读您的问题,很难判断您是否真的想要这种行为。是的,我想要;singleton将包含大量的数据缓存,并在需要时提供对数据的访问,而不需要每次使用类来刷新/获取数据(这是一个很长的过程)。
Lazy.Create(fun()->42)之间有什么区别吗
lazy(42)
或者它们只是同一事物的不同语法?如果
42
是一个构造函数调用,在两个版本中都会延迟吗?同样的事情;lazy(expr)意味着lazy.Create(fun()->expr)@Brian--基本的F#development不是基本上是单例的吗?我是说,认真地说--你赋值一次,然后一遍又一遍地读取该值。我不确定我是否理解这与单例模式之间的区别。@Onorio:单例模式是关于两件事的:让每个人对一个命名对象都有相同的引用(这有点像你所说的),并避免初始化代码产生不良的副作用(可能是实际的副作用,或者只是“性能”效应,例如速度慢,或者占用大量内存或其他资源)。你希望确保这些效应不会发生一次以上(你只需要一个对象),除非需要,否则它们不会发生(如果没有人使用对象,就没有效果)。延迟初始化可以获得这些效果保证。@Brian--好的,我相信我理解你的意思。1.可以将默认构造函数设为私有(如,
键入PersonSingleton private()=…
),在这种情况下,您可以在类型中使用
static let
。2.不要锁定类型实例;因为该类型是公共的,其他代码也可能锁定它,从而导致死锁。感谢您从未删除
// Standard approach in F# 2.0: using an implicit constructor.
type Singleton private() =
    static let instance = new Singleton()
    static member Instance = instance

// Abbreviated approach in F# 3.0: using an implicit constructor with auto property.
type Singleton private() =
    static member val Instance = Singleton()

// Alternative example: When you have to use an explicit ctor,
// and also want to check instanciation upon each access of the property.

/// This type is intended for private use within Singleton only.
type private SyncRoot = class end

type Singleton =
    [<DefaultValue>]
    static val mutable private instance: Singleton

    private new() = { }

    static member Instance = 
        lock typeof<SyncRoot> (fun() ->
            if box Singleton.instance = null then
                Singleton.instance <- Singleton())
        Singleton.instance    
// private constructor, just as any OO singleton
type public MyType private() =
  inherit SomeParent()

  static let mutable instance = lazy(new MyType())

  // Get the instance of the type
  static member Instance with get() = instance.Value