निम्नलिखित कोटलिन वर्ग को देखते हुए:
data class Test(val value: Int)
मैं Intगेटर को ओवरराइड कैसे करूंगा ताकि मान नकारात्मक होने पर यह 0 लौटे?
यदि यह संभव नहीं है, तो उपयुक्त परिणाम प्राप्त करने के लिए कुछ तकनीकें क्या हैं?
निम्नलिखित कोटलिन वर्ग को देखते हुए:
data class Test(val value: Int)
मैं Intगेटर को ओवरराइड कैसे करूंगा ताकि मान नकारात्मक होने पर यह 0 लौटे?
यदि यह संभव नहीं है, तो उपयुक्त परिणाम प्राप्त करने के लिए कुछ तकनीकें क्या हैं?
जवाबों:
कोटलिन के लेखन का लगभग एक पूरा साल दैनिक खर्च करने के बाद मैंने पाया है कि इस तरह से डेटा कक्षाओं को ओवरराइड करने का प्रयास एक बुरा अभ्यास है। इसके लिए 3 मान्य दृष्टिकोण हैं, और जब मैं उन्हें प्रस्तुत करता हूं, तो मैं समझाता हूं कि अन्य उत्तरों ने जो दृष्टिकोण सुझाया है वह खराब क्यों है।
अपने व्यावसायिक तर्क रखें जो data classनिर्माता को खराब मान के साथ कॉल करने से पहले 0 या उससे अधिक होने के लिए परिवर्तन को बनाता है । यह संभवतः अधिकांश मामलों के लिए सबसे अच्छा तरीका है।
एक का उपयोग न करें data class। एक नियमित का उपयोग करें classऔर अपने आईडीई आप के लिए equalsऔर hashCodeतरीके उत्पन्न (या, यदि आप उन्हें जरूरत नहीं है)। हां, यदि आपको किसी भी गुण को ऑब्जेक्ट पर बदला जाता है, तो आपको इसे फिर से जेनरेट करना होगा, लेकिन आप ऑब्जेक्ट के कुल नियंत्रण से बचे हैं।
class Test(value: Int) {
val value: Int = value
get() = if (field < 0) 0 else field
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Test) return false
return true
}
override fun hashCode(): Int {
return javaClass.hashCode()
}
}
उस ऑब्जेक्ट पर एक अतिरिक्त सुरक्षित संपत्ति बनाएं जो आपके पास एक निजी मूल्य रखने के बजाय जो आप चाहते हैं वह प्रभावी रूप से ओवरराइड हो।
data class Test(val value: Int) {
val safeValue: Int
get() = if (value < 0) 0 else value
}
एक बुरा दृष्टिकोण जो अन्य उत्तर सुझा रहे हैं:
data class Test(private val _value: Int) {
val value: Int
get() = if (_value < 0) 0 else _value
}
इस दृष्टिकोण के साथ समस्या यह है कि डेटा वर्ग वास्तव में इस तरह के डेटा को बदलने के लिए नहीं हैं। वे वास्तव में सिर्फ डेटा रखने के लिए हैं। इस तरह एक डेटा वर्ग के लिए गेटर अधिभावी कि मतलब होगा Test(0)और Test(-1)नहीं होगा equalएक दूसरे के और अलग अलग होता hashCodeहै, लेकिन जब आप कहा जाता है .value, वे एक ही परिणाम प्राप्त होगा। यह असंगत है, और जब यह आपके लिए काम कर सकता है, तो आपकी टीम के अन्य लोग, जो यह देखते हैं कि यह एक डेटा वर्ग है, गलती से बिना इसका एहसास किए दुरुपयोग कर सकता है कि आपने इसे कैसे बदल दिया है / यह अपेक्षा के अनुरूप काम नहीं किया है (यानी यह दृष्टिकोण ' t सही ढंग से Map(a Set) में काम करता है ।
data class class(@JsonProperty("iss_position") private val position: Map<String, Double>) { val latitude = position["latitude"]; val longitude = position["longitude"] }, और मैं इसे अपने मामले के लिए काफी अच्छा मानता हूं। आप इस बारे में क्या सोचते हैं? (वहाँ अन्य क्षेत्रों में थे और इसलिए मेरा मानना है कि यह मेरे लिए कोई मतलब नहीं है कि मेरे कोड में नेस्टेड json संरचना को पुनः बनाने के लिए)
parsing a string into an int, आप स्पष्ट रूप से अपने मॉडल वर्ग में गैर-संख्यात्मक स्ट्रिंग्स को पार्स करने और त्रुटि से निपटने के व्यावसायिक तर्क की अनुमति दे रहे हैं ...
Listऔर MutableListबिना किसी कारण के।
आप कुछ इस तरह की कोशिश कर सकते हैं:
data class Test(private val _value: Int) {
val value = _value
get(): Int {
return if (field < 0) 0 else field
}
}
assert(1 == Test(1).value)
assert(0 == Test(0).value)
assert(0 == Test(-1).value)
assert(1 == Test(1)._value) // Fail because _value is private
assert(0 == Test(0)._value) // Fail because _value is private
assert(0 == Test(-1)._value) // Fail because _value is private
एक डेटा वर्ग में आप के साथ या तो प्राथमिक निर्माता के मापदंडों को चिह्नित करने चाहिए valया var।
मैं का मान निर्दिष्ट कर रहा हूँ _valueकरने के लिए valueआदेश संपत्ति के लिए वांछित नाम का उपयोग करने में।
मैंने आपके द्वारा वर्णित तर्क के साथ संपत्ति के लिए एक कस्टम एक्सेसर को परिभाषित किया।
उत्तर इस बात पर निर्भर करता है कि आप वास्तव में किन क्षमताओं का उपयोग करते हैं data। @ ईपैड्रॉन ने निफ्टी ट्रिक (बेहतर संस्करण) का उल्लेख किया:
data class Test(private val _value: Int) {
val value: Int
get() = if (_value < 0) 0 else _value
}
कि अपेक्षा के अनुरूप काम करता है, Ei यह है एक , क्षेत्र, एक गेटर सही equals, hashcodeऔर component1। पकड़ यह है toStringऔर copyअजीब हैं:
println(Test(1)) // prints: Test(_value=1)
Test(1).copy(_value = 5) // <- weird naming
अपने साथ समस्या को ठीक करने के लिए toStringइसे हाथों से फिर से परिभाषित कर सकते हैं। मैं पैरामीटर नामकरण को ठीक करने का कोई तरीका नहीं जानता, लेकिन इसका उपयोग करने के लिए dataबिल्कुल नहीं।
मुझे पता है कि यह एक पुराना प्रश्न है, लेकिन ऐसा लगता है कि किसी ने भी इस तरह से मूल्य को निजी बनाने और कस्टम गेटर लिखने की संभावना का उल्लेख नहीं किया है:
data class Test(private val value: Int) {
fun getValue(): Int = if (value < 0) 0 else value
}
यह पूरी तरह से मान्य होना चाहिए क्योंकि कोटलिन निजी क्षेत्र के लिए डिफ़ॉल्ट गेट्टर उत्पन्न नहीं करेगा।
लेकिन अन्यथा मैं निश्चित रूप से spierce7 से सहमत हूं कि डेटा कक्षाएं डेटा रखने के लिए हैं और आपको वहां "व्यापार" तर्क को हार्डकोड करने से बचना चाहिए।
val value = test.getValue() और अन्य गेटर्स की तरह नहीं val value = test.value
.getValue()
मैंने आपका उत्तर देखा है, मैं मानता हूं कि डेटा कक्षाएं केवल डेटा रखने के लिए होती हैं, लेकिन कभी-कभी हमें उनमें से कुछ बनाने की आवश्यकता होती है।
यहाँ मैं अपने डेटा वर्ग के साथ क्या कर रहा हूँ, मैंने कुछ संपत्तियों को वैल से var में बदल दिया, और उन्हें कंस्ट्रक्टर में छोड़ दिया।
इस तरह:
data class Recording(
val id: Int = 0,
val createdAt: Date = Date(),
val path: String,
val deleted: Boolean = false,
var fileName: String = "",
val duration: Int = 0,
var format: String = " "
) {
init {
if (fileName.isEmpty())
fileName = path.substring(path.lastIndexOf('\\'))
if (format.isEmpty())
format = path.substring(path.lastIndexOf('.'))
}
fun asEntity(): rc {
return rc(id, createdAt, path, deleted, fileName, duration, format)
}
}
fun Recording(...): Recording { ... }) के रूप में कार्य करता है । इसके अलावा शायद एक डेटा वर्ग वह नहीं है जो आप चाहते हैं, क्योंकि गैर-डेटा कक्षाओं के साथ आप अपने निर्माण के मापदंडों से अपने गुणों को अलग कर सकते हैं। अपनी कक्षा की परिभाषा में अपने उत्परिवर्तन इरादों के साथ स्पष्ट होना बेहतर है। अगर उन क्षेत्रों में भी परिवर्तनशील मार्ग हो सकते हैं, तो एक डेटा वर्ग ठीक है, लेकिन मेरे लगभग सभी डेटा वर्ग अपरिवर्तनीय हैं।
यह कोटलिन की एक (अन्य) कष्टप्रद कमियों में से एक है।
ऐसा लगता है कि एकमात्र उचित समाधान, जो पूरी तरह से वर्ग के पिछड़ेपन को बनाए रखता है, उसे एक नियमित वर्ग (न कि "डेटा" वर्ग) में बदलना है, और हाथ से लागू करना है (आईडीई की सहायता से) तरीके: हैशकोड ( ), बराबर (), toString (), कॉपी () और कंपोनेंट ()
class Data3(i: Int)
{
var i: Int = i
override fun equals(other: Any?): Boolean
{
if (this === other) return true
if (other?.javaClass != javaClass) return false
other as Data3
if (i != other.i) return false
return true
}
override fun hashCode(): Int
{
return i
}
override fun toString(): String
{
return "Data3(i=$i)"
}
fun component1():Int = i
fun copy(i: Int = this.i): Data3
{
return Data3(i)
}
}
मैंने पाया कि बिना ब्रेक के आपको क्या हासिल करना है equalsऔर hashCode:
data class TestData(private var _value: Int) {
init {
_value = if (_value < 0) 0 else _value
}
val value: Int
get() = _value
}
// Test value
assert(1 == TestData(1).value)
assert(0 == TestData(-1).value)
assert(0 == TestData(0).value)
// Test copy()
assert(0 == TestData(-1).copy().value)
assert(0 == TestData(1).copy(-1).value)
assert(1 == TestData(-1).copy(1).value)
// Test toString()
assert("TestData(_value=1)" == TestData(1).toString())
assert("TestData(_value=0)" == TestData(-1).toString())
assert("TestData(_value=0)" == TestData(0).toString())
assert(TestData(0).toString() == TestData(-1).toString())
// Test equals
assert(TestData(0) == TestData(-1))
assert(TestData(0) == TestData(-1).copy())
assert(TestData(0) == TestData(1).copy(-1))
assert(TestData(1) == TestData(-1).copy(1))
// Test hashCode()
assert(TestData(0).hashCode() == TestData(-1).hashCode())
assert(TestData(1).hashCode() != TestData(-1).hashCode())
तथापि,
सबसे पहले, ध्यान दें कि _valueहै var, नहीं valहै, लेकिन दूसरी ओर, क्योंकि यह निजी है और, से यह काफी आसान लगता है कि यह वर्ग के भीतर संशोधित नहीं किया है या नहीं डेटा वर्गों विरासत में मिला नहीं किया जा सकता।
दूसरा, toString()अगर _valueयह नाम दिया गया था value, तो इसकी तुलना में थोड़ा अलग परिणाम देता है , लेकिन यह सुसंगत है और TestData(0).toString() == TestData(-1).toString()।
_valueinit ब्लॉक में संशोधित किया जा रहा है और equalsऔर hashCode टूटते नहीं हैं।