একাধিক চলক কোটলিনে দিন


127

কোটলিনে একাধিক নালযোগ্য ভেরিয়েবলের জন্য একাধিক চেইনের কোনও উপায় আছে কি?

fun example(first: String?, second: String?) {
    first?.let {
        second?.let {
            // Do something just if both are != null
        }
    }
}

মানে, এরকম কিছু:

fun example(first: String?, second: String?) {
    first?.let && second?.let { 
        // Do something just if both are != null
    }
}

1
আপনি কি 2 টি নয়, এন আইটেমগুলি চান? সমস্ত আইটেমের কি একই ধরণের, বা বিভিন্ন ধরণের প্রয়োজন? সমস্ত মানগুলি তালিকায় বা স্বতন্ত্র পরামিতি হিসাবে ফাংশনে প্রবেশ করা উচিত? প্রত্যাবর্তনের মানটি কি কোনও একক আইটেম বা ইনপুট হিসাবে একই সংখ্যক আইটেমের একটি গ্রুপ হওয়া উচিত?
জেইসন মিনার্ড

আমার সমস্ত যুক্তি দরকার, এই মামলার জন্য দুটি হতে পারে তবে আরও বেশি কিছু করার একটি উপায় জানতে চেয়েছিলেন, তাড়াতাড়ি খুব সহজ।
ড্যানিয়েল গোমেজ রিকো

আপনি কি নীচের উত্তরগুলির চেয়ে আলাদা কিছু সন্ধান করছেন, যদি তাই করেন তবে কী সন্ধান করছেন আপনি কী পার্থক্য তা মন্তব্য করুন।
জেইসন মিনার্ড

দ্বিতীয় লেকের ব্লকের মধ্যে প্রথম "এটি" উল্লেখ করা কেমন হবে?
জাভিয়ের মেন্ডোনিয়া

উত্তর:


48

যদি আগ্রহী হয় তবে এটি সমাধানের জন্য আমার দুটি ফাংশন।

inline fun <T: Any> guardLet(vararg elements: T?, closure: () -> Nothing): List<T> {
    return if (elements.all { it != null }) {
        elements.filterNotNull()
    } else {
        closure()
    }
}

inline fun <T: Any> ifLet(vararg elements: T?, closure: (List<T>) -> Unit) {
    if (elements.all { it != null }) {
        closure(elements.filterNotNull())
    }
}

ব্যবহার:


// Will print
val (first, second, third) = guardLet("Hello", 3, Thing("Hello")) { return }
println(first)
println(second)
println(third)

// Will return
val (first, second, third) = guardLet("Hello", null, Thing("Hello")) { return }
println(first)
println(second)
println(third)

// Will print
ifLet("Hello", "A", 9) {
 (first, second, third) ->
 println(first)
 println(second)
 println(third)
}

// Won't print
ifLet("Hello", 9, null) {
 (first, second, third) ->
 println(first)
 println(second)
 println(third)
}

এটি খুব সুন্দর, তবে আমি এখনও একটি কেস মিস করছি যেখানে আমি দ্বিতীয়টিতে প্রথম ইনপুট ব্যবহার করতে পারি। উদাহরণ: ifLet ("এ", টু লোয়ার (প্রথম)) {// প্রথম = "এ", দ্বিতীয় = "এ"}
ওটিজিই

IfLet বিবৃতিতে প্রথম যুক্তিটি এখনও মোড়কানো যায়নি, আপনার মতো কোনও ক্রিয়াকলাপ সম্ভব নয়। আমি কি গার্ডলেট ব্যবহার করার পরামর্শ দিতে পারি? এটি বেশ সোজা এগিয়ে। ভাল (প্রথম) = গার্ডলিট (100) {রিটার্ন} ভাল (দ্বিতীয়) = গার্ডলিট (101) {রিটার্ন} ভাল গড় = গড় (প্রথম, দ্বিতীয়) আমি জানি যে আপনি যা চেয়েছিলেন তা নয়, তবে আশা করি এটি সহায়তা করবে।
দারিও পেলেগ্রিনি

ধন্যবাদ। আমার এটি সমাধান করার একাধিক উপায় রয়েছে, বলার কারণটি হ'ল সুইফটে একে অপরকে কমা দ্বারা আলাদা করার পরে যদি একাধিক ifLets সম্ভব হয় এবং তারা পূর্ববর্তী চেকটির ভেরিয়েবল ব্যবহার করতে পারে। আমি আশা করি কোটলিনেও এটি সম্ভব হত। :)
ওটজিই

1
এটি উত্তর গ্রহণ করা যেতে পারে, কিন্তু প্রতিটি কল উপর ওভারহেড আছে। কারণ ভিএম প্রথমে ফাংশন অবজেক্ট তৈরি করে। ডেক্স সীমাবদ্ধতার কথা বিবেচনা করেও এটি প্রতিটি অনন্য চেকের জন্য 2 পদ্ধতি রেফারেন্স সহ ফাংশন শ্রেণির ঘোষণা যুক্ত করবে।
ওলেকসান্ডার আলবুল

146

আপনি কি স্টাইলটি ব্যবহার করতে চান তার উপর নির্ভর করে এখানে আপনার কয়েকটি বা বিভিন্ন ধরণের সমস্ত কিছু রয়েছে এবং যদি তালিকাটিতে অজানা সংখ্যক আইটেম রয়েছে ...

মিশ্রিত প্রকারগুলি, একটি নতুন মান গণনা করার জন্য সমস্ত অবশ্যই নালাগুলি নয়

মিশ্র প্রকারের জন্য আপনি প্রতিটি প্যারামিটার গণনার জন্য একাধিক ক্রিয়াকলাপ তৈরি করতে পারেন যা নির্বোধ দেখাচ্ছে, তবে মিশ্র প্রকারের জন্য খুব সুন্দরভাবে কাজ করুন:

inline fun <T1: Any, T2: Any, R: Any> safeLet(p1: T1?, p2: T2?, block: (T1, T2)->R?): R? {
    return if (p1 != null && p2 != null) block(p1, p2) else null
}
inline fun <T1: Any, T2: Any, T3: Any, R: Any> safeLet(p1: T1?, p2: T2?, p3: T3?, block: (T1, T2, T3)->R?): R? {
    return if (p1 != null && p2 != null && p3 != null) block(p1, p2, p3) else null
}
inline fun <T1: Any, T2: Any, T3: Any, T4: Any, R: Any> safeLet(p1: T1?, p2: T2?, p3: T3?, p4: T4?, block: (T1, T2, T3, T4)->R?): R? {
    return if (p1 != null && p2 != null && p3 != null && p4 != null) block(p1, p2, p3, p4) else null
}
inline fun <T1: Any, T2: Any, T3: Any, T4: Any, T5: Any, R: Any> safeLet(p1: T1?, p2: T2?, p3: T3?, p4: T4?, p5: T5?, block: (T1, T2, T3, T4, T5)->R?): R? {
    return if (p1 != null && p2 != null && p3 != null && p4 != null && p5 != null) block(p1, p2, p3, p4, p5) else null
}
// ...keep going up to the parameter count you care about

ব্যবহারের উদাহরণ:

val risk = safeLet(person.name, person.age) { name, age ->
  // do something
}   

তালিকার কোনও শূন্য আইটেম না থাকলে কোডের ব্লক কার্যকর করুন

দুটি স্বাদ এখানে, প্রথমে যখন তালিকায় সমস্ত নাল আইটেম থাকে তখন কোডের ব্লক কার্যকর করতে হয় এবং দ্বিতীয়ত যখন তালিকাটিতে কমপক্ষে একটি নাল আইটেম থাকে তখন একই কাজ করতে হয়। উভয় ক্ষেত্রেই কোড অবরুদ্ধ করার জন্য নাল আইটেমগুলির একটি তালিকা পাঠানো হয়:

কার্যাবলী:

fun <T: Any, R: Any> Collection<T?>.whenAllNotNull(block: (List<T>)->R) {
    if (this.all { it != null }) {
        block(this.filterNotNull()) // or do unsafe cast to non null collectino
    }
}

fun <T: Any, R: Any> Collection<T?>.whenAnyNotNull(block: (List<T>)->R) {
    if (this.any { it != null }) {
        block(this.filterNotNull())
    }
}

ব্যবহারের উদাহরণ:

listOf("something", "else", "matters").whenAllNotNull {
    println(it.joinToString(" "))
} // output "something else matters"

listOf("something", null, "matters").whenAllNotNull {
    println(it.joinToString(" "))
} // no output

listOf("something", null, "matters").whenAnyNotNull {
    println(it.joinToString(" "))
} // output "something matters"

ফাংশনটিতে সামান্য পরিবর্তন আইটেমগুলির তালিকা গ্রহণ করে এবং একই ক্রিয়াকলাপ করুন:

fun <T: Any, R: Any> whenAllNotNull(vararg options: T?, block: (List<T>)->R) {
    if (options.all { it != null }) {
        block(options.filterNotNull()) // or do unsafe cast to non null collection
    }
}

fun <T: Any, R: Any> whenAnyNotNull(vararg options: T?, block: (List<T>)->R) {
    if (options.any { it != null }) {
        block(options.filterNotNull())
    }
}

ব্যবহারের উদাহরণ:

whenAllNotNull("something", "else", "matters") {
    println(it.joinToString(" "))
} // output "something else matters"

এই ভিন্নতাগুলির মতো রিটার্ন মানগুলি পরিবর্তন করা যেতে পারে let()

প্রথম নন-নাল আইটেমটি ব্যবহার করুন (কোলেসেস)

কোনও এসকিউএল কোলেসেস ফাংশনের মতো, প্রথম নাল আইটেমটি ফিরিয়ে দিন। ফাংশনের দুটি স্বাদ:

fun <T: Any> coalesce(vararg options: T?): T? = options.firstOrNull { it != null }
fun <T: Any> Collection<T?>.coalesce(): T? = this.firstOrNull { it != null }

ব্যবহারের উদাহরণ:

coalesce(null, "something", null, "matters")?.let {
    it.length
} // result is 9, length of "something"

listOf(null, "something", null, "matters").coalesce()?.let {
    it.length
}  // result is 9, length of "something"

অন্যান্য প্রকরণ

... অন্যান্য বিভিন্নতা রয়েছে, তবে আরও একটি নির্দিষ্টকরণের সাথে এটি সংকুচিত করা যেতে পারে।


1
এছাড়াও আপনি একত্রিত পারে whenAllNotNullতাই মত ডেসট্রাকচারিং সঙ্গে listOf(a, b, c).whenAllNotNull { (d, e, f) -> println("$d $e $f")
ডাম্পট্রাকম্যান

10

আপনি এটির জন্য নিজের ফাংশন লিখতে পারেন:

 fun <T, U, R> Pair<T?, U?>.biLet(body: (T, U) -> R): R? {
     val first = first
     val second = second
     if (first != null && second != null) {
         return body(first, second)
     }
     return null
 }

 (first to second).biLet { first, second -> 
      // body
 }

7

আপনি একটি arrayIfNoNullsফাংশন তৈরি করতে পারেন :

fun <T : Any> arrayIfNoNulls(vararg elements: T?): Array<T>? {
    if (null in elements) {
        return null
    }
    @Suppress("UNCHECKED_CAST")
    return elements as Array<T>
}

তারপরে আপনি এটির সাথে ভেরিয়েবলের সংখ্যার জন্য এটি ব্যবহার করতে পারেন let:

fun example(first: String?, second: String?) {
    arrayIfNoNulls(first, second)?.let { (first, second) ->
        // Do something if each element is not null
    }
}

আপনার যদি ইতিমধ্যে একটি অ্যারে থাকে তবে আপনি একটি takeIfNoNullsফাংশন তৈরি করতে পারেন (দ্বারা অনুপ্রাণিত takeIfএবং requireNoNulls):

fun <T : Any> Array<T?>.takeIfNoNulls(): Array<T>? {
    if (null in this) {
        return null
    }
    @Suppress("UNCHECKED_CAST")
    return this as Array<T>
}

উদাহরণ:

array?.takeIfNoNulls()?.let { (first, second) ->
    // Do something if each element is not null
}

3

কেবল দুটি মান পরীক্ষা করার ক্ষেত্রে এবং তালিকাগুলির সাথে কাজ না করার ক্ষেত্রে:

fun <T1, T2> ifNotNull(value1: T1?, value2: T2?, bothNotNull: (T1, T2) -> (Unit)) {
    if (value1 != null && value2 != null) {
        bothNotNull(value1, value2)
    }
}

ব্যবহারের উদাহরণ:

var firstString: String?
var secondString: String?
ifNotNull(firstString, secondString) { first, second -> Log.d(TAG, "$first, $second") }

2

আসলে, আপনি কেবল এটি করতে পারেন, জানেন? ;)

if (first != null && second != null) {
    // your logic here...
}

কোটলিনে একটি সাধারণ নাল চেক ব্যবহার করে কোনও ভুল নেই।

এবং আপনার কোডটি অনুসন্ধান করবে এমন প্রত্যেকের পক্ষে এটি আরও বেশি পাঠযোগ্য।


36
পরিবর্তনীয় শ্রেণীর সদস্যের সাথে কাজ করার সময় এটি যথেষ্ট হবে না।
মিশা কে

3
এই ধরণের উত্তর দেওয়ার দরকার নেই, প্রশ্নের উদ্দেশ্য হ'ল এটি পরিচালনা করার আরও একটি "উত্পাদনশীল উপায়" সন্ধান করা, যেহেতু ভাষা letএই চেকগুলি করার শর্টকাট সরবরাহ করে
আলেজান্দ্রো মোয়া

1
রক্ষণাবেক্ষণের ক্ষেত্রে, এটি আমার পছন্দ, এমনকি যদি এটি মার্জিত না হয়। এটি স্পষ্টতই একটি ইস্যু যা প্রত্যেকে সর্বদা চলমান থাকে এবং ভাষাটি মোকাবেলা করা উচিত।
ব্রিল প্যাপিন

2

আমি নিম্নলিখিত সহায়িকার ফাংশনগুলি ব্যবহার করে এটি সমাধান করতে পছন্দ করি:

fun <A, B> T(tuple: Pair<A?, B?>): Pair<A, B>? =
    if(tuple.first == null || tuple.second == null) null
    else Pair(tuple.first!!, tuple.second!!)

fun <A, B, C> T(tuple: Triple<A?, B?, C?>): Triple<A, B, C>? =
    if(tuple.first == null || tuple.second == null || tuple.third == null) null
    else Triple(tuple.first!!, tuple.second!!, tuple.third!!)


fun <A, B> T(first: A?, second: B?): Pair<A, B>? =
    if(first == null || second == null) null
    else Pair(first, second)

fun <A, B, C> T(first: A?, second: B?, third: C?): Triple<A, B, C>? =
        if(first == null || second == null || third == null) null
        else Triple(first, second, third)

এবং এগুলি কীভাবে আপনার ব্যবহার করা উচিত তা এখানে:

val a: A? = someValue
val b: B? = someOtherValue
T(a, b)?.let { (a, b) ->
  // Shadowed a and b are of type a: A and b: B
  val c: C? = anotherValue
  T(a, b, c)
}?.let { (a, b, c) ->
  // Shadowed a, b and c are of type a: A, b: B and c: C
  .
  .
  .
}

1

আমি এটিকে কয়েকটি ফাংশন তৈরি করে সমাধান করেছি যা কম-বেশি এর সাথে এর আচরণের প্রতিরূপ তৈরি করে তবে একাধিক পরামিতি নেয় এবং কেবলমাত্র সমস্ত পরামিতিগুলির কার্যকারিতাটি অকার্যকর হয় inv

fun <R, A, B> withNoNulls(p1: A?, p2: B?, function: (p1: A, p2: B) -> R): R? = p1?.let { p2?.let { function.invoke(p1, p2) } }
fun <R, A, B, C> withNoNulls(p1: A?, p2: B?, p3: C?, function: (p1: A, p2: B, p3: C) -> R): R? = p1?.let { p2?.let { p3?.let { function.invoke(p1, p2, p3) } } }
fun <R, A, B, C, D> withNoNulls(p1: A?, p2: B?, p3: C?, p4: D?, function: (p1: A, p2: B, p3: C, p4: D) -> R): R? = p1?.let { p2?.let { p3?.let { p4?.let { function.invoke(p1, p2, p3, p4) } } } }
fun <R, A, B, C, D, E> withNoNulls(p1: A?, p2: B?, p3: C?, p4: D?, p5: E?, function: (p1: A, p2: B, p3: C, p4: D, p5: E) -> R): R? = p1?.let { p2?.let { p3?.let { p4?.let { p5?.let { function.invoke(p1, p2, p3, p4, p5) } } } } }

তারপরে আমি এটি এর মতো ব্যবহার করব:

withNoNulls("hello", "world", Throwable("error")) { p1, p2, p3 ->
    p3.printStackTrace()
    p1.plus(" ").plus(p2)
}?.let {
    Log.d("TAG", it)
} ?: throw Exception("One or more parameters was null")

এর সাথে সুস্পষ্ট সমস্যাটি হ'ল আমাকে যে প্রতিটি কেস (ভেরিয়েবলের সংখ্যা) প্রয়োজন তার জন্য আমাকে একটি ফাংশন সংজ্ঞায়িত করতে হবে তবে কমপক্ষে আমি মনে করি কোডগুলি সেগুলি ব্যবহার করার সময় পরিষ্কার দেখাচ্ছে।



1

আমি প্রত্যাশিত উত্তরটি কিছুটা আপগ্রেড করেছি:

inline fun <T: Any, R: Any> ifLet(vararg elements: T?, closure: (List<T>) -> R): R? {
    return if (elements.all { it != null }) {
        closure(elements.filterNotNull())
    } else null
}

এটি এটি সম্ভব করে তোলে:

iflet("first", "sconed") {
    // do somehing
} ?: run {
    // do this if one of the params are null
}

এটি দুর্দান্ত, তবে পরামিতিগুলির নাম দেওয়া হয়নি এবং প্রকারটি ভাগ করা উচিত।
ড্যানিয়েল গোমেজ রিকো

0

যে কোনও মানের মান পরীক্ষা করার জন্য আপনি এটি ব্যবহার করতে পারেন:

    fun checkNulls(vararg elements: Any?, block: (Array<*>) -> Unit) {
        elements.forEach { if (it == null) return }
        block(elements.requireNoNulls())
    }

এবং এটি এর মতো ব্যবহার করা হবে:

    val dada: String? = null
    val dede = "1"

    checkNulls(dada, dede) { strings ->

    }

ব্লকে প্রেরিত উপাদানগুলি ওয়াইল্ডকার্ড ব্যবহার করছে, আপনি মানগুলি অ্যাক্সেস করতে চান তবে আপনার প্রকারগুলি পরীক্ষা করতে হবে, যদি আপনাকে কেবল একটি প্রকারের প্রয়োজন হয় তবে আপনি এটি জেনারিকগুলিতে রূপান্তর করতে পারেন

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.