Scala如何告知编译器函数仅返回trait的子类型而非trait本身
问题核心原因
你定义的matchUrl返回类型是Option[Url],编译器只能识别返回值是父 trait Url类型,而你仅为Soundcloud、Youtube两个具体子类提供了GetContent类型类实例,父类Url没有对应的隐式实现,自然触发报错。
解决方案1:密封trait + 显式模式匹配(最简单)
先将Url定义为密封trait,告知编译器它的所有子类只有你定义的两个,再在拿到返回值后做穷尽匹配转成具体子类调用即可:
// 改Url为sealed,限定子类范围 sealed trait Url(url: String) case class Soundcloud(url: String) extends Url(url) case class Youtube(url: String) extends Url(url)
调用逻辑调整为:
matchUrl("youtube.com").map { case sc: Soundcloud => save(sc) case yt: Youtube => save(yt) }
注:你原有的正则写法匹配规则不全,建议调整为.*soundcloud.com.*这类通配格式,才能识别包含对应域名的完整URL
解决方案2:返回时绑定类型类实例
如果不想每次调用都写匹配,可以在matchUrl返回时直接将Url实例和对应的GetContent实现绑定,不需要编译器再隐式查找:
// 定义绑定类型类的Url包装类 trait UrlWithContent: type T <: Url val value: T val contentGetter: GetContent[T] // 调整matchUrl返回类型 def matchUrl(s: String): Option[UrlWithContent] = val sRegex = ".*soundcloud.com.*".r val yRegex = ".*youtube.com.*".r s match case sRegex() => Some(new UrlWithContent { type T = Soundcloud val value = Soundcloud(s) val contentGetter = summon[GetContent[Soundcloud]] }) case yRegex() => Some(new UrlWithContent { type T = Youtube val value = Youtube(s) val contentGetter = summon[GetContent[Youtube]] }) case _ => None
对应调整save方法入参:
def save(uwc: UrlWithContent) = uwc.contentGetter.get // 后续存库逻辑
调整后可以直接调用:
matchUrl("youtube.com").map(save)
内容的提问来源于stack exchange,提问作者erdnaxeli
相关产品推荐
相关产品推荐

