[英]Scala, typeclass and “could not find implicit value”
I am facing some weird problem with typeclass below: for some reason implicit object ContentUploader is not resolved on call to upload method of DemoActor
. 我遇到以下类型类奇怪的问题:由于某种原因,在调用
DemoActor
上载方法时未解析隐式对象DemoActor
。
import akka.actor.Actor
import java.io.File
import org.slf4j.LoggerFactory
class DemoActor extends Actor {
import DemoActor.UploaderImpl._
override def receive = {
case (x: DemoActor.Content) =>
DemoActor.upload(x)
}
}
object DemoActor {
val LOG = LoggerFactory.getLogger("DemoActor")
sealed trait UploadData {
val data: Array[File]
}
case class Content(data: Array[File]) extends UploadData
case class UploadResult(url: String, contentType: String, size: Long)
trait S3Uploader[T <: UploadData] {
def uploadToS3(filez: Array[File]): Iterable[UploadResult]
}
object UploaderImpl {
val LOG = LoggerFactory.getLogger("Uploader")
private def contentType(name: String): String = {
"application/octet-stream"
}
private def doUpload(filez: Array[File], bucketName: String) = {
LOG.debug("Uploading: {} to {}", filez, bucketName)
filez.flatMap {
case f =>
try {
val key = f.getName
val mime = contentType(f.getName)
Some(UploadResult("http://" + bucketName + ".s3.amazonaws.com/" + key, mime, f.length()))
} catch {
case e =>
LOG.error("Can not upload", e)
None
}
}
}
implicit object ContentUploader extends S3Uploader[Content] {
lazy val bucketName = "resources.aws.bucketname"
lazy val awsSecret = "resources.aws.secret.key"
lazy val awsAccess = "resources.aws.access.key"
override def uploadToS3(filez: Array[File]) = doUpload(filez, bucketName)
}
}
def upload[T <: UploadData](src: T)(implicit uploader: S3Uploader[T]) = uploader.uploadToS3(src.data)
}
What have I missed here? 我在这里错过了什么?
UPD UPD
if I move definition of class for DemoActor inside object DemoActor, like 如果我在对象 DemoActor中移动DemoActor的类的定义,例如
import akka.actor.Actor
import java.io.File
import org.slf4j.LoggerFactory
object DemoActor {
val LOG = LoggerFactory.getLogger("DemoActor")
sealed trait UploadData {
val data: Array[File]
}
case class Content(data: Array[File]) extends UploadData
case class UploadResult(url: String, contentType: String, size: Long)
trait S3Uploader[UploadData] {
def uploadToS3(filez: Array[File]): Iterable[UploadResult]
}
object UploaderImpl {
val LOG = LoggerFactory.getLogger("Uploader")
private def contentType(name: String): String = {
"application/octet-stream"
}
private def doUpload(filez: Array[File], bucketName: String) = {
LOG.debug("Uploading: {} to {}", filez, bucketName)
filez.flatMap {
case f =>
try {
val key = f.getName
val mime = contentType(f.getName)
Some(UploadResult("http://" + bucketName + ".s3.amazonaws.com/" + key, mime, f.length()))
} catch {
case e =>
LOG.error("Can not upload", e)
None
}
}
}
implicit object ContentUploader extends S3Uploader[DemoActor.Content] {
lazy val bucketName = "resources.aws.bucketname"
lazy val awsSecret = "resources.aws.secret.key"
lazy val awsAccess = "resources.aws.access.key"
override def uploadToS3(filez: Array[File]) = doUpload(filez, bucketName)
}
}
def upload[T <: UploadData](src: T)(implicit uploader: S3Uploader[T]) = uploader.uploadToS3(src.data)
class DemoActor extends Actor {
import DemoActor.UploaderImpl._
override def receive = {
case (x: DemoActor.Content) =>
DemoActor.upload(x)
}
}
}
then everything works well. 然后一切正常。 Are there some issues with namespacing?
命名空间是否存在一些问题?
It is not finding it because implicit forward references must be explicitly typed to be considered, and this one isn't. 找不到它是因为必须明确键入隐式前向引用才能被考虑,而这个不是。
If this is confusing, maybe two ways of fixing it might make it clear. 如果这令人困惑,则可能有两种解决方法可能很清楚。 First, you can declare the type of the implicit.
首先,您可以声明隐式的类型。 Remove the
implicit
from the object, and declare a val
pointing to it: 从对象中删除
implicit
对象,并声明一个指向它的val
:
implicit val contentUploader: S3Uploader[DemoActor.Content] = ContentUploader
The second way is moving the class DemoActor
declaration to the end of the file, so it stays after the the object DemoActor
declaration. 第二种方法是将
class DemoActor
声明移动到文件的末尾,因此它将保留在object DemoActor
声明之后。
The reason it works like this is that the compiler must search for the implicit before the rest of the file is fully typed, so it doesn't know, at that time, that object ContentUploader
satisfy the search. 之所以这样工作,是因为编译器必须在文件的其余部分完全键入之前搜索隐式对象,因此当时尚不知道对象
ContentUploader
满足搜索条件。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.