निजी [यह] बनाम निजी


112

स्काला में मुझे ऑब्जेक्ट-प्राइवेट वैरिएबल जैसी सुविधा दिखाई देती है। मेरी बहुत समृद्ध जावा पृष्ठभूमि से मैंने आवश्यक होने पर सब कुछ बंद करना (इसे निजी बनाना) और खुला (एक्सेसर्स प्रदान करना) सीखा। स्काला और भी अधिक सख्त पहुंच संशोधक का परिचय देता है। क्या मुझे इसे हमेशा डिफ़ॉल्ट रूप से उपयोग करना चाहिए? या क्या मुझे इसे केवल कुछ विशिष्ट मामलों में उपयोग करना चाहिए, जहां मुझे एक ही वर्ग की वस्तुओं के लिए भी फ़ील्ड के बदलते मूल्य को स्पष्ट रूप से प्रतिबंधित करने की आवश्यकता है? दूसरे शब्दों में मुझे कैसे चुनना चाहिए

class Dummy {
    private var name = "default name"
}

class Dummy {
    private[this] var name = "default name"
}

दूसरा अधिक सख्त है और मुझे यह पसंद है लेकिन क्या मुझे हमेशा इसका उपयोग करना चाहिए या केवल अगर मेरे पास एक मजबूत कारण है?

EDITED: जैसा कि मैं देख रहा हूं कि यहां private[this] कुछ सबकेस है और इसके बजाय thisमैं अन्य मॉडिफायर का उपयोग कर सकता हूं: "पैकेज, क्लास या सिंगलटन ऑब्जेक्ट"। तो मैं इसे कुछ विशेष मामले के लिए छोड़ दूँगा।


जवाबों:


59

मुझे नहीं लगता कि यह बहुत ज्यादा मायने रखता है, क्योंकि कोई भी बदलाव केवल एक वर्ग को छूएगा। तो पसंद करते हैं करने के लिए सबसे महत्वपूर्ण कारण privateअधिक protectedसे अधिक publicलागू नहीं होता।

का प्रयोग करें private[this]जहां प्रदर्शन वास्तव में मायने रखती है (क्योंकि आप सीधे क्षेत्र का उपयोग करने के बजाय तरीकों में से इस तरह मिल जाएगा)। अन्यथा, बस एक शैली पर समझौता करें ताकि लोगों को यह पता लगाने की आवश्यकता न हो कि यह संपत्ति क्यों है privateऔर यह एक है private[this]


6
@ om-nom-nom दरअसल, बताने के लिए बहुत कुछ नहीं है। जेआईटी को privateवैसे भी उत्पन्न एक्सेसर कॉल को इनलाइन करना चाहिए , इसलिए प्रभाव शून्य या कम से कम बहुत छोटा होना चाहिए।
एलेक्सी रोमानोव

9
यह उत्तर भ्रामक है, वास्तविक कारण घोषणा-स्थल का विचरण है (इस उत्तर को देखें: stackoverflow.com/a/9727849/445715 )।
एंड्री ब्रेस्लेव

1
@AndreyBreslav मैं सहमत नहीं है कि यह कारण। हां, ऐसा मामला मौजूद है, लेकिन जैसा कि उत्तर कहता है कि यह काफी दुर्लभ है।
एलेक्सी रोमानोव

3
हम्म। नीचे मर्क एडमेक का उत्तर निजी [यह] निजी चुनने का वास्तविक कारण लगता है। आशय एक विशिष्ट उदाहरण तक पहुंच को सीमित करना है, जैसा कि वर्ग के सभी उदाहरणों के विपरीत है।
राम राजमोनी

3
@AlexeyRomanov - सवाल पूछता है "क्या मुझे हमेशा डिफ़ॉल्ट रूप से इसका उपयोग करना चाहिए?"। मुझे लगता है कि आप यह कहकर अपने उत्तर में सुधार कर सकते हैं कि निजी [यह] का उपयोग नहीं किया जा सकता है यदि आपको उसी वर्ग के किसी अन्य उदाहरण से फ़ील्ड की आवश्यकता है।
राम राजमोनी 19

130

एक मामला है जहां private[this]कोड संकलन करने के लिए आवश्यक है। यह विचरण संकेतन और उत्परिवर्तनीय चरों के परस्पर क्रिया के साथ करना है। निम्नलिखित (बेकार) वर्ग पर विचार करें:

class Holder[+T] (initialValue: Option[T]) {
    // without [this] it will not compile
    private[this] var value = initialValue

    def getValue = value
    def makeEmpty { value = None }
}

इसलिए इस वर्ग को एक वैकल्पिक मूल्य रखने के लिए डिज़ाइन किया गया है, इसे एक विकल्प के रूप में लौटाएं और उपयोगकर्ता को makeEmptyमान को साफ़ करने के लिए कॉल करने में सक्षम करें (इसलिए संस्करण)। जैसा कि कहा गया है, यह बिंदु को प्रदर्शित करने के अलावा बेकार है।

यदि आप privateइसके बजाय इस कोड को संकलित करने का प्रयास करते हैं, तो private[this]यह निम्न त्रुटि संदेश के साथ विफल हो जाएगा:

त्रुटि: covariant टाइप T, कॉन्ट्रैक्टिव टाइप स्थिति [T] के मान value_ = वर्ग धारक [+ T] (आरंभिक: विकल्प [T]) {

यह त्रुटि इसलिए होती है क्योंकि मूल्य सहसंयोजक प्रकार T (+ T) पर एक परिवर्तनशील परिवर्तनशील है जो आम तौर पर एक समस्या है जब तक कि उदाहरण के लिए निजी के रूप में चिह्नित नहीं किया जाता है private[this]। संकलक के पास इस विशेष मामले को संभालने के लिए इसके विचरण जाँच में विशेष हैंडलिंग है।

तो यह गूढ़ है लेकिन एक ऐसा मामला है जहां private[this]पर आवश्यकता है private


1
मैं देख सकता हूं कि जब मिश्रण में परिवर्तनशीलता होती है तो यह विफल क्यों हो जाता है, लेकिन जब कुछ भी परिवर्तनशील नहीं होता है तो मुझे वही त्रुटि क्यों मिलती है ?
मैट कांटोर '

34

private var nameclass Dummy(और उसके साथी object Dummy) की किसी भी विधि से सुलभ है ।

private[this] var namethisकेवल वस्तु के तरीकों से ही सुलभ है , अन्य वस्तुओं से नहीं class Dummy


18

निजी [यह] (संरक्षित के बराबर [यह]) का अर्थ है कि "वाई" केवल उसी उदाहरण के तरीकों से दिखाई देता है। उदाहरण के लिए, आप y को दूसरे उदाहरण पर एक समान विधि में संदर्भित नहीं कर सकते, अर्थात, "this.y == that.y" "that.y" पर एक संकलन त्रुटि उत्पन्न करेगा। (स्रोत)

इसलिए आप हर बार निजी [यह] कर सकते हैं लेकिन यदि आपको इसे संदर्भित करने की आवश्यकता है तो आपको कुछ समस्या हो सकती है


13
private[this]के बराबर नहीं है protected[this]protected[this]सदस्य तक पहुँचने के लिए उपवर्ग उदाहरण देता है।
drexin

आप this.y == that.yन तो निजी और न ही निजी [यह] का उपयोग कर सकते हैं , मैंने दोनों की कोशिश की
लिसाक

12

यह स्कैला 2.11.5 का उपयोग करके परीक्षण किया गया था। नीचे दिए गए कोड पर विचार करें

class C(private val x: Int) {
  override def equals(obj: Any) = obj match {
    case other: C => x == other.x
    case _ => false
  }
}

println(new C(5) == new C(5)) //true
println(new C(5) == new C(4)) //false

यह इस जावा (1.8) कोड के रूप में संकलित और काम करेगा

class C {
    private int x;

    public C(int x) {
        this.x = x;
    }

    public boolean equals(Object obj) {
        if (obj instanceof C) {
            return ((C) obj).x == x;
        }
        else {
            return false;
        }
    }
}

System.out.println(new C(5).equals(new C(5))); //true
System.out.println(new C(5).equals(new C(4))); //false

हालाँकि यदि आप '[यह]' संशोधक का उपयोग करते हैं तो नीचे दिया गया कोड संकलित नहीं होगा

class C(private[this] val x: Int) {
  override def equals(obj: Any) = obj match {
    case other: C => this.x == other.x //problem is here
    case _ => false
  }
}

ऐसा इसलिए है क्योंकि पहले मामले में 'x' वर्ग स्तर पर सुलभ है, जबकि दूसरे मामले में यह अधिक सख्त उदाहरण स्तर है। इसका अर्थ है कि 'x' को केवल उसी उदाहरण से एक्सेस किया जा सकता है, जिसके पास यह है। तो 'this.x' ठीक है लेकिन 'other.x' नहीं है।

आप "एक्सेसरीज़ में प्रोग्रामिंग: एक व्यापक चरण-दर-चरण मार्गदर्शिका" पुस्तक की धारा 13.5 का उल्लेख कर सकते हैं, जो एक्सेस एम्पलीफायरों के बारे में अधिक जानकारी के लिए है।


1
सवाल यह नहीं पूछ रहा है कि क्या private[this]मतलब है। पहले वाक्य पर ध्यान दें।
एलेक्सी रोमानोव

9

निजी संशोधक ( निजी [एक्स] ) में गुंजाइश जोड़ते समय , यह प्रभावी रूप से "अप" एक्स के रूप में व्यवहार करता है, जहां एक्स कुछ संलग्न पैकेज, वर्ग या सिंगलटन ऑब्जेक्ट को नामित करता है।

उदाहरण के लिए, निजी [बार] , जहां बार एक पैकेज है इसका मतलब है कि पैकेज बार से संबंधित हर वर्ग का प्रत्येक उदाहरण जो भी सदस्य को प्रतिबंधित कर रहा है, तक पहुंच सकता है।

निजी [यह] के मामले में , इसका मतलब है कि सदस्य केवल प्रत्येक उदाहरण के लिए सुलभ है। यह निम्नलिखित उदाहरण में अधिक स्पष्ट हो जाता है:

class Foo(foo:Foo){  
   private[this] val i = 2
   println(this.i + foo.i)
}

>>error: value i is not a member of Foo

class Foo(foo:Foo){  
    private val i = 2
    println(this.i + foo.i)
}

>>defined class Foo

जैसा कि आप देख सकते हैं, दूसरी फू को कोई समस्या नहीं है क्योंकि कोई भी उदाहरण निजी वैल i तक पहुंच सकता है। हालाँकि, पहली Foo के लिए एक त्रुटि है क्योंकि प्रत्येक उदाहरण अन्य उदाहरण i को नहीं देख सकता है।

निजी [यह] लिखने के लिए एक अच्छा अभ्यास है क्योंकि यह एक बड़ा प्रतिबंध लगाता है।


6

जावा जैसे अधिकांश ओओपी प्रोग्रामिंग भाषा में, निजी क्षेत्रों / विधियों का मतलब है कि ये निजी क्षेत्र / विधियां कक्षा से बाहर नहीं पहुंच सकते हैं। हालाँकि, एक ही कक्षा के उदाहरण / ऑब्जेक्ट्स में असाइनमेंट ऑपरेटर का उपयोग करके या कॉपी कंस्ट्रक्टर के माध्यम से वस्तुओं के निजी क्षेत्रों तक पहुंच हो सकती है। स्काला में, निजी [यह] ऑब्जेक्ट निजी है, जो यह सुनिश्चित करता है कि एक ही वर्ग का कोई अन्य ऑब्जेक्ट निजी [यह] सदस्यों तक पहुंचने में असमर्थ है।

उदाहरण

1. निजी के साथ [यह]

object ObjectPrivateDemo {

  def main(args: Array[String]) {
    var real = new User("realUserName", "realPassword")
    var guest = new User("dummyUserName", "dummyPassword")
    real.displayUser(guest)

  }
}

class User(val username:String,val password:String) {
  private var _username=username
  private var _password=password



  def displayUser(guest:User){

         println(" guest username="+guest._username+" guest password="+guest._password)
       guest._username= this._username
    guest._password=  this._password
       println(" guest username="+guest._username+" guest password="+guest._password)


  }
}

2. निजी का उपयोग कर [यह]

class User(val username: String, val password: String) {
  private var _username = username
  private[this] var _password = password



  def displayUser(guest: User) {

    println(this._username)
    println(this._password)

    guest._username = this._username
    // for guest._password it will give this :error  value _password is not member of class User
    guest._password = this._password

  }
}

इसलिए निजी [यह] सुनिश्चित करता है कि _password फ़ील्ड केवल इसके साथ उपलब्ध है।


यह अब तक का सबसे स्पष्ट और अधिक वस्तुनिष्ठ उत्तर है।
लुकास लीमा

2

एलेक्सी रोमानोव ने प्रदर्शन के मुद्दे पर विस्तार से बताया, यहां मेरे कुछ अनुमान हैं। पुस्तक "कोस्टा में प्रोग्रामिंग: एक व्यापक चरण-दर-चरण मार्गदर्शिका, द्वितीय संस्करण" से धारा 18.2:

स्काला में, प्रत्येक संस्करण जो किसी वस्तु का गैर-निजी सदस्य है, स्पष्ट रूप से इसके साथ एक गेटर और एक सेटर विधि को परिभाषित करता है।

इसका परीक्षण करने के लिए, यह कोड संकलन त्रुटि का कारण बनेगा:

class PrivateTest{
  var data: Int = 0
  def data_=(x : Int){
    require(x > 0)
    data = x
  }
}

स्काला शिकायत करता है error: ambiguous reference to overloaded definition। ओवरराइड कीवर्ड जोड़ने से data_=यह साबित नहीं होना चाहिए कि कंपाइलर द्वारा विधि उत्पन्न की गई है। privateकीवर्ड को चर में जोड़ना dataअभी भी इस संकलन त्रुटि का कारण होगा। हालाँकि, निम्न कोड ठीक संकलित करता है:

class PrivateTest{
  private[this] var data: Int = 0
  def data_=(x : Int){
    require(x > 0)
    data = x
  }
}

इसलिए, मुझे लगता है कि private[this]स्केला को गटर और सेटर के तरीकों को उत्पन्न करने से रोका जाएगा। इस प्रकार, ऐसे वैरिएबल तक पहुंचने से गेट्टर और सेटर विधि को कॉल करने के ओवरहेड को बचाया जाएगा।


1

क्या मुझे इसे हमेशा डिफ़ॉल्ट रूप से उपयोग करना चाहिए? या क्या मुझे इसे केवल कुछ विशिष्ट मामलों में उपयोग करना चाहिए, जहां मुझे एक ही वर्ग की वस्तुओं के लिए भी फ़ील्ड के बदलते मूल्य को स्पष्ट रूप से प्रतिबंधित करने की आवश्यकता है? दूसरे शब्दों में मुझे कैसे चुनना चाहिए

private[this]यदि आप चर को सिंक्रनाइज़ करने की योजना बनाते हैं तो इसका उपयोग करना बेहतर है ।

यहाँ स्पार्क टीम के स्काला स्टाइल गाइड का एक अच्छा उदाहरण है :

// The following is still unsafe.
class Foo {
  private var count: Int = 0
  def inc(): Unit = synchronized { count += 1 }
}

// The following is safe.
class Foo {
  private[this] var count: Int = 0
  def inc(): Unit = synchronized { count += 1 }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.