【问题标题】:Scala: constrain a class type parameter for a member functionScala:为成员函数约束类类型参数
【发布时间】:2015-12-16 22:55:27
【问题描述】:

给定一个带有类型参数T 的类A,我该如何进一步限制T 的特定功能?在下面的示例中,我想强制 foo 只能在 TInt (或者,如果你喜欢的话)的子类型时被调用。 IE。 new A[Int]().foo() 应该编译,但 new A[Double]().foo() 不应该编译。

我可以通过T => Int 中的隐式转换实现我想要的,如foo 所示。然而,这会导致不必要的方法调用——隐含的证据是恒等函数。还有就是不好看……

class A[T] {
  val someValue: T = ???

  def foo()(implicit ev: T => Int): Int = ev(someValue)

  // some ideas that don't quite work
  // def bar[T2 <: Int :EqualTo[T]](t2: T2): T = t2.asInstanceOf[T]
  // def bam[T2 <: T with Int](): Int = someValue.asInstanceOf[Int]

  def thisOneDefinesItsOwnConstraintType[Z <: Int](z: Z): Z = z
  def thisOneDoesNotNeedToConstrainT(t: T): T = someValue
}

如果不需要施法,该解决方案将获得加分:)

注意:我知道我可以在类或方法级别定义类型约束(请参阅thisOneDefinesItsOwnConstraintType),但这对我没有帮助,因为我还有一些不需要约束类型的方法(见thisOneDoesNotNeedToConstrainT)。

【问题讨论】:

    标签: scala types


    【解决方案1】:

    我看不出没有隐含的方法,因为虽然您可以在类方法上设置一些约束 B &lt;: C,但您对 B &lt;: T 的要求很难概括,因为我们不知道 @987654324 如何@ 与任意 T 相关。幸运的是,Scala 已经为此提供了一个构造,&lt;:&lt; 类型类。在Predef 中生成的&lt;:&lt;[B, T] 实例将提供B &lt;: C 的证据。

    但不要只相信我的话,scaladoc 是这样说的:

    要约束在方法参数列表范围内的任何抽象类型 T(不仅仅是方法自己的类型参数),只需添加类型为 T <: u t l>

    例如:

    class E
    class F extends E
    class G extends F
    
    class A[T] {
      def constrained[B <: F](b: B)(implicit ev: B <:< T): B = b
    }
    

    这里,我们为contrained方法的类型参数B引入了F的上限。但是如果你想保证B &lt;: T(不添加其他类型参数),你可以添加隐式B &lt;:&lt; T

    scala> val a = new A[E]
    a: A[E] = A@5a63f509
    
    scala> a.constrained(new E)
    <console>:15: error: inferred type arguments [E] do not conform to method constrained's type parameter bounds [B <: F]
           a.constrained(new E)
             ^
    <console>:15: error: type mismatch;
     found   : E
     required: B
           a.constrained(new E)
                         ^
    
    scala> a.constrained(new F)
    res5: F = F@4a668b6e
    
    scala> a.constrained(new G)
    res6: G = G@4de4b452
    

    【讨论】:

    • 完美,在我的具体示例(不使用值参数)中,无需强制转换和其他方法调用即可:def foo()(implicit ev: T &lt;:&lt; Int): Int = someValue
    • @m-z 我很确定这是正确的答案,因为 scaladoc 建议这样做,不是为了争议,而是为了澄清原因:为什么这种方法比我提出的更好?我的好处是在快速完成任何 IDE 的方法列表中不显示 constrained
    【解决方案2】:

    怎么样:

    implicit class AIntOps(a: A[Int]) {
      def test(x: Int) = x
    }
    

    使用该方法,测试只会出现在 A[Int] 上,而对任何其他 A 来说根本不可用

    【讨论】:

    • 这实际上是我以前做过的,但我想摆脱,因为我想使用更少的隐含。如果你可以在一个列表中列出所有可用的方法,而不是让该列表加上一些隐式浮动...
    • 迟到了,但是参考您对已接受答案的评论,已接受的答案更完整,它参考了文档,并通过 REPL 显示了具体的示例用法(即“这有效,这是我做的”)。
    猜你喜欢
    • 2021-06-19
    • 1970-01-01
    • 1970-01-01
    • 2013-05-05
    • 2021-12-25
    • 1970-01-01
    • 1970-01-01
    • 2020-09-16
    • 1970-01-01
    相关资源
    最近更新 更多