【发布时间】:2021-12-21 04:07:04
【问题描述】:
我正在尝试编写一些获取 URL、从该 URL 获取内容并保存它的代码。从 URL 中获取内容的方法是特定于网站的,但是提取的内容使用通用格式,例如可以保存在数据库中。
所以我首先定义一个代表每个支持的 URL 的类型:
trait Url(url: String)
case class Soundcloud(url: String) extends Url(url)
case class Youtube(url: String) extends Url(url)
然后一个给定字符串的方法返回正确的 URL 类型:
def matchUrl(s: String): Option[Url] =
val s_regex = "soundcloud.com".r
var y_regex = "youtube.com".r
s match
case s_regex() => Some(Soundcloud(s))
case y_regex() => Some(Youtube(s))
case _ => None
然后我为内容提取器定义一个特征:
trait GetContent[T <: Url]:
def get: Unit // should actually return something like `Content`
这是我在数据库中保存 URL 内容的方法:
def save[T <: Url](t: T)(using gc: GetContent[T]) =
gc.get
// save into db
然后我提供GetContent 的两种实现,每种URL 类型一种:
given GetContent[Soundcloud] with
def get = println("getting some content from soundcloud")
given GetContent[Youtube] with
def get = println("getting some content from youtube")
最后我可以将它们全部连接在一起:
matchUrl("youtube.com").map(r => save(r))
编译器抱怨
没有为方法 save 的参数 gc 找到类型为 GetContent[Url] 的隐式参数
如果我这样调用我的方法,它可以正常工作:
save(Soundcloud("http://soundcloud.com/some/content"))
我需要告诉编译器matchUrl 只能返回Soundcloud 或Youtube 的实例,而不能返回Url。
【问题讨论】:
-
你可以让自己的枚举模仿
Option,但有一个额外的字段包含GetContent隐含。不过,它非常不令人满意(至少我最终实现它的方式)。 Scastie。 (有趣的是,我的 Scastie 揭示了编译器中关于多态函数的几个错误/实现限制。看起来我们必须等待它被完善)