I'm struggling to understand protocols and protocol extensions in swift.
I'm wanting to define a series of protocols that can be applied to a class, along with a set of protocol extensions to provide default implementations. Example code:
// MARK: - Protocols & Protocol Extensions
protocol OutputItem {
typealias ResultType
func rawValue() -> ResultType
// other requirements ...
}
protocol StringOutputItem : OutputItem {}
extension StringOutputItem {
typealias ResultType = String
override func rawValue() -> Self.ResultType {
return "string ouput"
}
}
protocol IntOutputItem: OutputItem {}
extension IntOutputItem {
typealias ResultType = Int
override func rawValue() -> Self.ResultType {
return 123
}
}
The above override functions for rawValue()
in the extensions give an error Ambiguous type name 'ResultType' in 'Self'
. If I remove Self
, from Self.ResultType
, I get the error 'ResultType' is ambiguous for type lookup in this context
.
How do I signal to the protocol extension which type to use for ResultType
?
My aim is to be able to apply the protocols and their extensions to a class as follows:
// MARK: - Base Class
class DataItem {
// Some base class methods
func randomMethod() -> String {
return "some random base class method"
}
}
// MARK: - Subclasses
class StringItem : DataItem, StringOutputItem {
// Some subclass methods
}
class AnotherStringItem : DataItem, StringOutputItem {
// Some subclass methods
}
class IntItem : DataItem, IntOutputItem {
// Some subclass methods
}
So that:
let item1 = StringItem()
print(item1.rawValue()) // should give "string output"
let item2 = AnotherStringItem()
print(item2.rawValue()) // should give "string output"
let item3 = IntItem()
print(item3.rawValue()) // should give 123
If I'm completely off base with how protocol extensions work to provide default implementations, I'm open ideas of how to achieve the same outcome.
The Swift compiler infers the type of ResultType
by the type signatures of the implemented protocol methods. For example, in the following declaration of StringOutputItem
, the compiler knows that StringOutputItem
's ResultType
is of type String
, even without an explicit declaration:
protocol StringOutputItem: OutputItem {}
extension StringOutputItem {
func rawValue() -> String {
return "string output"
}
}
class StringItem : DataItem, StringOutputItem {}
let item = StringItem()
print(item.rawValue()) // prints "string output"
We can explicitly declare the ResultType
in StringOutputItem
, which will just ensure that StringOutputItem
conforms to the OutputItem
protocol AND implements it with the right type.
To illustrate the type inference of the associated type, let's say that OutputItem
specifies another method as part of its protocol. If we provide a default implementation whereby the types do not match, the compiler will throw an error indicating that the implementing type does not conform to the protocol.
protocol OutputItem {
typealias ResultType
func rawValue() -> ResultType
func printValue(r: ResultType)
}
protocol StringOutputItem: OutputItem {}
extension StringOutputItem {
func rawValue() -> String {
return "string output"
}
func printValue(r: Int) { // Should be String
...
}
}
struct Test: StringOutputItem {} // Error: Type 'Test' does not conform to protocol 'OutputItem'
By explicitly declaring typealias ResultType = String
in StringOutputItem
, we are making sure that the correct type is used when implementing the protocol's methods.
protocol OutputItem {
typealias ResultType
func rawValue() -> ResultType
func printValue(r: ResultType)
}
protocol StringOutputItem: OutputItem {}
extension StringOutputItem {
typealias ResultType = String // without this typealias declaration, the program WILL compile since ResultType is inferred to be of type Int
func rawValue() -> Int {
return 123
}
func printValue(r: Int) {
...
}
}
struct Test: StringOutputItem {} // Error: Type 'Test' does not conform to protocol 'OutputItem'
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.