নিম্নলিখিত কোটলিন শ্রেণি দেওয়া:
data class Test(val value: Int)
Int
মানটি নেতিবাচক হলে আমি কীভাবে গেটকে ওভাররাইড করব যাতে এটি 0 ফেরত দেয়?
যদি এটি সম্ভব না হয় তবে উপযুক্ত ফলাফল অর্জনের জন্য কিছু কৌশল কী?
নিম্নলিখিত কোটলিন শ্রেণি দেওয়া:
data class Test(val value: Int)
Int
মানটি নেতিবাচক হলে আমি কীভাবে গেটকে ওভাররাইড করব যাতে এটি 0 ফেরত দেয়?
যদি এটি সম্ভব না হয় তবে উপযুক্ত ফলাফল অর্জনের জন্য কিছু কৌশল কী?
উত্তর:
কোটলিন দৈনিক লেখার প্রায় পুরো বছর ব্যয় করার পরে আমি দেখতে পেয়েছি যে এই জাতীয় ডেটা ক্লাস ওভাররাইড করার চেষ্টা করা একটি খারাপ অভ্যাস। এটির জন্য 3 টি বৈধ পন্থা রয়েছে এবং আমি এগুলি উপস্থাপন করার পরে, আমি উত্তর করব যে অন্যান্য উত্তরগুলির জন্য কেন দৃষ্টিভঙ্গি খারাপ।
আপনার ব্যবসায়ের যুক্তি আছে যা data class
খারাপ মান দিয়ে কনস্ট্রাক্টরকে কল করার আগে 0 বা তার চেয়ে বড় মান পরিবর্তন করে creates এটি বেশিরভাগ ক্ষেত্রে সম্ভবত সেরা পন্থা।
একটি ব্যবহার করবেন না 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)
would না equal
পরস্পর এবং বিভিন্ন থাকবে hashCode
গুলি, কিন্তু তোমাকে ডেকেছিলাম .value
, তারা একই ফলাফল হবে। এটি অসঙ্গতিপূর্ণ এবং এটি আপনার পক্ষে কার্যকর হতে পারে, আপনার দলের অন্যান্য লোকেরা যারা এটি একটি ডেটা শ্রেণি দেখছেন, আপনি কীভাবে এটি পরিবর্তন করেছেন / এটি প্রত্যাশিতভাবে কাজ না করেছেন তা উপলব্ধি না করে দুর্ঘটনাক্রমে এটির অপব্যবহার করতে পারে (অর্থাত্ এই পদ্ধতির ইচ্ছা হবে না) টি একটি Map
বা এ Set
) তে সঠিকভাবে কাজ করে ।
data class class(@JsonProperty("iss_position") private val position: Map<String, Double>) { val latitude = position["latitude"]; val longitude = position["longitude"] }
, এবং আমি এটি আমার ক্ষেত্রে টিবিএইচ জন্য বেশ ভাল মনে করি। আপনি এ ব্যপারে কী ভাবছেন? (অন্যান্য ক্ষেত্রগুলির মধ্যে অনেকগুলি ছিল এবং তাই আমি বিশ্বাস করি যে আমার কোডে নেস্টেড
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
}
এটি পুরোপুরি বৈধ হওয়া উচিত কারণ কোটলিন ব্যক্তিগত ক্ষেত্রে ডিফল্ট গেটার তৈরি করতে পারে না।
তবে অন্যথায় আমি স্পিয়ার্স with এর সাথে অবশ্যই একমত যে ডেটা ক্লাসগুলি ডেটা ধরে রাখার জন্য এবং সেখানে "ব্যবসায়" যুক্তি আপনার হার্ডকোডিং এড়ানো উচিত।
val value = test.getValue()
এবং অন্যান্য গেটের মতো নয় val value = test.value
.getValue()
আমি আপনার উত্তরটি দেখেছি, আমি সম্মত হয়েছি যে ডেটা ক্লাসগুলি কেবলমাত্র ডেটা রাখার জন্যই বোঝানো হয়, তবে কখনও কখনও আমাদের সেগুলি থেকে কিছুটা তৈরি করার প্রয়োজন হয়।
এখানে আমি আমার ডেটা ক্লাসটি দিয়ে যা করছি, আমি ভাল থেকে ভেরিতে কয়েকটি বৈশিষ্ট্য পরিবর্তন করেছি এবং সেগুলি কনস্ট্রাক্টরে ওভারিড করেছি।
তাই ভালো:
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 { ... }
) হিসাবে কাজ করে । এছাড়াও একটি ডেটা ক্লাস আপনি যা চান তা নয়, কারণ অ-ডেটা ক্লাসের সাহায্যে আপনি আপনার কনস্ট্রাক্টর প্যারামিটারগুলি থেকে আপনার সম্পত্তিগুলি আলাদা করতে পারেন। আপনার শ্রেণীর সংজ্ঞায় আপনার পরিবর্তনীয় উদ্দেশ্যগুলির সাথে স্পষ্ট হওয়া ভাল। যদি সেই ক্ষেত্রগুলিও যাইহোক পরিবর্তিত হতে পারে, তবে একটি ডেটা ক্লাস ভাল, তবে আমার প্রায় সমস্ত ডেটা ক্লাস অপরিবর্তনীয়।
এটি কোটলিনের এক (অন্যদের মধ্যে) বিরক্তিকর ত্রুটি বলে মনে হচ্ছে।
দেখে মনে হচ্ছে একমাত্র যুক্তিসঙ্গত সমাধান যা ক্লাসটির পশ্চাদপদ সামঞ্জস্যতা পুরোপুরি রাখে তা হ'ল এটিকে একটি নিয়মিত শ্রেণিতে রূপান্তর করা (কোনও "ডেটা" শ্রেণিতে নয়) এবং হাতে (আইডিইর সহায়তায়) পদ্ধতিগুলি প্রয়োগ করে: হ্যাশকোড ( ), সমান (), টু স্ট্রিং (), অনুলিপি () এবং উপাদান এন ()
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()
।
_value
আর ডি ব্লকে পরিবর্তন করা হচ্ছে equals
এবং hashCode
তা ভাঙ্গা হয়নি।