Scalaの隠された機能


149

すべてのScala開発者が知っておくべきScalaの隠された機能は何ですか?

回答ごとに1つの非表示機能をお願いします。


6
えっと、この質問は、質問自体と同様に、他の隠された機能の投稿へのリンクにも役立ちます。乾杯!
JohnMetta 2009年

1
@mettadore は、右側の関連リンクをご覧ください。
ダニエルC.ソブラル2010

2
@JohnMetta:またはタグを使用します。

回答:


85

もう1つ追加する必要がありました。RegexScalaのすべてのオブジェクトには、マッチグループにアクセスできるエクストラクター(上記の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"

2行目は、パターンマッチングとエクストラクターを使用することに慣れていない場合、混乱を招きます。valまたはを定義するときはいつでもvar、キーワードの後に​​来るのは単なる識別子ではなくパターンです。これが機能する理由です。

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

右手の表現はTuple3[Int, Double, String]、パターンに一致することができるを作成します(a, b, c)

ほとんどの場合、パターンはシングルトンオブジェクトのメンバーであるエクストラクターを使用します。たとえば、次のようなパターンを記述した場合

Some(value)

次に、暗黙的に抽出を呼び出していますSome.unapply

しかし、パターンでクラスインスタンスを使用することもできます。それがここで行われていることです。ヴァル・正規表現は、のインスタンスでありRegex、そしてあなたは、パターンで使用するとき、あなたは暗黙的に呼び出しているregex.unapplySequnapplyunapplySeqにマッチグループ抽出し、この答えの範囲を超えている)Seq[String]に順番に割り当てられているの要素を変数年、月、日。


1
これを投稿していただきありがとうございます。参考までに、第1版の503ページ、第2版の611ページの「Scalaでのプログラミング」という本の「正規表現による抽出」の章で言及されています。
ポール

51

構造型定義-つまり、それがサポートするメソッドによって記述される型。例えば:

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

パラメータのタイプcloseableは、closeメソッドがあること以外は定義されていないことに注意してください


1
「Scalaでのプログラミング」では、構造型についても言及されていません。リフレクションを使用して適切なメソッドを呼び出すため、型を渡す他の手法よりも少し遅くなります。(うまくいけば、彼らはそれをスピードアップする方法を考え出すでしょう。)
ケン・ブルーム

1
また、それらにエイリアスを作成することもできます。これは、外部割り当てインターフェース(非常に遅いインターフェース)のように機能します:タイプCloseable = {def close():Unit}
Alexey

45

タイプコンストラクターのポリモーフィズム(別名、より上位のタイプ)

この機能がなければ、たとえば、関数をリストにマッピングして別のリストを返す、または関数をツリーにマッピングして別のツリーを返すというアイデアを表現できます。しかし、一般的に、より高い種類なしではこのアイデアを表現することはできません。

より高い種類では、別の型でパラメーター化された任意の型のアイデアを取り込むことができます。1つのパラメーターを受け取る型コンストラクターは、種類と呼ばれます(*->*)。たとえば、List。別の型コンストラクタを返す型コンストラクタは、種類と呼ばれます(*->*->*)。たとえば、Function1。しかし、Scalaではより高い種類があるため、他の型コンストラクターでパラメーター化された型コンストラクターを持つことができます。だから彼らはのような種類です((*->*)->*)

例えば:

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スタイルのコードをパターンに置き換えることができるエクストラクター。これらが完全に隠されているわけではないことは知っていますが、私は数か月間Scalaを使用してきましたが、それらの力を本当に理解していませんでした。(長い)例の場合、私は置き換えることができます:

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

私はバックグラウンドで少しレッグワークをしなければなりません...

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

これはスイッチのようではないですか?多分これはもっとリファクタリングできるでしょう。
ジオ

14
パターンはターボチャージャー付きスイッチのようなものです。はるかに強力で明確です
oxbow_lakes

1
いいですが、スコープがマッチ{}よりも遠くまで到達するため、暗黙的に使用する必要があるのは好ましくありません。コードでProductを検索するメソッドをProductServiceに追加することもできます。いずれにしても、リファクタリングされたスニペットをメソッドにラップして、どこでも使用できるようにします。
Martin Konicek 2010

35

Scalaが型を具体化したかのように、実行時に型情報を取得する一種の方法であるマニフェスト


8
リンクではなく、回答ので答えを説明する方がいいと思います。ちなみにこんにちは、牛頭!:-)
ダニエルC.ソブラル

これは本当に隠された機能です... APIドキュメントにもありません。とても便利です。
アンドレ・ラズロ

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クラスは自動的にProductトレイトをミックスインし、フィールドへの型なしのインデックス付きアクセスを反映せずに提供します。

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)

タイパーフェーズを使用して、それがいかに便利かを実際に感じます。


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

標準のブロックと同じように型チェックを行うオプションのelseを使用してif-then-elseブロックを定義する方法を知っている人がいるかどうか知りたいです。
フィリップ

@フィリップ:zif[A : Zero](cond: => Boolean)(t: => A): A = if(cond) t else mzero。Scalazが必要です。
missingfaktor

26

@switch Scala 2.8の注釈:

一致式に適用される注釈。存在する場合、コンパイラは一致がtableswitchまたはlookupswitchにコンパイルされていることを確認し、代わりに一連の条件式にコンパイルされるとエラーを発行します。

例:

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、2011年

4
私は時々、PartialFunctionをある程度使用するコードでこれを行います:タイプ〜> [A、B] = PartialFunction [A、B]
raichoo

24

Scala 2.8はデフォルトと名前付きの引数を導入しました。これにより、Scalaがケースクラスに追加する新しい「コピー」メソッドを追加できるようになりました。これを定義すると:

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

そして、既存のFooのように、 "n"の値だけが異なる新しいFooを作成したい場合は、次のように言うだけです。

foo.copy(n = 3)

3
警告:あるケースクラスを別のケースクラスから継承した場合、copyメソッドはオーバーライドされません。したがって、手動で上書きする必要があります
Alexey

関連:ネストされた構造を更新するためのより
明確

5
ケースクラスは(Scala 2.8)ケースクラスから継承できなくなりました。Scalaの領主、この不浄な継承を廃止してくれてありがとう。
olle kullberg

24

scala 2.8では、@ specializedをジェネリッククラス/メソッドに追加できます。これにより、プリミティブ型(AnyValを拡張)のクラスの特別なバージョンが作成され、不要なボックス化/ボックス化解除のコストが節約されます。 class Foo[@specialized T]...

AnyValsのサブセットを選択できます。 class Foo[@specialized(Int,Boolean) T]...


1
あなたが私に指摘できるもっと長い説明はありますか?もっと知りたいです。
パヴェルPrażak

23

言語を拡張する。私はいつもJavaでこのようなことをしたいと思っていました(できませんでした)。しかし、Scalaでは次のことが可能です。

  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"は、パラメーターを取らず、Barを返すxa関数を定義します。x:=>バーはxを名前による呼び出しとして定義します。詳細については、scala.sygneca.com / faqs /…をご覧ください
agilefall 2009年

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
この構成は「初期初期化」と呼ばれます。
Randall Schulz、

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

無名関数のプレースホルダー構文

Scala言語仕様から:

SimpleExpr1 ::= '_'

(構文カテゴリのExpr)式に_は、識別子が有効な場所にアンダースコア記号が埋め込まれている場合があります。このような式は無名関数を表し、アンダースコアの後続の出現は連続するパラメーターを示します。

Scala言語の変更から:

_ + 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
これは、「無名関数のプレースホルダー構文」と呼ばれます。暗黙的はScalaでは明確な意味があり、これとは関係ありません。
レトロネーム2010年

リンクには、回答との明白な関係はありません。「暗黙的」は、これの正しい用語ではありません。上記のように、それは「プレースホルダー」であるべきです。
Alain O'Dea 2010

2
それは本当に「隠されている」わけではありません。私が読んだScalaのほぼすべてのチュートリアルでこの使用法を見てきました... :-)しかし、まだ見たことがない正式な定義に感謝します。
PhiLho 2011年

@PhiLho多分それは2009年にはあまり知られていない。私は知らない。
Eugene Yokota

最終編集日しか表示されないため、元の日付を逃しました。そして、このスレッドで説明されているすべての機能が「非表示」になっているわけではありません。とにかくクールな糸といい答え。
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

これで、doubleを渡してその関数を呼び出すことができます。

sizeBoundedString(12345.12345D, 8)

最後の引数は暗黙的であり、暗黙的なde宣言により自動的に渡されます。さらに、 "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 = _

これにより、Beanの規則に一致するフィールドのゲッターとセッターが自動的に生成されます。

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)たと思います。
ダニエルC.ソブラル2010

4

Scalaに相当する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ステートメントからメンバーを除外する

あなたが使用したいと仮定Loggerが含まれているprintlnprinterr方法を、しかし、あなただけのエラーメッセージのいずれかを使用し、古き良きを維持したいPredef.println標準出力のために。あなたはこれを行うことができます:

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

しかし、loggerインポートして使用したい別の12のメソッドも含まれている場合、それらをリストするのは不便になります。代わりに以下を試すことができます:

import logger.{println => donotuseprintlnt, _}

しかし、これはインポートされたメンバーのリストを「汚染」します。強力なワイルドカードを入力します。

import logger.{println => _, _}

そしてそれはちょうど正しいことをします ™。


2

requirePredef実行時にチェックされる追加の関数制約を定義できるメソッド(で定義)。さらに別のTwitterクライアントを開発していて、ツイートの長さを最大140シンボルに制限する必要があるとします。さらに、空のツイートを投稿することはできません。

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

不適切な長さの引数でpostを呼び出すと、例外が発生します。

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)

もう1つの例はこちらです。


ボーナス

要件が失敗するたびにアクションを実行できます。

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メソッドを持つトレイトはScalaの機能であり、他の多くのトレイトほど広く宣伝されていません。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に過ぎませんが、事前定義されたインポート、カスタムバインディング、およびクラスパスを使用してScalaインタープリターインスタンスを構築するために、これらのStackableトレイトを多く使用しました。スタッカブル形質はの線に沿って私の工場を作成することが可能になりnew InterpreterFactory with JsonLibs with LuceneLibs、その後、便利な輸入と範囲を持つユーザースクリプトのvaribles。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.