2013-04-07 6 views
6

यदि मैं यह मान वर्ग है:इन मामलों में, स्कैला मूल्य वर्ग "बॉक्सिंग" होगा, है ना?

class ActionId(val value: Int) extends AnyVal 

फिर, नीचे दिए सभी उदाहरणों में, एक वस्तु मूल्य वर्ग के लिए आवंटित किया जाएगा?

  1. एक समारोह है कि एक मूल्य वर्ग रिटर्न - (सही यह नहीं बस एक सादे 32 बिट पूर्णांक पर unwrapped किया जाएगा, यह "बॉक्सिंग" जाएगा?) - मूल्य वर्ग गुंजाइश बच निकलता है और होगा इसलिए "बॉक्सिंग" हो?

    def someFunction(): ActionId = { 
        ... 
        return ActionId(123) 
    } 
    
  2. एक समारोह है कि एक मूल्य वर्ग के सदस्य साथ देता है एक वस्तु - मूल्य वर्ग गुंजाइश निकल जाता है और इस कारण "बॉक्सिंग" किया जाएगा?

    case class Post(id: ActionId, ...) { ... } 
    
    def someFunction(): Post = { 
        ... 
        val somePost = Post(ActionId(123), ...) // ActionId will be "boxed", right? 
        return somePost 
    } 
    
  3. भी अगर एक मूल्य वर्ग के सदस्य के साथ वस्तु नहीं लौटे (वास्तव में गुंजाइश से बच नहीं करता है), मूल्य वर्ग अभी भी "बॉक्सिंग" हो जाएगा, जब यह एक के रूप में इस्तेमाल किया जाता है इस उदाहरण में Post कक्षा में किसी अन्य वर्ग के सदस्य (एक क्षेत्र के रूप में)?

    def anotherFunction() { 
        ... 
        val somePost = Post(ActionId(123), ...) // "Boxed" here too, right? 
    
        // ... do something with somePost 
    
        // But don't: return somePost 
    
        // However some *other* similar functions *do* return `somePost` — so 
        // class `Post` must be able to box the ActionId? Hence it's boxed (above)? 
    } 
    

इस से संबंधित है this answer है, जो कहता है कि जब मूल्य वर्ग गुंजाइश बच नहीं करता है, यह प्रभावी रूप से inlined जा रहा है। यह अधिक जानकारी के लिए स्केल इम्प्रूवमेंट प्रोसेस दस्तावेज़ SIP-15 को संदर्भित करता है। हालांकि जहां तक ​​मैं एसआईपी -15 को बता सकता हूं वास्तव में यह उल्लेख नहीं करता है कि दायरे से बचने वाले एक मूल्य वर्ग के उदाहरण को "बॉक्सिंग" किया जाएगा। लेकिन मुझे लगता है कि यह उचित लगता है कि इसे "बॉक्सिंग" होना होगा। (एसआईपी स्पष्ट रूप से क्यों नहीं बताती है कि अगर यह भाग जाए तो इसे बॉक्स किया जाएगा?)

उत्तर

10

अपने उदाहरण से कोई भी मुक्केबाजी में परिणाम है: यदि यह बॉक्स हैं आप इस तरह कुछ देखना होगा। मूल्य वर्ग केवल जेनिक्स के साथ, सरणी के साथ बॉक्स किए जाते हैं, और जब सुपरक्लास/विशेषता (उदाहरण के लिए कोई भी/AnyVal)

वे जेनेरिक के साथ बॉक्स किए गए हैं क्योंकि अन्यथा आप उन्हें मूल्य से अलग नहीं कर सकते हैं (और प्राइमेटिव्स आवश्यकता वैसे भी एक बॉक्स)। किसी के साथ वही सौदा, और अन्य सुपरक्लास/लक्षणों को एक बॉक्स की आवश्यकता होती है या प्रकार का रिश्ता गलत है।

वे सरणी के साथ बॉक्स किए गए हैं क्योंकि सरणी को सामग्री के प्रकार को जानने की आवश्यकता है, लेकिन JVM "मान प्रकार" की अवधारणा को समझ में नहीं आता है। तो आप एक सरणी के साथ समाप्त हो गए थे, जिसमें कहा गया था कि यह बॉक्सिंग किया जा रहा था, लेकिन जो स्कैला नाटक कर रहा था वह मूल्य प्रकार की सरणी थी; एक निर्णय किया गया था (ऐरे के साथ पिछले मुद्दों के आधार पर जब यह सिर्फ एक सादा जावा/जेवीएम सरणी नहीं था) जिससे इससे बहुत सूक्ष्म बग और कोने के मामले सामने आएंगे।

तीन तरीके का एक उदाहरण प्राप्त करने के लिए है मुक्केबाजी:

trait Q extends Any {} 
class X(val x: String) extends AnyVal with Q {} 

// Array 
val a = Array(new X("salmon")) // boxed 

// Generic 
val b = Option(new X("minnow")) // boxed 

// Upcast 
val c = (new X("perch"): Any) // boxed 
val d = (new X("cod"): AnyVal) // boxed 
val e = (new X("herring"): Q) // boxed 

बाकी सब कुछ - विभिन्न कार्यों के माध्यम से चारों ओर से गुजर रहा है, आदि .-- मुक्केबाजी की आवश्यकता नहीं है, अपने उदाहरण के सभी शामिल हैं। कुछ निहित के साथ

class Y(val repr: String) extends AnyVal {} 
val y1 = new Y("apple") // unboxed 
val y2 = new Y("orange") // unboxed 
val ys: Array[String] = Array(y1.repr, y2.repr) // no overhead 
val y3 = new Y(ys(0))  // no overhead 
+0

क्या आप सरणी से निपटने के दौरान सिंटैक्टिक ओवरहेड को कम करने के लिए लाइब्रेरी समर्थन की कल्पना कर सकते हैं? – ziggystar

+0

@ziggystar - ठीक है, अभी सिंटैक्टिक ओवरहेड को कम करने वाली हर चीज बाइटकोड ओवरहेड को बढ़ाती है। तो यह खेलना एक मुश्किल खेल है। जब यह मायने रखता है, तो आपके पास एक वैल्यू क्लास हो सकती है जो सरणी को लपेटती है और आपके लिए काम करती है (बहुत कम सिंटैक्टिक ओवरहेड के साथ), लेकिन मुझे एक छोटी सी फैक्ट्री बनाने का कोई तरीका नहीं है जो एक मूल्य वर्ग को संबंधित सरणी उत्पन्न करता है मूल्य वर्ग अंततः मैक्रोज़ वहां पहुंच जाएगा, मुझे लगता है। –

+0

@RexKerr तो क्या इसका मतलब यह है कि डेटा संरचनाओं के अंदर कोई मूल्य वर्ग नहीं है? दूसरे शब्दों में, सूची, मानचित्र, आदि हमेशा बॉक्स किए गए वर्ग को तुरंत चालू करेंगे? –

12

सभी तीन मामलों में कोई मुक्केबाजी नहीं होगी।

यह अपने स्वयं के द्वारा जांच करने के लिए काफी आसान है:

class ActionId(val value: Int) extends AnyVal 
object Foo { 
    def someFunction(): ActionId = { 
    new ActionId(123) 
    } 
} 

अब चलाने scalac की सुविधा देता है, और हम वर्ग फ़ाइलों (बाईटकोड साथ फ़ाइलें) का एक समूह होगा। जिसकी हमें आवश्यकता है वह Foo \ $ है।

» javap Foo\$ 
Compiled from "Boxing.scala" 
public final class Foo$ extends java.lang.Object{ 
    public static final Foo$ MODULE$; 
    public static {}; 
    public int someFunction(); 
} 

जैसा कि आप देख सकते हैं, भले ही मूल्य वर्ग कार्य से लीक हो, आमतौर पर इसे बॉक्स नहीं किया जाएगा।

case class Post(id: ActionId, notion: String) 

object Foo2 { 
    def someFunction(): Post = { 
    Post(new ActionId(123), "So ActionID will be boxed?") 
    } 
} 

scalac => javap:

» javap Post 
Compiled from "Boxing.scala" 
public class Post extends java.lang.Object implements scala.Product,scala.Serializable{ 
    public static scala.Function1 tupled(); 
    public static scala.Function1 curried(); 
    public int id(); 
    public java.lang.String notion(); 
    public Post copy(int, java.lang.String); 
    public int copy$default$1(); 
    public java.lang.String copy$default$2(); 
    public java.lang.String productPrefix(); 
    public int productArity(); 
    public java.lang.Object productElement(int); 
    public scala.collection.Iterator productIterator(); 
    public boolean canEqual(java.lang.Object); 
    public int hashCode(); 
    public java.lang.String toString(); 
    public boolean equals(java.lang.Object); 
    public Post(int, java.lang.String); 
} 

आप देख सकते हैं आईडी यहां सादा पूर्णांक (जैसे तीसरी विधि) के रूप में प्रतिनिधित्व।

आखिरकार, वर्ग वर्ग के मूल्य का मूल्य होगा यदि मूल्य वर्ग सदस्य के साथ वस्तु वापस नहीं आती है (वास्तव में दायरे से बच नहीं है)?

Code: 
    Stack=4, Locals=2, Args_size=1 
    0: new #15; //class Post 
    3: dup 
    4: bipush 123 
    6: ldC#17; //String Will be boxed? 
    8: invokespecial #20; //Method Post."<init>":(ILjava/lang/String;)V 
    11: astore_1 
    12: return 
    LocalVariableTable: 
    Start Length Slot Name Signature 
    0  13  0 this  LFoo3$; 
    12  0  1 post  LPost; 

वहाँ ActionId में पूर्णांक का कोई मुक्केबाजी है:

case class Post(id: ActionId, notion: String) 

object Foo3 { 
    def anotherFunction(): Unit { 
    val post = Post(new ActionId(123), "Will be boxed?") 
    } 
} 

अगर हम विधि के बाईटकोड को बारीकी से देखें, यहाँ हम क्या देखेंगे।

Code: 
    Stack=5, Locals=2, Args_size=1 
    0: new #15; //class Post 
    3: dup 
    4: new #17; //class ActionId 
    7: dup 
    8: bipush 123 
    10: invokespecial #20; //Method ActionId."<init>":(I)V 
    13: ldC#22; //String Will be boxed? 
    15: invokespecial #25; //Method Post."<init>":(LActionId;Ljava/lang/String;)V 
    18: astore_1 
    19: return 
    LocalVariableTable: 
    Start Length Slot Name Signature 
    0  20  0 this  LFoo3$; 
    19  0  1 post  LPost; 

तुम देखो, अंतर bipush 123 बनाम

4: new #17; //class ActionId 
    7: dup 
    8: bipush 123 
    10: invokespecial #20; //Method ActionId."<init>":(I)V 
+0

आपको एक उदाहरण है जब एक मूल्य वर्ग बॉक्स जाएगा दे सकते हैं? – ziggystar

+0

@ziggystar यह बॉक्स किया जाएगा यदि कोई मूल्य वर्ग को संग्रह में रखेगा, उदा। सूची –

2

डाले: क्योंकि आप पुरातन स्टोर और शून्य बाईटकोड भूमि के ऊपर के साथ मूल्य वर्ग के रूप में फिर से उन्हें बाहर खींच सकते हैं, लेकिन वाक्यात्मक भूमि के ऊपर का एक बहुत

सरणी एक विशेष मामले का एक सा कर रहे हैं रेक्स-केर द्वारा आवश्यक वाक्यविन्यास के बिना सरणी-मुद्दे के आसपास वास्तव में संभव है। मैं संयोजन के रूप में इसका इस्तेमाल किया How to reduce the number of objects created in Scala?

Y.scala साथ:

import scala.language.implicitConversions 

class Y(val repr: String) extends AnyVal {} 
object Y { 
    implicit def stringToY (v:String) = new Y(v) 
    implicit def yToString (v:Y) = v.repr 
} 

मुख्य फ़ाइल:

import Y._ 

val y1 = new Y("apple") // unboxed 
val y2 = new Y("orange") // unboxed 
val ys: Array[String] = Array(y1, y2) // Implicit cast 
val y3:Y = ys(0) 
संबंधित मुद्दे