防止隐式转换中的循环

时间:2015-01-16 21:16:53

标签: scala implicit-conversion

我想知道我是否有类似的情况,如何防止循环隐式转换?

编辑:一些上下文用于在用作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")

2 个答案:

答案 0 :(得分:1)

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

因此,当您将Author转换为DTOAuthor时,会发生类似这样的事情:

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

您可以通过使嵌套在每个author中的Book的列表books为空来解决此问题。为此,您必须在一个地方删除对隐式转化的依赖,并手动创建没有书籍的嵌套DTOAuthor

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

答案 1 :(得分:0)

这不是一个隐含的问题,它是一个数据结构问题;你的数据结构是循环的,这使事情复杂化。对于"普通"非隐式转换函数,您会遇到完全相同的问题。

你可以滥用可变性,但是"正确"方式可能是"信用卡转型"在https://www.haskell.org/haskellwiki/Tying_the_Knot中描述(记住Scala默认不是懒惰的,所以你需要通过传递函数来使用显式懒惰)。但最好的解决方案可能是看你是否可以避免在数据结构中使用这些循环。在不可变的数据结构中,它们是痛苦的处方,例如:想想如果你做的话会发生什么

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

作者的名字已经改变,但该书仍然认为其作者有旧名称!