F# - 功能不返回更新的数据

时间:2015-03-03 03:35:59

标签: function dictionary f# immutability mutable

我有一个GetCars函数,它不会返回更新后的状态。如果我添加一个参数,它工作正常,或者如果我在其他函数中执行相同的代码,它工作正常。

open System
open System.Collections.Concurrent

type Car = {
    Make : string
    Model : string
    ID : int
}

type Cars = {
    Count : int
    Collection : Car[]
}

module AppState = begin
    let state = new ConcurrentDictionary<string, obj>()

    let added = state.TryAdd("cars", {
        Count = 1
        Collection = [| { Make = "Honda"; Model = "Civic"; ID = 0 } |]
    })

    let DownCastCars (o : obj) =
        match o with
        | :? Cars as cars -> Some(cars)
        | _ -> None

    let GetCars = 
        let mutable cars : obj = null; 
        let success = state.TryGetValue("cars", &cars)
        if success then
            DownCastCars cars
        else
            None

    let AddCar car =
        match GetCars with
        | Some cars -> 
            state.TryUpdate("cars", { cars with Collection = Array.append cars.Collection [| car |] }, cars)
        | None ->
            false
end

let AddCarMakeModel make model =
    let car : Car = {
        Make = make
        Model = model
        ID = match AppState.GetCars with
                | Some cars -> cars.Collection.Length
                | None -> 0
    }
    let success = AppState.AddCar car
    if success then
        printfn "Successfully added car :)"
    else
        printfn "Failed to add car :("

[<EntryPoint>]
let main argv = 
    AddCarMakeModel "Honda" "Civic"
    AddCarMakeModel "Honda" "Civic LX"
    printfn "Press any key to continue"
    let s = Console.ReadLine()
    0 // return an integer exit code

如果我向GetCars添加一个参数,即

let GetCars notused = 
    let mutable cars : obj = null; 
    let success = state.TryGetValue("cars", &cars)
    if success then
        DownCastCars cars
    else
        None

然后GetCars函数每次都会返回最新值。或者,如果我只是将相同的代码放在我正在使用的其他方法中,即

let AddCarMakeModel Make Model =
    let car : Car = {
        Make = make
        Model = model
        ID = match AppState.GetCars with
                | Some cars -> cars.Collection.Length
                | None -> 0
    }
    let success = AppState.AddCar car
    if success then
        printfn "Successfully added car :)"
    else
        printfn "Failed to add car :("

我猜这与#34; Do Bindings&#34;但我不确定如何成功应用于GetCars。我确实注意到应用程序启动时会调用GetCars,如果我在函数内部设置了一个断点,它就再也没有了。

1 个答案:

答案 0 :(得分:2)

正如评论中已经说明的那样,解决方案是添加一个单位参数。

问题在于您声明的是常量值,而不是函数值。

如果你看一下它的签名就很明显:val GetCars : Cars option没有箭头,只有一个值,所以GetCars只会被执行一次并绑定到表达式右侧的值

通过添加单位参数,您将获得签名:val GetCars : unit -> Cars option所以现在在调用站点,您可以单独通过GetCars引用函数值,或者执行它并通过{{获得结果1}}。

另请注意,您不需要mutable,因为F#将函数返回值并将ref作为元组处理,您可以像这样编写GetCars()

GetCars

然后摆脱函数let GetCars() = match state.TryGetValue("cars") with | true, (:? Cars as cars) -> Some cars | _ -> None