我试图避免在类中使用可变的实例变量,但在尝试在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"))
}
}
}
signedIn
和infoSentOnce
是我想将其更改为不可变的两个可变变量。可变的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/