모든 스칼라 개발자가 알아야 할 스칼라의 숨겨진 기능은 무엇입니까?
답변 당 하나의 숨겨진 기능을 사용하십시오.
모든 스칼라 개발자가 알아야 할 스칼라의 숨겨진 기능은 무엇입니까?
답변 당 하나의 숨겨진 기능을 사용하십시오.
답변:
좋아, 나는 하나 더 추가했다. 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))
정확히 숨겨져 있지는 않지만 광고 기능인 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 augmentString
Predef.scala에 존재.
scalac -Xprint : <phase> 는 일부 컴파일러 단계 후에 구문 트리를 인쇄합니다. 사용 가능한 단계를 보려면 scalac -Xshow-phases를 사용하십시오 .
이것은 비하인드 스토리를 배우는 좋은 방법입니다.
함께 시도
case class X(a:Int,b:String)
정말 유용하다고 느끼기 위해 typer 단계를 사용합니다 .
자신 만의 제어 구조를 정의 할 수 있습니다. 그것은 단지 함수와 객체 그리고 일부 구문 설탕이지만, 실제처럼 보이고 행동합니다.
예를 들어, 다음 코드를 정의 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)
zif[A : Zero](cond: => Boolean)(t: => A): A = if(cond) t else mzero
. 스칼라 즈가 필요합니다.
@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 {
이것이 실제로 숨겨져 있다면 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
}
}
var foo2barConverter: Foo ConvertTo Bar
, 유형 매개 변수의 순서는 자명합니다.
Scala 2.8에는 기본 및 명명 된 인수가 도입되어 Scala가 사례 클래스에 추가하는 새로운 "복사"방법이 추가되었습니다. 이것을 정의하면 :
case class Foo(a: Int, b: Int, c: Int, ... z:Int)
"n"값만 다른 기존 Foo와 같은 새 Foo를 만들려면 다음과 같이 말하면됩니다.
foo.copy(n = 3)
scala 2.8에서는 일반 클래스 / 메소드에 @specialized를 추가 할 수 있습니다. 이렇게하면 기본 유형 (AnyVal 확장)에 대한 클래스의 특수 버전이 만들어지고 불필요한 박싱 / 언 박싱 비용이 절약됩니다.
class Foo[@specialized T]...
AnyVals의 하위 세트를 선택할 수 있습니다.
class Foo[@specialized(Int,Boolean) T]...
언어 확장. 나는 항상 자바에서 이와 같은 것을하고 싶었다. 그러나 스칼라에서는 다음을 가질 수 있습니다.
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)
이름 별 호출 매개 변수 (편집 됨 : 지연 매개 변수와 다릅니다!)를 함수에 지정할 수 있으며 함수에 의해 사용될 때까지 평가되지 않습니다 (사실 실제로는 매번 재평가됩니다. 익숙한). 자세한 내용은 이 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
*/
lazy val xx: Bar = x
당신의 방법과 같은 것을 하고 그 순간부터 당신이 사용하는 경우에 게으른 매개 변수로 사용할 수 있다고 생각합니다 xx
.
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
인라인이기 때문에 추가 오버 헤드가 발생하지 않습니다.
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
이 실행 되기 전에 초기화 됩니다.
'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
}
}
익명 함수에 대한 자리 표시 자 구문
스칼라 언어 사양에서 :
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))
암시 적 정의, 특히 전환
예를 들어, 입력 문자열의 형식을 "..."로 바꾸어 입력 문자열을 크기에 맞게 지정하는 함수를 가정하십시오.
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에 로그가 전송됩니다.
이 간단한 예제는 오버로드 및 개인 상태로 다시 작성할 수 있지만 암시 적에는 개인 상태가 필요하지 않으며 가져 오기를 통해 컨텍스트를 가져올 수 있습니다.
아마도 너무 숨겨져 있지는 않지만 이것이 유용하다고 생각합니다.
@scala.reflect.BeanProperty
var firstName:String = _
이것은 빈 규칙과 일치하는 필드에 대한 getter 및 setter를 자동으로 생성합니다.
developerworks 에서 추가 설명
클로저의 암묵적인 주장.
함수 인수는 메소드와 마찬가지로 암시 적으로 표시 될 수 있습니다. 함수 본문의 범위 내에서 내재적 매개 변수가 표시되며 내재적 분석에 적합합니다.
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")
})
}
Scala를 사용하여 무한한 데이터 구조를 구축하십시오 Stream
:
http://www.codecommit.com/blog/scala/infinite-lists-for-the-finitely-patient
결과 유형은 암시 적 해상도에 따라 다릅니다. 이를 통해 여러 디스패치 형태를 얻을 수 있습니다.
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)
.
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"))
}
import
진술 에서 회원 제외Logger
a println
및 printerr
메소드 가 포함 된를 사용하려고 하지만 오류 메시지에만 사용하고 Predef.println
표준 출력에 적합 하도록 유지하려고합니다 . 당신은 이것을 할 수 있습니다 :
val logger = new Logger(...)
import logger.printerr
그러나 logger
가져오고 사용하려는 다른 12 개의 메소드가 포함되어 있으면 나열하기가 불편합니다. 대신 시도해 볼 수 있습니다.
import logger.{println => donotuseprintlnt, _}
그러나 이것은 여전히 가져온 멤버 목록을 "오염"시킵니다. 우버 강력한 와일드 카드를 입력하십시오.
import logger.{println => _, _}
그리고 그것은 옳은 일을 할 것입니다 ™.
require
Predef
런타임에 검사 할 추가 함수 제약 조건을 정의 할 수 있는 메서드 (에서 정의 됨 ). 다른 트위터 클라이언트를 개발 중이고 트윗 길이를 최대 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
require
예약어가 아닙니다. 에 정의 된 메소드 일뿐입니다 Predef
.
와 형질 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.