满足 Swift 具有闭包属性的协议方法?
Satisfy Swift Protocol Methods with Closure Attributes?
我有一个带有方法的协议。一直以为method可以换成同名的闭包,但是好像不行:
protocol Foo {
func bar() // Type: Void -> Void
}
class X: Foo {
func bar() { }
}
class Y: Foo { // Compiler: doesn't conform to protocol Foo
let bar: Void->Void = {}
}
有没有办法让它工作?我想覆盖测试存根实现的方法行为。目前,我必须这样做,我想缩短它:
class Z: Foo {
var barClosure: Void -> Void = {}
func bar() {
barClosure()
}
}
let baz = Z()
baz.barClosure = { /* ... */ }
baz.bar() // Calls the closure replacement
你声明协议有一个函数,bar()
,但是在 class Y
中,你只有一个常量而不是函数,这就是问题所在。但是如果你想要 class Y
中的内容,你应该将协议更改为:
protocol Foo {
var bar: () -> () {get set}
}
然后像这样实现:
class Test: Foo {
private var _bar: (() -> ())?
var bar: () -> () {
get {
return {}
}
set {
self._bar = newValue
}
}
}
已更新
如果你要缩短你的class,你可以使用类似的东西:
protocol Foo {
var barClosure: Void -> Void {get set}
}
class Z: Foo {
var barClosure: Void -> Void = {
//do here something
}
}
let a = Z()
a.barClosure()
感谢@Dániel Nagy,我能够弄清楚我有哪些选择。该协议应要求关闭。这样,客户端代码就不会改变,因为闭包调用与方法调用相同。
- 使 属性 可变,以便实现可以决定是否要锁定该值
- 只需要 getter(出于同样的原因)
- 在生产代码中将 属性 初始化为不可变的 (
let
)
- 在测试代码中将 属性 初始化为可变 (
var
) 以在测试用例中提供替代实现,就像模拟观察者那样
这是一个修改后的示例,它通过返回字符串在 Playground 中运行良好:
protocol Foo {
var bar: () -> String { get }
}
class X: Foo {
// cannot be overwritten
let bar: () -> String = { return "default x" }
}
class Y: Foo {
private let _bar: () -> String = { return "default y" }
// Can be overwritten but doesn't have any effect
var bar: () -> String {
get {
return _bar
}
set {
}
}
}
class Z: Foo {
// Can be overwidden
var bar: () -> String = {
return "default z"
}
}
let bax = X()
bax.bar() // => "default x"
// bax.bar = { /* ... */ } // Forbidden
let bay = Y()
bay.bar() // => "default y"
bay.bar = { return "YY" }
bay.bar() // => "default y"
let baz = Z()
baz.bar() // => "default z"
baz.bar = { return "ZZ" }
baz.bar() // => "ZZ"
func
关键字在幕后做了一些你无法用属性复制的魔法 – 特别是在 类 的情况下,函数可以被覆盖,所以 vtables 需要待建等
也就是说,如果您要使用闭包表达式替换方法,您需要做的不仅仅是您提供的代码。相当于:
struct A {
let x: Int
func f() {
println("In f(), x is \(a.x)")
}
}
会更像这样:
struct A {
let x: Int
// returns a function that takes A objects, and
// returns a function that captures them
static let f: (A)->()->() = { a in
{ ()->() in println("In f(), x is \(a.x)") }
}
// equivalent of the dot notation call of f
var f: ()->() {
return A.f(self)
}
}
这复制了结构方法的实际工作方式,并允许您执行 f
方法所做的所有相同的事情:
let a = A(x: 5)
// static version of f
let A_f = A.f
// that static version bound to a self:
let f = A_f(a)
f()
// the above is equivalent to:
a.f()
但这仍然不足以让 A
遵守需要 f()
方法的协议。
我有一个带有方法的协议。一直以为method可以换成同名的闭包,但是好像不行:
protocol Foo {
func bar() // Type: Void -> Void
}
class X: Foo {
func bar() { }
}
class Y: Foo { // Compiler: doesn't conform to protocol Foo
let bar: Void->Void = {}
}
有没有办法让它工作?我想覆盖测试存根实现的方法行为。目前,我必须这样做,我想缩短它:
class Z: Foo {
var barClosure: Void -> Void = {}
func bar() {
barClosure()
}
}
let baz = Z()
baz.barClosure = { /* ... */ }
baz.bar() // Calls the closure replacement
你声明协议有一个函数,bar()
,但是在 class Y
中,你只有一个常量而不是函数,这就是问题所在。但是如果你想要 class Y
中的内容,你应该将协议更改为:
protocol Foo {
var bar: () -> () {get set}
}
然后像这样实现:
class Test: Foo {
private var _bar: (() -> ())?
var bar: () -> () {
get {
return {}
}
set {
self._bar = newValue
}
}
}
已更新
如果你要缩短你的class,你可以使用类似的东西:
protocol Foo {
var barClosure: Void -> Void {get set}
}
class Z: Foo {
var barClosure: Void -> Void = {
//do here something
}
}
let a = Z()
a.barClosure()
感谢@Dániel Nagy,我能够弄清楚我有哪些选择。该协议应要求关闭。这样,客户端代码就不会改变,因为闭包调用与方法调用相同。
- 使 属性 可变,以便实现可以决定是否要锁定该值
- 只需要 getter(出于同样的原因)
- 在生产代码中将 属性 初始化为不可变的 (
let
) - 在测试代码中将 属性 初始化为可变 (
var
) 以在测试用例中提供替代实现,就像模拟观察者那样
这是一个修改后的示例,它通过返回字符串在 Playground 中运行良好:
protocol Foo {
var bar: () -> String { get }
}
class X: Foo {
// cannot be overwritten
let bar: () -> String = { return "default x" }
}
class Y: Foo {
private let _bar: () -> String = { return "default y" }
// Can be overwritten but doesn't have any effect
var bar: () -> String {
get {
return _bar
}
set {
}
}
}
class Z: Foo {
// Can be overwidden
var bar: () -> String = {
return "default z"
}
}
let bax = X()
bax.bar() // => "default x"
// bax.bar = { /* ... */ } // Forbidden
let bay = Y()
bay.bar() // => "default y"
bay.bar = { return "YY" }
bay.bar() // => "default y"
let baz = Z()
baz.bar() // => "default z"
baz.bar = { return "ZZ" }
baz.bar() // => "ZZ"
func
关键字在幕后做了一些你无法用属性复制的魔法 – 特别是在 类 的情况下,函数可以被覆盖,所以 vtables 需要待建等
也就是说,如果您要使用闭包表达式替换方法,您需要做的不仅仅是您提供的代码。相当于:
struct A {
let x: Int
func f() {
println("In f(), x is \(a.x)")
}
}
会更像这样:
struct A {
let x: Int
// returns a function that takes A objects, and
// returns a function that captures them
static let f: (A)->()->() = { a in
{ ()->() in println("In f(), x is \(a.x)") }
}
// equivalent of the dot notation call of f
var f: ()->() {
return A.f(self)
}
}
这复制了结构方法的实际工作方式,并允许您执行 f
方法所做的所有相同的事情:
let a = A(x: 5)
// static version of f
let A_f = A.f
// that static version bound to a self:
let f = A_f(a)
f()
// the above is equivalent to:
a.f()
但这仍然不足以让 A
遵守需要 f()
方法的协议。