Is there a way in Swift that I can get a property from a struct without having to reference it?
For example
public struct ASValue<T: Hashable>: Hashable {
private let id = UUID()
public var item: T
public init(item: T) {
self.item = item
}
}
let val = ASValue(item: "Example")
print(val) // Prints: Example
CodePudding user response:
It's possible by adopting CustomStringConvertible
and constraining T
also to CustomStringConvertible
public struct ASValue<T: Hashable>: Hashable, CustomStringConvertible where T: CustomStringConvertible {
private let id = UUID()
public var item: T
public var description : String {
return "\(item)"
}
}
let val = ASValue(item: "Example")
print(val) // Prints: Example
And this is a struct, the init
method is for free.
CodePudding user response:
What you are looking for is exactly provided with property wrappers in swift. You have to make your ASValue
structproperty wrapper by applying @propertyWrapper
to the declaration:
@propertyWrapper
public struct ASValue<T: Hashable>: Hashable {
private let id = UUID()
public var wrappedValue: T
public init(wrappedValue: T) {
self.wrappedValue = wrappedValue
}
}
Then you can use this wrapper to wrap any property in another type and access that property directly. You can even access the ASValue
wrapper type by prefixing with _
:
class SomeClass {
@ASValue var val = "Example"
func printVal() {
// print(_val) for actual value
print(val) // Prints: Example
}
}
You can also pass this property with its wrapper identity to other function:
func printVal<T: Hashable>(@ASValue val: T) {
// print(_val) for actual value
print(val) // Prints: Example
}
let obj = SomeClass()
printVal(val: obj.val)
If for some constraint you can't use the property wrapper approach you can try the @dynamicCallable
attribute as a workaround. This allows values created from your types to be invoked as methods with specified arguments.
@dynamicCallable
public struct ASValue<T: Hashable>: Hashable {
private let id = UUID()
public var item: T
public init(item: T) {
self.item = item
}
// need to have withArguments with argument type confirming
// to ExpressibleByArrayLiteral
func dynamicallyCall(withArguments arg: [Int] = []) -> T {
return item
}
}
let val = ASValue(item: "Example")
print(val()) // Prints: Example