加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

scala – 可以对类型符合结果的泛型值执行模式匹配吗?

发布时间:2020-12-16 19:24:28 所属栏目:安全 来源:网络整理
导读:是否可以执行模式匹配,其结果符合外部方法的类型参数?例如.给定: trait Key[A] { def id: Int def unapply(k: Key[_]): Boolean = k.id == id // used for Fail2 def apply(thunk: = A): A = thunk // used for Fail3}trait Ev[A] { def pull[A1 : A](key:
是否可以执行模式匹配,其结果符合外部方法的类型参数?例如.给定:

trait Key[A] {
  def id: Int
  def unapply(k: Key[_]): Boolean = k.id == id // used for Fail2
  def apply(thunk: => A): A = thunk // used for Fail3
}

trait Ev[A] {
  def pull[A1 <: A](key: Key[A1]): Option[A1]
}

trait Test extends Ev[AnyRef] {
  val key1 = new Key[String] { def id = 1 }
  val key2 = new Key[Symbol] { def id = 2 }
}

是否有一个Test(它的pull方法)的实现,它在key参数上使用模式匹配,并为每个检查的键返回Option [A1],而不使用asInstanceOf?

一些可悲的尝试:

class Fails1 extends Test {
  def pull[A1 <: AnyRef](key: Key[A1]): Option[A1] = key match {
    case `key1` => Some("hallo")
    case `key2` => Some('welt)
  }
}

class Fails2 extends Test {
  def pull[A1 <: AnyRef](key: Key[A1]): Option[A1] = key match {
    case key1() => Some("hallo")
    case key2() => Some('welt)
  }
}

class Fails3 extends Test {
  def pull[A1 <: AnyRef](key: Key[A1]): Option[A1] = key match {
    case k @ key1() => Some(k("hallo"))
    case k @ key2() => Some(k('welt))
  }
}

没有用,显然……唯一的解决方案就是施放:

class Ugly extends Test {
  def pull[A1 <: AnyRef](key: Key[A1]): Option[A1] = key match {
    case `key1` => Some("hallo".asInstanceOf[A1])
    case `key2` => Some('welt  .asInstanceOf[A1])
  }
}

val u = new Ugly
u.pull(u.key1)
u.pull(u.key2)

解决方法

问题确实是模式匹配忽略了所有已擦除的类型.然而,人们可以使用一些隐含的诡计.以下内容将保留返回类型匹配所提供的类型解析.

abstract class UnErased[A]
implicit case object UnErasedString extends UnErased[String]
implicit case object UnErasedSymbol extends UnErased[Symbol]

class UnErasedTest extends Test {
  def pull[ A1 <: AnyRef ]( key: Key[ A1 ])(implicit unErased: UnErased[A1]): Option[ A1 ] = unErased match {
    case UnErasedString if key1.id == key.id => Some( "hallo" )
    case UnErasedSymbol if key2.id == key.id => Some( 'welt )
    case _ => None
  }
}

val u = new UnErasedTest 
println( u.pull( u.key1 ) )
println( u.pull( u.key2 ) )

然而,这几乎等同于仅定义Key的单独子类.我发现以下方法更可取但是如果现有代码使用Key [String]而无法更改为必要的KeyString(或者需要更改太多工作),它可能无效.

trait KeyString extends Key[String]
trait KeySymbol extends Key[Symbol]

trait Test extends Ev[ AnyRef ] {
   val key1 = new KeyString { def id = 1 }
   val key2 = new KeySymbol { def id = 2 }
}

class SubTest extends Test {
  def pull[ A1 <: AnyRef ]( key: Key[ A1 ]): Option[ A1 ] = key match {
    case k: KeyString if key1.id == k.id => Some( "hallo" )
    case k: KeySymbol if key2.id == k.id => Some( 'welt )
    case _ => None
  }
}

val s = new SubTest
println( s.pull( s.key1 ) )
println( s.pull( s.key2 ) )

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读