你如何testing函数和平等closures?

这本书说,“function和封闭是参考types”。 那么,你怎么知道引用是否相等? ==和===不起作用。

func a() { } let å = a let b = å === å // Could not find an overload for === that accepts the supplied arguments 

以下是Catterwauls如何处理这个问题:

多种shell和可自动closures

testing

Chris Lattner在开发者论坛上写道:

这是我们故意不想支持的function。 有各种各样的东西会导致函数的指针相等(在包括几种闭包的快速types系统意义上)根据优化而失败或改变。 如果在函数中定义了“===”,则编译器将不允许合并相同的方法体,共享thunk,并在闭包中执行某些捕获优化。 此外,在某些generics上下文中,这种平等是非常令人惊讶的,在这种情况下,可以获得将函数的实际签名调整为函数types所期望的特征的重新获取thunks。

https://devforums.apple.com/message/1035180#1035180

这意味着你甚至不应该试图比较闭包的平等,因为优化可能会影响结果。

我一直在寻找答案。 我终于find了。

你需要的是实际的函数指针和隐藏在函数对象中的上下文。

 func peekFunc<A,R>(f:A->R)->(fp:Int, ctx:Int) { typealias IntInt = (Int, Int) let (hi, lo) = unsafeBitCast(f, IntInt.self) let offset = sizeof(Int) == 8 ? 16 : 12 let ptr = UnsafePointer<Int>(lo+offset) return (ptr.memory, ptr.successor().memory) } @infix func === <A,R>(lhs:A->R,rhs:A->R)->Bool { let (tl, tr) = (peekFunc(lhs), peekFunc(rhs)) return tl.0 == tr.0 && tl.1 == tr.1 } 

这里是演示:

 // simple functions func genericId<T>(t:T)->T { return t } func incr(i:Int)->Int { return i + 1 } var f:Int->Int = genericId var g = f; println("(f === g) == \(f === g)") f = genericId; println("(f === g) == \(f === g)") f = g; println("(f === g) == \(f === g)") // closures func mkcounter()->()->Int { var count = 0; return { count++ } } var c0 = mkcounter() var c1 = mkcounter() var c2 = c0 println("peekFunc(c0) == \(peekFunc(c0))") println("peekFunc(c1) == \(peekFunc(c1))") println("peekFunc(c2) == \(peekFunc(c2))") println("(c0() == c1()) == \(c0() == c1())") // true : both are called once println("(c0() == c2()) == \(c0() == c2())") // false: because c0() means c2() println("(c0 === c1) == \(c0 === c1)") println("(c0 === c2) == \(c0 === c2)") 

请参阅下面的url来查找它的工作原理和工作原理:

正如你所看到的,它只能检查身份(第二次testing产生false )。 但是这应该够好了。

最简单的方法是将块types指定为@objc_block ,现在可以将其转换为与===相媲美的AnyObject。 例:

  typealias Ftype = @objc_block (s:String) -> () let f : Ftype = { ss in println(ss) } let ff : Ftype = { sss in println(sss) } let obj1 = unsafeBitCast(f, AnyObject.self) let obj2 = unsafeBitCast(ff, AnyObject.self) let obj3 = unsafeBitCast(f, AnyObject.self) println(obj1 === obj2) // false println(obj1 === obj3) // true 

我搜查了很多。 似乎没有办法进行函数指针比较。 我得到的最佳解决scheme是将函数或闭包封装在可哈希对象中。 喜欢:

 var handler:Handler = Handler(callback: { (message:String) in //handler body })) 

这是一个很好的问题,虽然克里斯·拉特纳故意不想支持这个function,但是像许多开发人员一样,我也不能放弃来自其他语言的感觉,因为这是一项微不足道的任务。 有很多unsafeBitCast例子,其中大部分没有显示完整的图片,下面是更详细的例子:

 typealias SwfBlock = () -> () typealias ObjBlock = @convention(block) () -> () func testSwfBlock(a: SwfBlock, _ b: SwfBlock) -> String { let objA = unsafeBitCast(a as ObjBlock, AnyObject.self) let objB = unsafeBitCast(b as ObjBlock, AnyObject.self) return "a is ObjBlock: \(a is ObjBlock), b is ObjBlock: \(b is ObjBlock), objA === objB: \(objA === objB)" } func testObjBlock(a: ObjBlock, _ b: ObjBlock) -> String { let objA = unsafeBitCast(a, AnyObject.self) let objB = unsafeBitCast(b, AnyObject.self) return "a is ObjBlock: \(a is ObjBlock), b is ObjBlock: \(b is ObjBlock), objA === objB: \(objA === objB)" } func testAnyBlock(a: Any?, _ b: Any?) -> String { if !(a is ObjBlock) || !(b is ObjBlock) { return "a nor b are ObjBlock, they are not equal" } let objA = unsafeBitCast(a as! ObjBlock, AnyObject.self) let objB = unsafeBitCast(b as! ObjBlock, AnyObject.self) return "a is ObjBlock: \(a is ObjBlock), b is ObjBlock: \(b is ObjBlock), objA === objB: \(objA === objB)" } class Foo { lazy var swfBlock: ObjBlock = self.swf func swf() { print("swf") } @objc func obj() { print("obj") } } let swfBlock: SwfBlock = { print("swf") } let objBlock: ObjBlock = { print("obj") } let foo: Foo = Foo() print(testSwfBlock(swfBlock, swfBlock)) // a is ObjBlock: false, b is ObjBlock: false, objA === objB: false print(testSwfBlock(objBlock, objBlock)) // a is ObjBlock: false, b is ObjBlock: false, objA === objB: false print(testObjBlock(swfBlock, swfBlock)) // a is ObjBlock: true, b is ObjBlock: true, objA === objB: false print(testObjBlock(objBlock, objBlock)) // a is ObjBlock: true, b is ObjBlock: true, objA === objB: true print(testAnyBlock(swfBlock, swfBlock)) // a nor b are ObjBlock, they are not equal print(testAnyBlock(objBlock, objBlock)) // a is ObjBlock: true, b is ObjBlock: true, objA === objB: true print(testObjBlock(foo.swf, foo.swf)) // a is ObjBlock: true, b is ObjBlock: true, objA === objB: false print(testSwfBlock(foo.obj, foo.obj)) // a is ObjBlock: false, b is ObjBlock: false, objA === objB: false print(testAnyBlock(foo.swf, foo.swf)) // a nor b are ObjBlock, they are not equal print(testAnyBlock(foo.swfBlock, foo.swfBlock)) // a is ObjBlock: true, b is ObjBlock: true, objA === objB: true 

有趣的部分是SwfBlock如何快速地将ObjBlock转换为SwfBlock,但实际上两个SwfBlock块将永远是不同的值,而ObjBlocks则不会。 当我们将ObjBlock施放给SwfBlock时,他们也会发生同样的事情,他们会变成两个不同的值。 所以,为了保持参考,应该避免这种铸造。

我仍然理解这整个主题,但是我留下的一个@convention(block)是能够在类/结构方法上使用@convention(block) ,所以我提出了一个function请求 ,需要进行投票或解释为什么这是一个坏主意。 我也觉得这个方法可能会很糟糕,如果有的话,任何人都可以解释为什么?

那已经过了两天了,没有人提出解决scheme,所以我会将我的评论改为一个答案:

据我所知,你不能检查函数(如你的例子)和元类(例如, MyClass.self )的平等或身份:

但是 – 这只是一个想法 – 我不禁注意到generics中的where子句似乎能够检查types的相等性。 那么也许你可以利用这一点,至less为了检查身份?

这是一个可能的解决scheme(概念上与'tuncay'相同)。 重点是定义一个包装一些function的类(例如Command):

迅速:

 typealias Callback = (Any...)->Void class Command { init(_ fn: @escaping Callback) { self.fn_ = fn } var exec : (_ args: Any...)->Void { get { return fn_ } } var fn_ :Callback } let cmd1 = Command { _ in print("hello")} let cmd2 = cmd1 let cmd3 = Command { (_ args: Any...) in print(args.count) } cmd1.exec() cmd2.exec() cmd3.exec(1, 2, "str") cmd1 === cmd2 // true cmd1 === cmd3 // false 

Java的:

 interface Command { void exec(Object... args); } Command cmd1 = new Command() { public void exec(Object... args) [ // do something } } Command cmd2 = cmd1; Command cmd3 = new Command() { public void exec(Object... args) { // do something else } } cmd1 == cmd2 // true cmd1 == cmd3 // false