কীভাবে সুইফট @ অটোক্লোজার ব্যবহার করবেন


148

আমি সুইফটে লিখার সময় লক্ষ্য করেছি assertযে প্রথম মানটি টাইপ করা আছে

@autoclosure() -> Bool

একটি ওভারলোড পদ্ধতি সঙ্গে একটি জেনেরিক ফিরে যাওয়ার Tমাধ্যমে মান, পরীক্ষা অস্তিত্বের LogicValue protocol

তবে হাতে থাকা প্রশ্নের সাথে কঠোরভাবে লেগে থাকা। এটি @autoclosureপ্রত্যাবর্তন করে এমনটি চায় যা প্রত্যাবর্তন করে Bool

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

assert({() -> Bool in return false}(), "No user has been set", file: __FILE__, line: __LINE__)

তবে সহজভাবে একটি বুল পাস করার কাজ করে:

assert(false, "No user has been set", file: __FILE__, line: __LINE__)

তাই কি ঘটছে? কী @autoclosure?

সম্পাদনা: @auto_closure নতুন নামকরণ করা হয়েছিল@autoclosure

উত্তর:


269

এমন একটি ফাংশন বিবেচনা করুন যা একটি যুক্তি গ্রহণ করে, একটি সাধারণ বন্ধ যা কোনও যুক্তি নেয় না:

func f(pred: () -> Bool) {
    if pred() {
        print("It's true")
    }
}

এই ফাংশনটি কল করতে, আমাদের একটি বন্ধে পাস করতে হবে

f(pred: {2 > 1})
// "It's true"

আমরা যদি ধনুর্বন্ধনী বাদ দিই, তবে আমরা একটি এক্সপ্রেশন দিয়ে যাচ্ছি এবং এটি একটি ত্রুটি:

f(pred: 2 > 1)
// error: '>' produces 'Bool', not the expected contextual result type '() -> Bool'

@autoclosureঅভিব্যক্তির চারপাশে একটি স্বয়ংক্রিয় বন্ধকরণ তৈরি করে। সুতরাং কলার যখন মত প্রকাশ করে তখন 2 > 1এটি স্বয়ংক্রিয়ভাবে বন্ধ হওয়ার {2 > 1}আগে আবদ্ধ হওয়ার আগে তা হয়ে যায় f। সুতরাং আমরা যদি ফাংশনটিতে এটি প্রয়োগ করি f:

func f(pred: @autoclosure () -> Bool) {
    if pred() {
        print("It's true")
    }
}

f(pred: 2 > 1)
// It's true

সুতরাং এটি বন্ধে মোড়ানোর প্রয়োজন ছাড়াই কেবল একটি অভিব্যক্তি নিয়ে কাজ করে।


2
আসলে শেষ এক, কাজ করে না। এটি হওয়া উচিতf({2 >1}())
রুই পেরেস

@ জোলফিশার আমি @ জ্যাকিবয়ের মতো একই জিনিসটি দেখছি। কলিং f(2 > 1)কাজ করে। কলিং f({2 > 1})ব্যর্থ হয় error: function produces expected type 'Bool'; did you mean to call it with '()'?। আমি এটি খেলার মাঠে এবং সুইফট আরপিএল দিয়ে পরীক্ষা করেছি।
ওলে বেগম্যান

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

3
তারা যে কারণটি করেছিল এটি সম্পর্কে একটি ব্লগ পোস্ট রয়েছে
app

5
দুর্দান্ত ব্যাখ্যা। আরও মনে রাখবেন যে সুইফট ১.২ এ 'অটোক্লোজার' এখন প্যারামিটার ঘোষণার একটি বৈশিষ্ট্য, তাই এটিfunc f(@autoclosure pred: () -> Bool)
মাসা

30

এখানে একটি ব্যবহারিক উদাহরণ - আমার printওভাররাইড (এটি হ'ল সুইফট 3):

func print(_ item: @autoclosure () -> Any, separator: String = " ", terminator: String = "\n") {
    #if DEBUG
    Swift.print(item(), separator:separator, terminator: terminator)
    #endif
}

আপনি যখন বলবেন print(myExpensiveFunction()), আমার printওভাররাইড সুইফটকে ওভাররাইড করে printএবং ডাকা হয়। myExpensiveFunction()এইভাবে একটি বন্ধে আবৃত হয় এবং মূল্যায়ন করা হয় না । আমরা যদি রিলিজ মোডে থাকি তবে এটি কখনই মূল্যায়ন করা item()হবে না , কারণ তাকে ডাকা হবে না। সুতরাং আমাদের কাছে এর একটি সংস্করণ প্রকাশিত printমোডে এর তর্কগুলি মূল্যায়ন করে না।


আমি পার্টিতে দেরি করছি, তবে মূল্যায়নের প্রভাব কী myExpensiveFunction()? যদি অটোক্লোজার ব্যবহার না করে আপনি প্রিন্ট করতে ফাংশনটি পাস করেন তবে print(myExpensiveFunction)কী প্রভাব পড়বে? ধন্যবাদ।
crom87

11

দস্তাবেজগুলি থেকে অটো_সমাপ্তির বিবরণ:

আপনি একটি ফাংশন ধরণের অটো_ক্লোজার বৈশিষ্ট্য প্রয়োগ করতে পারেন যার একটি প্যারামিটার ধরণের () রয়েছে এবং এটি একটি এক্সপ্রেশনের ধরণটি ফেরত দেয় (প্রকারের বৈশিষ্ট্যগুলি দেখুন)। একটি অটোক্লোজার ফাংশনটি এক্সপ্রেশনটির পরিবর্তে নির্দিষ্ট অভিব্যক্তির উপর একটি অন্তর্নিহিত বন্ধকে ক্যাপচার করে। নীচের উদাহরণটি খুব সাধারণ দাবী ফাংশনটি সংজ্ঞায়িত করতে অটো_ক্লোজার বৈশিষ্ট্যটি ব্যবহার করে:

এবং এটির সাথে আপেল ব্যবহারের উদাহরণ এখানে।

func simpleAssert(condition: @auto_closure () -> Bool, message: String) {
    if !condition() {
        println(message)
    }
}
let testNumber = 5
simpleAssert(testNumber % 2 == 0, "testNumber isn't an even number.")

মূলত এর অর্থ হ'ল আপনি একটি বুলিয়ান এক্সপ্রেশনটি বন্ধের পরিবর্তে প্রথম যুক্তি হিসাবে পাস করুন এবং এটি স্বয়ংক্রিয়ভাবে আপনার জন্য এটি বন্ধ করে দেয়। এজন্য আপনি পদ্ধতিতে মিথ্যা পাস করতে পারেন কারণ এটি একটি বুলিয়ান অভিব্যক্তি, তবে কোনও বন্ধকরণ পাস করতে পারে না।


15
নোট করুন যে আপনার @auto_closureএখানে আসলে ব্যবহারের দরকার নেই। কোড এটা ছাড়া কাজ করে জরিমানা: func simpleAssert(condition: Bool, message: String) { if !condition { println(message) } }। ব্যবহারের @auto_closureযখন আপনি বারবার একটি আর্গুমেন্ট নির্ণয় করা প্রয়োজন (যেমন, আপনি যদি একটি বাস্তবায়নের হয়েছে যদি while-একটি ফাংশন) অথবা আপনি একটি আর্গুমেন্ট (যেমন, স্বল্প-পরিক্রমার যদি আপনি বাস্তবায়ন হয়েছে বিলম্ব মূল্যায়ন প্রয়োজন &&)।
নাথান

1
@ নাথান হাই, নাথান আপনি কি দয়া করে আমাকে পছন্দ মতো autoclosureকোনও whileফাংশন ব্যবহারের জন্য একটি নমুনা উদ্ধৃত করতে পারেন ? আমি তা খুঁজে বের করতে পারে বলে মনে হয় না। আগাম ধন্যবাদ।
আনহিলিগ

@ কনর আপনি আপনার উত্তরটি সুইফট ৩
জারোরা

4

এটি https://airspeedvelocity.net/2014/06/28/extending-the-swift-language-is-cool-but-be-careful/ এর একটি দরকারী কেস দেখায়@autoclosure

এখন, শর্তসাপেক্ষ এক্সপ্রেশনটি প্রথম প্যারামিটার হিসাবে পাস হওয়া অবধি স্বয়ংক্রিয়ভাবে একটি ক্লোজার এক্সপ্রেশনে আবৃত হবে এবং প্রতিবার লুপের চারদিকে কল করা যেতে পারে

func until<L: LogicValue>(pred: @auto_closure ()->L, block: ()->()) {
    while !pred() {
        block()
    }
}

// doSomething until condition becomes true
until(condition) {
    doSomething()
}

2

এটি ক্লোজার কলগুলিতে কোঁকড়া ধনুর্বন্ধনী থেকে মুক্তি পাওয়ার সহজ উপায়, সাধারণ উদাহরণ:

    let nonAutoClosure = { (arg1: () -> Bool) -> Void in }
    let non = nonAutoClosure( { 2 > 1} )

    let autoClosure = { (arg1: @autoclosure () -> Bool) -> Void in }
    var auto = autoClosure( 2 > 1 ) // notice curly braces omitted

0

@autoclosureএকটি ফাংশন প্যারামিটার যা কোনও রান্না করা ফাংশন (বা প্রত্যাবর্তিত প্রকার) closureগ্রহণ করে এরই মধ্যে একজন সাধারণ একটি কাঁচা ফাংশন গ্রহণ করে

  • @ অটোক্লোজার আর্গুমেন্ট ধরণের পরামিতি অবশ্যই '()' হওয়া উচিত
    @autoclosure ()
  • @ অটোক্লোজার কেবলমাত্র উপযুক্ত টাইপযুক্ত কোনও ক্রিয়াকলাপ গ্রহণ করে
  • বন্ধের ফলাফলটি চাহিদা দ্বারা গণনা করা হয়

আসুন উদাহরণটি একবার দেখুন

func testClosures() {

    //closures
    XCTAssertEqual("fooWithClosure0 foo0", fooWithClosure0(p: foo0))
    XCTAssertEqual("fooWithClosure1 foo1 1", fooWithClosure1(p: foo1))
    XCTAssertEqual("fooWithClosure2 foo2 3", fooWithClosure2(p: foo2))

    XCTAssertEqual("fooWithClosure2 foo2 3", fooWithClosure2(p: { (i1, i2) -> String in
        return "fooWithClosure2 " + "foo2 " + String(i1 + i2)
    }))

    //@autoclosure
    XCTAssertEqual("fooWithAutoClosure HelloWorld", fooWithAutoClosure(a: "HelloWorld"))

    XCTAssertEqual("fooWithAutoClosure foo0", fooWithAutoClosure(a: foo0()))
    XCTAssertEqual("fooWithAutoClosure foo1 1", fooWithAutoClosure(a: foo1(i1: 1)))
    XCTAssertEqual("fooWithAutoClosure foo2 3", fooWithAutoClosure(a: foo2(i1: 1, i2: 2)))

}

//functions block
func foo0() -> String {
    return "foo0"
}

func foo1(i1: Int) -> String {
    return "foo1 " + String(i1)
}

func foo2(i1: Int, i2: Int) -> String {
    return "foo2 " + String(i1 + i2)
}

//closures block
func fooWithClosure0(p: () -> String) -> String {
    return "fooWithClosure0 " + p()
}

func fooWithClosure1(p: (Int) -> String) -> String {
    return "fooWithClosure1 " + p(1)
}

func fooWithClosure2(p: (Int, Int) -> String) -> String {
    return "fooWithClosure2 " + p(1, 2)
}

//@autoclosure
func fooWithAutoClosure(a: @autoclosure () -> String) -> String {
    return "fooWithAutoClosure " + a()
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.