在Swift中实现Generic Struct上的Equatable的奇怪行为

时间:2016-11-21 04:56:23

标签: swift generics

import Foundation

struct NotEquable {}

struct Box<T> {
    let id: Int
    let value: T
}

extension Box: Equatable {
    static func ==<T>(lhs: Box<T>, rhs: Box<T>) -> Bool {
        return lhs.id == rhs.id
    }

    static func ==<T: Equatable>(lhs: Box<T>, rhs: Box<T>) -> Bool {
        return lhs.id == rhs.id && lhs.value == rhs.value
    }
}

infix operator ====: AdditionPrecedence
public protocol OperatorEqual {
    static func ====(lhs: Self, rhs: Self) -> Bool
}

extension Box: OperatorEqual {
    static func ====<T>(lhs: Box<T>, rhs: Box<T>) -> Bool {
        return lhs.id == rhs.id
    }

    static func ====<T: Equatable>(lhs: Box<T>, rhs: Box<T>) -> Bool  {
        return lhs.id == rhs.id && lhs.value == rhs.value
    }
}

public protocol MethodStyleEquatable {
    static func equal(lhs: Self, rhs: Self) -> Bool
}

extension Box: MethodStyleEquatable {
    static func equal<T>(lhs: Box<T>, rhs: Box<T>) -> Bool {
        return lhs.id == rhs.id
    }

    static func equal<T: Equatable>(lhs: Box<T>, rhs: Box<T>) -> Bool  {
        return lhs.id == rhs.id && lhs.value == rhs.value
    }
}

func freeEqual<T>(lhs: Box<T>, rhs: Box<T>) -> Bool {
    return lhs.id == rhs.id
}

func freeEqual<T: Equatable>(lhs: Box<T>, rhs: Box<T>) -> Bool  {
    return lhs.id == rhs.id && lhs.value == rhs.value
}

let a = Box(id: 1, value: 1)
let b = Box(id: 1, value: 2)
a == b
a ==== b
freeEqual(lhs: a, rhs: b)
Box<Int>.equal(lhs: a, rhs: b)

let c = Box(id: 1, value: NotEquable())
let d = Box(id: 1, value: NotEquable())
c == d
c ==== d
freeEqual(lhs: c, rhs: d)
Box<NotEquable>.equal(lhs: c, rhs: d)

在上面的代码片段中,有Equatable的4个实现:默认实现,自定义运算符样式,方法样式和自由函数样式。我发现在默认情况下使用运算符样式或自定义情况总是调用相等函数的泛型版本。另一方面,使用方法或自由函数样式将根据T符合Equatable来调用正确的版本。这是一个错误或如何使通用结构正确符合Equatable

1 个答案:

答案 0 :(得分:4)

您将类的泛型参数与等于函数的参数混淆。如上所述,您的代码等同于:

class User::OrganisationMapperService #< ActiveRecord::Base

    def self.call(user: u)
      new(user: user).call
    end

    def initialize(user: u)
      self.user = user
    end

    def call
      if organisation_domain.present?
          OrgRequest.create(user: @user, organisation_id: organisation_domain.id) #if organisation

      else
      end
    end

    private

    attr_accessor :user


    def user_domain
      user.email.split('@').last
    end

    def organisation_domain
      @organisation ||= Organisation.find_by(email_format: user_domain)
     end


end

将您的定义更改为:

struct Box<T1> {
    let id: Int
    let value: T1
}

extension Box: Equatable {
    static func ==<T2>(lhs: Box<T2>, rhs: Box<T2>) -> Bool {
        return lhs.id == rhs.id
    }

    static func ==<T3: Equatable>(lhs: Box<T3>, rhs: Box<T3>) -> Bool {
        return lhs.id == rhs.id && lhs.value == rhs.value
    }
}

它按预期工作。