모든 스칼라 개발자가 알아야 할 스칼라의 숨겨진 기능은 무엇입니까?
답변 당 하나의 숨겨진 기능을 사용하십시오.
답변
좋아, 나는 하나 더 추가했다. 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
( unapply
대 unapplySeq
에 일치하는 그룹 추출하고,이 답변의 범위를 벗어납니다) 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))