সুইফটে এমনকি সুবিধামত কীওয়ার্ডটি কেন প্রয়োজন?


132

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

class Person {
    var name:String

    init(name: String) {
        self.name = name
    }

    init() {
        self.name = "John"
    }
}

সুতরাং কেন convenienceকীওয়ার্ডের অস্তিত্ব থাকবে? নিম্নলিখিতগুলি কি যথেষ্ট উন্নত করে?

class Person {
    var name:String

    init(name: String) {
        self.name = name
    }

    convenience init() {
        self.init(name: "John")
    }
}

13
ডকুমেন্টেশনে কেবল এটি পড়ে ছিল এবং এটি সম্পর্কে বিভ্রান্ত হয়ে পড়েছিল। : /
বোয়দকান

উত্তর:


235

বিদ্যমান উত্তরগুলি কেবল convenienceগল্পের অর্ধেকটি বলে । গল্পের অন্যান্য অর্ধেক, অর্ধেকটি বিদ্যমান উত্তরগুলির কোনওটিই কভার করে না, ডেসমন্ড মন্তব্যগুলিতে পোস্ট করেছেন এমন প্রশ্নের উত্তর দেয়:

সুইফট আমাকে কেন convenienceআমার আরম্ভকারী সংঘের সামনে রাখার জন্য বাধ্য করবে কারণ আমাকে self.initএটির কল করা দরকার ? `

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

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

স্পষ্টতই, একটি অবিচ্ছিন্ন উদাহরণ ভেরিয়েবল এমন কোনও তাত্ক্ষণিক ভেরিয়েবল যা ডিফল্ট মান দেওয়া হয় না (বিকল্পগুলি এবং স্পষ্টতভাবে মোড়কযুক্ত বিকল্পগুলি স্বয়ংক্রিয়ভাবে একটি ডিফল্ট মান ধরে নেয় nil)।

সুতরাং এই ক্ষেত্রে:

class Foo {
    var a: Int
}

aএকটি অবিবেচনা উদাহরণ পরিবর্তনশীল। আমরা aএকটি ডিফল্ট মান না দিলে এটি সংকলন করবে না :

class Foo {
    var a: Int = 0
}

বা aএকটি ইনিশিয়াল পদ্ধতিতে সূচনা:

class Foo {
    var a: Int

    init(a: Int) {
        self.a = a
    }
}

এখন দেখা যাক আমরা সাবক্লাস করলে কী হয় Foo?

class Bar: Foo {
    var b: Int

    init(a: Int, b: Int) {
        self.b = b
        super.init(a: a)
    }
}

রাইট? আমরা একটি ভেরিয়েবল যুক্ত করেছি, এবং আমরা একটি মান সেট করতে একটি প্রাথমিককরণ যুক্ত করেছি bযাতে এটি সংকলিত হয়। আপনি কোন ভাষা থেকে আসছেন তার উপর নির্ভর করে আপনি আশা করতে পারেন যে Barউত্তরাধিকার Fooসূচনার উত্তরাধিকার সূত্রে প্রাপ্ত হয়েছে init(a: Int)। তবে তা হয় না। এবং এটা কিভাবে পারে? কেমন করে Foo'র init(a: Int)জানেন কিভাবে একটি মান নির্ধারণ করতে bযে পরিবর্তনশীল Barযোগ? এটা হয় না। সুতরাং আমরা Barকোনও ইনিশিয়ালাইজার দিয়ে কোনও সূচনা দিতে পারি না যা আমাদের সমস্ত মানকে আরম্ভ করতে পারে না।

এর কোনটির সাথে কী সম্পর্ক আছে convenience?

আচ্ছা, আসুন আরম্ভের উত্তরাধিকারের নিয়মগুলি দেখুন :

বিধি 1

যদি আপনার সাবক্লাস কোনও মনোনীত প্রারম্ভিক সংজ্ঞা দেয় না, এটি স্বয়ংক্রিয়ভাবে তার সমস্ত সুপারক্লাস মনোনীত প্রারম্ভিকদের উত্তরাধিকার সূত্রে প্রাপ্ত হয়।

বিধি 2

যদি আপনার সাবক্লাস তার সুপারক্লাস নির্ধারিত প্রাথমিক সকলের একটি বাস্তবায়ন সরবরাহ করে — হয় নিয়ম 1 অনুযায়ী উত্তরাধিকার সূত্রে বা তার সংজ্ঞা হিসাবে অংশ হিসাবে একটি কাস্টম বাস্তবায়ন সরবরাহ করে — তবে এটি স্বয়ংক্রিয়ভাবে সমস্ত সুপারক্লাস সুবিধার্থে প্রাথমিকভাবে উত্তরাধিকার সূত্রে প্রাপ্ত হয়।

বিধি 2 নোটিশে, সুবিধামত প্রাথমিকদের উল্লেখ রয়েছে।

তাই কি convenienceশব্দ নেই করি আমাদের কাছে যা initializers ইঙ্গিত উত্তরাধিকারসূত্রে যাবে উপশ্রেণী যে ডিফল্ট মান ছাড়া অ্যাড উদাহরণস্বরূপ ভেরিয়েবল।

এই উদাহরণ Baseবর্গ গ্রহণ করা যাক :

class Base {
    let a: Int
    let b: Int

    init(a: Int, b: Int) {
        self.a = a
        self.b = b
    }

    convenience init() {
        self.init(a: 0, b: 0)
    }

    convenience init(a: Int) {
        self.init(a: a, b: 0)
    }

    convenience init(b: Int) {
        self.init(a: 0, b: b)
    }
}

আমাদের তিনটি আছে লক্ষ্য করুন convenience এখানে সূচনা রয়েছে। এর অর্থ আমাদের উত্তরাধিকারসূত্রে প্রাপ্ত তিনটি সূচনা রয়েছে। এবং আমাদের একটি মনোনীত ইনিশিয়ালাইজার রয়েছে (একটি মনোনীত প্রারম্ভকালীন কেবল কোনও প্রাথমিক সূচক যা কোনও সুবিধাপূর্ণ আরম্ভকারী নয়)।

আমরা বেস শ্রেণীর উদাহরণগুলি চারটি বিভিন্ন উপায়ে ইনস্ট্যান্ট করতে পারি:

এখানে চিত্র বর্ণনা লিখুন

সুতরাং, একটি সাবক্লাস তৈরি করা যাক।

class NonInheritor: Base {
    let c: Int

    init(a: Int, b: Int, c: Int) {
        self.c = c
        super.init(a: a, b: b)
    }
}

আমরা উত্তরাধিকার সূত্রে পেয়েছি Base। আমরা আমাদের নিজস্ব ইনস্টল ভেরিয়েবল যুক্ত করেছি এবং আমরা এটিকে একটি ডিফল্ট মান দিতে পারি নি, তাই আমাদের অবশ্যই নিজের নিজস্ব আরম্ভকারীগুলি যুক্ত করতে হবে। আমরা এক যোগ init(a: Int, b: Int, c: Int), কিন্তু এটা মেলে না স্বাক্ষর Baseবর্গ সূচনাকারী মনোনীত আছে: init(a: Int, b: Int)। এর অর্থ, আমরা কোনও প্রারম্ভিককে উত্তরাধিকার সূত্রে নিচ্ছি না Base:

এখানে চিত্র বর্ণনা লিখুন

সুতরাং, যদি আমরা উত্তরাধিকার সূত্রে প্রাপ্ত হই তবে কী হবে Baseতবে আমরা এগিয়ে গিয়ে একটি ইনিশিয়ালাইজার প্রয়োগ করেছি যা থেকে মনোনীত প্রাথমিকের সাথে মিল রয়েছে Base?

class Inheritor: Base {
    let c: Int

    init(a: Int, b: Int, c: Int) {
        self.c = c
        super.init(a: a, b: b)
    }

    convenience override init(a: Int, b: Int) {
        self.init(a: a, b: b, c: 0)
    }
}

এখন, আমরা এই ক্লাসে সরাসরি দুটি বাস্তবায়নকারীকে প্রয়োগ করেছি, কারণ আমরা একটি প্রাথমিক শিক্ষাকারীর সাথে ম্যাচিং Baseক্লাসের মনোনীত ইনিশিয়ালাইজার প্রয়োগ করেছি , আমরা Baseক্লাসের সমস্ত আরম্ভকারীদের উত্তরাধিকারী হতে পারি convenience:

এখানে চিত্র বর্ণনা লিখুন

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


16
একমাত্র উত্তর যা আসলে প্রশ্নের উত্তর দেয় এবং দস্তাবেজগুলি অনুসরণ করে। আমি যদি ওপি থাকি তবে আমি তা মেনে নেব।
ফ্রি ডাকনাম

12
আপনার একটি বই লেখা উচিত;)
কুলবিট

1
@ এসএলএন এই উত্তরটি কীভাবে সুইফট ইনিশিয়ালাইজারের উত্তরাধিকার কাজ করে তা নিয়ে অনেক কিছু জুড়ে।
nhgrif

1
@ এসএলএন কারণ একটি বার তৈরি করা শুরুর কারণ init(a: Int)হবে bনা।
ইয়ান ওয়ারবার্টন

2
@ ইয়ানবারবার্টন আমি এই বিশেষ "কেন" এর উত্তর জানি না। আপনার মন্তব্যের দ্বিতীয় অংশে আপনার যুক্তিটি আমার কাছে মনে হয়েছে ঠিকই, তবে ডকুমেন্টেশনে স্পষ্টভাবে বলা হয়েছে যে এটি কীভাবে কাজ করে এবং আপনি কোনও খেলার মাঠে যা জিজ্ঞাসা করছেন তার একটি উদাহরণ ছড়িয়ে দেওয়া ডকুমেন্টযুক্ত আচরণের সাথে মেলে তা নিশ্চিত করে।
nhgrif

9

বেশিরভাগ স্পষ্টতা। আপনার কাছ থেকে দ্বিতীয় উদাহরণ,

init(name: String) {
    self.name = name
}

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

var gender: Gender?

যেখানে লিঙ্গ একটি এনাম

enum Gender {
  case Male, Female
}

আপনার মত সুবিধামত প্রাথমিক হতে পারে

convenience init(maleWithName: String) {
   self.init(name: name)
   gender = .Male
}

convenience init(femaleWithName: String) {
   self.init(name: name)
   gender = .Female
}

সুবিধাপ্রাপ্তির শুরুতে তাদের অবশ্যই মনোনীত বা প্রয়োজনীয় প্রারম্ভিককে কল করতে হবে। যদি আপনার ক্লাসটি একটি সাবক্লাস হয় তবে অবশ্যই এটির সূচনাতে কল করতে হবে super.init()


2
সুতরাং এটি convenienceকীওয়ার্ড ছাড়াই একাধিক প্রারম্ভিকগুলির সাথে আমি কী করার চেষ্টা করছি সংকলকটির জন্য এটি সম্পূর্ণরূপে সুস্পষ্ট হবে তবে সুইফট এখনও এটি সম্পর্কে বাগড হবে। অ্যাপল =) এর কাছ থেকে আমি যে ধরনের সরলতার প্রত্যাশা করছিলাম তা নয়
ডেসমন্ড হিউম

2
এই উত্তর কিছুই উত্তর দেয় না। আপনি "স্পষ্টতা" বলেছিলেন, তবে কীভাবে এটি কিছু পরিষ্কার করে দেয় তা ব্যাখ্যা করেননি।
রোবো রোবোক

7

ঠিক আছে, আমার মনে প্রথম জিনিসটি আসে কোড কোড এবং পাঠযোগ্যতার জন্য এটি শ্রেণীর উত্তরাধিকারে ব্যবহৃত হয়। আপনার Personক্লাসের সাথে চালিয়ে যাওয়া , এই জাতীয় দৃশ্যের কথা ভাবুন

class Person{
    var name: String
    init(name: String){
        self.name = name
    }

    convenience init(){
        self.init(name: "Unknown")
    }
}


class Employee: Person{
    var salary: Double
    init(name:String, salary:Double){
        self.salary = salary
        super.init(name: name)
    }

    override convenience init(name: String) {
        self.init(name:name, salary: 0)
    }
}

let employee1 = Employee() // {{name "Unknown"} salary 0}
let john = Employee(name: "John") // {{name "John"} salary 0}
let jane = Employee(name: "Jane", salary: 700) // {{name "Jane"} salary 700}

সুবিধামত ইনিশিয়ালাইজারের সাহায্যে আমি Employee()কোনও মূল্য ছাড়াই একটি অবজেক্ট তৈরি করতে সক্ষম হয়েছি , সুতরাং শব্দটিconvenience


2
convenienceকীওয়ার্ডগুলি সরিয়ে নিয়ে যাওয়ার সাথে সাথে , সুইফট কি একই রকম আচরণ করার জন্য পর্যাপ্ত তথ্য পাবে না?
ডেসমন্ড হিউম

না, আপনি convenienceকীওয়ার্ডটি সরিয়ে ফেললে আপনি Employeeকোনও যুক্তি ছাড়াই অবজেক্টটি আরম্ভ করতে পারবেন না ।
u54r

বিশেষত, কলিং Employee()কল করে (উত্তরাধিকারসূত্রে, কারণে convenience) আরম্ভকারীকে init(), যা কল করে self.init(name: "Unknown")init(name: String)এছাড়াও এর জন্য একটি সুবিধাপূর্ণ প্রাথমিককরণকে Employee, মনোনীত ইনিশিয়ালাইজার বলে।
বলপয়েন্টবেন

1

অন্যান্য ব্যবহারকারীরা এখানে যে বিষয়গুলি ব্যাখ্যা করেছেন সেগুলি ছাড়াও আমার বোঝার বিট।

আমি সুবিধামত আরম্ভকারী এবং এক্সটেনশনের মধ্যে সংযোগটি দৃ strongly়ভাবে অনুভব করি। আমার পক্ষে সুবিধামত প্রাথমিক শিক্ষাগুলি সর্বাধিক দরকারী যখন আমি কোনও বিদ্যমান শ্রেণীর সূচনা (বেশিরভাগ ক্ষেত্রে এটি সংক্ষিপ্ত বা সহজ করে তুলি) শুরু করতে চাই।

উদাহরণস্বরূপ কিছু তৃতীয় পক্ষের শ্রেণি যা আপনি ব্যবহার করেন তার initচারটি পরামিতি রয়েছে তবে আপনার প্রয়োগে সর্বশেষ দুটিটির মান একই রকম। আরও টাইপ করা এড়াতে এবং আপনার কোডটি পরিষ্কার করার জন্য আপনি convenience initকেবল দুটি প্যারামিটার সহ একটি সংজ্ঞায়িত করতে পারেন এবং এর অভ্যন্তরে self.initডিফল্ট মানগুলির সাথে শেষ থেকে পরামিতিগুলির কল করতে পারেন।


1
সুইফ্ট আমাকে কেন convenienceআমার প্রারম্ভকালের সামনে রাখার জন্য বাধ্য করবে কারণ আমাকে self.initএটির কল করার দরকার ছিল ? এটিকে রিডান্ট্যান্ট এবং কিছুটা অসুবিধাগ্রস্থ বলে মনে হচ্ছে।
ডেসমন্ড হিউম

1

সুইফট ২.১ ডকুমেন্টেশন অনুসারে , convenienceআরম্ভকারীদের কিছু নির্দিষ্ট নিয়ম মেনে চলতে হবে:

  1. একটি convenienceইনিশিয়ালাইজার কেবল সুপার ক্লাসে নয়, কেবল একই ক্লাসে ইনটালাইজারদের কল করতে পারে (কেবল পার না, আপ নয়)

  2. একটি convenienceইনিশিয়ালাইজারকে চেইনের কোথাও একটি মনোনীত ইনিশিয়ালাইজার কল করতে হবে

  3. একটি convenienceসূচনাকারী পরিবর্তন করতে পারবেন না কোন যেহেতু একটি মনোনীত সূচনাকারী - সম্পত্তি আগেই অন্য সূচনাকারী ডেকেছেন হয়েছে আরেকটি সূচনাকারী কল করার আগে বৈশিষ্ট্য যে বর্তমান বর্গ দ্বারা চালু করা হয় আরম্ভ।

convenienceকীওয়ার্ডটি ব্যবহার করে , সুইফ্ট সংকলক জানে যে এটি এই শর্তগুলির জন্য পরীক্ষা করতে হবে - অন্যথায় এটি পারেনি।


যুক্তিযুক্তভাবে, সংকলক সম্ভবত convenienceকীওয়ার্ড ছাড়াই এটিকে বাছাই করতে পারে ।
nhgrif

তদুপরি, আপনার তৃতীয় পয়েন্টটি বিভ্রান্তিকর। একটি সুবিধাপূর্ণ আরম্ভকারী কেবল বৈশিষ্ট্য পরিবর্তন করতে পারে (এবং letবৈশিষ্ট্যগুলি পরিবর্তন করতে পারে না )। এটি বৈশিষ্ট্য আরম্ভ করতে পারে না। একটি মনোনীত ইনিশিয়ালাইজারের কাছে কল করার আগে একটি প্রবর্তিত প্রাথমিকের সমস্ত প্রবর্তিত বৈশিষ্ট্য সূচনা করার দায়িত্ব রয়েছে super
nhgrif

1
কমপক্ষে সুবিধার কীওয়ার্ডটি এটি বিকাশকারীকে পরিষ্কার করে দেয়, এটি পঠনযোগ্যতাও গণনা করা হয় (প্লাস বিকাশকারীদের প্রত্যাশার বিপরীতে ইনিশিয়ালাইজারটি পরীক্ষা করা)। আপনার দ্বিতীয় বিষয়টি একটি ভাল, আমি সেই অনুযায়ী আমার উত্তরটি পরিবর্তন করেছি।
TheEye

1

একটি শ্রেণিতে একাধিক মনোনীত প্রারম্ভিক থাকতে পারে। সুবিধাপূর্ণ আরম্ভকারী হ'ল একটি মাধ্যমিক সূচক যা অবশ্যই একই বর্গের একজন মনোনীত প্রারম্ভিককে কল করতে পারে।

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