【问题标题】:Scala, typeclass and "could not find implicit value"Scala,类型类和“找不到隐式值”
【发布时间】:2013-12-08 13:02:28
【问题描述】:

我在下面的 typeclass 中遇到了一些奇怪的问题:由于某种原因,隐式对象 ContentUploader 在调用 DemoActorupload 方法时无法解析。

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)


}

我在这里错过了什么?

UPD

如果我将 DemoActor 的 class 定义移动到 object 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)
    }

  }


}

然后一切正常。命名空间是否存在一些问题?

【问题讨论】:

    标签: scala typeclass


    【解决方案1】:

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

    如果这令人困惑,也许有两种解决方法可能会让它变得清晰。首先,您可以声明隐式的类型。从对象中删除implicit,并声明一个指向它的val

    implicit val contentUploader: S3Uploader[DemoActor.Content] = ContentUploader
    

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

    这样做的原因是编译器必须在文件的其余部分完全键入之前搜索隐式,所以当时它不知道对象ContentUploader 满足搜索。

    【讨论】:

    • 确实有道理,谢谢!所以一般隐式应该在使用之前定义
    • @jdevelop 我更喜欢总是明确声明它们的类型。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-30
    • 2011-08-29
    相关资源
    最近更新 更多