【问题标题】:Scala – Make implicit value classes available in another scopeScala – 使隐式值类在另一个范围内可用
【发布时间】:2017-06-26 22:47:54
【问题描述】:

我有一个包foo,其中包含类FStreamfoo 的包对象定义了一些为FStream 提供扩展方法的隐式值类。我想将这些值类从包对象中移出并放入它们自己的单独文件中,但我也希望它们在我使用 FStream 时始终可用(或者最好是在我使用 foo 包中的任何内容时)。有可能做到这一点吗?我尝试将隐式值类放入其他对象,但我无法从对象扩展。尝试将它们放入类或特征中,但隐式值类只能在其他对象中定义。

foo/FStream.scala

package foo

class FStream {
  def makeFoo(): Unit = ???
}

foo/package.scala

package foo

package object foo {

  // I want to move these definitions into separate files:

  implicit class SuperFoo(val stream: FStream) extends AnyVal {
    def makeSuperFoo(): Unit = ???
  }

  implicit class HyperFoo(val stream: FStream) extends AnyVal {
    def makeHyperFoo(): Unit = ???
  }
} 

bar/usage.scala

package bar

import foo._ // something nice and short that doesn't reference individual value classes

val x: FStream = ???
x.makeSuperFoo() // should work
x.makeHyperFoo() // should work

【问题讨论】:

    标签: scala implicit-conversion scoping


    【解决方案1】:

    我建议您先阅读强制性的tutorial

    我的解决方案是使用FStream 的伴生对象。因此,您只需导入 FStream 并获得所有功能。这也使用 trait 来分隔文件。

    foo/FStream.scala

    package foo
    
    class FStream {
      def makeFoo(): Unit = ???
    }
    
    // companion provides implicit
    object FStream extends FStreamOp
    

    foo/FStreamOp.scala

    package foo
    
    // value class may not be a member of another class
    class SuperFoo(val stream: FStream) extends AnyVal {
      def makeSuperFoo(): Unit = ???
    }
    
    class HyperFoo(val stream: FStream) extends AnyVal {
      def makeHyperFoo(): Unit = ???
    }
    trait FStreamOp {
      // you need to provide separate implicit conversion
      implicit def makeSuper(stream: FStream) = new SuperFoo(stream)
      implicit def makeHyper(stream: FStream) = new HyperFoo(stream)
    }
    

    usage.scala

    import foo.FStream
    
    object Main {
      def main(args: Array[String]): Unit = {
        val x: FStream = ???
        x.makeSuperFoo() // should work
        x.makeHyperFoo() // should work
      }
    }
    

    【讨论】:

    • 这是正确的回答,但我不同意关于不使用隐式的建议。隐式是 scala 中一个非常强大的功能,它可以实现“零成本”(不完全)的语法丰富,以及 Typeclass 模式。
    • 我不知道正确的答案,但 Herrington Darkholme 绝对是正确的名字。我也会和 Hugo Firth 一起去。我很矛盾。
    • 公平地说,这不是我的建议,而是 scala 编译器的建议,如果你在编译时添加 -feature 参数,编译器会警告你隐式使用。解决隐含非常复杂,请参阅我上面链接的教程。
    • 已编辑答案并删除隐式使用的 cmets。 OP想要一个答案,而不是布道。
    • 太棒了,非常感谢!我以前没看过那篇文章,现在正在阅读。很好的技术使价值类变得非隐式。即使我们显式调用new SuperFoo,它也不会生成运行时分配(我检查过javap)。我的意思是,回想起来有点明显,值类不需要是隐式的以避免运行时分配。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多