Swift 中的装饰器
Decorators in Swift
我是 Swift 的新手,我想知道该语言是否有一些等同于 Python 的装饰器模式。
例如:
import functools
def announce(func):
"""Print a function's arguments and return value as it's called."""
@functools.wraps(func)
def announced_func(*args, **kwargs):
rv = func(*args, **kwargs)
print('In: {0}, {1}'.format(args, kwargs))
print('Out: {}'.format(rv))
return rv
return announced_func
@announce # add = announce(add)
def add(a, b):
return a + b
add(2, 5)
# In: (2, 5), {}
# Out: 7
# 7
也许我还没有找到它,但 Swift 似乎没有办法将任意参数转发给函数或保留包装函数的信息(如 functools.wraps ).
是否有等效项,或者该模式不打算在 Swift 中使用?
你可以使用这个:
func decorate<T, U>(_ function: @escaping (T) -> U, decoration: @escaping (T, U) -> U) -> (T) -> U {
return { args in
decoration(args, function(args))
}
}
let add: (Int, Int) -> Int = decorate(+) { args, rv in
print("In: \(args)")
print("Out: \(rv)")
return rv
}
add(2, 5) // In: (2, 5)\nOut: 7
或announce
作为函数而不是闭包,允许重用:
func announce<T, U>(input args: T, output rv: U) -> U {
print("In: \(args)")
print("Out: \(rv)")
return rv
}
let add: (Int, Int) -> Int = decorate(+, decoration: announce)
add(2, 5) // In: (2, 5)\nOut: 7
let length = decorate({(str: String) in str.characters.count }, decoration: announce)
length("Hello world!") // In: Hello world!\nOut: 12
上面的示例更新为 Swift 4+。要求参数形式上是元组。我还添加了一个装饰字符串的示例。
func decorate<T, U>(_ function: @escaping (T) -> U,
decoration: @escaping (T, U) -> U) -> (T) -> U {
return { args in
decoration(args, function(args))
}
}
let add: ((Int, Int)) -> Int = decorate(+) {args, rv in
print("In: \(args)")
print("Out: \(rv)")
return rv
}
add((2, 5)) // In: (2, 5)\nOut: 7
func announce<T, U>(input args: T, output rv: U) -> U {
print("In: \(args)")
print("Out: \(rv)")
return rv
}
let multiply: ((Int, Int)) -> Int = decorate(*, decoration: announce)
multiply((2, 5)) // In: (2, 5)\nOut: 10
let length = decorate( { (str: String) in str.count }, decoration: announce)
length("Hello world!") // In: Hello world!\nOut: 12
let greet: ((String)) -> String = decorate( {"Hello, \([=10=])" }, decoration: announce)
greet(("Paul")) // In: Paul\nOut: Hello, Paul
以上示例更新为 Swift 5.1+
@propertyWrapper
struct Announced<T, U> {
private let announcedFunction: (T) -> U
var wrappedValue: (T) -> U { announcedFunction }
init(wrappedValue: @escaping (T) -> U) {
announcedFunction = { args in
let rv = wrappedValue(args)
print("In: \(args)")
print("Out: \(rv)")
return rv
}
}
}
struct Test {
@Announced static var add: ((Int, Int)) -> Int = { [=10=].0 + [=10=].1 }
@Announced static var multiply: ((Int, Int)) -> Int = { [=10=].0 * [=10=].1 }
@Announced static var length : (String) -> Int = { (str: String) in str.count }
@Announced static var greet: (String) -> String = { "Hello, \([=10=])" }
}
Test.add((2, 5)) // In: (2, 5)\n Out: 7
Test.multiply((2, 5)) // In: (2, 5)\n Out: 10
Test.length("Hello world!") // In: Hello world!\n Out: 12
Test.greet("Paul") // In: Paul\n Out: Hello, Paul
[编辑]其实可以简化一下:
@propertyWrapper
struct Announced<T, U> {
let wrappedValue: (T) -> U
init(wrappedValue: @escaping (T) -> U) {
self.wrappedValue = { args in
let rv = wrappedValue(args)
print("In: \(args)")
print("Out: \(rv)")
return rv
}
}
}
我是 Swift 的新手,我想知道该语言是否有一些等同于 Python 的装饰器模式。
例如:
import functools
def announce(func):
"""Print a function's arguments and return value as it's called."""
@functools.wraps(func)
def announced_func(*args, **kwargs):
rv = func(*args, **kwargs)
print('In: {0}, {1}'.format(args, kwargs))
print('Out: {}'.format(rv))
return rv
return announced_func
@announce # add = announce(add)
def add(a, b):
return a + b
add(2, 5)
# In: (2, 5), {}
# Out: 7
# 7
也许我还没有找到它,但 Swift 似乎没有办法将任意参数转发给函数或保留包装函数的信息(如 functools.wraps ).
是否有等效项,或者该模式不打算在 Swift 中使用?
你可以使用这个:
func decorate<T, U>(_ function: @escaping (T) -> U, decoration: @escaping (T, U) -> U) -> (T) -> U {
return { args in
decoration(args, function(args))
}
}
let add: (Int, Int) -> Int = decorate(+) { args, rv in
print("In: \(args)")
print("Out: \(rv)")
return rv
}
add(2, 5) // In: (2, 5)\nOut: 7
或announce
作为函数而不是闭包,允许重用:
func announce<T, U>(input args: T, output rv: U) -> U {
print("In: \(args)")
print("Out: \(rv)")
return rv
}
let add: (Int, Int) -> Int = decorate(+, decoration: announce)
add(2, 5) // In: (2, 5)\nOut: 7
let length = decorate({(str: String) in str.characters.count }, decoration: announce)
length("Hello world!") // In: Hello world!\nOut: 12
上面的示例更新为 Swift 4+。要求参数形式上是元组。我还添加了一个装饰字符串的示例。
func decorate<T, U>(_ function: @escaping (T) -> U,
decoration: @escaping (T, U) -> U) -> (T) -> U {
return { args in
decoration(args, function(args))
}
}
let add: ((Int, Int)) -> Int = decorate(+) {args, rv in
print("In: \(args)")
print("Out: \(rv)")
return rv
}
add((2, 5)) // In: (2, 5)\nOut: 7
func announce<T, U>(input args: T, output rv: U) -> U {
print("In: \(args)")
print("Out: \(rv)")
return rv
}
let multiply: ((Int, Int)) -> Int = decorate(*, decoration: announce)
multiply((2, 5)) // In: (2, 5)\nOut: 10
let length = decorate( { (str: String) in str.count }, decoration: announce)
length("Hello world!") // In: Hello world!\nOut: 12
let greet: ((String)) -> String = decorate( {"Hello, \([=10=])" }, decoration: announce)
greet(("Paul")) // In: Paul\nOut: Hello, Paul
以上示例更新为 Swift 5.1+
@propertyWrapper
struct Announced<T, U> {
private let announcedFunction: (T) -> U
var wrappedValue: (T) -> U { announcedFunction }
init(wrappedValue: @escaping (T) -> U) {
announcedFunction = { args in
let rv = wrappedValue(args)
print("In: \(args)")
print("Out: \(rv)")
return rv
}
}
}
struct Test {
@Announced static var add: ((Int, Int)) -> Int = { [=10=].0 + [=10=].1 }
@Announced static var multiply: ((Int, Int)) -> Int = { [=10=].0 * [=10=].1 }
@Announced static var length : (String) -> Int = { (str: String) in str.count }
@Announced static var greet: (String) -> String = { "Hello, \([=10=])" }
}
Test.add((2, 5)) // In: (2, 5)\n Out: 7
Test.multiply((2, 5)) // In: (2, 5)\n Out: 10
Test.length("Hello world!") // In: Hello world!\n Out: 12
Test.greet("Paul") // In: Paul\n Out: Hello, Paul
[编辑]其实可以简化一下:
@propertyWrapper
struct Announced<T, U> {
let wrappedValue: (T) -> U
init(wrappedValue: @escaping (T) -> U) {
self.wrappedValue = { args in
let rv = wrappedValue(args)
print("In: \(args)")
print("Out: \(rv)")
return rv
}
}
}