@dynamicCallable

77 阅读2分钟

是一种语法糖, 有两种实现方式, 输入类型和输出类型都可定义。 不能添加到扩展, 只能在类型主定义中

请看下面使用案例:

@dynamicCallable
struct Greeter {
    // 还可以添加正常的属性和方法
    func greet(name: String) {
        print(name)
    }

    // 方法1 和方法2 定义不冲突,但是调用会发生模糊不清
    //func dynamicallyCall(withArguments args: [Int]) {
      //  for n in args {
         //   print("num = \(n)")
       // }
    //}

    // 方法2
    func dynamicallyCall(withArguments args: [Int]) -> Double {
        for num in args {
            return Double(num) * 2
        }
        return 0.0
    }

    // 方法3
    func dynamicallyCall(withArguments args: [String]) {
        for str in args {
            print("str = \(str)")
        }
    }
    
    // 方法4
    func dynamicallyCall(withKeywordArguments args: KeyValuePairs<String, String>) {
        for (key, value) in args {
            print("key = \(key)")
            print("Hi, \(value).")
        }
    }
}

更多的写法

对于第一个方法(没有参数标签),您可以使用任何符合ExpressibleByArrayLiteral的任何方法,如数组、数组切片和集;对于第二种方法(带有参数标签),您可以使用任何符合ExpressibleByDictionaryLiteral文本,如字典和键值对。

使用集合

func dynamicallyCall(withArguments args: Set<Int>) {
    for n in args {
        print("num = \(n)")
    }
}

使用字典 (此时, 调用时标签字段不能重复)

func dynamicallyCall(withKeywordArguments args: [String: String] ) {
    for (key, value) in args {
        print("key = \(key)")
        print("Hi, \(value).")
    }
}

调用

一种不带带标签的调用, 另一种带标签的。

let gretter = Greeter()

gretter(name: "Tyler")
gretter(person: "Bob", name2: "Tim", person: "Nancy")
let d = gretter(1, 2, 3)
gretter(name: "Hello")
// 调用方法1
gretter(1, 2, 3)
// 调用方法2
let d = gretter(1, 2, 3)
// 调用的 方法3
greeter("Jack")
// 调用的 方法4, person标签传了两次, 且后面的没覆盖前面的person
gretter(person: "Bob", name2: "Tim", person: "Nancy")

注意点

  • 在不实现 dynamicallyCall(withArguments 方法时, 去调用dynamicallyCall(withKeywordArguments 也可不用传参数,此时的 key 为空 greeter("Jack")

KeyValuePairs

具有的特点

  • 您的密钥不需要符合Hashable.
  • 您可以使用重复的键添加项。(不会覆盖自定中添加的值)
  • 添加项的顺序将保留。(是DictionAry变有序)