如何将方法限制为仅用于特定类型?

时间:2019-05-02 10:49:04

标签: scala

假设我下面有一个案例类

case class SomeCaseClass[M] private (
  value: String
) 

在另一个文件中,我具有以下特征和对象。

trait SomeTrait[A] {
  def get(oldId: String): A
   :
}

object SomeObject {
  private[this] def init[A](): SomeTrait[A] = new SomeTrait[A] {
    def get(oldId: String): A = id(oldId)
     :
  }

  val aaa: SomeTrait[String] = init[String]()
  val bbb: SomeTrait[SomeCaseClass[String]] = init[SomeCaseClass[String]]()
}

我应该如何修改代码,以便将init方法限制为只能与SomeCaseClass [_]类型一起使用,而不能与上述任何类型的字符串一起使用?

理想情况下,对代码进行了一些修改,第val aaa: SomeTrait[String] = init[String]()行应导致编译错误。

3 个答案:

答案 0 :(得分:6)

这是我想出的:

case class SomeCaseClass[M] private (
  value: String
) 

trait SomeTrait[A] {
  def get(oldId: String): A
}

private[this] def init[A <: SomeCaseClass[_]](): SomeTrait[A] = new SomeTrait[A] {
  def get(oldId: String): A = ???
}

val aaa: SomeTrait[String] = init[String]() // Will fail
val bbb: SomeTrait[SomeCaseClass[String]] = init[SomeCaseClass[String]]()

失败并

  

ScalaFiddle.scala:16:错误:类型参数[String]不符合方法初始化的类型参数范围[A <:ScalaFiddle.this.SomeCaseClass [_ $ 1] forSome {type _ $ 1}]

您可以选中此scalafiddle

我不知道这是否是最好的方法,但是init[A <: SomeCaseClass[_]]正在添加绑定到A的类型,并强制A成为子类SomeCaseClass中的。我很想知道是否还有更好的方法。

答案 1 :(得分:5)

您可以使用隐式参数强制类型参数等于某个类型B

def foo[A](implicit e: A =:= B): …

另请参阅this question

为该答案添加更多价值。 以下代码显示了如何使用隐式参数e: A =:= StringA转换为String

def bar(b: String): Unit = println(b)
def foo[A](a: A)(implicit e: A =:= String): Unit = {
  bar(e(a))
}

foo("hi")  //compiles

foo(5)     //error: Cannot prove that scala.this.Int =:= String.

问题解答OP

这个问题要简单得多:仅将方法参数设为A的参数SomeCaseClass[A],而不要使用整个类型SomeCaseClass[A]作为类型参数:

private[this] def init[A](): SomeTrait[SomeCaseClass[A]] = new
  SomeTrait[SomeCaseClass[A]] {
    def get(oldId: String): SomeCaseClass[A] = ???
  }

答案 2 :(得分:3)

这是基于上面的答案:

case class SomeCaseClass[M] private (
  value: String
) 

trait SomeTrait[A] {
  def get(oldId: String): SomeCaseClass[A]
}

private[this] def init[A](): SomeTrait[A] = new SomeTrait[A] {
  def get(oldId: String): SomeCaseClass[A] = ???
}

val aaa: SomeTrait[String] = init[String]()

https://scalafiddle.io/sf/KuXZc0h/3

这不允许将SomeCaseClass以外的其他类型与SomeTrait一起使用。