[scala] 스칼라의 숨겨진 기능

모든 스칼라 개발자가 알아야 할 스칼라의 숨겨진 기능은 무엇입니까?

답변 당 하나의 숨겨진 기능을 사용하십시오.



답변

좋아, 나는 하나 더 추가했다. Regex스칼라의 모든 개체에는 일치 그룹에 액세스 할 수있는 추출기가 있습니다 (위의 oxbox_lakes에서 답변 참조). 따라서 다음과 같은 작업을 수행 할 수 있습니다.

// Regex to split a date in the format Y/M/D.
val regex = "(\\d+)/(\\d+)/(\\d+)".r
val regex(year, month, day) = "2010/1/13"

패턴 일치 및 추출기를 사용하지 않는 경우 두 번째 줄이 혼란스러워 보입니다. 당신이를 정의 할 때마다 val또는 var, 어떤 키워드 다음에 오는 것은 단순히 오히려 식별자하지만 패턴이 아니다. 이것이 이것이 작동하는 이유입니다.

val (a, b, c) = (1, 3.14159, "Hello, world")

오른쪽 식은 Tuple3[Int, Double, String]패턴과 일치 할 수 있는를 만듭니다 (a, b, c).

대부분의 패턴은 싱글 톤 객체의 멤버 인 추출기를 사용합니다. 예를 들어 다음과 같은 패턴을 작성하면

Some(value)

그런 다음 추출기를 암시 적으로 호출합니다 Some.unapply.

그러나 클래스 인스턴스를 패턴으로 사용할 수도 있으며 이것이 바로 여기서 일어나고 있습니다. 발에 정규식의 인스턴스 Regex, 그리고 당신이 패턴을 사용할 때, 당신은 암시 적으로 전화하는거야 regex.unapplySeq( unapplyunapplySeq에 일치하는 그룹 추출하고,이 답변의 범위를 벗어납니다) Seq[String]에 순서대로 할당이되는 요소를 변수 년, 월 및 일.


답변

구조적 유형 정의-지원되는 메소드에 의해 설명되는 유형. 예를 들면 다음과 같습니다.

object Closer {
    def using(closeable: { def close(): Unit }, f: => Unit) {
      try { 
        f
      } finally { closeable.close }
    }
}

매개 변수 의 유형 은 메소드 closeable가 아닌 다른 유형 으로 정의되지 않았습니다.close


답변

유형 생성자 다형성 (일명 상위 유형)

예를 들어이 기능이 없으면 목록에 함수를 매핑하여 다른 목록을 반환하거나 트리에 함수를 매핑하여 다른 트리를 반환한다는 아이디어를 표현할 수 있습니다. 그러나이 아이디어는 일반적으로 더 높은 종류 가 없으면 표현할 수 없습니다 .

더 높은 종류를 사용하면 다른 유형으로 매개 변수화 된 모든 유형 의 아이디어를 포착 할 수 있습니다 . 하나의 매개 변수를 사용하는 형식 생성자는 일종이라고합니다 (*->*). 예를 들면 다음과 같습니다 List. 다른 형식 생성자를 반환하는 형식 생성자는 일종이라고합니다 (*->*->*). 예를 들면 다음과 같습니다 Function1. 그러나 스칼라에는 더 높은 종류가 있으므로 다른 유형 생성자로 매개 변수화되는 유형 생성자를 가질 수 있습니다. 그래서 그들은 같은 종류 ((*->*)->*)입니다.

예를 들면 다음과 같습니다.

trait Functor[F[_]] {
  def fmap[A, B](f: A => B, fa: F[A]): F[B]
}

이제가있는 경우 Functor[List]목록을 매핑 할 수 있습니다. 가있는 경우 Functor[Tree]나무 위로 매핑 할 수 있습니다. 그러나 더 중요한 것은 Functor[A] 어떤 종류의 A(*->*) 가 있다면 함수를에 매핑 할 수 있습니다 A.


답변

지저분한 if-elseif-else스타일 코드를 패턴 으로 바꿀 수있는 추출기 . 나는 이것들이 정확히 숨겨져 있지는 않지만 실제로 몇 달 동안 스칼라를 사용하여 그 힘을 이해하지 못했습니다 . (긴) 예를 들어 다음을 대체 할 수 있습니다.

val code: String = ...
val ps: ProductService = ...
var p: Product = null
if (code.endsWith("=")) {
  p = ps.findCash(code.substring(0, 3)) //e.g. USD=, GBP= etc
}
else if (code.endsWith(".FWD")) {
  //e.g. GBP20090625.FWD
  p = ps.findForward(code.substring(0,3), code.substring(3, 9))
}
else {
  p = ps.lookupProductByRic(code)
}

이것으로, 내 의견으로 는 훨씬 더 명확합니다.

implicit val ps: ProductService = ...
val p = code match {
  case SyntheticCodes.Cash(c) => c
  case SyntheticCodes.Forward(f) => f
  case _ => ps.lookupProductByRic(code)
}

나는 백그라운드에서 약간의 legwork을해야합니다 …

object SyntheticCodes {
  // Synthetic Code for a CashProduct
  object Cash extends (CashProduct => String) {
    def apply(p: CashProduct) = p.currency.name + "="

    //EXTRACTOR
    def unapply(s: String)(implicit ps: ProductService): Option[CashProduct] = {
      if (s.endsWith("=") 
        Some(ps.findCash(s.substring(0,3))) 
      else None
    }
  }
  //Synthetic Code for a ForwardProduct
  object Forward extends (ForwardProduct => String) {
    def apply(p: ForwardProduct) = p.currency.name + p.date.toString + ".FWD"

    //EXTRACTOR
    def unapply(s: String)(implicit ps: ProductService): Option[ForwardProduct] = {
      if (s.endsWith(".FWD") 
        Some(ps.findForward(s.substring(0,3), s.substring(3, 9)) 
      else None
    }
  }

그러나 합법적 인 가치는 비즈니스 로직을 합리적인 장소로 분리한다는 점에서 가치가 있습니다. Product.getCode다음과 같이 메소드를 구현할 수 있습니다 .

class CashProduct {
  def getCode = SyntheticCodes.Cash(this)
}

class ForwardProduct {
  def getCode = SyntheticCodes.Forward(this)     
}


답변

스칼라가 유형을 구체화 한 것처럼 런타임에 유형 정보를 얻는 일종의 방법 인 매니페스트 .


답변

scala 2.8에서는 scala.util.control.TailCalls 패키지 (실제로 트램폴린)를 사용하여 꼬리 재귀 메서드를 사용할 수 있습니다.

예를 들면 :

def u(n:Int):TailRec[Int] = {
  if (n==0) done(1)
  else tailcall(v(n/2))
}
def v(n:Int):TailRec[Int] = {
  if (n==0) done(5)
  else tailcall(u(n-1))
}
val l=for(n<-0 to 5) yield (n,u(n).result,v(n).result)
println(l)


답변

사례 클래스는 제품 특성을 자동으로 혼합하여 반영없이 필드에 유형화되지 않은 색인 액세스를 제공합니다.

case class Person(name: String, age: Int)

val p = Person("Aaron", 28)
val name = p.productElement(0) // name = "Aaron": Any
val age = p.productElement(1) // age = 28: Any
val fields = p.productIterator.toList // fields = List[Any]("Aaron", 28)

이 기능은 또한 toString메소드 의 출력을 변경하는 간단한 방법을 제공합니다 .

case class Person(name: String, age: Int) {
   override def productPrefix = "person: "
}

// prints "person: (Aaron,28)" instead of "Person(Aaron, 28)"
println(Person("Aaron", 28))