Scala,类型类和"找不到隐含的价值"

jde*_*lop 1 scala typeclass

我面临着一些类似于类型类的奇怪问题:由于某种原因,隐式对象ContentUploader在调用upload方法时没有得到解决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)


}
Run Code Online (Sandbox Code Playgroud)

我错过了什么?

UPD

如果我在对象 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)
    }

  }


}
Run Code Online (Sandbox Code Playgroud)

一切都运作良好.命名空间是否存在一些问题?

Dan*_*ral 5

它没有找到它,因为必须明确键入隐式前向引用才能被考虑,而这个不是.

如果这令人困惑,可能有两种方法可以解决它.首先,您可以声明隐式的类型.implicit从对象中删除,并声明val指向它:

implicit val contentUploader: S3Uploader[DemoActor.Content] = ContentUploader
Run Code Online (Sandbox Code Playgroud)

第二种方法是将class DemoActor声明移动到文件的末尾,因此它保留在object DemoActor声明之后.

这样工作的原因是编译器必须在完全键入文件的其余部分之前搜索隐式,因此在那时它不知道该对象ContentUploader满足搜索.