आत्म-प्रकार और विशेषता उपवर्गों में क्या अंतर है?


387

एक लक्षण के लिए एक स्व-प्रकार A:

trait B
trait A { this: B => }

कहते हैं कि " Aएक ठोस वर्ग में नहीं मिला जा सकता है जो विस्तार नहीं करता है B"

दूसरी ओर, निम्नलिखित:

trait B
trait A extends B

का कहना है कि "कोई भी (ठोस या सार) वर्ग मिश्रण में Aभी बी में मिश्रण होगा"

क्या इन दोनों कथनों का मतलब एक ही नहीं है? स्व-प्रकार एक सरल संकलन-समय त्रुटि की संभावना बनाने के लिए केवल सेवा करने के लिए लगता है।

मैं क्या खो रहा हूँ?


मैं वास्तव में यहाँ स्व प्रकार और लक्षण में उपवर्ग के बीच अंतर में दिलचस्पी रखता हूँ। मुझे पता है कि स्व-प्रकार के कुछ सामान्य उपयोग हैं; मैं सिर्फ एक कारण नहीं खोज सकता कि वे सबटाइपिंग के साथ अधिक स्पष्ट रूप से उसी तरह क्यों नहीं करेंगे।
डेव

32
एक स्वयं-प्रकार के भीतर प्रकार के मापदंडों का उपयोग कर सकता है: trait A[Self] {this: Self => }कानूनी है, trait A[Self] extends Selfनहीं है।
ब्लिसोरब्लेड

3
एक स्व प्रकार भी एक वर्ग हो सकता है, लेकिन एक गुण एक वर्ग से विरासत में नहीं मिल सकता है।
cvogt

10
@cvogt: एक गुण एक वर्ग से विरासत में मिल सकता है (कम से कम 2.10 के रूप में): pastebin.com/zShvr8LX
Erik Kaplun

1
@ ब्लेज़रब्लेड: क्या वह चीज़ नहीं है जिसे एक छोटी सी भाषा फिर से डिज़ाइन करके हल किया जा सकता है, हालांकि, और एक मौलिक सीमा नहीं है? (प्रश्न के दृष्टिकोण से कम से कम)
एरिक कपलुन

जवाबों:


273

यह मुख्य रूप से डिपेंडेंसी इंजेक्शन के लिए उपयोग किया जाता है , जैसे कि केक पैटर्न में। केक पैटर्न सहित स्केला में निर्भरता इंजेक्शन के कई अलग-अलग रूपों को कवर करने वाला एक शानदार लेख मौजूद है । यदि आप Google "केक पैटर्न और स्काला" बनाते हैं, तो आपको प्रस्तुतियों और वीडियो सहित कई लिंक मिलेंगे। अभी के लिए, यहां एक और प्रश्न का लिंक दिया गया है ।

अब, जैसा कि एक स्व प्रकार के बीच अंतर क्या है और एक विशेषता का विस्तार, यह सरल है। यदि आप कहते हैं B extends A, तो B है एक A। जब आप स्व-प्रकार का उपयोग करते हैं, तो एक की B आवश्यकता होती है A। दो विशिष्ट आवश्यकताएं हैं जो आत्म-प्रकार के साथ बनाई गई हैं:

  1. यदि Bबढ़ाया गया है, तो आपको मिक्स-इन करना आवश्यक है A
  2. जब एक ठोस वर्ग अंत में इन लक्षणों में विस्तार / मिश्रण करता है, तो कुछ वर्ग / विशेषता को लागू करना चाहिए A

निम्नलिखित उदाहरणों पर विचार करें:

scala> trait User { def name: String }
defined trait User

scala> trait Tweeter {
     |   user: User =>
     |   def tweet(msg: String) = println(s"$name: $msg")
     | }
defined trait Tweeter

scala> trait Wrong extends Tweeter {
     |   def noCanDo = name
     | }
<console>:9: error: illegal inheritance;
 self-type Wrong does not conform to Tweeter's selftype Tweeter with User
       trait Wrong extends Tweeter {
                           ^
<console>:10: error: not found: value name
         def noCanDo = name
                       ^

यदि Tweeterएक उपवर्ग था User, तो कोई त्रुटि नहीं होगी। उपरोक्त कोड में, हम आवश्यक एक Userजब भी Tweeterप्रयोग किया जाता है, फिर भी एक Userके लिए प्रदान नहीं किया गया Wrongहै, तो हम एक त्रुटि मिली। अब, ऊपर दिए गए कोड के दायरे में अभी भी, विचार करें:

scala> trait DummyUser extends User {
     |   override def name: String = "foo"
     | }
defined trait DummyUser

scala> trait Right extends Tweeter with User {
     |   val canDo = name
     | }
defined trait Right 

scala> trait RightAgain extends Tweeter with DummyUser {
     |   val canDo = name
     | }
defined trait RightAgain

के साथ Right, मिक्स-इन की आवश्यकता Userसंतुष्ट है। हालांकि, ऊपर उल्लिखित दूसरी आवश्यकता संतुष्ट नहीं है: कार्यान्वयन का बोझ Userअभी भी उन वर्गों / लक्षणों के लिए बना हुआ है जो विस्तार करते हैं Right

साथ RightAgainदोनों शर्तों को पूरा किया जाता है। ए Userऔर कार्यान्वयन Userप्रदान किए जाते हैं।

अधिक व्यावहारिक उपयोग के मामलों के लिए, कृपया इस उत्तर की शुरुआत में लिंक देखें! लेकिन, उम्मीद है कि अब आपको यह मिल जाएगा।


3
धन्यवाद। केक पैटर्न का 90% मतलब है कि मैं आत्म-प्रकारों के बारे में प्रचार के बारे में क्यों बात करता हूं ... यह वह जगह है जहां मैंने पहली बार विषय को देखा था। जोनास बोनर का उदाहरण बहुत अच्छा है क्योंकि यह मेरे प्रश्न के बिंदु को रेखांकित करता है। यदि आपने अपने हीटर उदाहरण में उप-प्रकार होने के लिए स्व-प्रकार को बदल दिया तो क्या अंतर होगा (घटक त्रुटि को परिभाषित करते समय आपको मिली त्रुटि के अलावा) यदि आप सही सामान में मिश्रण नहीं करते हैं?
डेव

29
@ क्या: आप की तरह मतलब है trait WarmerComponentImpl extends SensorDeviceComponent with OnOffDeviceComponent? यही कारण WarmerComponentImplहै कि उन इंटरफेस होगा। वे विस्तारित होने वाली किसी भी चीज के लिए उपलब्ध होंगे WarmerComponentImpl, जो स्पष्ट रूप से गलत है, क्योंकि यह ए नहीं है SensorDeviceComponent, न ही ए OnOffDeviceComponent। एक स्व प्रकार के रूप में, ये निर्भरताएँ विशेष रूप से उपलब्ध हैं WarmerComponentImpl। A Listका उपयोग a Arrayऔर इसके विपरीत के रूप में किया जा सकता है । लेकिन वे सिर्फ एक ही बात नहीं कर रहे हैं।
डैनियल सी। सोबरल

10
धन्यवाद डैनियल। यह शायद वह मुख्य अंतर है जिसकी मुझे तलाश थी। व्यावहारिक समस्या यह है कि उपवर्ग का उपयोग करने से आपके इंटरफ़ेस में कार्यक्षमता का रिसाव होगा जिसका आप इरादा नहीं करते हैं। इसके और अधिक सैद्धांतिक के उल्लंघन का एक परिणाम है "लक्षण के लिए एक नियम" का एक हिस्सा है। स्व-प्रकार भागों के बीच एक "उपयोग-एक" संबंध व्यक्त करते हैं।
डेव

11
@ रोडनी नहीं, यह नहीं होना चाहिए। वास्तव में, thisस्वयं के प्रकारों का उपयोग करना कुछ ऐसा है जिस पर मैं नीचे देखता हूं, क्योंकि यह मूल कारण के लिए छाया नहीं है this
डैनियल सी। सोबरल

9
@opensas कोशिश करो self: Dep1 with Dep2 =>
डैनियल सी। सोबरल

156

स्वयं प्रकार आपको चक्रीय निर्भरता को परिभाषित करने की अनुमति देता है। उदाहरण के लिए, आप इसे प्राप्त कर सकते हैं:

trait A { self: B => }
trait B { self: A => }

का उपयोग कर वंशानुक्रम की extendsअनुमति नहीं है। प्रयत्न:

trait A extends B
trait B extends A
error:  illegal cyclic reference involving trait A

ओडस्की पुस्तक में, खंड 33.5 (स्प्रेडशीट यूआई अध्याय बनाते हुए) देखें जहां इसका उल्लेख है:

स्प्रेडशीट उदाहरण में, क्लास मॉडल इवैल्यूएटर से विरासत में मिला है और इस प्रकार अपनी मूल्यांकन पद्धति तक पहुंच प्राप्त करता है। दूसरे तरीके से जाने के लिए, क्लास इवैल्यूएटर अपने सेल्फ टाइप को मॉडल के रूप में परिभाषित करता है, जैसे:

package org.stairwaybook.scells
trait Evaluator { this: Model => ...

उम्मीद है की यह मदद करेगा।


3
मैंने इस परिदृश्य पर विचार नहीं किया था। इसका कुछ उदाहरण जो मैंने देखा है कि यह एक आत्म-प्रकार के समान नहीं है जैसा कि यह उपवर्ग के साथ है। हालांकि, यह एक प्रकार का किनारा-मामला है और, अधिक महत्वपूर्ण है, यह एक बुरे विचार की तरह लगता है (मैं आमतौर पर चक्रीय निर्भरता को परिभाषित करने के लिए मेरे रास्ते से बहुत दूर जाता हूं!)। क्या आप इसे सबसे महत्वपूर्ण भेद मानते हैं?
डेव

4
मुझे ऐसा लगता है। मुझे कोई अन्य कारण नहीं दिखाई देता है कि मैं क्लॉज़ को बढ़ाने के लिए आत्म-प्रकार क्यों पसंद करूंगा। स्व-प्रकार क्रिया हैं, वे विरासत में नहीं मिलते हैं (इसलिए आपको अनुष्ठान के रूप में सभी उपप्रकारों में आत्म-प्रकार जोड़ना होगा और आप केवल सदस्य देख सकते हैं लेकिन उन्हें ओवरराइड नहीं कर सकते। मैं केक पैटर्न और डीआई के लिए आत्म-प्रकारों का उल्लेख करने वाले कई पदों से अच्छी तरह से परिचित हूं। लेकिन किसी तरह मैं आश्वस्त नहीं हूं। मैंने बहुत पहले यहाँ एक नमूना ऐप बनाया था ( bitbucket.org/mushtaq/scala-di )। विशेष रूप से / src / configs फ़ोल्डर को देखें। मैंने आत्म-प्रकारों के बिना जटिल स्प्रिंग कॉन्फ़िगरेशन को बदलने के लिए DI हासिल किया।
मुश्ताक अहमद

मुश्ताक, हम समझौते में हैं। मुझे लगता है कि अनजाने की कार्यक्षमता को उजागर नहीं करने के बारे में डैनियल का कथन एक महत्वपूर्ण है लेकिन, जैसा कि आप इसे कहते हैं, इस 'सुविधा' का एक दर्पण दृश्य है ... कि आप कार्यक्षमता को ओवरराइड नहीं कर सकते हैं या भविष्य के उपवर्गों में इसका उपयोग नहीं कर सकते हैं। यह बहुत स्पष्ट रूप से मुझे बताता है कि जब डिजाइन एक से दूसरे के लिए कॉल करेगा। मैं तब तक आत्म-प्रकारों से बचता रहूँगा जब तक मुझे एक वास्तविक आवश्यकता नहीं मिल जाती - अर्थात यदि मैं डैनियल के मॉड्यूल के रूप में वस्तुओं का उपयोग करना शुरू कर दूं। मैं निहित मापदंडों और एक सीधे बूटस्ट्रैपपर ऑब्जेक्ट के साथ निर्भरता को स्वत: प्राप्त कर रहा हूं। मुझे सादगी पसंद है।
डेव

@ डैनियल सी। सोबर आपकी टिप्पणी के लिए धन्यवाद हो सकता है, लेकिन इस समय इसमें आपके ऐक्सरसाइज की तुलना में अधिक बदलाव है। अपवोटिंग दोनों :)
rintcius

सिर्फ एक लक्षण एबी क्यों नहीं बनाया? जैसा कि लक्षण ए और बी को हमेशा किसी भी अंतिम वर्ग में जोड़ा जाना चाहिए, उन्हें पहले स्थान पर अलग क्यों करें?
अमीर ओलिवर

56

एक अतिरिक्त अंतर यह है कि स्व-प्रकार गैर-वर्ग प्रकार निर्दिष्ट कर सकते हैं। उदाहरण के लिए

trait Foo{
   this: { def close:Unit} => 
   ...
}

यहाँ स्व प्रकार एक संरचनात्मक प्रकार है। प्रभाव यह है कि कोई भी चीज़ जो फू में घुलमिल जाती है, उसे नो-अर्ग "क्लोज़" विधि रिटर्निंग यूनिट को लागू करना चाहिए। यह बतख-टाइपिंग के लिए सुरक्षित मिश्रण की अनुमति देता है।


41
वास्तव में आप संरचनात्मक प्रकारों के साथ वंशानुक्रम का भी उपयोग कर सकते हैं: अमूर्त वर्ग A का विस्तार {def close: Unit}
Adrian

12
मुझे लगता है कि संरचनात्मक टाइपिंग प्रतिबिंब का उपयोग कर रही है, इसलिए केवल तभी उपयोग करें जब कोई अन्य विकल्प न हो ...
एरन मेडन

@ एड्रियन, मेरा मानना ​​है कि आपकी टिप्पणी गलत है। `अमूर्त वर्ग ए का विस्तार {डिफ क्लोज़: यूनिट}` ऑब्जेक्ट सुपरक्लास के साथ सिर्फ एक सार वर्ग है। निरर्थक भावों के लिए यह केवल एक स्काला का अनुमेय वाक्यविन्यास है। आप कर सकते हैं `दसवीं कक्षा फैली {डी एफ = 1}; उदाहरण के लिए new X ()। f`
एलेक्सी

1
@Alexey मैं नहीं देखता कि आपका उदाहरण (या मेरा) निरर्थक क्यों है।
एड्रियन

1
@ एड्रियन, abstract class A extends {def close:Unit}के बराबर है abstract class A {def close:Unit}। इसलिए इसमें संरचनात्मक प्रकार शामिल नहीं हैं।
एलेक्सी

13

मार्टिन ओडस्की के मूल स्काला पेपर स्केलेबल कंपोनेंट ऐब्स्ट्रक्शन की धारा 2.3 "सेल्फपेप्ट एनोटेशन" वास्तव में मिक्सिन कंपोजिशन से परे सेल्फाइट के उद्देश्य को बहुत अच्छी तरह से समझाती है: एक वर्ग को एक अमूर्त प्रकार के साथ जोड़ने का एक वैकल्पिक तरीका प्रदान करती है।

कागज में दिया गया उदाहरण निम्नलिखित था, और यह एक सुंदर उप-संवाददाता नहीं लगता है:

abstract class Graph {
  type Node <: BaseNode;
  class BaseNode {
    self: Node =>
    def connectWith(n: Node): Edge =
      new Edge(self, n);
  }
  class Edge(from: Node, to: Node) {
    def source() = from;
    def target() = to;
  }
}

class LabeledGraph extends Graph {
  class Node(label: String) extends BaseNode {
    def getLabel: String = label;
    def self: Node = this;
  }
}

उन लोगों के लिए जो सबक्लासिंग का समाधान नहीं करेंगे, यह सोचकर धारा 2.3 यह भी कहती है: “C_n के साथ… मिश्रित मिश्रण रचना C_0 के प्रत्येक संचालक को एक कक्षा का संदर्भ देना चाहिए। मिश्रित संरचना तंत्र किसी भी C_i को एक अमूर्त प्रकार को संदर्भित करने की अनुमति नहीं देता है। यह प्रतिबंध अस्पष्टता के लिए वैधानिक रूप से जांच करना और उस बिंदु पर विरोधाभासों को दूर करना संभव बनाता है जहां एक वर्ग की रचना की जाती है। "
ल्यूक मौरर

12

एक और बात जिसका उल्लेख नहीं किया गया है: क्योंकि स्व-प्रकार आवश्यक वर्ग के पदानुक्रम का हिस्सा नहीं है, उन्हें पैटर्न मिलान से बाहर रखा जा सकता है, खासकर जब आप एक सील पदानुक्रम के खिलाफ पूरी तरह से मेल खाते हैं। जब आप ऑर्थोगोनल व्यवहार को मॉडल करना चाहते हैं तो यह सुविधाजनक है:

sealed trait Person
trait Student extends Person
trait Teacher extends Person
trait Adult { this : Person => } // orthogonal to its condition

val p : Person = new Student {}
p match {
  case s : Student => println("a student")
  case t : Teacher => println("a teacher")
} // that's it we're exhaustive

10

TL, DR अन्य उत्तरों का सारांश:

  • आपके द्वारा विस्तारित किए गए प्रकार विरासत में दिए गए प्रकारों के संपर्क में हैं, लेकिन स्व-प्रकार नहीं हैं

    उदाहरण: class Cow { this: FourStomachs }आपको केवल उपलब्ध रमनियों के तरीकों का उपयोग करने की अनुमति देता है, जैसे कि digestGrass। गाय का विस्तार करने वाले लक्षणों में हालांकि ऐसा कोई विशेषाधिकार नहीं होगा। दूसरी ओर, जो कोई भी class Cow extends FourStomachsउजागर करेगा ।digestGrassextends Cow

  • स्व-प्रकार चक्रीय निर्भरता की अनुमति देते हैं, अन्य प्रकार का विस्तार नहीं करते हैं


9

चलो चक्रीय निर्भरता के साथ शुरू करते हैं।

trait A {
  selfA: B =>
  def fa: Int }

trait B {
  selfB: A =>
  def fb: String }

हालाँकि, इस समाधान की मापकता उतनी महान नहीं है जितनी पहली बार दिखाई दे सकती है, क्योंकि आप स्वयं प्रकार को ओवरराइड कर सकते हैं:

trait A1 extends A {
  selfA1: B =>
  override def fb = "B's String" }
trait B1 extends B {
  selfB1: A =>
  override def fa = "A's String" }
val myObj = new A1 with B1

यद्यपि, यदि आप किसी स्व-प्रकार के सदस्य को ओवरराइड करते हैं, तो आप मूल सदस्य तक पहुँच खो देते हैं, जो अभी भी वंशानुक्रम का उपयोग करके सुपर के माध्यम से पहुँचा जा सकता है। तो विरासत के उपयोग से वास्तव में क्या हासिल होता है:

trait AB {
  def fa: String
  def fb: String }
trait A1 extends AB
{ override def fa = "A's String" }        
trait B1 extends AB
{ override def fb = "B's String" }    
val myObj = new A1 with B1

अब मैं केक पैटर्न की सभी बारीकियों को समझने का दावा नहीं कर सकता, लेकिन यह मुझे चौंकाता है कि प्रतिरूपता को लागू करने का मुख्य तरीका विरासत या आत्म प्रकारों के बजाय रचना के माध्यम से है।

वंशानुक्रम संस्करण छोटा है, लेकिन मुख्य कारण जो मुझे स्व प्रकारों पर विरासत पसंद है, वह यह है कि मुझे प्रारंभिक प्रकार को आत्म प्रकारों के साथ सही करने के लिए अधिक मुश्किल लगता है। हालाँकि, कुछ चीजें हैं जो आप स्वयं प्रकार के साथ कर सकते हैं जो आप विरासत के साथ नहीं कर सकते हैं। स्व प्रकार एक प्रकार का उपयोग कर सकते हैं जबकि विरासत के लिए एक विशेषता या एक वर्ग की आवश्यकता होती है:

trait Outer
{ type T1 }     
trait S1
{ selfS1: Outer#T1 => } //Not possible with inheritance.

आप भी कर सकते हैं:

trait TypeBuster
{ this: Int with String => }

हालाँकि आप इसे कभी भी इंस्टाल नहीं कर पाएंगे। मुझे किसी भी प्रकार से विरासत में नहीं मिलने का कोई पूर्ण कारण दिखाई नहीं देता है, लेकिन मुझे निश्चित रूप से लगता है कि पथ निर्माता वर्ग और लक्षण होना उपयोगी होगा क्योंकि हमारे पास टाइप निर्माता / वर्ग हैं। दुर्भाग्य से

trait InnerA extends Outer#Inner //Doesn't compile

हमारे पास यह है:

trait Outer
{ trait Inner }
trait OuterA extends Outer
{ trait InnerA extends Inner }
trait OuterB extends Outer
{ trait InnerB extends Inner }
trait OuterFinal extends OuterA with OuterB
{ val myV = new InnerA with InnerB }

या यह:

  trait Outer
  { trait Inner }     
  trait InnerA
  {this: Outer#Inner =>}
  trait InnerB
  {this: Outer#Inner =>}
  trait OuterFinal extends Outer
  { val myVal = new InnerA with InnerB with Inner }

एक बिंदु जिसे सहानुभूति अधिक होनी चाहिए वह यह है कि लक्षण कक्षाओं का विस्तार कर सकते हैं। इस ओर इशारा करने के लिए डेविड मैकलेवर को धन्यवाद। यहाँ मेरे अपने कोड से एक उदाहरण है:

class ScnBase extends Frame
abstract class ScnVista[GT <: GeomBase[_ <: TypesD]](geomRI: GT) extends ScnBase with DescripHolder[GT] )
{ val geomR = geomRI }    
trait EditScn[GT <: GeomBase[_ <: ScenTypes]] extends ScnVista[GT]
trait ScnVistaCyl[GT <: GeomBase[_ <: ScenTypes]] extends ScnVista[GT]

ScnBaseस्विंग फ्रेम वर्ग से विरासत में मिला है , इसलिए इसे एक स्व प्रकार के रूप में इस्तेमाल किया जा सकता है और फिर अंत में (तात्कालिकता पर) मिलाया जा सकता है। हालाँकि, val geomRइनहेरिट करने वाले लक्षणों का उपयोग करने से पहले इसे आरंभ करने की आवश्यकता है। इसलिए हमें पहले के प्रारंभिककरण को लागू करने के लिए एक वर्ग की आवश्यकता है geomR। तब वर्ग ScnVistaको कई ऑर्थोगोनल लक्षणों से विरासत में लिया जा सकता है जो खुद से विरासत में मिले हैं। कई प्रकार के मापदंडों (जेनेरिक) का उपयोग करना, मॉड्यूलरिटी का एक वैकल्पिक रूप प्रदान करता है।


7
trait A { def x = 1 }
trait B extends A { override def x = super.x * 5 }
trait C1 extends B { override def x = 2 }
trait C2 extends A { this: B => override def x = 2}

// 1.
println((new C1 with B).x) // 2
println((new C2 with B).x) // 10

// 2.
trait X {
  type SomeA <: A
  trait Inner1 { this: SomeA => } // compiles ok
  trait Inner2 extends SomeA {} // doesn't compile
}

4

एक स्व प्रकार आपको यह निर्दिष्ट करने देता है कि किसी विशेषता को मिलाने के लिए किस प्रकार की अनुमति है। उदाहरण के लिए, यदि आपके पास स्वयं प्रकार के साथ एक विशेषता है Closeable, तो उस विशेषता को पता है कि केवल चीजों को इसमें मिश्रण करने की अनुमति है, उन्हें Closeableइंटरफ़ेस को लागू करना होगा ।


3
@ ब्लेज़रब्लेड: मुझे आश्चर्य है कि क्या आपने किकबोबो के जवाब को गलत माना हो सकता है - एक विशेषता का आत्म प्रकार वास्तव में आपको उन प्रकारों को कसने की अनुमति देता है जो इसे मिश्रण कर सकते हैं, और यह इसकी उपयोगिता का हिस्सा है। उदाहरण के लिए, यदि हम परिभाषित करते हैं trait A { self:B => ... }तो एक घोषणा X with Aकेवल मान्य होती है यदि एक्स बी का विस्तार करता है। हां, आप कह सकते हैं X with A with Q, जहां क्यू बी का विस्तार नहीं करता है, लेकिन मेरा मानना ​​है कि किकिबो की बात यह थी कि एक्स बहुत विवश है। या किसी को याद किया था?
अमीगोइको

1
धन्यवाद, आप सही कह रहे हैं। मेरा वोट लॉक हो गया था, लेकिन सौभाग्य से मैं जवाब को संपादित कर सकता था और फिर अपना वोट बदल सकता था।
ब्लिसॉर्बलेड

1

अपडेट: एक प्रमुख अंतर यह है कि स्व-प्रकार कई वर्गों पर निर्भर कर सकते हैं (मैं मानता हूं कि यह थोड़ा कोने वाला मामला है)। उदाहरण के लिए, आपके पास हो सकता है

class Person {
  //...
  def name: String = "...";
}

class Expense {
  def cost: Int = 123;
}

trait Employee {
  this: Person with Expense =>
  // ...

  def roomNo: Int;

  def officeLabel: String = name + "/" + roomNo;
}

यह Employeeमिक्सचिन को केवल उसी चीज़ में जोड़ने की अनुमति देता है जो उप-वर्ग है Personऔर Expense। निश्चित रूप से, यह केवल तभी सार्थक है जब इसका Expenseविस्तार Personया इसके विपरीत हो। मुद्दा यह है कि स्व-प्रकारों का Employeeउपयोग करना उन वर्गों के पदानुक्रम से स्वतंत्र हो सकता है जो इस पर निर्भर करते हैं। यह इस बात की परवाह नहीं करता है कि क्या विस्तार होता है - यदि आप Expenseबनाम की पदानुक्रम को बदलते हैं Person, तो आपको संशोधित करने की आवश्यकता नहीं है Employee


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

@MorganCreighton मेला काफी, मुझे नहीं पता था कि लक्षण कक्षाओं का विस्तार कर सकते हैं। मैं इसके बारे में सोचूंगा अगर मुझे एक बेहतर उदाहरण मिल सके।
पेट्र पुडलक

हां, यह एक आश्चर्यजनक भाषा सुविधा है। यदि कर्मचारी कर्मचारी वर्ग व्यक्ति का विस्तार करता है, तो अंत में जो भी वर्ग "कर्मचारी" होता है, उसे भी व्यक्ति का विस्तार करना होगा। लेकिन वह प्रतिबन्ध अभी भी मौजूद है अगर कर्मचारी ने व्यक्ति को निकालने के बजाय एक स्व प्रकार का उपयोग किया। चीयर्स, पेट्र!
मॉर्गन क्रेयटन

1
मैं यह नहीं देखता कि "यह केवल तभी सार्थक है जब व्यय व्यक्ति या इसके विपरीत बढ़ाता है।"
रॉबिन ग्रीन

0

पहले मामले में, बी के एक उप-लक्षण या उप-वर्ग को मिलाया जा सकता है, जो कि ए। बी का उपयोग करता है।


नहीं, बी दोनों मामलों में एक "अमूर्त विशेषता" हो सकती है (और वास्तव में) है। इसलिए उस दृष्टिकोण से कोई अंतर नहीं है।
रॉबिन ग्रीन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.