Scala 找出一种将var实现转换为val的方法
我正在使用Java库中的以下接口:Scala 找出一种将var实现转换为val的方法,scala,functional-programming,var,Scala,Functional Programming,Var,我正在使用Java库中的以下接口: // This is a Java class from a library I'm using public interface Listener { void receiveConfigInfo(final String configInfo); } 我在Scala中将其扩展如下: //MyClass needs to extends the Listener interface final class MyClass extends Listene
// This is a Java class from a library I'm using
public interface Listener {
void receiveConfigInfo(final String configInfo);
}
我在Scala中将其扩展如下:
//MyClass needs to extends the Listener interface
final class MyClass extends Listener {
private var config = Option.empty
// Implement the the Listener interface
override def receiveConfigInfo(configInfo: String): Unit = {
try {
config = decode[Map[String, String]](configInfo) match {
case Right(config) => Some(config)
case Left(_) => None
}
} catch {
case _: Throwable => nacosConfig = None
}
}
override def getConfig():Option[Map[String, String]] = nacosConfig
}
receiveConfigInfo
将在相关时自动调用
getConfig
返回配置的最新值
有没有办法将config
转换成val
,而不是可变的var
?我无法更改receiveConfigInfo
的签名,因为它需要尊重父类的签名
目标是无论何时调用
getConfig
,我都应该获得最新的配置值。但是,我当前的实现有一个var
,这不好,有没有办法更改此代码使其变为val,或者如果可能的话,还有其他方法?鉴于您正在实现的Java接口似乎需要一个实现来接受任意多个新的configInfo
,我建议最诚实的做法是保留var,但将其封装为只能通过receiveConfigInfo
进行更改
所以可能是
object MyClass {
private[MyClass] Config {
private var underlying: Map[String, String] = Map.empty
override def get(key: String): Option[String] =
synchronized { underlying.get(key) }
override def toMap: Map[String, String] =
synchronized { underlying }
override def update(configInfo: String): Unit =
synchronized {
// I'm assuming that decode is somewhere statically accessible
// I'm also assuming that a function returning an `Either` won't throw non-fatal exceptions... if it can return a Left, a Right, or throw, then:
// Try { decode[...](configInfo) }.flatMap(_.left.map(msg => new RuntimeException(msg)).toTry)
val decoded =
decode[Map[String, String]](configInfo)
.left
.map(_ => new RuntimeException("decode failed")
.toTry
decoded.foreach { newConfig => underlying = newConfig }
decoded.recoverWith { _ =>
underlying = Map.empty
decoded
}
}
}
}
class MyClass extends Listener {
private val config = new MyClass.Config
override def receiveConfigInfo(configInfo: String): Unit = config.update(configInfo)
}
有了这样一个解决方案,配置对于MyClass
中不调用update
的任何东西都是不可变的(希望这与分配给var
相比足够明显)
如果出现错误的
configInfo
时,我将保留取消设置配置的行为;在这种情况下,保持configInfo
不变可能更有意义,这将使在实践中更难无意中更改配置,除非MyClass
的客户端调用receiveConfigInfo
使用有效的配置。鉴于您正在实现的Java接口似乎需要一个实现来接受任意多个新的configInfo
,我建议最诚实的做法是保留var,但将其封装为只能通过receiveConfigInfo
更改
所以可能是
object MyClass {
private[MyClass] Config {
private var underlying: Map[String, String] = Map.empty
override def get(key: String): Option[String] =
synchronized { underlying.get(key) }
override def toMap: Map[String, String] =
synchronized { underlying }
override def update(configInfo: String): Unit =
synchronized {
// I'm assuming that decode is somewhere statically accessible
// I'm also assuming that a function returning an `Either` won't throw non-fatal exceptions... if it can return a Left, a Right, or throw, then:
// Try { decode[...](configInfo) }.flatMap(_.left.map(msg => new RuntimeException(msg)).toTry)
val decoded =
decode[Map[String, String]](configInfo)
.left
.map(_ => new RuntimeException("decode failed")
.toTry
decoded.foreach { newConfig => underlying = newConfig }
decoded.recoverWith { _ =>
underlying = Map.empty
decoded
}
}
}
}
class MyClass extends Listener {
private val config = new MyClass.Config
override def receiveConfigInfo(configInfo: String): Unit = config.update(configInfo)
}
有了这样一个解决方案,配置对于MyClass
中不调用update
的任何东西都是不可变的(希望这与分配给var
相比足够明显)
如果出现错误的
configInfo
时,我将保留取消设置配置的行为;在这种情况下,保持configInfo
不变可能更有意义,这将使在实践中更难无意中更改配置,除非MyClass
的客户端调用receiveConfigInfo
有了有效的配置。如果你真的想使用val
,你可以使用中的一个可变结构。但是,它会更迂回,可能容易出错,并且在幕后实际使用var
,因此你也可以直接使用var
(你的代码已经是这样)
//在类结构中
val config=collection.mutable.IndexedSeq[Option[Map[String,String]](无)
...
//接收配置信息
配置(0)=解码。。。
//在getConfig中
配置(0)
如果您真的想使用val
,您可以使用中的一种可变结构。但是,它会更迂回,可能会出错,并且在幕后实际使用var
,因此您最好直接使用var
(您的代码已经是这样)
//在类结构中
val config=collection.mutable.IndexedSeq[Option[Map[String,String]](无)
...
//接收配置信息
配置(0)=解码。。。
//在getConfig中
配置(0)
没有(简单的)方法删除var
。好吧,你可以使用cats effect
中的[Deferred](),但这会改变你使用代码的方式。我宁愿将重点放在删除try
一个和None[Map[String,String]]
不是有效语法,也不是必需的。该类需要实现接口not extend。@RajaShekar该示例不幸地将Java和Scala混合在一起,但在Scala中,您可以使用extend
进行任何操作,包括Java接口(只要它们是您扩展的第一件事,关键字with
必须用于以下特征和接口)。旁注:不要捕获可丢弃的s,我建议改用非致命的提取器(此答案中的更多详细信息:)。没有(简单)删除var
的方法。您可以使用cats effect
中的[Deferred](),但这将大大改变您使用代码的方式。我更愿意将重点放在删除try
一个None[Map[String,String]]
不是有效语法,也不是必需的。该类需要实现接口not extend。@RajaShekar该示例不幸地将Java和Scala混合在一起,但在Scala中,您可以使用extend
进行任何操作,包括Java接口(只要它们是您扩展的第一件事,关键字with
必须用于以下特征和接口)。旁注:不要捕获可丢弃的s,我建议改用非致命的提取器进行编译(此答案中有更多详细信息:)。