【问题标题】:How to pattern match on the type of the message received in F# akka.net?如何对 F# akka.net 中收到的消息类型进行模式匹配?
【发布时间】:2015-04-17 09:31:26
【问题描述】:

请查看上次编辑。

为新手问题道歉。我正在尝试使用 Akka.net 在 F# 中实现一些东西。我对 F# 很陌生,我只使用过 Scala 的 Akka。基本上我正在尝试在 Scala 中实现一些非常简单的东西,即让 Actor 根据它接收到的消息类型做不同的事情。

我的代码如下,它是对来自 akka.net 网站的 hello world 示例的轻微修改。我相信我的代码的第一个问题是它确实记录了模式匹配而不是类型模式匹配,但是我无法编写一个没有编译错误的类型匹配......任何帮助将不胜感激。谢谢。

open Akka.FSharp
open Actors
open Akka
open Akka.Actor

type Entries = { Entries: List<string>}

let system = ActorSystem.Create "MySystem"

let feedBrowser = spawn system "feedBrowser" <| fun mailbox -> 
    let rec loop() = actor {
        let! msg = mailbox.Receive()
        match msg with 
        | { Entries = entries} -> printf "%A" entries
        | _ -> printf "unmatched message %A" msg 
        return! loop()}
    loop()

[<EntryPoint>]
let main argv = 

    feedBrowser <! "abc"        // this should not blow up but it does

    system.AwaitTermination()

    0

编辑:错误是运行时错误,System.InvalidCastException,无法将 String 类型的对象转换为 Entries。

后来编辑:我得到了这个来处理这个变化,向下转换为对象:

let feedBrowser = spawn system "feedBrowser" <| fun mailbox -> 
    let rec loop() = actor {
        let! msg = mailbox.Receive()
        let msgObj = msg :> Object
        match msgObj with 
        | :? Entries as e  -> printfn "matched message %A" e
        | _ -> printf "unmatched message %A" msg 
        return! loop()}
    loop()

现在这两行正常工作

feedBrowser <! "abc"
feedBrowser <! { Entries = ["a"; "b"] }

第一个打印“unmatched message abc”,第二个输出条目。

在没有演员阵容的情况下,有没有更好的方法来解决这个问题? akka.net 有专门针对这种情况的东西吗? 谢谢。

【问题讨论】:

  • 你应该指定错误是什么。
  • 我已经编辑了帖子并添加了异常消息。
  • 呃,你通过"abc" - 你期待什么?也许你想要feedBrowser (Entries(List([|"abc"|])))? (假设这不是 F# 的 list,在这种情况下是 feedBrowser (Entries ["abc"])。)
  • 我期待它打印“unmatched message abc”,这正是它找不到匹配项的关键。
  • 但你永远不会投射 - 你可能会收到关于 _ 匹配永远不会发生的警告。您需要使用类型测试模式,而不是记录模式

标签: f# pattern-matching akka.net


【解决方案1】:

您应该使用Discriminated Union(本示例中的命令类型)。然后你可以对它的选项进行模式匹配。

type Entries = { Entries: List<string>}

type Command = 
    | ListEntries of Entries
    | OtherCommand of string

let stack() = 

    let system = ActorSystem.Create "MySystem"

    let feedBrowser = spawn system "feedBrowser" <| fun mailbox -> 
        let rec loop() = actor {
            let! msg = mailbox.Receive()
            match msg with 
            | ListEntries { Entries = entries} -> printf "%A" entries
            | OtherCommand s -> printf "%s" s
            return! loop() }
        loop()

并发送您应该使用的消息:

feedBrowser <! OtherCommand "abc"
feedBrowser <! ListEntries { Entries = ["a"; "b"] }

重要的是要说发送运算符具有以下签名:

#ICanTell -> obj -> unit

因此,如果您传递不同类型的消息,例如字符串,则会引发异常。

【讨论】:

  • 谢谢。它比转换为 Object 更干净。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-08
  • 2013-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-09
相关资源
最近更新 更多