সম্পর্কিত মানগুলির সাথে সুইফট এনামগুলির সাম্যতা কীভাবে পরীক্ষা করা যায়


192

আমি দুটি সুইফট এনাম মানের সমতা পরীক্ষা করতে চাই। উদাহরণ স্বরূপ:

enum SimpleToken {
    case Name(String)
    case Number(Int)
}
let t1 = SimpleToken.Number(123)
let t2 = SimpleToken.Number(123)
XCTAssert(t1 == t2)

তবে সংকলক সমতা প্রকাশটি সংকলন করবে না:

error: could not find an overload for '==' that accepts the supplied arguments
    XCTAssert(t1 == t2)
    ^~~~~~~~~~~~~~~~~~~

আমি কি সমতা অপারেটরের নিজের ওভারলোডটি সংজ্ঞায়িত করেছি? আমি আশা করছিলাম সুইফট সংকলকটি স্বয়ংক্রিয়ভাবে এটি পরিচালনা করবে, অনেকটা স্কালা এবং ওক্যামেলের মতো।


1
খোলার রাইডার: // 17408414 ( ওপেনারডার.মি / রেদার? id = 6404186140835840 )।
জে লাইস্কে

1
এসই -0185 এর কারণে সুইফট 4.1 থেকে , সুইফট সংশ্লেষকরণ Equatableএবং Hashableসম্পর্কিত মানগুলির সাথে এনামগুলির জন্যও সমর্থন করে ।
jedwidz

উত্তর:


244

সুইফট ৪.১+

যেহেতু @ জেদ্বিদজ সহায়তার সাথে উল্লেখ করেছেন, সুইফট ৪.১ থেকে ( এসই -১০৮৫ -এর কারণে , সুইফট সংশ্লেষও সমর্থন করে EquatableএবংHashable সম্পর্কিত মানগুলির সাথে এনামগুলিতেও ।

তাই আপনি যদি সুইফট 4.1 অথবা ঊর্ধ্বতন সংস্করণ ব্যস্ত রয়েছেন কিনা নিম্নলিখিত স্বয়ংক্রিয়ভাবে যেমন যে প্রয়োজনীয় পদ্ধতি সমন্বয় হবে XCTAssert(t1 == t2)কাজ করে। কীটি হ'ল Equatableআপনার এনমগুলিতে প্রোটোকল যুক্ত করা।

enum SimpleToken: Equatable {
    case Name(String)
    case Number(Int)
}
let t1 = SimpleToken.Number(123)
let t2 = SimpleToken.Number(123)

সুইফটের আগে ৪.১

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

enum SimpleToken: Equatable {
    case Name(String)
    case Number(Int)
}

public func ==(lhs: SimpleToken, rhs: SimpleToken) -> Bool {
    switch (lhs, rhs) {
    case let (.Name(a),   .Name(b)),
         let (.Number(a), .Number(b)):
      return a == b
    default:
      return false
    }
}

এটি আদর্শের থেকে অনেক দূরে - প্রচুর পুনরাবৃত্তি রয়েছে - তবে অন্তত ভিতরে-বিবৃতি দিয়ে আপনাকে নেস্টেড সুইচগুলি করার দরকার নেই।


39
যে বিষয়টি সম্পর্কে ডুবছে তা হ'ল আপনাকে স্যুইচটিতে ডিফল্ট বিবৃতিটি ব্যবহার করা দরকার, সুতরাং আপনি যদি নতুন এনাম কেস যুক্ত করেন তবে সংকলক নিশ্চিত করে না যে আপনি সাম্যতার জন্য এই নতুন কেসের তুলনা করার জন্য ধারাটি যুক্ত করেছেন - আপনি পরে যখন আপনি লাইনের নীচে পরিবর্তনগুলি করেন তখন কেবল মনে রাখতে হবে এবং সাবধান থাকতে হবে!
মাইকেল জলপ্রপাত

20
আপনি প্রতিস্থাপনের defaultমাধ্যমে উল্লিখিত @ মাইকেল ওয়াটারফলের সমস্যা থেকে মুক্তি পেতে পারেন case (.Name, _): return false; case(.Number, _): return false
কাজমাসিউরাস

25
আরও ভাল: case (.Name(let a), .Name(let b)) : return a == bইত্যাদি
মার্টিন আর

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

1
এটি উভয়ই কাজ করতে enumএবং ==ফাংশনটি অবশ্যই বিশ্বব্যাপী স্কোপ (আপনার দর্শন নিয়ামকের স্কোপের বাইরে) প্রয়োগ করা উচিত।
আন্দ্রেজ

75

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

if case .NotRecognized = error {
    // Success
} else {
    XCTFail("wrong error")
}

... বা পরামিতি মূল্যায়নের ক্ষেত্রে:

if case .Unauthorized401(_, let response, _) = networkError {
    XCTAssertEqual(response.statusCode, 401)
} else {
    XCTFail("Unauthorized401 was expected")
}

এখানে আরও বিস্তৃত বিবরণ পান: https://mdcdePLer.wordpress.com/2016/12/16/unit-testing-swift-enums/


এটি পরীক্ষার ভিত্তিতে না ব্যবহার করার চেষ্টা করার সময় আপনি আরও একটি সম্পূর্ণ উদাহরণ দিতে পারেন?
teradyl

আমি নিশ্চিত না যে এখানে প্রশ্ন কি। if caseএবং guard caseকেবলমাত্র ভাষা নির্মাতারা, কেবল ইউনিট টেস্টগুলিতে নয়, এই ক্ষেত্রে এনামগুলির সমতা পরীক্ষা করার সময় আপনি এগুলি যে কোনও জায়গায় ব্যবহার করতে পারেন।
এমবিপ্রো

3
প্রযুক্তিগতভাবে এই উত্তরটি প্রশ্নের উত্তর দেয় না, তবে আমি সন্দেহ করি এটি আসলে অনেক লোককে অনুসন্ধানের মাধ্যমে এখানে পৌঁছে দেয়, বুঝতে পারি তারা শুরু করার জন্য ভুল প্রশ্ন জিজ্ঞাসা করছে। ধন্যবাদ!
নিকোলে সুভান্দজিয়েভ

15

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

"উদাহরণস্বরূপ, যদি আপনি কোনও জটিল ডেটা মডেল উপস্থাপনের জন্য আপনার নিজস্ব শ্রেণি বা কাঠামো তৈরি করেন, তবে সেই শ্রেণি বা কাঠামোর জন্য" সমান "এর অর্থ সুইফট আপনার পক্ষে অনুমান করতে পারে এমন কিছু নয়” " [1]

সাম্যতার তুলনা বাস্তবায়নের জন্য, এমন কিছু লিখতে হবে:

@infix func ==(a:SimpleToken, b:SimpleToken) -> Bool {
    switch(a) {

    case let .Name(sa):
        switch(b) {
        case let .Name(sb): return sa == sb
        default: return false
        }

    case let .Number(na):
        switch(b) {
        case let .Number(nb): return na == nb
        default: return false
        }
    }
}

[1] https://developer.apple.com/library/content/docamentation/Swift/Concepual/Swift_Programming_Language/AdvancedOperators.html#//apple_ref/doc/uid/TP40014097-CH27-XID_43 এ "ইক্যুভ্যালেন্স অপারেটর" দেখুন


14

এখানে অন্য বিকল্প। এটি if caseসিনট্যাক্স ব্যবহার করে নেস্টেড সুইচ স্টেটমেন্টগুলি এড়ানো ব্যতীত অন্যদের মতোই মূলত একই । আমি মনে করি এটি এটিকে কিছুটা বেশি পঠনযোগ্য (/ বহনযোগ্য) করে তোলে এবং এটি ডিফল্ট কেসটি পুরোপুরি এড়িয়ে যাওয়ার সুবিধা রয়েছে।

enum SimpleToken: Equatable {
    case Name(String)
    case Number(Int)
}
extension SimpleToken {
    func isEqual(st: SimpleToken)->Bool {
        switch self {
        case .Name(let v1): 
            if case .Name(let v2) = st where v1 == v2 { return true }
        case .Number(let i1): 
            if case .Number(let i2) = st where i1 == i2 { return true }
        }
        return false
    }
}

func ==(lhs: SimpleToken, rhs: SimpleToken)->Bool {
    return lhs.isEqual(rhs)
}

let t1 = SimpleToken.Number(1)
let t2 = SimpleToken.Number(2)
let t3 = SimpleToken.Name("a")
let t4 = SimpleToken.Name("b")

t1 == t1  // true
t1 == t2  // false
t3 == t3  // true
t3 == t4  // false
t1 == t3  // false

14
enum MyEnum {
    case None
    case Simple(text: String)
    case Advanced(x: Int, y: Int)
}

func ==(lhs: MyEnum, rhs: MyEnum) -> Bool {
    switch (lhs, rhs) {
    case (.None, .None):
        return true
    case let (.Simple(v0), .Simple(v1)):
        return v0 == v1
    case let (.Advanced(x0, y0), .Advanced(x1, y1)):
        return x0 == x1 && y0 == y1
    default:
        return false
    }
}

এটি এমন কিছু দিয়ে লেখা case (.Simple(let v0), .Simple(let v1)) যেতে পারে এছাড়াও অপারেটর staticএনামের ভিতরে থাকতে পারে । আমার উত্তর এখানে দেখুন।
LShi

11

আমি ইউনিট পরীক্ষার কোডটিতে এই সাধারণ কাজটি ব্যবহার করছি:

extension SimpleToken: Equatable {}
func ==(lhs: SimpleToken, rhs: SimpleToken) -> Bool {
    return String(stringInterpolationSegment: lhs) == String(stringInterpolationSegment: rhs)
}

এটি তুলনা সম্পাদন করতে স্ট্রিং ইন্টারপোলেশন ব্যবহার করে। আমি এটি উত্পাদন কোডের জন্য সুপারিশ করব না, তবে এটি সংক্ষিপ্ত এবং ইউনিট পরীক্ষার জন্য কাজ করে।


2
আমি একমত, ইউনিট পরীক্ষার জন্য এটি একটি শালীন সমাধান।
ড্যানিয়েল উড

থিম (স্ট্রিংইন্টারপোলেশনসেশন :) এ অ্যাপল ডকস বলেছেন: "এই ইনিশিয়ালাইজারটিকে সরাসরি কল করবেন না string শুধু ব্যবহার "\(lhs)" == "\(rhs)"
স্কেজেডাল

আপনি ব্যবহার করতে পারেন String(describing:...)বা সমতুল্য "\(...)"। তবে সম্পর্কিত মানগুলি পৃথক করে থাকলে এটি কাজ করে না :(
মার্টিন

10

আর একটি বিকল্প হ'ল মামলার স্ট্রিং উপস্থাপনাগুলির তুলনা করা:

XCTAssert(String(t1) == String(t2))

উদাহরণ স্বরূপ:

let t1 = SimpleToken.Number(123) // the string representation is "Number(123)"
let t2 = SimpleToken.Number(123)
let t3 = SimpleToken.Name("bob") // the string representation is "Name(\"bob\")"

String(t1) == String(t2) //true
String(t1) == String(t3) //false

3

if caseকমা দিয়ে আরও একটি পদ্ধতি যা সুইফট 3 এ কাজ করে:

enum {
  case kindOne(String)
  case kindTwo(NSManagedObjectID)
  case kindThree(Int)

  static func ==(lhs: MyEnumType, rhs: MyEnumType) -> Bool {
    if case .kindOne(let l) = lhs,
        case .kindOne(let r) = rhs {
        return l == r
    }
    if case .kindTwo(let l) = lhs,
        case .kindTwo(let r) = rhs {
        return l == r
    }
    if case .kindThree(let l) = lhs,
        case .kindThree(let r) = rhs {
        return l == r
    }
    return false
  }
}

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


2

t1 এবং t2 সংখ্যা নয়, এগুলি সংযুক্ত মানের সাথে সিম্পল টোকেনের উদাহরণ।

তুমি বলতে পারো

var t1 = SimpleToken.Number(123)

আপনি তখন বলতে পারেন

t1 = SimpleToken.Name(Smith) 

একটি সংকলক ত্রুটি ছাড়া।

টি 1 থেকে মানটি পুনরুদ্ধার করতে, একটি স্যুইচ বিবৃতি ব্যবহার করুন:

switch t1 {
    case let .Number(numValue):
        println("Number: \(numValue)")
    case let .Name(strValue):
        println("Name: \(strValue)")
}

2

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

enum SimpleToken: Equatable {
    case Name(String)
    case Number(Int)
}
extension SimpleToken {
    func isEqual(st: SimpleToken)->Bool {
        switch self {
        case .Name(let v1):
            switch st {
            case .Name(let v2): return v1 == v2
            default: return false
            }
        case .Number(let i1):
            switch st {
            case .Number(let i2): return i1 == i2
            default: return false
            }
        }
    }
}


func ==(lhs: SimpleToken, rhs: SimpleToken)->Bool {
    return lhs.isEqual(rhs)
}

let t1 = SimpleToken.Number(1)
let t2 = SimpleToken.Number(2)
let t3 = SimpleToken.Name("a")
let t4 = SimpleToken.Name("b")

t1 == t1  // true
t1 == t2  // false
t3 == t3  // true
t3 == t4  // false
t1 == t3  // false

2

এমবিপ্রির উত্তরটি প্রসারিত করে, এখানে কিছু প্রান্তের ক্ষেত্রে সম্পর্কিত মানগুলির সাথে সুইফট এনামগুলির সাম্যতা যাচাই করার জন্য আমি সেই পদ্ধতির ব্যবহারটি কীভাবে করেছি।

অবশ্যই আপনি একটি স্যুইচ স্টেটমেন্ট করতে পারেন, তবে কখনও কখনও এটি কেবল একটি লাইনে একটি মান পরীক্ষা করে দেখতে ভাল। আপনি এটি এর মতো করতে পারেন:

// NOTE: there's only 1 equal (`=`) sign! Not the 2 (`==`) that you're used to for the equality operator
// 2nd NOTE: Your variable must come 2nd in the clause

if case .yourEnumCase(associatedValueIfNeeded) = yourEnumVariable {
  // success
}

যদি আপনি যদি শর্তটি একইভাবে 2 শর্তের তুলনা করতে চান তবে আপনাকে &&অপারেটরের পরিবর্তে কমা ব্যবহার করতে হবে :

if someOtherCondition, case .yourEnumCase = yourEnumVariable {
  // success
}

2

সুইফট ৪.১ Equatableথেকে আপনার এনামে কেবল প্রোটোকল যুক্ত করুন এবং ব্যবহার করুন XCTAssertবা XCTAssertEqual:

enum SimpleToken : Equatable {
    case Name(String)
    case Number(Int)
}
let t1 = SimpleToken.Number(123)
let t2 = SimpleToken.Number(123)
XCTAssertEqual(t1, t2) // OK

-1

আপনি সুইচ ব্যবহার করে তুলনা করতে পারেন

enum SimpleToken {
    case Name(String)
    case Number(Int)
}

let t1 = SimpleToken.Number(123)
let t2 = SimpleToken.Number(123)

switch(t1) {

case let .Number(a):
    switch(t2) {
        case let . Number(b):
            if a == b
            {
                println("Equal")
        }
        default:
            println("Not equal")
    }
default:
    println("No Match")
}

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