简体   繁体   English

如何在Scala中的案例类上强制使用具有特征的属性?

[英]How to enforce properties with traits on a case class in scala?

case class CaseClassJobEvent(
                   jobId: String,
                   jobType: Option[String],
                   inPlanning: Option[Boolean],

                   teamId: String,
                   actorId: String,
                   adminActorId: Option[String],
                   sessionId: String,
                   clientSessionId: Option[String],
                   clientCreatedAt: Long,
                   seqId: Long,
                   isSideEffect: Option[Boolean],

                   opAction: String,
                   stepId: Option[String],
                   jobBaseStepId: Option[String],
                   fieldId: Option[String],

                   serverReceivedAt: Option[Long]) extends Event

With the trait: 具有特征:

trait Event {
  var teamId: String
  var actorId: String
}

Produces this error: 产生此错误:

class CaseClassJobEvent needs to be abstract, since:
[error] it has 2 unimplemented members.
[error] /** As seen from class CaseClassJobEvent, the missing signatures are as follows.
[error]  *  For convenience, these are usable as stub implementations.
[error]  */
[error]   def actorId_=(x$1: String): Unit = ???
[error]   def teamId_=(x$1: String): Unit = ???
[error]   case class CaseClassJobEvent(
[error]              ^

What am I doing wrong? 我究竟做错了什么? What should I be doing? 我该怎么办? Is there anyway to use traits or inheritance to enforce properties on a case class? 无论如何,是否可以使用特征或继承来对案例类实施属性? I don't want to enforce methods just properties. 我不想只强制执行属性方法。

Luis Miguel Mejía Suárez already answered your question, so I thought I would add something here so you might reconsider the design of your class. 路易斯·米格尔·梅贾·苏亚雷斯(Luis MiguelMejíaSuárez)已经回答了您的问题,所以我想在这里添加一些内容,以便您可以重新考虑班级的设计。

Instead of creating a var in your case class, use the .copy method for case class to generate a new object with the changed fields. 代替在案例类中创建var,而对案例类使用.copy方法来生成具有更改字段的新对象。

So, if you want to change teamId or actorId in your case class do something like this: 因此,如果要在案例类中更改teamId或actorId,请执行以下操作:

val jobEvent = CaseClassJobEvent(...)
val changedJobEvent = jobEvent.copy( teamId = "somenewvalue", actorId = "somenewvalue" )

To answer your original question: 要回答您的原始问题:

trait Event {
  def teamId: String
  def actorId: String
}

case class CaseClassJobEvent(
                   jobId: String,
                   jobType: Option[String],
                   inPlanning: Option[Boolean],

                   var teamId: String,
                   var actorId: String,
                   adminActorId: Option[String],
                   sessionId: String,
                   clientSessionId: Option[String],
                   clientCreatedAt: Long,
                   seqId: Long,
                   isSideEffect: Option[Boolean],

                   opAction: String,
                   stepId: Option[String],
                   jobBaseStepId: Option[String],
                   fieldId: Option[String],

                   serverReceivedAt: Option[Long]) extends Event

A design like this is probably what you wanted. 这样的设计可能就是您想要的。 It's fine for a school project, but you would never do something like this in production, especially if you are working in a multithreaded environment. 这对于学校项目来说很好,但是您绝不会在生产中执行此类操作,尤其是在多线程环境中工作时。 Immutable values are always thread-safe, and you would be breaking that by adding vars to your class. 不可变的值始终是线程安全的,您可以通过在类中添加var来打破不固定的值。

Just something to consider. 只是要考虑的事情。

======= =======

We are currently discussing how to implement CaseClassJobEvent without using mutable values. 我们目前正在讨论如何在不使用可变值的情况下实现CaseClassJobEvent。 Here is my suggested implementation. 这是我建议的实现。

trait Event {
  def teamId: String
  def actorId: String
}

case class CaseClassJobEvent(
                   jobId: String,
                   jobType: Option[String],
                   inPlanning: Option[Boolean],

                   teamId: String,
                   actorId: String,
                   adminActorId: Option[String],
                   sessionId: String,
                   clientSessionId: Option[String],
                   clientCreatedAt: Long,
                   seqId: Long,
                   isSideEffect: Option[Boolean],

                   opAction: String,
                   stepId: Option[String],
                   jobBaseStepId: Option[String],
                   fieldId: Option[String],

                   serverReceivedAt: Option[Long]) extends Event

Everything is the same as the solution you want except teamId and actorId are not vars. 除了teamId和actorId不是vars之外,其他所有内容都与所需的解决方案相同。

If you need to change the value of teamId and actorId in your case class to something else, do something like this: 如果需要将案例类中的teamId和actorId的值更改为其他值,请执行以下操作:

def setTeamIdAndActorId(myEvent: CaseClasJobEvent, newTeamId: Option[String], newActorId: Option[String]): CaseClassJobEvent = {
  val newEvent1 = if (newTeamId.isDefined) myEvent.copy(teamId = newTeamId.get) else myEvent
  val newEvent2 = if (newactorId.isDefined) newEvent1.copy(actorId = newActorId.get) else newEvent1
  newEvent2
}

If this seems like a horribly verbose way to have to modify a case class, you're right. 如果这似乎是必须修改案例类的极其冗长的方法,那么您是对的。 What we currently do at our company is use the quicklens library from softwaremill to modify deeply nested case classes with more elegant syntax. 我们公司目前的工作是使用softwaremill的quicklens库以更优雅的语法修改深层嵌套的case类。 It is still not as simple as reassigning a var, but it is more correct in a multithreaded environment, and it is less verbose than calling copy all the time. 它仍然不像重新分配var那样简单,但是在多线程环境中它更正确,并且比一直调用copy更为冗长。 However, for your purposes, if you want correctness without learning a new library, copy may be your best bet. 但是,出于您的目的,如果您想在不学习新库的情况下获得正确性,那么复制可能是您的最佳选择。

======= =======

The way the conversation is evolving now is that the person who asked the question just wants to have an input that will do something if it has certain fields. 对话的发展方式是,提出问题的人只想输入一个可以在某些字段中起作用的输入。 This sounds like a job for inheritance. 这听起来像是一项继承工作。

Suppose I have lots of events. 假设我有很多事件。

trait Event

I want to have a function that only does something if my event has actorId and teamId. 我希望有一个仅在我的事件具有actorId和teamId的情况下才能执行某些操作的函数。

trait IdEvent {
  def teamId: String
  def actorId: String
} extends Event

Here is my function, that only does something if my event is an IdEvent 这是我的函数,仅当我的事件是IdEvent时才执行某些操作

def processEvent(e: Event): Option[Int] = {
  e match {
    case event: IdEvent => someProcess(event)
    case event: Event => None
  }
}

where someProcess has signature 其中someProcess具有签名

def someProcess(input: IdEvent): Option[Int]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM