Scala'nın her Scala geliştiricisinin bilmesi gereken gizli özellikleri nelerdir?
Cevap başına bir gizli özellik lütfen.
Scala'nın her Scala geliştiricisinin bilmesi gereken gizli özellikleri nelerdir?
Cevap başına bir gizli özellik lütfen.
Yanıtlar:
Tamam, bir tane daha eklemek zorunda kaldım. Regex
Scala'daki her nesnede, size maç gruplarına erişmenizi sağlayan bir çıkarıcı vardır (yukarıdaki oxbox_lakes'den gelen cevaba bakınız). Böylece şöyle bir şey yapabilirsiniz:
// 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"
İkinci satır, desen eşleştirme ve çıkarıcılar kullanmaya alışkın değilseniz kafa karıştırıcı görünür. Bir val
veya tanımladığınızda var
, anahtar kelimeden sonra gelenler yalnızca bir tanımlayıcı değil, bir kalıptır. Bu yüzden bu işe yarıyor:
val (a, b, c) = (1, 3.14159, "Hello, world")
Sağ el ifadesi Tuple3[Int, Double, String]
, kalıpla eşleşebilecek bir ifade oluşturur (a, b, c)
.
Çoğunlukla kalıplarınız tekil nesnelerin üyesi olan çıkarıcılar kullanır. Örneğin, şöyle bir desen yazarsanız
Some(value)
o zaman dolaylı olarak çıkarıcıyı çağırıyorsunuz Some.unapply
.
Ancak sınıf örneklerini kalıplarda da kullanabilirsiniz ve burada olan da budur. Val regex bir örneğidir Regex
ve bir desende bunu kullandığınızda, örtük aradığınız regex.unapplySeq
( unapply
versus unapplySeq
bir içine maç gruplarını ayıklar, bu yanıt kapsamı dışındadır) Seq[String]
, amacıyla tahsis edildiği unsurlarını yıl, ay ve gün değişkenleri.
Yapısal tip tanımları - yani hangi yöntemleri desteklediğini açıklayan tip. Örneğin:
object Closer {
def using(closeable: { def close(): Unit }, f: => Unit) {
try {
f
} finally { closeable.close }
}
}
Parametrenin türününcloseable
bir close
yöntemi dışında tanımlanmadığına dikkat edin
Bu özellik olmadan, örneğin, başka bir listeyi döndürmek için bir işlevi bir liste üzerinde eşleme veya başka bir ağacı döndürmek için bir işlevi ağaç üzerinde eşleştirme fikrini ifade edebilirsiniz. Ancak bu fikri genellikle daha yüksek türler olmadan ifade edemezsiniz .
Daha yüksek türlerle, başka bir türle parametrelenen herhangi bir tür fikrini yakalayabilirsiniz . Bir parametre alan bir tür yapıcısının türünün olduğu söylenir (*->*)
. Örneğin List
,. Başka bir tür yapıcı döndüren bir tür yapıcısının tür olduğu söylenir (*->*->*)
. Örneğin Function1
,. Ancak Scala'da daha yüksek çeşitlerimiz var, bu yüzden diğer tip kurucularla parametreleştirilmiş tip kurucularımız olabilir. Yani bunlar gibi ((*->*)->*)
.
Örneğin:
trait Functor[F[_]] {
def fmap[A, B](f: A => B, fa: F[A]): F[B]
}
Şimdi, a'nız varsa Functor[List]
listeler üzerinde harita oluşturabilirsiniz. Eğer varsa, Functor[Tree]
ağaçların üzerinden harita çizebilirsiniz. Ama daha da önemlisi, Functor[A]
herhangi bir A çeşidiniz(*->*)
varsa, bir işlevi eşleyebilirsiniz A
.
Dağınık if-elseif-else
stil kodunu desenlerle değiştirmenizi sağlayan aspiratörler . Bunların tam olarak gizli olmadığını biliyorum ama birkaç aydır Scala'yı gerçekten gücünü anlamadan kullanıyorum. (Uzun) bir örnek için ben değiştirebilirsiniz:
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)
}
Bu, bence çok daha net
implicit val ps: ProductService = ...
val p = code match {
case SyntheticCodes.Cash(c) => c
case SyntheticCodes.Forward(f) => f
case _ => ps.lookupProductByRic(code)
}
Arka planda biraz ayak işi yapmalıyım ...
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
}
}
Ancak, iş parçası, bir iş mantığını bir parçasını mantıklı bir yere ayırdığı için buna değer. Product.getCode
Yöntemlerimi aşağıdaki gibi uygulayabilirim .
class CashProduct {
def getCode = SyntheticCodes.Cash(this)
}
class ForwardProduct {
def getCode = SyntheticCodes.Forward(this)
}
Scala türleri birleştirmiş gibi, çalışma zamanında tür bilgilerini almanın bir yolu olan tezahürler .
Skala 2.8'de scala.util.control.TailCalls paketini kullanarak kuyruk özyinelemeli yöntemlere sahip olabilirsiniz (aslında trampolindir).
Bir örnek:
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)
Vaka sınıfları otomatik olarak Ürün özelliğini karıştırır ve alanlara yansıma olmadan türlenmemiş, dizine alınmış erişim sağlar:
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)
Bu özellik ayrıca toString
yöntemin çıktısını değiştirmek için basitleştirilmiş bir yol sağlar :
case class Person(name: String, age: Int) {
override def productPrefix = "person: "
}
// prints "person: (Aaron,28)" instead of "Person(Aaron, 28)"
println(Person("Aaron", 28))
Tam olarak gizli değil, ama kesinlikle reklamı altında bir özellik: scalac -Xprint .
Kullanımın bir örneği olarak aşağıdaki kaynağı göz önünde bulundurun:
class A { "xx".r }
Bunu scalac -Xprint: typer çıktılarıyla derleme :
package <empty> {
class A extends java.lang.Object with ScalaObject {
def this(): A = {
A.super.this();
()
};
scala.this.Predef.augmentString("xx").r
}
}
Uyarı scala.this.Predef.augmentString("xx").r
bir uygulamadır, implicit def augmentString
Predef.scala içinde mevcut.
scalac -Xprint: <faz> , bir derleyici aşamasından sonra sözdizimi ağacını yazdırır. Kullanılabilir aşamaları görmek için scalac -Xshow-aşamalarını kullanın .
Bu, perde arkasında neler olup bittiğini öğrenmenin harika bir yoludur.
İle deneyin
case class X(a:Int,b:String)
gerçekten ne kadar yararlı olduğunu hissetmek için typer aşamasını kullanmak .
Kendi kontrol yapılarınızı tanımlayabilirsiniz. Gerçekten sadece fonksiyonlar ve nesneler ve bazı sözdizimsel şeker, ama gerçek şey gibi görünüyorlar ve davranıyorlar.
Örneğin, aşağıdaki kod dont {...} unless (cond)
ve dont {...} until (cond)
şunları tanımlar :
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
}
}
Şimdi aşağıdakileri yapabilirsiniz:
/* 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
. Skaler gerektirir.
@switch
Scala 2.8'deki açıklama:
Eşleşme ifadesine uygulanacak bir ek açıklama. Varsa, derleyici eşleşmenin bir tablo anahtarına veya arama anahtarına derlendiğini doğrular ve bunun yerine bir dizi koşullu ifadeye derlenirse bir hata verir.
Misal:
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 {
Bu gerçekten gizli ise Dunno, ama oldukça güzel buluyorum.
2 tip parametre alan tip yapıcılar infix gösteriminde yazılabilir
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
, tür parametrelerinin sırasını açıkça gösterir.
Scala 2.8, Scala'nın vaka sınıflarına eklediği yeni bir "kopya" yönteminin eklenmesini mümkün kılan varsayılan ve adlandırılmış argümanları tanıttı. Bunu tanımlarsanız:
case class Foo(a: Int, b: Int, c: Int, ... z:Int)
ve sadece farklı bir "n" değerine sahip, mevcut bir Foo gibi yeni bir Foo oluşturmak istiyorsanız, şunu söyleyebilirsiniz:
foo.copy(n = 3)
scala 2.8'de genel sınıflarınıza / yöntemlerinize @specialized ekleyebilirsiniz. Bu, ilkel türler (AnyVal'ı genişleterek) için sınıfın özel sürümlerini oluşturur ve gereksiz boks / kutulama maliyetinden tasarruf eder:
class Foo[@specialized T]...
AnyVals'ın bir alt kümesini seçebilirsiniz:
class Foo[@specialized(Int,Boolean) T]...
Dili genişletme. Her zaman Java'da böyle bir şey yapmak istedim (yapamadım). Ama Scala'da sahip olabilirim:
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
}
ve sonra şunu yazın:
val numbers = List(12, 42, 3, 11, 6, 3, 77, 44)
val sorted = timed { // "timed" is a new "keyword"!
numbers.sortWith(_<_)
}
println(sorted)
ve Al
Executed in: 6.410311 millisec
List(3, 3, 6, 11, 12, 42, 44, 77)
Bir işleve bir Call-by-name parametresi (EDITED: bu sonra tembel bir parametreden farklıdır!) Atayabilirsiniz ve işlev tarafından kullanılana kadar değerlendirilmez (EDIT: aslında, her seferinde yeniden değerlendirilir. Kullanılmış). Ayrıntılar için bu SSS'ye bakın
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
ve o andan itibaren sadece kullanırsanız tembel bir param olarak kullanabileceğinizi düşünüyorum xx
.
locally
Noktalı virgül çıkarım sorunlarına neden olmadan yerel bir blok tanıtmak için kullanabilirsiniz .
Kullanımı:
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" da şöyle tanımlanır:
@inline def locally[T](x: T): T = x
Satır içi olduğundan, ek yük getirmez.
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)
Çıktı:
In AbstractT2:
AbstractT2: value = 10, inverse = 0.1
c2c.value = 10, inverse = 0.1
Anonimden
value
önce, bloktaki alanı başlatan anonim bir iç sınıf başlatırızwith AbstractT2
. Bu , komut dosyasını çalıştırdığınızda gösterildiği gibivalue
, gövdesininAbstractT2
yürütülmesinden önce başlatıldığını garanti eder .
'With' anahtar kelimesi ile yapısal türleri oluşturabilirsiniz
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
}
}
anonim işlevler için yer tutucu sözdizimi
Scala Dil Spesifikasyonundan:
SimpleExpr1 ::= '_'
Bir ifade (sözdizimsel kategoride
Expr
),_
tanımlayıcıların yasal olduğu yerlerde gömülü alt çizgi sembolleri içerebilir . Böyle bir ifade, sonraki alt çizgi oluşumlarının ardışık parametreleri ifade ettiği anonim bir işlevi temsil eder.
Gönderen Scala Dil Değişiklikler :
_ + 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)
Bunu kullanarak şöyle bir şey yapabilirsiniz:
def filesEnding(query: String) =
filesMatching(_.endsWith(query))
Örtük tanımlar, özellikle dönüşümler.
Örneğin, bir girdi dizesini ortasına "..." ile değiştirerek bir boyuta uyacak şekilde biçimlendirecek bir işlev olduğunu varsayalım:
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
}
Bunu herhangi bir String ile kullanabilir ve elbette, herhangi bir şeyi dönüştürmek için toString yöntemini kullanabilirsiniz. Ama bunu şöyle de yazabilirsiniz:
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
}
Ve sonra, bunu yaparak diğer türden sınıfları geçebilirsiniz:
implicit def double2String(d: Double) = d.toString
Şimdi bu işlevi bir çift geçerek çağırabilirsiniz:
sizeBoundedString(12345.12345D, 8)
Son argüman örtüktür ve örtülü bildirim nedeniyle otomatik olarak iletilir. Bundan başka, "s" olan tedavi ondan String bir kapalı dönüştürme çünkü sizeBoundedString içinde bir String gibi.
Beklenmeyen dönüşümlerden kaçınmak için nadir türler için bu tür etkiler daha iyi tanımlanır. Ayrıca bir dönüşümü açık bir şekilde iletebilirsiniz ve yine de sizeBoundedString içinde örtük olarak kullanılacaktır:
sizeBoundedString(1234567890L, 8)((l : Long) => l.toString)
Ayrıca birden çok örtük argümanınız da olabilir, ancak ya hepsini geçmeniz ya da hiçbirini geçmemeniz gerekir. Örtük dönüşümler için bir kısayol sözdizimi de vardır:
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
}
Bu tamamen aynı şekilde kullanılır.
Çıkarımların herhangi bir değeri olabilir. Örneğin kütüphane bilgilerini gizlemek için kullanılabilirler. Örneğin aşağıdaki örneği ele alalım:
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")
}
}
Bu örnekte, Y nesnesindeki "f" çağrısı, günlüğü varsayılan arka plan programına ve X örneğinde Daemon X arka plan programına gönderir. Ancak X'in bir örneğinde g çağrılması, günlüğü açıkça verilen DefaultDaemon'a gönderir.
Bu basit örnek aşırı yük ve özel durumla yeniden yazılabilirken, imalar özel durum gerektirmez ve ithalatla bağlama getirilebilir.
Belki çok gizli değil, ama bunun yararlı olduğunu düşünüyorum:
@scala.reflect.BeanProperty
var firstName:String = _
Bu otomatik olarak fasülye kuralına uyan alan için bir alıcı ve ayarlayıcı oluşturur.
Developerworks'te daha fazla açıklama
Kapaklarda örtük argümanlar.
İşlev bağımsız değişkeni, yöntemlerde olduğu gibi örtük olarak işaretlenebilir. İşlev gövdesi kapsamında, örtük parametre görünür ve örtük çözümlemeye uygundur:
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'nın Stream
s:
http://www.codecommit.com/blog/scala/infinite-lists-for-the-finitely-patient ile sonsuz veri yapıları oluşturun
Sonuç türleri örtük çözünürlüğe bağlıdır. Bu size birden fazla gönderim şekli verebilir:
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
kullanımları bir a
önceki Bu komutların yürütülmesi için ortamda mevcut olmalı. Demek istediğini sanıyorum z.perform(x)
.
Scala, sınıfın gövdesiyle (yapıcı) o sınıfın örneğini başlatmak için ifadeler içeren anonim bir alt sınıf oluşturmanıza olanak tanır.
Bu model, bileşen tabanlı kullanıcı arabirimleri (örneğin Swing, Vaadin) oluştururken, UI bileşenleri oluşturmasına ve özelliklerini daha kısa bir şekilde bildirmesine izin verdiği için çok kullanışlıdır.
Daha fazla bilgi için http://spot.colorado.edu/~reids/papers/how-scala-experience-improved-our-java-development-reid-2011.pdf adresine bakın .
Vaadin düğmesi oluşturma örneği:
val button = new Button("Click me"){
setWidth("20px")
setDescription("Click on this")
setIcon(new ThemeResource("icons/ok.png"))
}
import
ifadelerden hariç tutmaLogger
A println
ve printerr
yöntem içeren bir kullanmak istediğinizi , ancak yalnızca hata iletileri için kullanmak istediğinizi ve Predef.println
standart çıktı için eskiyi saklamak istediğinizi varsayalım . Bunu yapabilirsin:
val logger = new Logger(...)
import logger.printerr
ancak logger
içe aktarmak ve kullanmak istediğiniz başka bir oniki yöntem daha içeriyorsa bunları listelemek zorlaşır. Bunun yerine deneyebilirsiniz:
import logger.{println => donotuseprintlnt, _}
ancak bu hâlâ ithal edilen üyelerin listesini "kirletiyor". Über-güçlü joker karaktere girin:
import logger.{println => _, _}
ve bu doğru olanı yapacak ™.
require
Predef
çalışma zamanı sırasında denetlenecek ek işlev kısıtlamaları tanımlamanızı sağlayan yöntem (içinde tanımlanmış ). Başka bir twitter istemcisi geliştirdiğinizi ve tweet uzunluğunu 140 simgeye kadar sınırlamanız gerektiğini düşünün. Üstelik boş tweet gönderemezsiniz.
def post(tweet: String) = {
require(tweet.length < 140 && tweet.length > 0)
println(tweet)
}
Şimdi uygunsuz uzunluk argümanıyla gönderi çağırmak bir istisnaya neden olacaktır:
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)
Birden çok gereksinim yazabilir veya hatta her birine açıklama ekleyebilirsiniz:
def post(tweet: String) = {
require(tweet.length > 0, "too short message")
require(tweet.length < 140, "too long message")
println(tweet)
}
Şimdi istisnalar ayrıntılı:
scala> post("")
java.lang.IllegalArgumentException: requirement failed: too short message
at scala.Predef$.require(Predef.scala:157)
at .post(<console>:8)
Bir örnek daha burada .
Gereksinim her başarısız olduğunda bir eylem gerçekleştirebilirsiniz:
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
ayrılmış bir sözcük değil. Bu, içinde tanımlanan bir yöntemdir Predef
.
İle Özellikleri abstract override
yöntemleri gibi yaygın diğerleri olarak bildirilmez Scala'da bir özelliğidir. Değiştirici ile yöntemlerin abstract override
amacı bazı işlemler yapmak ve çağrıyı devretmektir super
. Daha sonra bu özellikler, abstract override
yöntemlerinin somut uygulamaları ile karıştırılmalıdır .
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
Örneğim gerçekten fakir bir adamın AOP'sinden çok daha fazla olmasa da, bu İstiflenebilir Özellikleri çok önceden tanımlanmış ithalatlar, özel bağlamalar ve sınıfyolları ile Scala yorumlayıcı örnekleri oluşturma isteğimle kullandım. İstif Özellikleri mümkün çizgisinde benim fabrika yaratmak için yapılmış new InterpreterFactory with JsonLibs with LuceneLibs
ve daha sonra kullanışlı ithalatı var ve kapsam kullanıcıları komut dosyaları için varibles.