return FALSE; $r = well_tag_thread__update(array('id' => $id), $update); return $r; } function well_tag_thread_find($tagid, $page, $pagesize) { $arr = well_tag_thread__find(array('tagid' => $tagid), array('id' => -1), $page, $pagesize); return $arr; } function well_tag_thread_find_by_tid($tid, $page, $pagesize) { $arr = well_tag_thread__find(array('tid' => $tid), array(), $page, $pagesize); return $arr; } ?>Scala deconstruct like javascript objects - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Scala deconstruct like javascript objects - Stack Overflow

programmeradmin3浏览0评论

I want javascripts ability to deconstruct in scala. Consider an object in js and a case class in scala. If I want just the first and last attribute from the object/case class then in scala I need to list out all the attributes or I get a pile error.

In scala case class deconstruction (from what I know) is positional using the unapply method

case class ABC(a: Int, b: Int, c: Int)
val obj = ABC(1,2,3)
// deconstruction
val (a, _, c) = obj

while in javascript its by attribute name

const obj = { a: 1, b: 2, c: 3 }
const { a, c } = obj
// or
const { a: attrA, c: attrC } = obj
// scala deconstruction is essentially javascript array deconstruction
const arr = [1,2,3]
const [ first, _, last ] = arr

Is it possible to use a 'javascript like' object deconstruction in scala? The difference is trivial in this example but with many more attributes that might change order in future revisions, the scala code bees harder to manage.

I want javascripts ability to deconstruct in scala. Consider an object in js and a case class in scala. If I want just the first and last attribute from the object/case class then in scala I need to list out all the attributes or I get a pile error.

In scala case class deconstruction (from what I know) is positional using the unapply method

case class ABC(a: Int, b: Int, c: Int)
val obj = ABC(1,2,3)
// deconstruction
val (a, _, c) = obj

while in javascript its by attribute name

const obj = { a: 1, b: 2, c: 3 }
const { a, c } = obj
// or
const { a: attrA, c: attrC } = obj
// scala deconstruction is essentially javascript array deconstruction
const arr = [1,2,3]
const [ first, _, last ] = arr

Is it possible to use a 'javascript like' object deconstruction in scala? The difference is trivial in this example but with many more attributes that might change order in future revisions, the scala code bees harder to manage.

Share Improve this question asked Mar 13, 2018 at 19:18 andykaisandykais 1,0842 gold badges14 silver badges28 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 6

Correct me if I'm wrong, but as far as I understand it,

const {a, c} = obj

simply brings the values obj.a and obj.c under the names a and c into scope. If pattern matching is too verbose, you can easily achieve a similar effect using import, for example:

case class Abc(a: Int, b: Int, c: Int)
val obj = Abc(1, 2, 3)
val somethingUsingOnlyAandC = {
  import obj.{a, c}
  a + c
}

println(somethingUsingOnlyAandC) // Output: 4

This works also if you have multiple objects of the same class with renaming imports:

case class Abc(a: Int, b: Int, c: Int)

val x = Abc(1, 2, 3)
val y = Abc(4, 5, 6)

val bar = {
  import x.{a => a1, c => c1}
  import y.{a => a2, c => c2}
  a1 * a2 + c1 * c2
}

println(bar) // prints "22", 1 * 4 + 3 * 6

You can destructure everything that provides an unapply method (extractor):

class Test(val a: String, val b: Int)

object Test {

  def unapply(test: Test): Option[(String, Int)] = Some((test.a, test.b))
}

val test = new Test("test", 0)
val (a, b) = test

It is automatically generated for case classes so your example allows it as well:

case class ABC(a: Int, b: Int, c: Int)
val obj = ABC(1,2,3)
// deconstruction
val ABC(a, _, c) = obj

Notice that there is a name of object containing extractor - it tells piler where to search for it (as you might have several extractors if you want!).

The same mechanism is used for pattern matching, so when you use:

option match {
  case Some(value) => // uses Some.unapply(option)
  case None        => // uses None.unapply(option)
}

either match {
  case Left(left)   => // uses Left.unapply(either)
  case Right(right) => // uses Right.unapply(either)
}

extractors to obtain Option of a tuple with content - Some mean that matching succeeded and None that it failed.

For collections you might want to look up exact example depending on what do you math against:

list match {
  case v1 :: v2 :: Nil => // 2-element list
  case head :: tail    => // non-empty list
  case Nil             => // empty list
}

seq match {
  case Seq()             => // empty Seq
  case Seq(a, b)         => // 2-element Seq
  case Seq(a, tail @ _*) => destructures into a and iterable tail
}

If you insist on using extractors, you can use the idea from this answer

object && {
  def unapply[A](a: A): Option[(A, A)] = Some((a, a))
}

and additionally define a separate extractor for each member variable:

case class Abc(a: Int, b: Int, c: Int)

object Abc {
  object A { def unapply(x: Abc): Option[Int] = Some(x.a) }
  object B { def unapply(x: Abc): Option[Int] = Some(x.b) }
  object C { def unapply(x: Abc): Option[Int] = Some(x.c) }
}

Now you can use it in patter matching like this:

val z = Abc(42, 100, 58)
import Abc._
val A(a) && B(b) = z
println(s"a = $a , b = $b")

The output for this example is:

a = 42 , b = 100

Note that it works with an arbitrary number of extractors chained together with &&, for example:

case class Abc(a1: Int, a2: Int, a3: Int, a4: Int, a5: Int, a6: Int, a7: Int, a8: Int)

object Abc {
  object A1 { def unapply(x: Abc): Option[Int] = Some(x.a1) }
  object A2 { def unapply(x: Abc): Option[Int] = Some(x.a2) }
  object A3 { def unapply(x: Abc): Option[Int] = Some(x.a3) }
  object A4 { def unapply(x: Abc): Option[Int] = Some(x.a4) }
  object A5 { def unapply(x: Abc): Option[Int] = Some(x.a5) }
  object A6 { def unapply(x: Abc): Option[Int] = Some(x.a6) }
  object A7 { def unapply(x: Abc): Option[Int] = Some(x.a7) }
  object A8 { def unapply(x: Abc): Option[Int] = Some(x.a8) }

}

object && {
  def unapply[A](a: A): Option[(A, A)] = Some((a, a))
}

val z = Abc(1, 2, 3, 4, 5, 6, 7, 8)
import Abc._
val A3(a3) && A5(a5) && A7(a7) = z
println(s"$a3 $a5 $a7")

outputs

3 5 7

as expected. If you really want to work with such unwieldy objects so often, you should consider code generation for the boilerplate code anyway.

发布评论

评论列表(0)

  1. 暂无评论