【发布时间】:2019-01-04 12:26:31
【问题描述】:
我有一个 Set,我想在调用该 Set 时将另一个值隐式添加到该 Set 的末尾。
例如,我需要这样的东西才能工作:
implicit def addToSet(set: Set[Int]) = set + 4
val s = Set(1, 2, 3)
println(s) // Set(1, 2, 3, 4)
用例:
我正在构建一个网站(使用 PlayFramework),我有大约 20-30 组角色,它们对应于不同的功能。对于每个页面,只有某些角色可以访问某些功能,所以每次我需要检查角色权限时我都有一些功能(伪代码:if(role.canAccess(/*name of page*/))),它检查用户登录的角色是否包含在/*name of page*/对应的Set。
我现在正在创建一个超级用户,它可以访问每个页面上的每个功能,因此用户的“角色”需要在每个集合中。我不想通过手动将此角色添加到每个 Set 来执行此操作,因为我希望它具有可扩展性且易于维护,因此我希望有一个解决方案,它只是在幕后自动将这个新的超级角色添加到每个 Set .
我也愿意接受非隐式答案,只要他们不修改我已有的原始集合。
【问题讨论】:
-
隐式 def 会创建一个隐式转换。所以,如果你需要一个 Set[Long] 并且你提供一个 Set[Int] 它会选择它......没有理由编译器去转换那个集合,所以在那里什么都不会做。只需创建一个与您的集合一起使用的小方法,如果您使用的是不可变集合,则更改它没有问题,您将返回一个新集合。此外,隐式转换真的很诱人,因为代码“干净”,但意味着你隐藏了代码的真正作用。
-
@LuisMiguelMejíaSuárez 现在我已经做了类似于拉曼建议的事情——在这个例子中,它类似于
object MyObj { implicit class MyClass(in: Set[Int]) { def values = in + 4 } }; import MyObj._; ...——我在我的每个集合之后都放了.values。我宁愿不碰我原来的套装,但这是我目前想出的最干净的解决方案。 -
@JamesWhiteley 带有扩展方法的隐式类是个好主意!因为它们很清晰,而且隐含性很明确(听起来很奇怪,但我希望你明白我的意思)。如果您想要更多的类型安全,您可以为角色创建自己的类型(它可能是一个简单的类型别名),并仅为角色集创建隐式类,并且该方法可以称为@ 987654327@ 这将使一切变得超级清晰。我知道在每个地方都这样做很痛苦,但总比你无法控制的黑魔法好。
-
@JamesWhiteley 另外,如果您打算使用隐式类解决方案,您可以查看value classes,以避免实例化每个隐式类的成本。
-
你为什么不抽象
canAccess(role, allowed)方法或控制器的共同特征或类似的东西。这个方法可以实现为role == SuperAdmin || allowed.contains(role)