简体   繁体   中英

Can @dynamicMemberLookup be used to call methods?

In the documentation for @dynamicMemberLookup it says,

Apply this attribute to a class, structure, enumeration, or protocol to enable members to be looked up by name at runtime.

If I'm not mistaken, instance methods are considered members of a struct / class. However, when I try to call a function dynamically I get an error saying:

Dynamic key path member lookup cannot refer to instance method foo()

To reproduce the problem:

struct Person {
    var name: String
    var age: Int
    
    func greet() {
        print("hello, my name is \(name)")
    }
}

@dynamicMemberLookup
struct Wrapper {
    var value: Person
    
    subscript<T>(dynamicMember keypath: KeyPath<Person, T>) -> T {
        value[keyPath: keypath]
    }
}

let person = Person(name: "John Doe", age: 21)
let wrapper = Wrapper(value: person)

wrapper.greet()  // << Error: Dynamic key path member lookup cannot refer to instance method `greet()`
// Or
let function = wrapper.greet  // << Error: Dynamic key path member lookup cannot refer to instance method `greet()`
function()

How can I dynamically call greet() using @dynamicMemberLookup ? Is there any way to achieve what I'm trying to do?

Thanks in advance!

No, dynamicMemberLookup does not work for methods. As the signature of the subscript suggests, it only works for things that can be represented as a KeyPath . Method calls cannot be part of a key path. :(

Key-Path Expression

A key-path expression refers to a property or subscript of a type.

The path consists of property names, subscripts, optional-chaining expressions, and forced unwrapping expressions. Each of these key-path components can be repeated as many times as needed, in any order.

At compile time, a key-path expression is replaced by an instance of the KeyPath class.

I suspect the reason why it is called "dynamic member lookup" is because it also works with subscripts. The alternative of dynamicPropertyOrSubscriptLookup is rather a mouthful isn't it?

One rather hacky fix would be to change greet into a computed property:

var greet: () -> Void { {
    print("hello, my name is \(name)")
} }

If greet has had parameters, you could also change it into a subscript, but I think that is an even uglier solution.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM