【发布时间】:2021-07-26 15:05:04
【问题描述】:
假设您使用的 API 最多可为您提供 100 个元素,并允许您获取更多元素,而不是通过指定页码,而只需告诉它您收到的最后一个元素。然后你会想要抽象这个准分页。 你会如何在 Scala 中做到这一点?
我想出了这段可能有问题(= 未经过彻底测试)且非常有状态的代码:
abstract class IteratorThatKeepsOnGiving[T] extends Iterator[T] {
private var currentIter: Iterator[T] = _
private var currentElement: T = _
def nextIterator(lastElement: Option[T]): Iterator[T]
fetchNewBatch(None)
def fetchNewBatch(lastElement: Option[T]) = {
currentIter = nextIterator(lastElement)
}
def hasNext: Boolean = currentIter.hasNext || {
fetchNewBatch(Some(currentElement))
currentIter.hasNext
}
def next(): T = {
currentIter.nextOption() match {
case Some(value) =>
currentElement = value
value
case None =>
fetchNewBatch(Some(currentElement))
next()
}
}
}
我不喜欢它。
用途:
val numberIterator = new IteratorThatKeepsOnGiving[Int] {
def nextIterator(lastElement: Option[Int]): Iterator[Int] = {
val i = lastElement.getOrElse(-1)
((i + 1) to (i + 4)).iterator
}
}
必须有更好的方法来做到这一点。当然,我不是第一个被这种分页困扰的人。无论如何,正确的术语是什么?以及如何对其进行抽象?
有问题的 API 是 Discord 的消息列表 API:https://discord.com/developers/docs/resources/channel#get-channel-messages
考虑的替代方案
我发现了这个问题:Making a Scala Iterator for a Paginated API
但是,就我而言,我没有总页数。 这个答案还假设页面大小是恒定的,虽然在我的情况下给出了这个,但我真的更喜欢一个解决方案,它可以只知道“我得到的最后一个元素是 X。我怎样才能得到 some 更多元素?”而不是“我上次得到 X,我如何得到下一个 Y 元素?”。此外,这无关紧要,因为我不能直接指定页码。
Akka Streams 中还有 flatMapConcat(和 mapConcat)也遇到了同样的问题。
【问题讨论】:
-
fwiw 我已经对上述迭代器进行了稍微改进和测试的版本:gist.github.com/phdoerfler/557a4cc4031475def4a9143a9cebccbc
标签: scala pagination discord