Как сопоставить шаблон по типу сообщения, полученного в F# akka.net?
Пожалуйста, смотрите последнее редактирование.
Извиняюсь за вопрос новичка. Я пытаюсь реализовать что-то в F# с помощью Akka.net. Я очень новичок в F#, и я использовал только Акку из Scala. По сути, я пытаюсь реализовать что-то довольно простое в Scala, а именно заставить актера делать разные вещи в зависимости от типа получаемого им сообщения.
Мой код приведен ниже, и это небольшая модификация примера "Привет, мир", взята с сайта akka.net. Я считаю, что первая проблема с моим кодом заключается в том, что он выполняет сопоставление с образцом записи вместо сопоставления с образцом типа, однако я не смог написать сопоставление с типом без ошибок компиляции... Любая помощь будет принята с благодарностью. Спасибо.
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 к записям.
Позднее редактирование: я получил это для работы с этим изменением, понижая до объекта:
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"] }
первый выводит "непревзойденное сообщение abc", а второй выводит записи.
Есть ли лучший способ обойти это без актерского состава? Есть ли у akka.net что-то конкретно для этого случая? Спасибо.
1 ответ
Вы должны использовать Дискриминационный Союз (тип Команды в этом примере). Тогда вы можете сопоставить шаблон с его параметрами.
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
Поэтому, если вы передадите сообщение другого типа, например строку, оно вызовет исключение.