How to make method return the same generic as the input?

前端 未结 3 1035
面向向阳花
面向向阳花 2021-02-07 10:20

I want to split a string delimited by commas and use the result as either a Seq or a Set:

def splitByComma(commaDelimited: String): Arr         


        
相关标签:
3条回答
  • 2021-02-07 10:42

    There's a simple workaround for this. Not exactly the requested syntax but just as concise and it should be 2.13 compatible.

    def simpleSplitByComma(coll :Iterable[String]) =
      coll.flatMap(_.trim.split(","))
    
    simpleSplitByComma(Set("hello,world"))          //res0: Set(hello, world)
    simpleSplitByComma(Seq("bellow,world"))         //res1: List(bellow, world)
    simpleSplitByComma(Array("fellow,old"))         //res2: ArrayBuffer(fellow, old)
    simpleSplitByComma(Stream("end,of,the,world"))  //res3: Stream(end, ?)
    
    0 讨论(0)
  • 2021-02-07 10:45

    @KrzysztofAtłasik's answer works great for Scala 2.12.
    This is a solution for 2.13. (Not completely sure if this is the best way).

    import scala.collection.Factory
    import scala.language.higherKinds
    
    def splitByComma[C[_]](commaDelimited: String)(implicit f: Factory[String, C[String]]): C[String] =
      f.fromSpecific(commaDelimited.split(","))
      // Or, as Dmytro stated, which I have to agree looks better.
      commaDelimited.split(",").to(f)
    

    Which you can use like this:

    splitByComma[Array]("hello,world!")
    // res: Array[String] = Array(hello, world!)
    
    splitByComma[Set]("hello,world!")
    // res: Set[String] = Set(hello, world!)
    
    splitByComma[List]("hello,world!")
    // res: List[String] = List(hello, world!)
    
    0 讨论(0)
  • 2021-02-07 11:01

    There's a method in Scala called to which can transform arbitrary collection to another as long as there is typeclass called CanBuildFrom in scope.

    import scala.collection.generic.CanBuildFrom
    import scala.languageFeature.higherKinds
    
    def genericSplitByComma[S[_]](s: String)(implicit cbf: CanBuildFrom[Nothing, String, S[String]]): S[String] = {
        s.split(",").to[S]
    }
    
    genericSplitByComma[Set]("Hello, hello") //Set(Hello,  hello)
    genericSplitByComma[List]("Hello, hello") //List(Hello,  hello)
    genericSplitByComma[Array]("Hello, hello") //Array(hello, world!)
    

    We don't need to constrain S[_] because this function won't compile if there is no suitable CanBuildFrom in scope. For example, this will fail:

    genericSplitByComma[Option]("Hello, hello")
    

    Below will also fail because our type constructor S[_] accepts only one type argument and the map expects two:

    genericSplitByComma[Map]("Hello, hello")
    

    As Luis Miguel Mejía Suárez and Dmytro Mitin noticed, there was major refactor in collections in just-released Scala 2.13, so it will work up to Scala 2.12.

    0 讨论(0)
提交回复
热议问题