我可以在 Scala 匹配语句中使用类变量吗?

发布于 2024-09-30 14:37:28 字数 657 浏览 1 评论 0原文

假设我有这样的事情:

obj match {
    case objTypeOne : TypeOne => Some(objTypeOne)
    case objTypeTwo : TypeTwo => Some(objTypeTwo)
    case _ => None
}

现在我想概括一下,传递一种类型来匹配:

obj match {
    case objTypeOne : clazz => Some(objTypeOne)
    case objTypeTwo : TypeTwo => Some(objTypeTwo)
    case _ => None
}

但这是不允许的,我认为是出于语法而不是语义的原因(尽管我也猜想,尽管 clazz 是Class[C] 类型被擦除,因此选项的类型将丢失)。

我最后的结论是:

if(clazzOne.isAssignableFrom(obj.getClass)) Some(clazz.cast(obj))
if(obj.isInstanceOf[TypeTwo]) Some(obj.asInstanceOf[TypeTwo])
None

我只是想知道是否有更好的方法。

Say I have something like this:

obj match {
    case objTypeOne : TypeOne => Some(objTypeOne)
    case objTypeTwo : TypeTwo => Some(objTypeTwo)
    case _ => None
}

Now I want to generalise, to pass in one of the types to match:

obj match {
    case objTypeOne : clazz => Some(objTypeOne)
    case objTypeTwo : TypeTwo => Some(objTypeTwo)
    case _ => None
}

But this isn't allowed, I think for syntactic rather than semantic reasons (although I guess also that even though the clazz is a Class[C] the type is erased and so the type of the Option will be lost).

I ended up with:

if(clazzOne.isAssignableFrom(obj.getClass)) Some(clazz.cast(obj))
if(obj.isInstanceOf[TypeTwo]) Some(obj.asInstanceOf[TypeTwo])
None

I just wondered if there was a nicer way.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

逆光飞翔i 2024-10-07 14:37:28

您可以定义一个提取器来匹配您的对象:

class IsClass[T: Manifest] {
  def unapply(any: Any): Option[T] = {
    if (implicitly[Manifest[T]].erasure.isInstance(any)) {
       Some(any.asInstanceOf[T])
    } else {
       None
    }
  }
}

所以让我们测试一下:

class Base { def baseMethod = () }
class Derived extends Base

val IsBase = new IsClass[Base]

def test(a:Any) = a match {
    case IsBase(b) => 
      println("base")
      b.baseMethod
    case _ => println("?")
  }

test(new Base)
test(1)

您必须为提取器定义一个 val,例如,您不能内联 IsBase。否则它会被解释为提取器。

You could define an extractor to match your object:

class IsClass[T: Manifest] {
  def unapply(any: Any): Option[T] = {
    if (implicitly[Manifest[T]].erasure.isInstance(any)) {
       Some(any.asInstanceOf[T])
    } else {
       None
    }
  }
}

So let's test it:

class Base { def baseMethod = () }
class Derived extends Base

val IsBase = new IsClass[Base]

def test(a:Any) = a match {
    case IsBase(b) => 
      println("base")
      b.baseMethod
    case _ => println("?")
  }

test(new Base)
test(1)

You will have to define a val for your extractor, you can't inline IsBase, for example. Otherwise it would be interpreted as an extractor.

星星的軌跡 2024-10-07 14:37:28

您可以使用模式防护来实现这一点。尝试这样的事情:

obj match {
    case objTypeTwo : TypeTwo => Some(objTypeTwo)
    case objTypeOne if clazz.isAssignableFrom(objTypeOne.getClass) => Some(clazz.cast(objTypeOne))
    case _ => None
}

You could use pattern guards to achieve that. Try something like this:

obj match {
    case objTypeTwo : TypeTwo => Some(objTypeTwo)
    case objTypeOne if clazz.isAssignableFrom(objTypeOne.getClass) => Some(clazz.cast(objTypeOne))
    case _ => None
}
旧时模样 2024-10-07 14:37:28

您可以使用本地类型别名:

def matcher[T](obj: Any)(implicit man: Manifest[T]) = {
   val instance = man.erasure.newInstance.asInstanceOf[AnyRef]
   type T = instance.type // type alias
   obj match { 
      case objTypeOne : T => "a"
      case objTypeTwo : TypeTwo => "b"
      case _ => "c"
   }
}

scala> matcher[TypeOne](TypeOne())
res108: java.lang.String = a

scala> matcher[TypeTwo](TypeOne())
res109: java.lang.String = c


更新: Aaron Novstrup 指出,单例类型仅在 man.erasure.newInstance==obj 时才有效(请参阅规范的 §3.2.1)

You can use a local type alias for that:

def matcher[T](obj: Any)(implicit man: Manifest[T]) = {
   val instance = man.erasure.newInstance.asInstanceOf[AnyRef]
   type T = instance.type // type alias
   obj match { 
      case objTypeOne : T => "a"
      case objTypeTwo : TypeTwo => "b"
      case _ => "c"
   }
}

scala> matcher[TypeOne](TypeOne())
res108: java.lang.String = a

scala> matcher[TypeTwo](TypeOne())
res109: java.lang.String = c


UPDATE: Aaron Novstrup has pointed out that singleton type will only work if man.erasure.newInstance==obj (see §3.2.1 of the spec)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文