স্পষ্টভাবে একটি জেনেরিক ফাংশন বিশেষজ্ঞ করতে পারে না


92

আমি নিম্নলিখিত কোড সহ সমস্যা আছে:

func generic1<T>(name : String){
}

func generic2<T>(name : String){
     generic1<T>(name)
}

generic1 (নাম) কম্পাইলার ত্রুটির RESULT "স্পষ্টভাবে একটি জেনেরিক ফাংশন বিশেষজ্ঞ যাবে না"

এই ত্রুটি এড়ানোর কোনও উপায় কি? আমি জেনেরিক 1 ফাংশনের স্বাক্ষর পরিবর্তন করতে পারি না, সুতরাং এটি (স্ট্রিং) -> শূন্য হওয়া উচিত


4
প্রসঙ্গের জন্য অনুমান করা যায় না, তবে জেনেরিক টাইপটি এখানে ব্যবহার করার কী আছে? যদি জেনেরিক প্রকারটি কেবল অভ্যন্তরীণভাবে ব্যবহৃত হয় তবে আপনাকে ফাংশনের মূল অংশের মধ্যে প্রকারটি নির্দিষ্ট করতে হবে।
কিরস্টেইন

প্লেসোল্ডার ধরণটি কি Tআদৌ ব্যবহৃত হয় generic1()? আপনি কীভাবে সেই ফাংশনটিকে কল করবেন , যাতে সংকলকটি ধরণটি নির্ধারণ করতে পারে?
মার্টিন আর

4
আমি আশা করি যে জেনেটিক 1 <ব্লা ক্লাস> ("সোমার স্ট্রিং") এর মতো ফাংশন কল করার কিছু উপায় আছে
গ্রেইসফ

4
জেনেরিকস কেবলমাত্র সে ক্ষেত্রে নয় যখন সংকলক প্রসঙ্গটি অনুমান করতে পারে। স্পষ্টভাবে ফাংশন বিশেষীকরণ কোডের অন্যান্য অংশ infered করার অনুমতি দেয়। উদাহরণস্বরূপ: func foo<T>() -> T { ... }এটি tটাইপ Tএবং রিটার্নের সাথে কিছু করে t। স্পষ্টত বিশেষায়িতকরণ inোকানো হতে Tদেয় । আমি আশা করি এইভাবেও ফাংশনগুলি কল করার কোনও উপায় ছিল। সি # এটির অনুমতি দেয়t1var t1 = foo<T>()
nacho4d

4
আমি শুধু এই মধ্যে দৌড়ে এসেছি। যদি আপনি কোনও পরামিতি হিসাবে টাইপটি পাস করতে বাধ্য হন তবে জেনেরিক ফাংশন তৈরি করা শূন্য ধারণা তৈরি করে। এই ঠিক একটি বাগ হতে হবে ?!
নিক

উত্তর:


161

আমারও এই সমস্যা ছিল এবং আমি আমার মামলার জন্য একটি সমাধান খুঁজে পেয়েছি।

এই নিবন্ধে লেখক একই সমস্যা আছে

https://www.iphonelife.com/blog/31369/swift-programming-101- জেনারিকস- প্র্যাকটিকাল- গাইড

সুতরাং সমস্যাটি মনে হচ্ছে, যে সংকলকটি কোনওভাবে টি এর ধরণের অনুমান করা দরকার। তবে এটি কেবল জেনেরিক <টাইপ> (প্যারাম ...) ব্যবহার করার অনুমতি নেই।

সাধারণত, সংকলক টি প্যারামিটারের ধরণগুলি স্ক্যান করে টি এর ধরণের সন্ধান করতে পারে কারণ এখানেই অনেক ক্ষেত্রে টি ব্যবহৃত হয়।

আমার ক্ষেত্রে এটি কিছুটা আলাদা ছিল, কারণ আমার ফাংশনের রিটার্নের ধরনটি টি ছিল your আপনার ক্ষেত্রে মনে হয় আপনি আপনার ফাংশনে টি ব্যবহার করেন নি। আমার ধারণা আপনি উদাহরণ কোডটি সহজ করেছেন।

সুতরাং আমি নিম্নলিখিত ফাংশন আছে

func getProperty<T>( propertyID : String ) -> T

এবং উদাহরণস্বরূপ, ক্ষেত্রে

getProperty<Int>("countProperty")

সংকলকটি আমাকে ত্রুটি দেয়:

স্পষ্টভাবে একটি জেনেরিক ফাংশন বিশেষজ্ঞ করতে পারে না

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

var value : Int = getProperty("countProperty")

এইভাবে সংকলক জানে যে টি একটি পূর্ণসংখ্যা হতে হবে।

সুতরাং আমি মনে করি সামগ্রিকভাবে এর অর্থ হ'ল আপনি যদি জেনেরিক ফাংশন নির্দিষ্ট করে থাকেন তবে আপনাকে কমপক্ষে আপনার প্যারামিটারের ধরনগুলিতে বা কোনও রিটার্ন টাইপ হিসাবে টি ব্যবহার করতে হবে।


4
আমাকে এক টন সময় বাঁচিয়েছে। ধন্যবাদ.
ক্রিসারসন

4
যদি কোনও ফেরতের মূল্য না থাকে তবে কী করার উপায় আছে? অর্থাত্func updateProperty<T>( propertyID : String )
কাইল বাশুর

4
আমি দেখতে পাচ্ছি না কেন আপনি এটি করতে চান? যেহেতু আপনি কোনও কিছুই ফিরিয়ে দেন না, আপনার ফাংশনটি জেনেরিক হিসাবে ঘোষণা করার কোনও সুবিধা নেই।
থটচিফ

@ থটচিফের প্রচুর উপকার রয়েছে যেমন আপনি কীপথগুলি ব্যবহার করছেন / তৈরি করছেন, বা স্ট্রিং হিসাবে টাইপ নাম পেয়ে
যাচ্ছেন

দুর্দান্ত উত্তর ধন্যবাদ। আমি আশা করি let value = foo() as? Typeএটি এর সাথে কাজ করবে যাতে এটি ifguard
একটিতে

54

সুইফট 5

সাধারণত জেনেরিক ফাংশন সংজ্ঞায়িত করার বিভিন্ন উপায় রয়েছে। তবে সেগুলি শর্তের ভিত্তিতে যা Tঅবশ্যই একটি parameter, বা এ হিসাবে ব্যবহার করা উচিত return type

extension UIViewController {
    class func doSomething<T: UIView>() -> T {
        return T()
    }

    class func doSomethingElse<T: UIView>(value: T) {
        // Note: value is a instance of T
    }

    class func doLastThing<T: UIView>(value: T.Type) {
        // Note: value is a MetaType of T
    }
}

এর পরে, Tকল করার সময় আমাদের অবশ্যই সরবরাহ করতে হবে ।

let result = UIViewController.doSomething() as UIImageView // Define `T` by casting, as UIImageView
let result: UILabel = UIViewController.doSomething() // Define `T` with property type, as UILabel
UIViewController.doSomethingElse(value: UIButton()) // Define `T` with parameter type, as UIButton
UIViewController.doLastThing(value: UITextView.self) // Define `T` with parameter type, as UITextView

রেফ:

  1. http://austinzheng.com/2015/01/02/swift-generics-pt-1/
  2. https://dispatchswift.com/type-constraints-for-generics-in-swift-d6bf2f0dbbb2

সাধারণ সমস্যার দুর্দান্ত উত্তর ... যেহেতু এটি সমাধানের অনেকগুলি উপায় রয়েছে। আমি বুঝতে পেরেছি self.result = UIViewController.doSomething()যতক্ষণ আপনি সম্পত্তি ঘোষণার সময় সম্পত্তিটি টাইপ করেন ততক্ষণ তার নিজের কাজ করে।
teradyl

মহান উত্তর অনেক কিছুই ব্যাখ্যা।
ওখন ওকবায়ে

জাভা সুইফটে doLastThing<UITextView>()পরিণত হয় doLastThing(UITextView.self), যা ... সবচেয়ে খারাপ নয়, অন্তত। স্পষ্টভাবে জটিল ফলাফল টাইপ করার চেয়ে ভাল। কর্মক্ষেত্রের জন্য ধন্যবাদ।
এরহানিস

18

সমাধানটি ক্লাসের ধরণটিকে প্যারামিটার হিসাবে গ্রহণ করছে (জাভার মতো)

সংকলককে জানতে দিন যে তিনি কোন ধরণের যুক্তি হিসাবে ক্লাসটি পাস করছেন

extension UIViewController {
    func navigate<ControllerType: UIViewController>(_ dump: ControllerType.Type, id: String, before: ((ControllerType) -> Void)?){
        let controller = self.storyboard?.instantiateViewController(withIdentifier: id) as! ControllerType
        before?(controller)
        self.navigationController?.pushViewController(controller, animated: true)
    }
}

যেমন কল করুন:

self.navigate(UserDetailsViewController.self, id: "UserDetailsViewController", before: {
        controller in
        controller.user = self.notification.sender
    })

4
এটি গ্রহণযোগ্য উত্তরের চেয়ে দুর্দান্ত এবং অনেক ভাল। Pleaseতিহাসিক অংশটি সরাতে সম্পাদনা বিবেচনা করুন বা কমপক্ষে সমাধানের নীচে রাখুন। ধন্যবাদ!
ড্যান রোজনস্টার্ক

4
প্রতিক্রিয়ার জন্য :) @DanRosenstark ধন্যবাদ
Orkhan Alikhanov

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

@ স্মাইলবট আপনি বোঝাতে চান উদাহরণটি খারাপ বা পদ্ধতির?
ওর্খন আলিখানোভ

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

4

আপনার এখানে জেনেরিকের দরকার নেই যেহেতু আপনার কাছে স্ট্যাটিক প্রকার (প্যারামিটার হিসাবে স্ট্রিং) রয়েছে তবে আপনি যদি জেনেরিক ফাংশন কল করতে চান তবে নিম্নলিখিতটি করতে পারেন।

জেনেরিক পদ্ধতি ব্যবহার করে

func fetchObjectOrCreate<T: NSManagedObject>(type: T.Type) -> T {
    if let existing = fetchExisting(type) {
       return existing
    }
    else {
        return createNew(type)
    }
}

func fetchExisting<T: NSManagedObject>(type: T.Type) -> T {
    let entityName = NSStringFromClass(type)
     // Run query for entiry
} 

func createNew<T: NSManagedObject>(type: T.Type) -> T {
     let entityName = NSStringFromClass(type)
     // create entity with name
} 

জেনেরিক ক্লাস ব্যবহার করে (জেনেরিক হিসাবে কম নমনীয় কেবল উদাহরণস্বরূপ 1 ধরণের জন্য সংজ্ঞায়িত করা যেতে পারে)

class Foo<T> {

   func doStuff(text: String) -> T {
      return doOtherStuff(text)
   }

   func doOtherStuff(text: String) -> T {

   }  

}

let foo = Foo<Int>()
foo.doStuff("text")

3

আমি মনে করি যে আপনি জেনেরিক ফাংশন নির্দিষ্ট করার সময় আপনার টি জাতীয় কিছু পরামিতি নির্দিষ্ট করা উচিত:

func generic1<T>(parameter: T) {
    println("OK")
}

func generic2<T>(parameter: T) {
    generic1(parameter)
}

এবং যদি আপনি হ্যান্ডেল () পদ্ধতিতে কল করতে চান তবে আপনি প্রোটোকল লিখে এবং টির জন্য টাইপ সীমাবদ্ধতা নির্দিষ্ট করে এটি করতে পারেন:

protocol Example {
    func handle() -> String
}

extension String: Example {
    func handle() -> String {
        return "OK"
    }
}

func generic1<T: Example>(parameter: T) {
    println(parameter.handle())
}

func generic2<T: Example>(parameter: T) {
    generic1(parameter)
}

সুতরাং আপনি স্ট্রিং সহ এই জেনেরিক ফাংশনটিকে কল করতে পারেন:

generic2("Some")

এবং এটি সংকলন করা হবে


1

এখনও অবধি আমার ব্যক্তিগত সেরা অনুশীলন @ অর্খন-আলিখানোভের উত্তর ব্যবহার করেছে। আজ, যখন SwiftUI দিকে তাকিয়ে এবং কিভাবে .modifier()এবং ViewModifierবাস্তবায়িত হয়, আমি অন্য উপায় খুঁজে পেয়েছে (অথবা এটা আরো একটি কার্যসংক্রান্ত নেই?)

কেবলমাত্র দ্বিতীয় ফাংশনটি একটিতে মোড়ানো struct

উদাহরণ:

যদি এটি আপনাকে "জেনেরিক ফাংশন স্পষ্টভাবে বিশেষজ্ঞ করতে পারে না" দেয়

func generic2<T>(name: String){
     generic1<T>(name)
}

এই এক সাহায্য করতে পারে। এর ঘোষণাকে মোড়কে generic1একটি struct:

struct Generic1Struct<T> {
    func generic1(name: String) {## do, whatever it needs with T ##}
}

এবং এর সাথে কল করুন:

func generic2<T>(name : String){
     Generic1Struct<T>().generic1(name: name)
}

মন্তব্য:

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

0

আমার জেনেরিক ক্লাস ফাংশনটিতে আমার একই সমস্যা ছিল class func retrieveByKey<T: GrandLite>(key: String) -> T?

let a = retrieveByKey<Categories>(key: "abc")বিভাগগুলি গ্র্যান্ডলাইটের একটি সাবক্লাস যেখানে আমি এটি কল করতে পারি না ।

let a = Categories.retrieveByKey(key:"abc")গ্রেডলাইট ফিরিয়েছেন, বিভাগগুলি নয়। জেনেরিক ফাংশনগুলি তাদের কল করে এমন শ্রেণীর উপর ভিত্তি করে অনুমান করে না।

class func retrieveByKey<T: GrandLite>(aType: T, key: String>) -> T?let a = Categories.retrieveByKey(aType: Categories, key: "abc")বিভাগগুলি গ্র্যান্ডলাইটের সাবক্লাস হওয়া সত্ত্বেও বিভাগগুলি টাইপ করে গ্র্যান্ডলাইটে রূপান্তর করতে পারে না এমন সময় আমাকে ত্রুটি দিয়েছিল আমাকে যখন একটি ত্রুটি দিয়েছিল। যাহোক...

class func retrieveByKey<T: GrandLite>(aType: [T], key: String) -> T? করেনি কাজ যদি আমি চেষ্টা let a = Categories.retrieveByKey(aType: [Categories](), key: "abc")দৃশ্যত একটি উপশ্রেণী কাজ করে না এর একটি সুনির্দিষ্ট নিয়োগ, কিন্তু একটি অন্তর্নিহিত অন্য জেনেরিক টাইপ (অ্যারে) ব্যবহার assigment সুইফট 3 কাজ করে।


4
ত্রুটিটি ঠিক করতে, আপনাকে নিজেরাই রাখার পরিবর্তে aTypeউদাহরণ হিসাবে সরবরাহ করতে হবে। উদা: । আর একটি সমাধান সংজ্ঞায়িত করা হয় । তারপরে পদ্ধতিটি কল করুনTCategorieslet a = Categories.retrieveByKey(aType: Categories(), key: "abc")aType: T.Typelet a = Categories.retrieveByKey(aType: Categories.self, key: "abc")
nahung89
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.