【问题标题】:Prevent cycles in implicit conversion防止隐式转换中的循环
【发布时间】:2015-01-16 21:16:53
【问题描述】:

我想知道我是否有与以下类似的场景,如何防止循环隐式转换?

编辑:一些上下文,用于在用作 ORM 实体的某些类和用作 DTO 的案例类之间进行转换。

class Author(var name: String) {
  def books : List[Book] = List(new Book("title", this))// get books
}

class Book(var title: String, var author: Author)

case class DTOBook(title: String, author: Option[DTOAuthor])

case class DTOAuthor(name: String, books: List[DTOBook])

implicit def author2Author(author: Author) : DTOAuthor = {
  DTOAuthor(author.name, author.books.map(x => x : DTOBook) : List[DTOBook])
}

implicit def book2Book(book: Book) : DTOBook = {
  DTOBook(book.title, Option(book.author : DTOAuthor))
}

val author: DTOAuthor = new Author("John Brown")

【问题讨论】:

    标签: scala implicit-conversion


    【解决方案1】:

    问题在于您的数据结构是循环的。 Author 包含 Books,其中包含 Author,其中包含 Books 等。

    所以当你将Author 转换为DTOAuthor 时,会发生这样的事情:

    • author2Author 被称为
    • 在第一个 author2Author 调用中,author.books 必须转换为 List[DTOBook]
    • 这意味着每个Book 中的author 必须转换为DTOAuthor
    • 重复

    您可以通过使嵌套在每个Book 中的author 具有一个空的books 列表来解决此问题。为此,您必须在一处消除对隐式转换的依赖,并手动创建嵌套的 DTOAuthor 而不使用书籍。

    implicit def book2Book(book: Book) : DTOBook = {
      DTOBook(book.title, Option(DTOAuthor(book.author.name, Nil)))
    }
    

    【讨论】:

      【解决方案2】:

      这不是隐含的问题,而是数据结构的问题;您的数据结构是循环的,这使事情变得复杂。对于“正常”的非隐式转换函数,您会遇到完全相同的问题。

      您可以为此滥用可变性,但“正确”的方式可能是https://www.haskell.org/haskellwiki/Tying_the_Knot 中描述的“信用卡转换”(请记住,Scala 默认情况下不是惰性的,因此您需要通过传递函数来使用显式惰性)。但最好的解决方案可能是看看您是否可以完全避免在数据结构中出现这些循环。在不可变的数据结构中,它们是痛苦的秘诀,例如想想如果你这样做会发生什么

      val updatedAuthor = dtoAuthor.copy(name="newName")
      updatedAuthor.books.head.author.get.name
      

      作者的名字变了,但书还是认为它的作者是旧名!

      【讨论】:

        猜你喜欢
        • 2020-12-30
        • 1970-01-01
        • 1970-01-01
        • 2016-07-09
        • 1970-01-01
        • 1970-01-01
        • 2016-07-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多