스칼라의 숨겨진 기능


149

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

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


6
이 질문은 질문 자체와 마찬가지로 다른 숨겨진 기능 게시물에 대한 링크에 유용합니다. 건배!
JohnMetta 2016 년

1
@mettadore 는 오른쪽 의 관련 링크를 살펴보십시오 .
Daniel C. Sobral

2
@JohnMetta : 또는 태그를 사용하십시오 .

답변:


85

좋아, 나는 하나 더 추가했다. 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]에 순서대로 할당이되는 요소를 변수 년, 월 및 일.


1
이것을 게시 해 주셔서 감사합니다! 참고로 1 판 503 페이지의 "스칼라 프로그래밍", 2 판 611 페이지의 "정규 표현식으로 추출"장에서 언급했습니다.
earthling paul

51

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

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

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


1
구조 유형은 "스칼라 프로그래밍"에서도 언급되지 않았습니다. 리플렉션을 사용하여 올바른 메소드를 호출하기 때문에 유형을 전달하는 다른 기술보다 약간 느립니다. (희망스럽게도 속도를 높일 수있는 방법을 찾게 될 것입니다.)
Ken Bloom

1
그리고 외부 적으로 할당 된 인터페이스 (매우 느린 것)처럼 작동하는 별칭을 만들 수도 있습니다. type Closeable = {def close () : Unit}
Alexey

45

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

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

더 높은 종류를 사용하면 다른 유형으로 매개 변수화 된 모든 유형 의 아이디어를 포착 할 수 있습니다 . 하나의 매개 변수를 사용하는 형식 생성자는 일종이라고합니다 (*->*). 예를 들면 다음과 같습니다 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.


39

지저분한 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)     
}

이것이 스위치와 같지 않습니까? 아마도 이것은 더 리팩토링 될 수 있습니다.
Geo

14
패턴은 터보 차저 스위치와 같습니다. 훨씬 강력하고 명확합니다
oxbow_lakes

1
멋지지만 범위가 일치하는 {} 이상으로 도달하기 때문에 암시 적을 사용해야하는 것은 좋지 않습니다. 코드별로 제품을 찾는 방법을 ProductService에 추가 할 수도 있습니다. 어쨌든 리팩토링 된 스 니펫을 방법으로 감싸서 어디에서나 사용할 수 있습니다.
Martin Konicek

35

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


8
링크를 참조하는 대신 답변 답변을 설명하는 것이 바람직하다고 생각합니다 . 그건 그렇고, 안녕 agai oxbow! :-)
Daniel C. Sobral

이것은 API 문서조차도 실제로 숨겨진 기능입니다. 그래도 매우 유용합니다.
André Laszlo

35

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)

35

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

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)) 

32

정확히 숨겨져 있지는 않지만 광고 기능인 scalac -Xprint 입니다.

사용의 예로써 다음 출처를 고려하십시오.

class A { "xx".r }

이것을 scalac -Xprint : typer 출력으로 컴파일 :

package <empty> {
  class A extends java.lang.Object with ScalaObject {
    def this(): A = {
      A.super.this();
      ()
    };
    scala.this.Predef.augmentString("xx").r
  }
}

공지 사항 scala.this.Predef.augmentString("xx").r의 상기 응용 프로그램입니다, implicit def augmentStringPredef.scala에 존재.

scalac -Xprint : <phase> 는 일부 컴파일러 단계 후에 구문 트리를 인쇄합니다. 사용 가능한 단계를 보려면 scalac -Xshow-phases를 사용하십시오 .

이것은 비하인드 스토리를 배우는 좋은 방법입니다.

함께 시도

case class X(a:Int,b:String)

정말 유용하다고 느끼기 위해 typer 단계를 사용합니다 .


30

자신 만의 제어 구조를 정의 할 수 있습니다. 그것은 단지 함수와 객체 그리고 일부 구문 설탕이지만, 실제처럼 보이고 행동합니다.

예를 들어, 다음 코드를 정의 dont {...} unless (cond)dont {...} until (cond):

def dont(code: => Unit) = new DontCommand(code)

class DontCommand(code: => Unit) {
  def unless(condition: => Boolean) =
    if (condition) code

  def until(condition: => Boolean) = {
    while (!condition) {}
    code
  }
}

이제 다음을 수행 할 수 있습니다.

/* This will only get executed if the condition is true */
dont {
  println("Yep, 2 really is greater than 1.")
} unless (2 > 1) 

/* Just a helper function */
var number = 0;
def nextNumber() = {
  number += 1
  println(number)
  number
}

/* This will not be printed until the condition is met. */
dont {
  println("Done counting to 5!")
} until (nextNumber() == 5) 

여기에 몇 가지 예가 더 있습니다 : programmers.stackexchange.com/questions/13072/…
missingfaktor

누군가가 표준 블록과 같은 유형 검사를 사용하여 if-then-else 블록을 정의하는 방법을 알고 있다면 궁금합니다.
Philippe

@ 필리핀 : zif[A : Zero](cond: => Boolean)(t: => A): A = if(cond) t else mzero. 스칼라 즈가 필요합니다.
missingfaktor

26

@switch 스칼라 2.8의 주석 :

일치 표현식에 적용 할 주석입니다. 존재하는 경우 컴파일러는 일치 항목이 테이블 스위치 또는 조회 스위치로 컴파일되었는지 확인하고 대신 일련의 조건식으로 컴파일하는 경우 오류를 발생시킵니다.

예:

scala> val n = 3
n: Int = 3

scala> import annotation.switch
import annotation.switch

scala> val s = (n: @switch) match {
     |   case 3 => "Three"
     |   case _ => "NoThree"
     | }
<console>:6: error: could not emit switch for @switch annotated match
       val s = (n: @switch) match {

26

이것이 실제로 숨겨져 있다면 Dunno이지만 꽤 좋습니다.

2 가지 유형의 매개 변수를 사용하는 유형 생성자는 접두사 표기법으로 쓸 수 있습니다.

object Main {                                                                   
  class FooBar[A, B]

  def main(args: Array[String]): Unit = {
    var x: FooBar[Int, BigInt] = null
    var y: Int FooBar BigInt   = null
  }
}

1
좋은! 가독성을 향상시키는 데 유용한 경우가 종종 있습니다. 예를 들어 var foo2barConverter: Foo ConvertTo Bar, 유형 매개 변수의 순서는 자명합니다.
Esko Luontola

4
때로는 PartialFunction을 어느 정도 사용하는 코드에서이 작업을 수행합니다. type ~> [A, B] = PartialFunction [A, B]
raichoo

24

Scala 2.8에는 기본 및 명명 된 인수가 도입되어 Scala가 사례 클래스에 추가하는 새로운 "복사"방법이 추가되었습니다. 이것을 정의하면 :

case class Foo(a: Int, b: Int, c: Int, ... z:Int)

"n"값만 다른 기존 Foo와 같은 새 Foo를 만들려면 다음과 같이 말하면됩니다.

foo.copy(n = 3)

3
경고 : 한 사례 클래스를 다른 사례 클래스에서 상속하는 경우 복사 방법이 재정의되지 않습니다. 따라서 수동으로 재정의해야합니다
Alexey

관련 항목 : 중첩 구조를 업데이트하는
보다 확실한

5
사례 클래스는 더 이상 사례 클래스에서 상속 할 수 없습니다 (Scala 2.8). 이 거룩하지 않은 상속을 폐지 한 스칼라 군주 께 감사드립니다.
olle kullberg

24

scala 2.8에서는 일반 클래스 / 메소드에 @specialized를 추가 할 수 있습니다. 이렇게하면 기본 유형 (AnyVal 확장)에 대한 클래스의 특수 버전이 만들어지고 불필요한 박싱 / 언 박싱 비용이 절약됩니다. class Foo[@specialized T]...

AnyVals의 하위 세트를 선택할 수 있습니다. class Foo[@specialized(Int,Boolean) T]...


1
더 자세히 설명해 주시겠습니까? 더 배우고 싶습니다.
Paweł Prażak

23

언어 확장. 나는 항상 자바에서 이와 같은 것을하고 싶었다. 그러나 스칼라에서는 다음을 가질 수 있습니다.

  def timed[T](thunk: => T) = {
    val t1 = System.nanoTime
    val ret = thunk
    val time = System.nanoTime - t1
    println("Executed in: " + time/1000000.0 + " millisec")
    ret
  }

그리고 다음과 같이 작성하십시오.

val numbers = List(12, 42, 3, 11, 6, 3, 77, 44)
val sorted = timed {   // "timed" is a new "keyword"!
  numbers.sortWith(_<_)
}
println(sorted)

그리고 얻다

Executed in: 6.410311 millisec
List(3, 3, 6, 11, 12, 42, 44, 77)

23

이름 별 호출 매개 변수 (편집 됨 : 지연 매개 변수와 다릅니다!)를 함수에 지정할 수 있으며 함수에 의해 사용될 때까지 평가되지 않습니다 (사실 실제로는 매번 재평가됩니다. 익숙한). 자세한 내용은 이 FAQ 를 참조하십시오

class Bar(i:Int) {
    println("constructing bar " + i)
    override def toString():String = {
        "bar with value: " + i
    }
}

// NOTE the => in the method declaration.  It indicates a lazy paramter
def foo(x: => Bar) = {
    println("foo called")
    println("bar: " + x)
}


foo(new Bar(22))

/*
prints the following:
foo called
constructing bar 22
bar with value: 22
*/

"x : => Bar"는 x가 매개 변수를 사용하지 않고 Bar를 반환하는 함수라는 것을 의미했습니다. 따라서 "new bar (22)"는 익명 함수일 뿐이며 다른 함수와 마찬가지로 함수로 평가됩니다.
Alex Black

1
"x : () => Bar"는 매개 변수를 사용하지 않고 x를 반환하는 xa 함수를 정의합니다. x : => Bar는 x를 이름 별 호출로 정의합니다. 자세한 내용 은 scala.sygneca.com/faqs/… 를 참조하십시오
agilefall

3
표시되는 것은 이름 별 호출 매개 변수입니다. 게으른 매개 변수는 아직 구현되지 않았습니다 : lampsvn.epfl.ch/trac/scala/ticket/240
ArtemGr

나는 당신이 lazy val xx: Bar = x당신의 방법과 같은 것을 하고 그 순간부터 당신이 사용하는 경우에 게으른 매개 변수로 사용할 수 있다고 생각합니다 xx.
크리스티안 브라 비

20

locally세미콜론 추론 문제를 일으키지 않고 로컬 블록을 도입하는 데 사용할 수 있습니다 .

용법:

scala> case class Dog(name: String) {
     |   def bark() {
     |     println("Bow Vow")
     |   }
     | }
defined class Dog

scala> val d = Dog("Barnie")
d: Dog = Dog(Barnie)

scala> locally {
     |   import d._
     |   bark()
     |   bark()
     | }
Bow Vow
Bow Vow

locally "Predef.scala"에서 다음과 같이 정의됩니다.

@inline def locally[T](x: T): T = x

인라인이기 때문에 추가 오버 헤드가 발생하지 않습니다.



17

초기 초기화 :

trait AbstractT2 {
  println("In AbstractT2:")
  val value: Int
  val inverse = 1.0/value
  println("AbstractT2: value = "+value+", inverse = "+inverse)
}

val c2c = new {
  // Only initializations are allowed in pre-init. blocks.
  // println("In c2c:")
  val value = 10
} with AbstractT2

println("c2c.value = "+c2c.value+", inverse = "+c2c.inverse)

산출:

In AbstractT2:  
AbstractT2: value = 10, inverse = 0.1  
c2c.value = 10, inverse = 0.1

익명의 내부 클래스를 인스턴스화 value하여 with AbstractT2절 앞의 블록 에서 필드를 초기화합니다 . 이렇게 하면 스크립트를 실행할 때 표시되는 것처럼 value본문 AbstractT2이 실행 되기 전에 초기화 됩니다.


1
이 구조를 "초기 초기화"라고합니다.
랜달 슐츠

17

'with'키워드를 사용하여 구조 유형을 작성할 수 있습니다

object Main {
  type A = {def foo: Unit}
  type B = {def bar: Unit}

  type C = A with B

  class myA {
    def foo: Unit = println("myA.foo")
  }


  class myB {
    def bar: Unit = println("myB.bar")
  }
  class myC extends myB {
    def foo: Unit = println("myC.foo")
  }

  def main(args: Array[String]): Unit = { 
    val a: A = new myA 
    a.foo
    val b: C = new myC 
    b.bar
    b.foo
  }
}

17

익명 함수에 대한 자리 표시 자 구문

스칼라 언어 사양에서 :

SimpleExpr1 ::= '_'

(구문 카테고리의 Expr) 표현 _은 식별자가 유효한 장소에 삽입 된 밑줄 기호 를 포함 할 수 있습니다 . 이러한 표현식은 후속 밑줄이 연속적인 매개 변수를 나타내는 익명 함수를 나타냅니다.

에서 스칼라 언어 변경 :

_ + 1                  x => x + 1
_ * _                  (x1, x2) => x1 * x2
(_: Int) * 2           (x: Int) => x * 2
if (_) x else y        z => if (z) x else y
_.map(f)               x => x.map(f)
_.map(_ + 1)           x => x.map(y => y + 1)

이것을 사용하면 다음과 같이 할 수 있습니다 :

def filesEnding(query: String) =
  filesMatching(_.endsWith(query))

2
이것을 '익명 함수의 자리 표시 자 구문'이라고합니다. 스칼라에서는 암시적인 의미가 뚜렷하며 이와 관련이 없습니다.
retronym

링크는 답변과 명백하지 않은 관계가 있습니다. "암시 적"은 이에 대한 올바른 용어가 아닙니다. 위와 같이 "자리 표시 자"여야합니다.
Alain O'Dea

2
그것은 실제로 "숨겨진"것이 아닙니다, 나는 읽은 스칼라에 관한 거의 모든 튜토리얼에서이 사용법을 보았습니다 ... :-) 그러나 나는 아직 보지 못한 공식적인 정의에 감사합니다.
PhiLho

@PhiLho 2009 년에는 잘 알려지지 않았을 것입니다.
유진 요코타

마지막 편집 날짜 만 표시되므로 원래 날짜를 놓쳤습니다. 그리고이 글에서 설명 된 모든 기능들이 "숨겨진"것은 아닙니다. 어쨌든 멋진 실과 좋은 대답.
PhiLho

16

암시 적 정의, 특히 전환

예를 들어, 입력 문자열의 형식을 "..."로 바꾸어 입력 문자열을 크기에 맞게 지정하는 함수를 가정하십시오.

def sizeBoundedString(s: String, n: Int): String = {
  if (n < 5 && n < s.length) throw new IllegalArgumentException
  if (s.length > n) {
    val trailLength = ((n - 3) / 2) min 3
    val headLength = n - 3 - trailLength
    s.substring(0, headLength)+"..."+s.substring(s.length - trailLength, s.length)
  } else s
}

모든 String과 함께 사용할 수 있으며 물론 toString 메서드를 사용하여 모든 것을 변환 할 수 있습니다. 그러나 다음과 같이 작성할 수도 있습니다.

def sizeBoundedString[T](s: T, n: Int)(implicit toStr: T => String): String = {
  if (n < 5 && n < s.length) throw new IllegalArgumentException
  if (s.length > n) {
    val trailLength = ((n - 3) / 2) min 3
    val headLength = n - 3 - trailLength
    s.substring(0, headLength)+"..."+s.substring(s.length - trailLength, s.length)
  } else s
}

그런 다음 다음을 수행하여 다른 유형의 클래스를 전달할 수 있습니다.

implicit def double2String(d: Double) = d.toString

이제 그 함수를 더블로 전달할 수 있습니다 :

sizeBoundedString(12345.12345D, 8)

마지막 인수는 암시 적이며 암시 적 선언으로 인해 자동으로 전달됩니다. 또한 "s"는 sizeBoundedString 내부에서 String 으로 처리 되므로 암시 적으로 String으로 변환됩니다.

이 유형의 내재는 예기치 않은 변환을 피하기 위해 일반적이지 않은 유형에 대해 더 잘 정의됩니다. 변환을 명시 적으로 전달할 수도 있으며 sizeBoundedString 내부에서 여전히 암시 적으로 사용됩니다.

sizeBoundedString(1234567890L, 8)((l : Long) => l.toString)

여러 개의 암시 적 인수를 가질 수도 있지만 모든 인수를 전달하거나 전달하지 않아야합니다. 암시 적 변환을위한 바로 가기 구문도 있습니다.

def sizeBoundedString[T <% String](s: T, n: Int): String = {
  if (n < 5 && n < s.length) throw new IllegalArgumentException
  if (s.length > n) {
    val trailLength = ((n - 3) / 2) min 3
    val headLength = n - 3 - trailLength
    s.substring(0, headLength)+"..."+s.substring(s.length - trailLength, s.length)
  } else s
}

이것은 정확히 같은 방식으로 사용됩니다.

암시 적은 어떤 값이든 가질 수 있습니다. 예를 들어 라이브러리 정보를 숨기는 데 사용할 수 있습니다. 예를 들어 다음 예를 보자.

case class Daemon(name: String) {
  def log(msg: String) = println(name+": "+msg)
}

object DefaultDaemon extends Daemon("Default")

trait Logger {
  private var logd: Option[Daemon] = None
  implicit def daemon: Daemon = logd getOrElse DefaultDaemon

  def logTo(daemon: Daemon) = 
    if (logd == None) logd = Some(daemon) 
    else throw new IllegalArgumentException

  def log(msg: String)(implicit daemon: Daemon) = daemon.log(msg)
}

class X extends Logger {
  logTo(Daemon("X Daemon"))

  def f = {
    log("f called")
    println("Stuff")
  }

  def g = {
    log("g called")(DefaultDaemon)
  }
}

class Y extends Logger {
  def f = {
    log("f called")
    println("Stuff")
  }
}

이 예에서 Y 객체에서 "f"를 호출하면 로그가 기본 데몬으로, X 인스턴스에서 데몬 X 데몬으로 로그가 전송됩니다. 그러나 X 인스턴스에서 g를 호출하면 명시 적으로 지정된 DefaultDaemon에 로그가 전송됩니다.

이 간단한 예제는 오버로드 및 개인 상태로 다시 작성할 수 있지만 암시 적에는 개인 상태가 필요하지 않으며 가져 오기를 통해 컨텍스트를 가져올 수 있습니다.


13

아마도 너무 숨겨져 있지는 않지만 이것이 유용하다고 생각합니다.

@scala.reflect.BeanProperty
var firstName:String = _

이것은 빈 규칙과 일치하는 필드에 대한 getter 및 setter를 자동으로 생성합니다.

developerworks 에서 추가 설명


6
예를 들어 import scala.reflect. {BeanProperty => BP}
Alexey

13

클로저의 암묵적인 주장.

함수 인수는 메소드와 마찬가지로 암시 적으로 표시 될 수 있습니다. 함수 본문의 범위 내에서 내재적 매개 변수가 표시되며 내재적 분석에 적합합니다.

trait Foo { def bar }

trait Base {
  def callBar(implicit foo: Foo) = foo.bar
}

object Test extends Base {
  val f: Foo => Unit = { implicit foo =>
    callBar
  }
  def test = f(new Foo {
    def bar = println("Hello")
  })
}


12

결과 유형은 암시 적 해상도에 따라 다릅니다. 이를 통해 여러 디스패치 형태를 얻을 수 있습니다.

scala> trait PerformFunc[A,B] { def perform(a : A) : B }
defined trait PerformFunc

scala> implicit val stringToInt = new PerformFunc[String,Int] {
  def perform(a : String)  = 5
}
stringToInt: java.lang.Object with PerformFunc[String,Int] = $anon$1@13ccf137

scala> implicit val intToDouble = new PerformFunc[Int,Double] {
  def perform(a : Int) = 1.0
}
intToDouble: java.lang.Object with PerformFunc[Int,Double] = $anon$1@74e551a4

scala> def foo[A, B](x : A)(implicit z : PerformFunc[A,B]) : B = z.perform(x)
foo: [A,B](x: A)(implicit z: PerformFunc[A,B])B

scala> foo("HAI")
res16: Int = 5

scala> foo(1)
res17: Double = 1.0

그럴 수도 있지만 위의 세션은 잘못된 것입니다. 이러한 명령을 실행하기 전에 환경에 있어야 foo하는 용도에 대한 정의 a. 나는 당신이 의미한다고 가정합니다 z.perform(x).
Daniel C. Sobral

4

스칼라의 Java 이중 괄호 초기화와 동일합니다.

Scala를 사용하면 명령문이 포함 된 클래스 본문 (생성자)을 사용하여 해당 클래스의 인스턴스를 초기화하는 익명 서브 클래스를 만들 수 있습니다.

이 패턴은 UI 구성 요소를 만들고 속성을보다 간결하게 선언 할 수 있으므로 구성 요소 기반 사용자 인터페이스 (예 : Swing, Vaadin)를 구축 할 때 매우 유용합니다.

자세한 내용은 http://spot.colorado.edu/~reids/papers/how-scala-experience-improved-our-java-development-reid-2011.pdf 를 참조하십시오.

Vaadin 버튼을 만드는 예는 다음과 같습니다.

val button = new Button("Click me"){
 setWidth("20px")
 setDescription("Click on this")
 setIcon(new ThemeResource("icons/ok.png"))
}

3

import진술 에서 회원 제외

Loggera printlnprinterr메소드 가 포함 된를 사용하려고 하지만 오류 메시지에만 사용하고 Predef.println표준 출력에 적합 하도록 유지하려고합니다 . 당신은 이것을 할 수 있습니다 :

val logger = new Logger(...)
import logger.printerr

그러나 logger가져오고 사용하려는 다른 12 개의 메소드가 포함되어 있으면 나열하기가 불편합니다. 대신 시도해 볼 수 있습니다.

import logger.{println => donotuseprintlnt, _}

그러나 이것은 여전히 ​​가져온 멤버 목록을 "오염"시킵니다. 우버 강력한 와일드 카드를 입력하십시오.

import logger.{println => _, _}

그리고 그것은 옳은 일을 할 것입니다 ™.


2

requirePredef런타임에 검사 할 추가 함수 제약 조건을 정의 할 수 있는 메서드 (에서 정의 됨 ). 다른 트위터 클라이언트를 개발 중이고 트윗 길이를 최대 140 개의 기호로 제한해야한다고 상상해보십시오. 또한 빈 트윗을 게시 할 수 없습니다.

def post(tweet: String) = {
  require(tweet.length < 140 && tweet.length > 0) 
  println(tweet)
 }

이제 부적절한 길이의 인수로 게시물을 호출하면 예외가 발생합니다.

scala> post("that's ok")
that's ok

scala> post("")
java.lang.IllegalArgumentException: requirement failed
    at scala.Predef$.require(Predef.scala:145)
    at .post(<console>:8)

scala> post("way to looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong tweet") 
java.lang.IllegalArgumentException: requirement failed
    at scala.Predef$.require(Predef.scala:145)
    at .post(<console>:8)

여러 요구 사항을 작성하거나 각각에 설명을 추가 할 수도 있습니다.

def post(tweet: String) = {
  require(tweet.length > 0, "too short message")
  require(tweet.length < 140, "too long message")
  println(tweet)
}

이제 예외는 장황하다 :

scala> post("")
java.lang.IllegalArgumentException: requirement failed: too short message
    at scala.Predef$.require(Predef.scala:157)
    at .post(<console>:8)

또 다른 예가 여기 있습니다 .


보너스

요구 사항이 실패 할 때마다 작업을 수행 할 수 있습니다.

scala> var errorcount = 0
errorcount: Int = 0

def post(tweet: String) = {
  require(tweet.length > 0, {errorcount+=1})
  println(tweet)
  }

scala> errorcount
res14: Int = 0

scala> post("")
java.lang.IllegalArgumentException: requirement failed: ()
    at scala.Predef$.require(Predef.scala:157)
    at .post(<console>:9)
...

scala> errorcount
res16: Int = 1

1
require예약어가 아닙니다. 에 정의 된 메소드 일뿐입니다 Predef.
missingfaktor

1

와 형질 abstract override방법은 널리 많은 사람들로 광고하지 않는 스칼라의 기능입니다. abstract override수정자를 사용한 메소드의 의도 는 일부 작업을 수행하고에 대한 호출을 위임하는 것 super입니다. 그런 다음 이러한 특성을 구체적인 구현 abstract override방법 과 혼합해야 합니다.

trait A {
  def a(s : String) : String
}

trait TimingA extends A {
  abstract override def a(s : String) = {
    val start = System.currentTimeMillis
    val result = super.a(s)
    val dur = System.currentTimeMillis-start
    println("Executed a in %s ms".format(dur))
    result
  }
}

trait ParameterPrintingA extends A {
  abstract override def a(s : String) = {
    println("Called a with s=%s".format(s))
    super.a(s)
  }
}

trait ImplementingA extends A {
  def a(s: String) = s.reverse
}

scala> val a = new ImplementingA with TimingA with ParameterPrintingA

scala> a.a("a lotta as")
Called a with s=a lotta as
Executed a in 0 ms
res4: String = sa attol a

내 예제는 실제로 가난한 AOP 이상의 것이 아니지만 사전 정의 된 가져 오기, 사용자 정의 바인딩 및 클래스 경로가있는 스칼라 인터프리터 인스턴스를 빌드하기 위해이 Stackable Traits를 많이 사용했습니다 . 스택 특색은 가능의 라인을 따라 내 공장을 만들려고 new InterpreterFactory with JsonLibs with LuceneLibs하고 유용한 수입이 있고 범위는 사용자 스크립트 varibles.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.