【问题标题】:Overload Equality Operator (==) to compare String and Int重载相等运算符 (==) 以比较 String 和 Int
【发布时间】:2020-01-21 18:00:33
【问题描述】:

我正在体验协议并挑战自己编写一个代码 sn-p 重载 == 运算符,以便当我将随机 String 与值 "42"Int 进行比较时,它 returns true42。请不要通过简单地在 String 上返回 42 来质疑其有用性,重点是让 Equality Operator 在两种不同的类型上运行。

这是我尝试过的:

版本 1

import Foundation

protocol IntTransformable: Equatable {
    func toInt() -> Int
}

extension String: IntTransformable {
    func toInt() -> Int {
        return 42
    }
}

extension Int: IntTransformable {
    func toInt() -> Int {
        return self
    }
}

extension IntTransformable {
    static func == (lhs: Self, rhs: Self) -> Bool {
        return lhs.toInt() == rhs.toInt()
    }
}

// throws: Ambiguous reference to operator function '=='
if "42" == 42 {
    print("equal")
} else {
    print("unequal")
}

版本 2

import Foundation

protocol IntTransformable: Equatable {
    func toInt() -> Int
}

extension String: IntTransformable {
    func toInt() -> Int {
        return 42
    }
}

extension Int: IntTransformable {
    func toInt() -> Int {
        return self
    }
}

extension IntTransformable {
    // throws: Protocol 'IntTransformable' can only be used as a generic constraint because it has Self or associated type requirements
    static func == (lhs: IntTransformable, rhs: IntTransformable) -> Bool {
        return lhs.toInt() == rhs.toInt()
    }
}

// throws: Ambiguous reference to operator function '=='
if "42" == 42 {
    print("equal")
} else {
    print("unequal")
}

【问题讨论】:

  • 您可以像static func == (lhs: Self, rhs: Self) -> Bool { return lhs.toInt() == rhs.toInt() } 一样简单地使您的协议工作,但是,在StringInt 上使用运算符仍然会导致相同的错误。
  • 你不能使用协议来做到这一点,因为协议并不是真正的类型。
  • @DávidPásztor 感谢代码改进提示。
  • @matt 如果我不能使用协议,我能做些什么呢?
  • 顺便说一句,如果你想为类型 T 引入不同的相等概念,我建议你制作一个包装 Tstruct,并通过实现新的平等的定义。在现有类型上定义 == 通常会导致这种歧义/混乱

标签: swift protocols equality


【解决方案1】:

你应该使用这两个函数:

func ==(lhs: String, rhs: @autoclosure ()->Int) -> Bool {
    guard let stringIntValue = Int(lhs) else { return false }
    return stringIntValue == rhs()
}

func ==(lhs: Int, rhs: String) -> Bool {
    guard let stringIntValue = Int(rhs) else { return false }
    return lhs == stringIntValue
}

但如果你真的想在这里让Protocols 参与进来,你应该这样做:

extension IntTransformable {
    static func ==<T: IntTransformable>(lhs: Self, rhs: T) -> Bool {
        return lhs.toInt() == rhs.toInt()
    }
}

用法:

print( 42 == "42" )
print( "42" == 42 )

【讨论】:

  • 在你的第二个例子中,我猜你的意思是return lhs.toInt() == rhs.toInt()
  • 我认为协议的目的是进行多极比较。比如,Double、Float、Int32、Char 等。在这种情况下,第一个解决方案将是很多不同的功能
  • @Vollan toInt() 限制为Int,那么他应该考虑使用函数的重载,而不是使用这种严格的协议。
  • 协议版本对我不起作用,为什么你在两个函数中使用autoclosure
  • @MojtabaHosseini 明白了,谢谢伙计!我刚刚阅读了另一篇关于它的文章,它变得更加清晰。我错过了参数本身可以作为函数/方法/传递的观点。谢谢你的帮助。在这里学到了很多东西。
【解决方案2】:

你想太多了。这里没有理由使用协议,而且你真的不能这样做,因为协议不是真正的类型。只需在顶层编写您的运算符:

func == (lhs: Int, rhs: String) -> Bool {
    return lhs == Int(rhs)
}
func == (lhs: String, rhs: Int) -> Bool {
    return Int(lhs) == rhs
}

测试:

print(5 == "5") // true

【讨论】:

  • 我也试图绕过在全球范围内定义运算符,但当你说我想太多时,我想你是对的。
  • @ChrisGraf 如果有任何区别,您也可以将它们声明为 Int 的扩展
  • 运算符没有命名空间。 ====,无论是在结构中定义还是在顶层定义。真的没什么区别
  • @Alexander 我试图摆脱的是 OP 代码中的 Self / IntTransformable 可爱。简单明了通常是最好的。 “说出你的意思”是一门编程公案。
  • @matt 我的评论是为了回应 Chris 的“试图绕过在全局级别上定义运算符”
【解决方案3】:

创建一个字符串扩展,比如

public string ToInt(this int value) { // 一些转换代码

返回转换字符串值; }

或者你可以使用 uint.TryParse(string value, out uint output) 如果转换成功,此语句将返回 true。

【讨论】:

    猜你喜欢
    • 2020-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-12
    • 2020-12-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多