简体   繁体   中英

Yield mutable.seq from mutable.traversable type in Scala

I have a variable underlying of type Option[mutable.Traversable[Field]]

All I wanted todo in my class was provide a method to return this as Sequence in the following way:

def toSeq: scala.collection.mutable.Seq[Field] = {
  for {
    f <- underlying.get
  } yield f
}

This fails as it complains that mutable.traversable does not conform to mutable.seq . All it is doing is yielding something of type Field - in my mind this should work?

A possible solution to this is:

def toSeq: Seq[Field] = {
  underlying match {
    case Some(x) => x.toSeq
    case None =>
  }
}

Although I have no idea what is actually happening when x.toSeq is called and I imagine there is more memory being used here that actually required to accomplish this.

An explanation or suggestion would be much appreciated.

I am confused why you say that "I imagine there is more memory being used here than actually required to accomplish". Scala will not copy your Field values when doing x.toSeq , it is simply going to create an new Seq which will have pointers to the same Field values that underlying is pointing to. Since this new structure is exactly what you want there is no avoiding the additional memory associated with the extra pointers (but the amount of additional memory should be small). For a more in-depth discussion see the wiki on persistent data structures .

Regarding your possible solution, it could be slightly modified to get the result you're expecting:

def toSeq : Seq[Field] = 
  underlying
    .map(_.toSeq)
    .getOrElse(Seq.empty[Field])

This solution will return an empty Seq if underlying is a None which is safer than your original attempt which uses get . I say it's "safer" because get throws a NoSuchElementException if the Option is a None whereas my toSeq can never fail to return a valid value.

Functional Approach

As a side note: when I first started programming in scala I would write many functions of the form:

def formatSeq(seq : Seq[String]) : Seq[String] = 
  seq map (_.toUpperCase)

This is less functional because you are expecting a particular collection type, eg formatSeq won't work on a Future .

I have found that a better approach is to write:

def formatStr(str : String) = str.toUpperCase

Or my preferred coding style:

val formatStr = (_ : String).toUpperCase

Then the user of your function can apply formatStr in any fashion they want and you don't have to worry about all of the collection casting:

val fut : Future[String] = ???
val formatFut = fut map formatStr

val opt : Option[String] = ???
val formatOpt = opt map formatStr

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM