কোটলিনে, মূল্যহীন মানগুলির সাথে সম্পর্কিত বা রেফারেন্সিং বা রূপান্তরিত করার অলৌকিক উপায় কী


177

আমার যদি একটি নলাবদ্ধ টাইপ থাকে তবে Xyz?আমি এটি উল্লেখ করতে চাই বা এটিকে একটি নন-নালযোগ্য টাইপতে রূপান্তর করতে চাই Xyz। কোটলিনে এমন করার মূর্তিমান পদ্ধতি কী?

উদাহরণস্বরূপ, এই কোডটি ত্রুটিযুক্ত:

val something: Xyz? = createPossiblyNullXyz()
something.foo() // Error: "Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type Xyz?"

তবে আমি যদি প্রথমে নাল পরীক্ষা করি তবে এটি অনুমোদিত?

val something: Xyz? = createPossiblyNullXyz()
if (something != null) {
    something.foo() 
}

আমি নিশ্চিতভাবে জানি যে এটি সত্যই কখনও হয় না তা ধরে রেখে আমি কীভাবে কোনও মান পরিবর্তন বা চেকের nullপ্রয়োজন ছাড়াই চিকিত্সা না করে চিকিত্সা ifকরব null? উদাহরণস্বরূপ, আমি এখানে মানচিত্রের একটি মান পুনরুদ্ধার করছি যা আমি গ্যারান্টি দিতে পারি যা বিদ্যমান আছে এবং এর ফলাফলটি get()নেই null। তবে আমার একটি ত্রুটি রয়েছে:

val map = mapOf("a" to 65,"b" to 66,"c" to 67)
val something = map.get("a")
something.toLong() // Error: "Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type Int?"

পদ্ধতিটি get()মনে করে যে এটি সম্ভব যে আইটেমটি অনুপস্থিত এবং প্রেরণের ধরন Int?। অতএব, মানটির ধরণটি বাধ্যযোগ্য না করার সর্বোত্তম উপায় কী?

দ্রষ্টব্য: এই প্রশ্নটি লেখক ইচ্ছাকৃতভাবে লিখেছেন এবং উত্তর দিয়েছেন ( স্ব-উত্তরযুক্ত প্রশ্ন ), যাতে সাধারণভাবে জিজ্ঞাসিত কোটলিন বিষয়গুলির বুদ্ধিমান উত্তরগুলি এসওতে উপস্থিত থাকে। কোটলিনের আলফাসের জন্য লিখিত কিছু সত্যিকারের পুরানো উত্তরগুলিও স্পষ্ট করা যা বর্তমান সময়ের কোটলিনের জন্য সঠিক নয়।

উত্তর:


296

প্রথমত, আপনার কোটলিনে নুল সুরক্ষা সম্পর্কিত সমস্তগুলি পড়া উচিত যা কেসগুলি পুরোপুরি coversেকে রাখে।

কোটলিনে, আপনি এটি নিশ্চিত না হয়েই কোনও শনাক্তযোগ্য মান অ্যাক্সেস করতে পারবেন না null( শর্তে নাল পরীক্ষা করা ), বা নিশ্চিত করে বলা যায় যে এটি অবশ্যই নিশ্চিত অপারেটরটিnull ব্যবহার করছে না , এটি নিরাপদ কল দিয়ে অ্যাক্সেস করছে বা শেষ পর্যন্ত এমন কিছু দেয় যা সম্ভবত একটি এলভিস অপারেটর ব্যবহার করে ডিফল্ট মান ।!!?.null?:

আপনার প্রশ্নে আপনার 1 ম কেসের জন্য আপনার কোডগুলির উদ্দেশ্য অনুসারে বিকল্প রয়েছে যা আপনি এর মধ্যে একটি ব্যবহার করবেন এবং সবগুলি বুদ্ধিমানের তবে ভিন্ন ফলাফল রয়েছে:

val something: Xyz? = createPossiblyNullXyz()

// access it as non-null asserting that with a sure call
val result1 = something!!.foo()

// access it only if it is not null using safe operator, 
// returning null otherwise
val result2 = something?.foo()

// access it only if it is not null using safe operator, 
// otherwise a default value using the elvis operator
val result3 = something?.foo() ?: differentValue

// null check it with `if` expression and then use the value, 
// similar to result3 but for more complex cases harder to do in one expression
val result4 = if (something != null) {
                   something.foo() 
              } else { 
                   ...
                   differentValue 
              }

// null check it with `if` statement doing a different action
if (something != null) { 
    something.foo() 
} else { 
    someOtherAction() 
}

"নাল চেক করা হলে এটি কেন কাজ করে" এর জন্য স্মার্ট ক্যাসেটগুলিতে নীচে ব্যাকগ্রাউন্ডের তথ্য পড়ুন ।

আপনার প্রশ্নের আপনার 2nd ক্ষেত্রে জন্য সঙ্গে প্রশ্নে Map, যদি আপনি একটি ডেভেলপার হিসেবে ফলাফলের কখনো হচ্ছে নিশ্চিত null, ব্যবহার !!একটি বিবৃতি হিসাবে নিশ্চিত অপারেটর:

val map = mapOf("a" to 65,"b" to 66,"c" to 67)
val something = map.get("a")!!
something.toLong() // now valid

বা অন্য কোনও ক্ষেত্রে, যখন মানচিত্রটি শূন্য হয় তবে আপনি একটি ডিফল্ট মান সরবরাহ করতে পারেন, তারপরে Mapনিজেই একটি getOrElseপদ্ধতি রয়েছে :

val map = mapOf("a" to 65,"b" to 66,"c" to 67)
val something = map.getOrElse("z") { 0 } // provide default value in lambda
something.toLong() // now valid

পেছনের তথ্য:

দ্রষ্টব্য: নীচের উদাহরণগুলিতে আমি আচরণটি পরিষ্কার করার জন্য সুস্পষ্ট ধরণের ব্যবহার করছি। প্রকার অনুমানের সাথে, সাধারণত স্থানীয় ভেরিয়েবল এবং ব্যক্তিগত সদস্যদের জন্য প্রকারগুলি বাদ দেওয়া যেতে পারে।

!!নিশ্চিত অপারেটর সম্পর্কে আরও

!!অপারেটর asserts যে মান নয় nullঅথবা একটি NPE ছোঁড়ার। এটি এমন ক্ষেত্রে ব্যবহার করা উচিত যেখানে বিকাশকারী গ্যারান্টি দিচ্ছেন যে মান কখনই হবে না null। এটিকে স্মার্ট কাস্ট দ্বারা অনুসরণ করা দৃ as় হিসাবে মনে করুন ।

val possibleXyz: Xyz? = ...
// assert it is not null, but if it is throw an exception:
val surelyXyz: Xyz = possibleXyz!! 
// same thing but access members after the assertion is made:
possibleXyz!!.foo()

আরও পড়ুন: !! অবশ্যই অপারেটর


nullচেকিং এবং স্মার্ট কাস্টস সম্পর্কে আরও

যদি আপনি কোনও nullচেকের সাহায্যে এক প্রকার প্রকারভেদে অ্যাক্সেস রক্ষা করেন তবে সংকলকটি বিবৃতিটির মূল অংশের মধ্যে মূল্যকে অ-শরীয়াত করতে হবে cast কিছু জটিল প্রবাহ রয়েছে যেখানে এটি ঘটতে পারে না, তবে সাধারণ ক্ষেত্রে এটি ঠিক কাজ করে।

val possibleXyz: Xyz? = ...
if (possibleXyz != null) {
   // allowed to reference members:
   possiblyXyz.foo()
   // or also assign as non-nullable type:
   val surelyXyz: Xyz = possibleXyz
}

বা যদি আপনি isএকটি অ-শনাক্তযোগ্য প্রকারের জন্য চেক করেন:

if (possibleXyz is Xyz) {
   // allowed to reference members:
   possiblyXyz.foo()
}

এবং 'যখন' এক্সপ্রেশনগুলির জন্যও এটি নিরাপদ cast

when (possibleXyz) {
    null -> doSomething()
    else -> possibleXyz.foo()
}

// or

when (possibleXyz) {
    is Xyz -> possibleXyz.foo()
    is Alpha -> possibleXyz.dominate()
    is Fish -> possibleXyz.swim() 
}

কিছু জিনিস অনুমতি দেয় না nullচেক স্মার্ট ঢালাই ভেরিয়েবলের পরে ব্যবহার করার জন্য। উপরের উদাহরণটিতে একটি স্থানীয় ভেরিয়েবল ব্যবহার করা হয়েছে যা কোনওভাবেই অ্যাপ্লিকেশন প্রবাহে রূপান্তর করতে পারে না, এই ভেরিয়েবলটির কোনওটিতে রূপান্তর করার কোনও সুযোগ ছিল না valবা varনা null। তবে, অন্যান্য ক্ষেত্রে যেখানে সংকলক প্রবাহ বিশ্লেষণের গ্যারান্টি দিতে পারে না, এটি ত্রুটি হবে:

var nullableInt: Int? = ...

public fun foo() {
    if (nullableInt != null) {
        // Error: "Smart cast to 'kotlin.Int' is impossible, because 'nullableInt' is a mutable property that could have been changed by this time"
        val nonNullableInt: Int = nullableInt
    }
}

ভেরিয়েবলের জীবনচক্র nullableIntসম্পূর্ণরূপে দৃশ্যমান নয় এবং অন্য থ্রেড থেকে নির্ধারিত হতে পারে, nullচেকটি কোনও অ-মূল্যহীন মান হিসাবে স্মার্ট কাস্ট করা যাবে না । কার্যবিধির জন্য নীচে "সেফ কল" বিষয়টি দেখুন।

স্মার্ট কাস্ট দ্বারা valপরিবর্তিত হতে না পারে এমন আরেকটি কেস হ'ল একটি কাস্টম গেটার রয়েছে এমন কোনও জিনিসের সম্পত্তি। এই ক্ষেত্রে, সংকলকটির মানটি কী রূপান্তরিত করে তার কোনও দৃশ্যমানতা নেই এবং তাই আপনি একটি ত্রুটি বার্তা পাবেন:

class MyThing {
    val possibleXyz: Xyz? 
        get() { ... }
}

// now when referencing this class...

val thing = MyThing()
if (thing.possibleXyz != null) {
   // error: "Kotlin: Smart cast to 'kotlin.Int' is impossible, because 'p.x' is a property that has open or custom getter"
   thing.possiblyXyz.foo()
}

আরও পড়ুন: শর্তে নাল পরীক্ষা করা হচ্ছে


?.নিরাপদ কল অপারেটর সম্পর্কে আরও

বাম দিকের মান শূন্য হলে নিরাপদ কল অপারেটর নাল ফেরায়, অন্যথায় ডানদিকে অভিব্যক্তিটি মূল্যায়ন করতে অবিরত।

val possibleXyz: Xyz? = makeMeSomethingButMaybeNullable()
// "answer" will be null if any step of the chain is null
val answer = possibleXyz?.foo()?.goo()?.boo()

অন্য একটি উদাহরণ যেখানে আপনি একটি তালিকা পুনরাবৃত্তি করতে চান তবে কেবল nullএবং খালি না হলে আবারও নিরাপদ কল অপারেটরটি কাজে আসবে:

val things: List? = makeMeAListOrDont()
things?.forEach {
    // this loops only if not null (due to safe call) nor empty (0 items loop 0 times):
}

উপরের উদাহরণগুলির মধ্যে একটিতে আমাদের একটি কেস হয়েছিল যেখানে আমরা একটি ifচেক করেছি তবে সুযোগ পেয়েছে অন্য থ্রেডের মানটি পরিবর্তিত হয়েছে এবং সেইজন্য কোনও স্মার্ট কাস্ট নেই । এটি সমাধানের জন্য আমরা letফাংশন সহ নিরাপদ কল অপারেটরটি ব্যবহার করতে এই নমুনাটি পরিবর্তন করতে পারি :

var possibleXyz: Xyz? = 1

public fun foo() {
    possibleXyz?.let { value ->
        // only called if not null, and the value is captured by the lambda
        val surelyXyz: Xyz = value
    }
}

আরও পড়ুন: নিরাপদ কল


?:এলভিস অপারেটর সম্পর্কে আরও

যখন অপারেটরের বাম দিকে একটি অভিব্যক্তি থাকে তখন এলভিস অপারেটর আপনাকে একটি বিকল্প মান সরবরাহ করতে দেয় null:

val surelyXyz: Xyz = makeXyzOrNull() ?: DefaultXyz()

এর কিছু সৃজনশীল ব্যবহারও রয়েছে, উদাহরণস্বরূপ যখন কিছু থাকে তখন একটি ব্যতিক্রম নিক্ষেপ করুন null:

val currentUser = session.user ?: throw Http401Error("Unauthorized")

বা কোনও ফাংশন থেকে তাড়াতাড়ি ফিরে আসতে:

fun foo(key: String): Int {
   val startingCode: String = codes.findKey(key) ?: return 0
   // ...
   return endingValue
}

আরও পড়ুন: এলভিস অপারেটর


সম্পর্কিত ফাংশন সহ নাল অপারেটরগুলি

কোটলিন স্টিডলিবের উপরে রয়েছে উল্লিখিত অপারেটরগুলির সাথে একটি দুর্দান্ত ক্রিয়া রয়েছে যা কাজ করে। উদাহরণ স্বরূপ:

// use ?.let() to change a not null value, and ?: to provide a default
val something = possibleNull?.let { it.transform() } ?: defaultSomething

// use ?.apply() to operate further on a value that is not null
possibleNull?.apply {
    func1()
    func2()
}

// use .takeIf or .takeUnless to turn a value null if it meets a predicate
val something = name.takeIf { it.isNotBlank() } ?: defaultName

val something = name.takeUnless { it.isBlank() } ?: defaultName

সম্পর্কিত বিষয়

কোটলিনে, বেশিরভাগ অ্যাপ্লিকেশন nullমানগুলি এড়ানোর চেষ্টা করে তবে এটি সবসময় সম্ভব হয় না। এবং কখনও কখনও nullনিখুঁত জ্ঞান তোলে। এ সম্পর্কে ভাবার জন্য কয়েকটি গাইডলাইন:

  • কিছু ক্ষেত্রে, এটি বিভিন্ন রিটার্নের ধরণের বার্তা দেয় যা পদ্ধতি কলের স্থিতি এবং সফল হলে ফলাফল অন্তর্ভুক্ত করে। মত লাইব্রেরি ফল আপনি একটি সফলতা বা ব্যর্থতা ফলাফলের প্রকার যে আপনার কোড শাখায় বিভক্ত করতে দেব। আর Kotlin জন্য অঙ্গীকার গ্রন্থাগার নামক Kovenant প্রতিশ্রুতি আকারে একই আছে।

  • সংগ্রহের জন্য রিটার্নের ধরণ হিসাবে সর্বদা একটি এর পরিবর্তে একটি খালি সংগ্রহ ফেরত দেয় null, যদি না আপনার "তত্সহ উপস্থিত" তৃতীয় অবস্থার প্রয়োজন হয় না। এই খালি মানগুলি তৈরি করতে emptyList()বাemptySet() যেমন কোটলিনে সহায়ক কার্য রয়েছে ।

  • এমন কোনও পদ্ধতি যখন আপনি কোনও ডিফল্ট বা বিকল্প হিসাবে নলযোগ্য মানটি ফিরিয়ে দেন, তখন কোনও ডিফল্ট মান সরবরাহ করতে এলভিস অপারেটরটি ব্যবহার করুন। একটি Mapব্যবহারের ক্ষেত্রে getOrElse()যা Mapপদ্ধতির পরিবর্তে একটি ডিফল্ট মান উত্পন্ন করতে দেয় get()যা একটি অযোগ্য মান দেয়। একই জন্যgetOrPut()

  • জাভা থেকে কোথলিন জাভা কোডের শূন্যতা সম্পর্কে নিশ্চিত নয় এমন পদ্ধতিগুলি যখন অররাইড করে তখন ?আপনি স্বাক্ষর এবং কার্যকারিতাটি কী হবে তা নিশ্চিত হলে আপনি সর্বদা আপনার ওভাররাইড থেকে অযোগ্যতা বাদ দিতে পারেন। সুতরাং আপনার ওভাররাইড পদ্ধতিটি আরও nullনিরাপদ। কোটলিনে জাভা ইন্টারফেস বাস্তবায়নের জন্য একই, আপনি যা জানেন তা বৈধ হওয়ার জন্য nlalability পরিবর্তন করুন।

  • ইতিমধ্যে সহায়তা করতে পারে এমন ফাংশনগুলি সন্ধান করুন যেমন এর জন্য String?.isNullOrEmpty()এবং String?.isNullOrBlank()যা নিরাপদে কোনও মূল্যহীন মূল্যের উপর পরিচালনা করতে পারে এবং আপনি যা প্রত্যাশা করেন তা করতে পারেন। প্রকৃতপক্ষে, আপনি স্ট্যান্ডার্ড লাইব্রেরিতে কোনও ফাঁক পূরণ করতে নিজের এক্সটেনশান যুক্ত করতে পারেন।

  • স্ট্যান্ডার্ড লাইব্রেরিতে checkNotNull()এবং মত দৃ functions়তা ফাংশন requireNotNull()

  • সহায়ক ফাংশনগুলির মতো filterNotNull()যা সংগ্রহ থেকে নালগুলি সরিয়ে দেয়, বা listOfNotNull()একটি শূন্য বা একক আইটেম তালিকাটি সম্ভবত কোনও nullমান থেকে ফিরিয়ে দেয় ।

  • সেখানে একটি নিরাপদ (নলযোগ্য) castালাই অপারেটর রয়েছে যা সম্ভব না হলে একটি নিক্ষিপ্ত অ-প্র্রজনীয় প্রকারের রিটার্ন নালকে অনুমতি দেয়। তবে এর জন্য আমার কাছে বৈধ ব্যবহারের কেস নেই যা উপরে বর্ণিত অন্যান্য পদ্ধতি দ্বারা সমাধান করা হয়নি।


1

পূর্ববর্তী উত্তর অনুসরণ করা একটি কঠোর আইন, তবে এখানে একটি দ্রুত এবং সহজ উপায়:

val something: Xyz = createPossiblyNullXyz() ?: throw RuntimeError("no it shouldn't be null")
something.foo() 

যদি এটি সত্যই কখনই বাতিল হয় না, ব্যতিক্রম ঘটবে না, তবে যদি কখনও হয় তবে আপনি কী ভুল হয়েছে তা দেখতে পাবেন।


12
ভাল কিছু: জাইজ = তৈরি করুন সম্ভাব্য নলএক্সিজ () !! যখন তৈরির সম্ভাব্য নলএক্সাইজ () বাতিল করে দেয় তখন একটি এনপিই ফেলবে। এটি সহজ এবং আপনি জানেন এমন কোনও মূল্য বাতিল করার জন্য সম্মেলনের অনুসরণ করে
স্টিভেন ওয়াটারম্যান
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.