我想将对象定义为函数并将其依赖于其他函数:
type FetchPage = String => String
type FindImages = String => List[String]
object WillFetchPage extends FetchPage {
def apply(url:String):String = /* get content of the url */
}
class WillFindImages(fetchPage: FetchPage) extends FindImages {
def apply(url:String):List[String] = {
val html = fetchPage(url)
// get image srcs from the <img> tags
}
}
然后我可以WillFetchPage
注入WillFindImages
:
val findImages = new WillFindImages(WillFetchPage)
还可以通过注入模拟函数轻松地测试WillFindImages
:
val testFindImages = new WillFindImages(_ => "html-have-3-images")
val images = testFindImages("any-url")
// assertion
您可以看到类型别名FetchPage
只是一个类型别名,因此我可以将其他String => String
函数错误地传递给WillFindImages
,所以我正在寻找类型安全溶液
然后我从scalaz听说Tagged type
:http://eed3si9n.com/learning-scalaz/Tagged+type.html
这个例子令人兴奋:
sealed trait KiloGram
def KiloGram[A](a: A): A @@ KiloGram = Tag[A, KiloGram](a)
val mass = KiloGram(20.0)
2 * mass
您可以看到此处的mass
实际上是双20.0
,但它有一些独特的类型。
我想用它来改进我的代码,但遗憾的是我无法找到办法。我试过了:
object FetchPage extends ((String => Try[String]) @@ FetchType)
但它提供了编译错误:
Error:(18, 51) class type required but String => scala.util.Try[String] with
scalaz.Tagged[object_as_func.FetchType] found
object FetchPage extends ((String => Try[String]) @@ FetchType) {
^
如何解决?
答案 0 :(得分:2)
你使用什么scalaz版本?它在7.0.6和7.1.0中略有不同。以下是7.1.0的示例
import scalaz.@@
object PageFetcher
type FetchPage = String => String
type FindImages = String => List[String]
val WillFetchPage: FetchPage @@ PageFetcher.type =
scalaz.Tag[FetchPage, PageFetcher.type](url => "Content")
class WillFindImages(fetchPage: FetchPage @@ PageFetcher.type) extends FindImages {
def apply(url: String): List[String] = scalaz.Tag.unwrap(fetchPage)(url).grouped(1).toList
}
val images = new WillFindImages(WillFetchPage)("url")
println(images)
val testFetcher: FetchPage @@ PageFetcher.type =
scalaz.Tag[FetchPage, PageFetcher.type](url => "TestContent")
val testImages = new WillFindImages(testFetcher)("url")
println(testImages)