Swift中的装饰器

问题描述 投票:4回答:2

我是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中使用的模式?

swift decorator composition
2个回答
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

或者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

0
投票

上面的示例已更新为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, \($0)" }, decoration: announce)
greet(("Paul")) // In: Paul\nOut: Hello, Paul
© www.soinside.com 2019 - 2024. All rights reserved.