首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >缺失Sized.unapply

缺失Sized.unapply
EN

Stack Overflow用户
提问于 2014-04-15 17:34:22
回答 1查看 238关注 0票数 8

object Sized中(在“shapeless/sized.scala”中)有unapplySeq,不幸的是,它不提供静态检查。例如,下面的代码将在运行时使用MatchError失败

代码语言:javascript
复制
Sized(1, 2, 3) match { case Sized(x, y) => ":(" }

如果采用unapply方法,返回元组的选项,并根据实例的大小构造元组的具体形状,则更好。例如:

代码语言:javascript
复制
Sized(1) => x
Sized(1, 2) => (x, y)
Sized(1, 2, 3) => (x, y, z)

在这种情况下,以前的代码片段将无法使用constructor cannot be instantiated to expected type进行编译。

请帮我实现unapply for object Sized。此方法是否已在任何地方实现?

提前感谢!

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-04-19 19:21:37

这是绝对可能的(至少在Sized中,N小于23),但是我能想到的唯一方法(除了宏等等)。有点乱。首先,我们需要一个类型类,它将帮助我们将大小的集合转换为HList

代码语言:javascript
复制
import shapeless._, Nat._0
import scala.collection.generic.IsTraversableLike

trait SizedToHList[R, N <: Nat] extends DepFn1[Sized[R, N]] {
  type Out <: HList
}

object SizedToHList {
  type Aux[R, N <: Nat, Out0 <: HList] = SizedToHList[R, N] { type Out = Out0 }

  implicit def emptySized[R]: Aux[R, Nat._0, HNil] = new SizedToHList[R, _0] {
    type Out = HNil
    def apply(s: Sized[R, _0]) = HNil
  }

  implicit def otherSized[R, M <: Nat, T <: HList](implicit
    sth: Aux[R, M, T],
    itl: IsTraversableLike[R]
  ): Aux[R, Succ[M], itl.A :: T] = new SizedToHList[R, Succ[M]] {
    type Out = itl.A :: T
    def apply(s: Sized[R, Succ[M]]) = s.head :: sth(s.tail)
  }

  def apply[R, N <: Nat](implicit sth: SizedToHList[R, N]): Aux[R, N, sth.Out] =
    sth

  def toHList[R, N <: Nat](s: Sized[R, N])(implicit
    sth: SizedToHList[R, N]
  ): sth.Out = sth(s)
}

然后,我们可以定义一个提取器对象,它使用这种转换:

代码语言:javascript
复制
import ops.hlist.Tupler

object SafeSized {
  def unapply[R, N <: Nat, L <: HList, T <: Product](s: Sized[R, N])(implicit
    itl: IsTraversableLike[R],
    sth: SizedToHList.Aux[R, N, L],
    tupler: Tupler.Aux[L, T]
  ): Option[T] = Some(sth(s).tupled)
}

然后:

代码语言:javascript
复制
scala> val SafeSized(x, y, z) = Sized(1, 2, 3)
x: Int = 1
y: Int = 2
z: Int = 3

但是:

代码语言:javascript
复制
scala> val SafeSized(x, y) = Sized(1, 2, 3)
<console>:18: error: wrong number of arguments for object SafeSized
       val SafeSized(x, y) = Sized(1, 2, 3)
                    ^
<console>:18: error: recursive value x$1 needs type
       val SafeSized(x, y) = Sized(1, 2, 3)
                     ^

如你所愿。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23090657

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档