我试图避免在类中使用可变的实例变量,但在尝试在Play应用程序中创建用户时,在以下情况下无法解决问题:

用户信息(例如,membershipList)可以在用户登录时更改。当这种情况更改时,应用程序使用Play的Ok.feed(...)作为服务器发送事件(SSE)通知用户。

编辑:@drstevens指出,由于User显示为Case类,因此必须移出单播提要。编辑以使User不是案例类。

class User(id: Long, firstName: String, lastName: String,
           membershipList: List[Group], @volatile private var signedIn = true) {
  private var infoSentOnce = false;
  private val unicastFeed: Option[Enumerator[JsValue]] = if(signedIn) Concurrent.unicast[JsValue](onStart, onComplete, onError) else None

  private def onStart(channel: Channel[JsValue]) {
    if(signedIn) {
      if(!infoSentOnce) {
        channel.push(json)
        channel.end
        infoSentOnce = true;
      }
    } else {
      channel.eofAndEnd
    }
  }

  private def onComplete = ....

  private def onError(message: String, iteratee: Iteratee[JsValue]) = .....

  def json = {
    .....
  }

  def signedOut = signedIn = false

  def feed = unicastFeed
}

Controller 中的操作将是:
class MyController extends Controller with MyAuth {
  def userFeed = Authenticated { request =>
     request.user.feed.fold(Ok(request.user.json)) { feed =>
       Ok.feed(feed
               >& Concurrent.buffer(10)
               >& new EventSource()).as("text/event-stream"))
     }
  }
}
signedIninfoSentOnce是我想将其更改为不可变的两个可变变量。可变的infoSentOnce也可能与我无法正确理解Play的枚举器有关。每当用户信息更改时,我都会创建一个新的User对象,但会从同一个用户的先前实例通过单播枚举器进行复制。创建新的User实例后,会将Json推送到用户的单播频道一次。

也许将infoSentOnce设为var可以,因为无法通过任何外部交互进行修改?

最佳答案

由于您的User类本身正在处理事件,因此它将必须维护状态,这意味着可变。

当外部力量对它们进行处理时,不可变类最有用,例如MyController正在登录用户,并且可以创建user = user.copy(signedOn = true)
如果类本身正在管理状态,那么,您就需要可变性。

您可以在此处作弊,通过将您的布尔变量替换为val来获取所有AtomicBoolean,但这只是将可变性提高了一级。

关于scala - Scala:避免可变的实例变量,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22176822/

10-13 09:11