表达类似值对象的惯用scala / FP方式

时间:2016-02-22 08:10:23

标签: scala functional-programming

我想知道表达类似消息(值对象)的惯用方法是什么 我们假设我要发送一些消息:UserEnter,UserLeft,UserSendGreeting等'。我希望以下内容可以表达我的困境

我认为有两个选项可以表达它:

trait UserAction
case class UserEnter (username:String,hour:Long,day:WeekDay,room:Int)
case class UserLeft (username:String,hour:Long,day:WeekDay,room:Int)
case class UserSendGreeting (username:String,,hour:Long,day:WeekDay,greeting:String)

def foo(userActions:List[UserAction]) = {
userActions match {
case UserEnter(userName)::tail =>
sendWelcomeMessage(userName)
handleOtherActions(tail) 

case UserLeft::tail => "must enter first"
case _ => "do something else"
}

另一种方式是:

    trait Action
    case class Enter(room:Int) extends Action
    case object Left(room:Int) extends Action
    case object Greet(msg:String) extends Action

    case class UserAction(username:String,action:Action,,hour:Long,day:WeekDay)

    def foo(userActions:List[UserAction]) = {
    userActions match {
    case head::tail if head.action == Enter =>
    sendWelcomeMessage(head.userName)    
    handleOtherActions(tail)             
    case head::tail if head.action == Left => "must enter first"
    case _ => "do something else"
    }

第一个选项更明确,更容易进行模式匹配,但更重复的代码。 另一个对动作本身更明确,但模式匹配更详细 哪种方式更好?

3 个答案:

答案 0 :(得分:3)

不要过分复杂化。如果您需要一对User(在您的案例中为字符串名称)和Action,请使用Tuple。收集所有" ...其他属性"也是有意义的。在相应的Action内。

type User = String

sealed trait Action

case class Enter(room:Int) extends Action

case class Left(room:Int) extends Action

case class Greet(msg:String) extends Action


def foo(userActions:List[(User, Action)]) = userActions match {
    case (username, _:Enter)::tail =>
      sendWelcomeMessage(username)
      handleOtherActions(tail)
    case (username, _:Left)::tail => "must enter first"
    case _ => "do something else"
  }

另外请不要忘记,模式匹配允许您unapply任意深度的层次结构:

case (username, Enter(room))::tail =>

答案 1 :(得分:0)

我认为1种方法更好,但您可以对UserAction特性进行约束以获得用户名字段:

trait UserAction {
  def username: String
}
case class UserEnter(username:String, room:Int)
case class UserLeft(username:String, room:Int)
case class UserSendGreeting(username:String, greeting:String)

这种方式很容易

1)模式匹配

2)使用通用UserAction获取用户名字段

答案 2 :(得分:0)

如何:TABLES: VBRK. DATA: BEGIN OF it_test, BUKRS(5), "longer version of VBRK-BUKRS, FKDAT LIKE VBRK-FKDAT, END OF it_test. DATA: tt_test TYPE STANDARD TABLE OF it_test. * I would strongly recommend to set a filter! SELECT * FROM VBRK INTO CORRESPONDING FIELD OF it_test. IF it_test-BUKRS = 'xxxx'. it_test-BUKRS = 'XXXXX'. APPEND it_test to tt_test. ENDIF. ENDSELECT.

case class UserAction(user: User, action: Action)

甚至更好

def foo(actions: Seq[UserActions]) = actions match {
    case UserAction(user, _: EnterAction)::tail => 
      processEnter(user)
      handleOtherActions(tail)
    case UserExit(user, _: ExitAction)::tail => processExit(user)
    ...
}

或者,也许,只是

def foo(actions: Seq[UserAction]) = actions.find { ua => 
  !ua.action.process(ua.user)
}