当我有一个相当干净的数据模型,包含具有共同特征的案例类并希望在其上实现通用算法时,就会发生这种情况.作为一个例子,生成的算法应该采用类型A的类,它是特征T的子类,并且应该返回具有一些更新字段的具体类A的副本.
当我可以简单地将抽象复制方法添加到基本特征并在所有子类中实现它时,这很容易实现.然而,这可能会使用某些算法仅需要的方法来污染模型,有时不可能,因为模型可能不受我的控制.
下面是一个演示问题的简化示例和使用运行时强制转换的解决方案.
请不要挂断细节.
假设有一个特征和一些我不能改变的案例类:
trait Share { def absolute: Int } case class CommonShare( issuedOn: String,absolute: Int,percentOfCompany: Float) extends Share case class PreferredShare( issuedOn: String,percentOfCompany: Float) extends Share
这是一种简单的方法,可以在共享总数更改时重新计算当前的percentOfCompany并更新案例类中的字段
def recalculateShare[A <: Share](share: A,currentTotalShares: Int): A = { def copyOfShareWith(newPercentage: Float) = { share match { case common: CommonShare => common.copy(percentOfCompany = newPercentage) case preferred: PreferredShare => preferred.copy(percentOfCompany = newPercentage) } } copyOfShareWith(share.absolute / currentTotalShares.toFloat).asInstanceOf[A] }
REPL上的一些示例调用:
scala> recalculateShare(CommonShare("2014-01-01",100,0.5f),400) res0: CommonShare = CommonShare(2014-01-01,0.25) scala> recalculateShare(PreferredShare("2014-01-01",50,400) res1: PreferredShare = PreferredShare(2014-01-01,0.125)
所以它的工作原理,据我所知,.asInstanceOf [A]调用永远不会失败,但需要编译代码.有没有办法在没有隐式转换的情况下以类型安全的方式避免运行时转换?
解决方法
asInstanceOf
你的解决方案感觉很脏,但我认为它并不是那么糟糕,并且gnarliness非常好.
类型类
为数据类型提供行为同时仍然保持代码中关注点分离的一种很好的方法是Enrich Your Library / typeclass模式.我希望我有一个完美的参考,但我没有.查找这些术语或“隐含类”,你应该能够找到足够的例子来获得漂移.
您可以创建一个特性copyable [A] {def copy(?):A}类型类(隐式类)并为每个类型创建它的实例.这里的问题是它有点冗长,特别是如果你想让复制方法完全通用的话.我把它的参数列表作为一个问号留下了,因为你可以根据实际需要将其简单地定制,或者你可以尝试让它适用于任何案例类,这将非常困难.
光学
镜头是为解决这种尴尬而制作的.您可能想查看Monocle,这是解决此问题的一个很好的通用方法.虽然它仍然没有真正解决冗长问题,但如果你在整个项目中反复出现这个问题,可能就是要走的路,特别是如果你发现自己试图在对象图中深入进行更改.
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。