स्काला की छिपी विशेषताएं


149

स्काला की ऐसी कौन सी छुपी हुई विशेषताएँ हैं जिनके बारे में प्रत्येक स्काला डेवलपर को पता होना चाहिए?

कृपया प्रति उत्तर एक छिपी हुई सुविधा।


6
हे, यह प्रश्न उतना ही उपयोगी है जितना कि अन्य छिपी हुई फीचर पोस्ट्स के लिंक के रूप में इस प्रश्न के लिए। चीयर्स!
जॉनमेटा 20

1
@mettadore बस दाईं ओर संबंधित लिंक को देखें।
डैनियल सी। सोबरल

2
@ जॉनमेटा: या टैग का उपयोग करें ।

जवाबों:


85

ठीक है, मुझे एक और जोड़ना था। Regexस्काला की प्रत्येक वस्तु में एक एक्सट्रैक्टर होता है (ऊपर दिए गए ऑक्सबॉक्स_लक्स से उत्तर देखें) जो आपको मैच समूहों तक पहुंच प्रदान करता है। तो आप कुछ ऐसा कर सकते हैं:

// 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]से तत्वों को क्रम में सौंपा गया है। चर वर्ष, माह और दिन।


1
यह पोस्ट करने के लिए Thx! FYI करें इसका उल्लेख अध्याय "नियमित अभिव्यक्ति के साथ निकालना" पुस्तक में "क्रम में प्रोग्रामिंग" पृष्ठ पर पहले संस्करण में 503 और दूसरे संस्करण में पृष्ठ 611 पर किया गया है।
पृथ्वी के पौल

51

संरचनात्मक प्रकार की परिभाषाएँ - अर्थात एक प्रकार जो यह वर्णित करता है कि यह किन विधियों का समर्थन करता है। उदाहरण के लिए:

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

ध्यान दें कि पैरामीटर का प्रकारcloseable एक closeविधि के अलावा अन्य परिभाषित नहीं है


1
"स्कैला में प्रोग्रामिंग" में संरचनात्मक प्रकारों का भी उल्लेख नहीं किया गया है। वे अन्य तकनीकों की तुलना में थोड़े धीमे हैं क्योंकि वे सही तरीकों को कॉल करने के लिए प्रतिबिंब का उपयोग करते हैं। (उम्मीद है कि वे इसे गति देने का एक तरीका लेकर आएंगे।)
केन ब्लूम

1
और उनके लिए उर्फ ​​बनाना भी संभव है, जो बाहरी रूप से असाइन किए गए इंटरफ़ेस (बहुत धीमी गति से) की तरह काम करता है: टाइप क्लोजेबल = {डिफ क्लोज (): यूनिट}
एलेक्सी

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


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

मुझे पृष्ठभूमि में थोड़ा सा काम करना होगा ...

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

यह एक स्विच की तरह नहीं है? शायद यह अधिक refactored जा सकता है।
जियो

14
पैटर्न टर्बो-चार्ज स्विच की तरह हैं: बहुत अधिक शक्तिशाली और स्पष्ट
ox__akes

1
अच्छा है, लेकिन मुझे यह पसंद नहीं है कि आपको निहित का उपयोग करना होगा क्योंकि इसका दायरा मैच {} से आगे तक पहुंचता है। आप केवल ProductService के लिए एक विधि जोड़ सकते हैं जो कोड द्वारा उत्पाद दिखता है। आप अपने रिफैक्टर्ड स्निपेट को एक विधि में लपेट लेंगे, वैसे भी हर जगह इसका उपयोग करने में सक्षम होने के लिए।
मार्टिन कोनिसक

35

मैनिफेस्ट जो कि रनटाइम पर टाइप जानकारी प्राप्त करने का एक प्रकार है, जैसे कि स्काला ने प्रकारों को संशोधित किया था।


8
मुझे लगता है कि किसी लिंक का संदर्भ देने के बजाय उत्तर में व्याख्या करना बेहतर होगा । वैसे, हाय अगाई बैल! :-)
डैनियल सी। सोबरल

यह वास्तव में छिपी हुई विशेषता है ... एपीआई डॉक्स में भी नहीं। हालांकि बहुत उपयोगी है।
एंड्रे लास्ज़्लो

35

स्कैला 2.8 में आप पैकेज scala.util.control.TailCalls (वास्तव में यह trampolining है) का उपयोग करके पूंछ-पुनरावर्ती तरीके हो सकते हैं।

एक उदाहरण:

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

यह बिल्कुल छिपा नहीं है, लेकिन निश्चित रूप से एक विज्ञापित विशेषता के तहत है: स्केलैक -एक्सप्रिंट

उपयोग के दृष्टांत के रूप में निम्नलिखित स्रोत पर विचार करें:

class A { "xx".r }

इसे स्केल-एक्सप्रिंट के साथ संकलित करना: टाइपर आउटपुट:

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पूर्वनिर्धारित का एक आवेदन है ।

scalac -Xprint: <चरण> कुछ संकलक चरण के बाद सिंटैक्स ट्री प्रिंट करेगा। उपलब्ध चरणों को देखने के लिए स्केल -Xshow- चरणों का उपयोग करें ।

यह सीखने का एक शानदार तरीका है कि पर्दे के पीछे क्या चल रहा है।

के साथ प्रयास करें

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/…
7

अगर किसी को वैकल्पिक तरीके से ब्लॉक करने का तरीका पता है, तो मैं उत्सुक होऊंगा कि मानक के समान टाइप-चेक करें या नहीं।
फिलिप

@Philippe: zif[A : Zero](cond: => Boolean)(t: => A): A = if(cond) t else mzero। स्कलाज़ की आवश्यकता है।
लापताफैक्टर

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

डनो अगर यह वास्तव में छिपा हुआ है, लेकिन मुझे यह काफी अच्छा लगता है।

टाइपकोस्ट्रक्टर्स जो 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, प्रकार के मापदंडों का क्रम स्वयं स्पष्ट होगा।
एस्को लुओंटोला

4
मैं कभी-कभी कोड में ऐसा करता हूं जो कुछ हद तक PartialFunction का उपयोग करता है: टाइप ~> [A, B] = PartialFunction [A, B]
17

24

स्काला 2.8 ने डिफ़ॉल्ट और नामित तर्कों को पेश किया, जिसने केसला कक्षाओं में एक नई "कॉपी" विधि को जोड़ना संभव बनाया। यदि आप इसे परिभाषित करते हैं:

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

और आप एक नया फू बनाना चाहते हैं जो मौजूदा फू की तरह है, केवल एक अलग "एन" मूल्य के साथ, तो आप बस कह सकते हैं:

foo.copy(n = 3)

3
चेतावनी: यदि आप एक केस क्लास को दूसरे से विरासत में लेते हैं तो कॉपी मेथड को ओवरराइड नहीं किया जाएगा। तो आपको इसे मैन्युअल रूप से ओवरराइड करना होगा
एलेक्सी

संबंधित: नेस्टेड संरचनाओं को अपडेट करने का क्लीनर तरीका stackoverflow.com/q/3900307/203968
oluies

5
केस क्लास अब नहीं है (स्काला 2.8) को केस क्लास से वारिस करने की अनुमति है। इस अपवित्र विरासत को अपदस्थ करने के लिए स्काला के स्वामी का धन्यवाद।
ओले कुल्बर्ग

24

scala 2.8 में आप अपने सामान्य वर्ग / विधियों में @ विशिष्टीकृत कर सकते हैं। यह आदिम प्रकार (AnyVal का विस्तार) के लिए वर्ग के विशेष संस्करण बनाएगा और गैर-आवश्यक बॉक्सिंग / बॉक्सिंग की लागत को बचाएगा: class Foo[@specialized T]...

आप AnyVals के सबसेट का चयन कर सकते हैं: class Foo[@specialized(Int,Boolean) T]...


1
क्या अब कोई स्पष्टीकरण है जो आप मुझे बता सकते हैं? मैं और सीखना चाहूंगा।
पवन प्रोक

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

आप एक कॉल-बाय-नाम पैरामीटर (EDITED: यह एक फ़ंक्शन के लिए एक आलसी पैरामीटर है!) अलग है और फ़ंक्शन द्वारा उपयोग किए जाने तक इसका मूल्यांकन नहीं किया जाएगा (EDIT: वास्तव में, यह हर बार इसे फिर से मूल्यांकन किया जाएगा। उपयोग किया गया)। विवरण के लिए यह देखें

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: => बार" का मतलब है कि x एक ऐसा कार्य है जो कोई पैरामीटर नहीं लेता है और एक बार वापस लौटता है। तो, "नया बार (22)" केवल एक अनाम फ़ंक्शन है, और किसी अन्य फ़ंक्शन की तरह फ़ंक्शन के रूप में मूल्यांकन किया जाता है।
एलेक्स ब्लैक

1
"x: () => बार" xa फ़ंक्शन को परिभाषित करता है जो कोई पैरामीटर नहीं लेता है और एक बार लौटाता है। x: => बार नाम से एक्स को परिभाषित करता है। अधिक जानकारी के लिए scala.sygneca.com/faqs/… पर एक नज़र डालें
agilefall

3
आप जो दिखाते हैं वह कॉल-बाय-नेम पैरामीटर है। आलसी मापदंडों को अभी तक लागू नहीं किया गया है: lampsvn.epfl.ch/trac/scala/ticket/240
ArtemGr

मुझे लगता है कि आप इसे एक आलसी परम के रूप में उपयोग कर सकते हैं यदि आप lazy val xx: Bar = xअपनी पद्धति में कुछ ऐसा करते हैं और उस क्षण से केवल आप ही उपयोग करते हैं xx
बजे क्रिस्टियन Vrabie

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 इस रूप में परिभाषित किया गया है:

@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

आप 'के साथ' कीवर्ड के साथ संरचनात्मक प्रकारों की रचना कर सकते हैं

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
इसे 'अनाम कार्यों के लिए प्लेसहोल्डर सिंटैक्स' के रूप में जाना जाना चाहिए। Scala में Implicit का एक अलग अर्थ है, और यह इस से संबंधित नहीं है।
रेट्रो

लिंक का उत्तर के लिए एक गैर-स्पष्ट संबंध है। "निहित" इसके लिए सही शब्द नहीं है। ऊपर के रूप में यह "प्लेसहोल्डर" होना चाहिए।
Alain O'Dea

2
यह वास्तव में "छिपा हुआ" नहीं है, मैंने स्कला पर लगभग सभी ट्यूटोरियल में यह उपयोग देखा है जो मैंने पढ़ा है ... :-) लेकिन मैं उस औपचारिक परिभाषा की सराहना करता हूं जिसे मैंने अभी तक नहीं देखा है।
फीलो

@PhiLho शायद यह 2009 में कम जाना जाता था। मुझे नहीं पता।
यूजीन योकोटा

मुझे मूल तिथि याद आ गई, क्योंकि केवल अंतिम संपादन तिथि दर्शाई गई है। और अच्छी तरह से, इस धागे में वर्णित सभी विशेषताएं "छिपी" नहीं हैं। वैसे भी कूल धागा और अच्छा जवाब।
फीलोहो

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
}

आप किसी भी स्ट्रिंग के साथ उपयोग कर सकते हैं, और, ज़ाहिर है, कुछ भी परिवर्तित करने के लिए स्ट्रीटिंग विधि का उपयोग करें। लेकिन आप इसे इस तरह भी लिख सकते हैं:

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)

अंतिम तर्क निहित है, और निहित डे घोषणा के कारण स्वचालित रूप से पारित किया जा रहा है। इसके अलावा, "एस" का आकार के अंदर स्ट्रिंग की तरह व्यवहार किया जा रहा हैबाउंडेडस्ट्रिंग क्योंकि इसमें स्ट्रिंग से एक अंतर्निहित रूपांतरण है।

अप्रत्याशित रूपांतरणों से बचने के लिए असामान्य प्रकारों के लिए इस प्रकार के इम्प्लाइक बेहतर परिभाषित हैं। आप एक रूपांतरण को भी आसानी से पास कर सकते हैं, और यह अभी भी आकार के अंदर उपयोग किया जाएगा।

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
}

यह बिल्कुल उसी तरह उपयोग किया जाता है।

Implicits का कोई भी मूल्य हो सकता है। उदाहरण के लिए, लाइब्रेरी जानकारी को छिपाने के लिए उनका उपयोग किया जा सकता है। उदाहरण के लिए, निम्नलिखित उदाहरण लें:

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

इस उदाहरण में, वाई ऑब्जेक्ट में "एफ" कॉल करने पर लॉग को डिफ़ॉल्ट डेमॉन में भेज दिया जाएगा, और एक्स के डेमन एक्स डेमन को इंस्टेंस पर। लेकिन एक्स के एक उदाहरण पर जी कॉल करने से लॉग को स्पष्ट रूप से दिए गए डिफाल्डमन में भेज दिया जाएगा।

हालांकि इस सरल उदाहरण को अधिभार और निजी राज्य के साथ फिर से लिखा जा सकता है, लेकिन इंपीटिस को निजी राज्य की आवश्यकता नहीं है, और आयात के संदर्भ में लाया जा सकता है।


13

शायद बहुत छिपा हुआ नहीं है, लेकिन मुझे लगता है कि यह उपयोगी है:

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

यह स्वचालित रूप से बीन सम्मेलन से मेल खाने वाले क्षेत्र के लिए एक गेट्टर और सेटर उत्पन्न करेगा।

पर इसके अलावा वर्णन डेवलपर


6
और आप इसके लिए शॉर्टकट बना सकते हैं यदि आप इसका बहुत अधिक उपयोग करते हैं, जैसे: आयात scala.reflect। {बीनप्रोपर्टी => बीपी}
एलेक्सी

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)
डैनियल सी। सोबरल

4

जावा डबल ब्रेस इनिशलाइज़र का स्काला का समकक्ष।

स्काला आपको उस वर्ग के उदाहरण को आरंभीकृत करने के लिए बयानों वाले वर्ग (कंस्ट्रक्टर) के साथ एक अनाम उपवर्ग बनाने की अनुमति देता है।

घटक-आधारित उपयोगकर्ता इंटरफ़ेस (उदाहरण के लिए स्विंग, वाडिन) का निर्माण करते समय यह पैटर्न बहुत उपयोगी है क्योंकि यह यूआई घटकों को बनाने और उनके गुणों को अधिक स्पष्ट रूप से घोषित करने की अनुमति देता है।

अधिक जानकारी के लिए http://spot.colorado.edu/~reids/papers/how-scala-experience-improved-our-java-development-reid-2011.pdf देखें ।

यहां वाडिन बटन बनाने का एक उदाहरण दिया गया है:

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

3

importबयानों से सदस्यों को छोड़कर

मान लें कि आप एक का उपयोग करना चाहते हैं Loggerजिसमें एक विधि printlnऔर एक printerrविधि है, लेकिन आप केवल त्रुटि संदेशों के लिए उपयोग करना चाहते हैं, और Predef.printlnमानक आउटपुट के लिए अच्छे पुराने को बनाए रखें । आप ऐसा कर सकते हैं:

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

लेकिन अगर आपके पास loggerएक और बारह विधियां हैं, जिन्हें आप आयात और उपयोग करना चाहते हैं, तो उन्हें सूचीबद्ध करना असुविधाजनक हो जाता है। आप इसके बजाय कोशिश कर सकते हैं:

import logger.{println => donotuseprintlnt, _}

लेकिन यह अभी भी आयातित सदस्यों की सूची को "प्रदूषित" करता है। Über-शक्तिशाली वाइल्डकार्ड दर्ज करें:

import logger.{println => _, _}

और वह सिर्फ सही काम करेगा ™।


2

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

1
requireएक आरक्षित शब्द नहीं है। यह एक विधि है, लेकिन इसमें परिभाषित है Predef
फरवरी को

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 लक्षण यह संभव की तर्ज पर मेरा कारखाना बनाने के लिए किया जाता new InterpreterFactory with JsonLibs with LuceneLibsहै और फिर उपयोगी आयात किया है और क्षेत्र के लिए उन लिपियों varibles।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.