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

在这个参数化的Scala函数中,为什么需要强制转换?

发布时间:2020-12-16 09:59:34 所属栏目:安全 来源:网络整理
导读:在这个参数化函数中,为什么我需要演员?我怎么能摆脱它呢? /** Filters `xs` to have only every nth element. */def everyNth[A % Iterable[B],B](xs: A,n: Int,offset: Int = 0): A = (xs.zipWithIndex collect { case (x,i) if (i - offset) % n == 0 =
在这个参数化函数中,为什么我需要演员?我怎么能摆脱它呢?

/** Filters `xs` to have only every nth element.
  */
def everyNth[A <% Iterable[B],B](xs: A,n: Int,offset: Int = 0): A =
  (xs.zipWithIndex collect { case (x,i) if (i - offset) % n == 0 => x }).asInstanceOf[A]

如果我最后没有演员,我会收到以下错误消息:

type mismatch; found : Iterable[B] required: A

这个函数(使用强制转换)适用于我尝试过的所有情况,我知道在REPL中输入类似下面的内容,Scala能够在不在参数化函数的上下文中正确推断结果类型:

scala> val a: Stream[Int] = (Stream.from(0).zipWithIndex collect { case (x,i) if (i + 3) % 5 == 0 => x })
a: Stream[Int] = Stream(2,?)

scala> a take 10 force
res20: scala.collection.immutable.Stream[Int] = Stream(2,7,12,17,22,27,32,37,42,47)

请解释!

解决方法

根据评论中的一些建议,我查看了CanBuildFrom,这就是我想出的:

import scala.collection.IterableLike
import scala.collection.generic.CanBuildFrom

/** Filters `xs` to have only every nth element.
  */
def everyNth[A,It <: Iterable[A]]
        (xs: It with IterableLike[A,It],offset: Int = 0)
        (implicit bf: CanBuildFrom[It,A,It]): It = {
  val retval = bf()
  retval ++= xs.zipWithIndex collect { case (x,i) if (i - offset) % n == 0 => x }
  retval.result     
}

是的,它的工作原理!

而且没有演员阵容.因此,它甚至适用于Ranges.

然而,不得不从一个空的retval开始,然后使用“=”填充它似乎有点不优雅,所以如果有人有一个更优雅的解决方案,我都是耳朵.

这是我实现的另一个通用函数,它比上面有点棘手,因为返回类型与参数类型不同.即,输入是A的序列,但输出是(A,A)的序列:

def zipWithSelf[A,It[A] <: Iterable[A]]
        (xs: It[A] with IterableLike[A,It[A]])
        (implicit bf:  CanBuildFrom[It[A],(A,A),It[(A,A)]]): It[(A,A)] = {
    val retval = bf()
    if (xs.nonEmpty) {
      retval ++= xs zip xs.tail
      retval.result
  } else retval.result
}

这是另一个:

/** Calls `f(x)` for all x in `xs` and returns an Iterable containing the indexes for
  * which `f(x)` is true.
  *
  * The type of the returned Iterable will match the type of `xs`. 
  */
def findAll[A,It[A]])
        (f: A => Boolean)
        (implicit bf:  CanBuildFrom[It[A],Int,It[Int]]): It[Int] = {
    val retval = bf()
    retval ++= xs.zipWithIndex filter { p => f(p._1) } map { _._2 }
    retval.result
}

我仍然没有对“Like”类型和CanBuildFrom有任何深刻理解,但我得到了要点.在大多数情况下,将通用函数的转换版本编写为第一遍是很容易的,然后添加CanBuildFrom和IterableLike样板以使函数更通用且完全类型安全.

(编辑:李大同)

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

    推荐文章
      热点阅读