Self를 반환하는 프로토콜 func
개체의 복사본을 반환하는 프로토콜 P가 있습니다.
protocol P {
func copy() -> Self
}
P를 구현하는 클래스 C :
class C : P {
func copy() -> Self {
return C()
}
}
그러나 Self
다음 오류가 발생 하면 반환 값을 입력했는지 여부 :
'C'유형의 반환 식을 'Self'반환 유형으로 변환 할 수 없습니다.
나는 또한 반환을 시도했다 C
.
class C : P {
func copy() -> C {
return C()
}
}
그 결과 다음과 같은 오류가 발생했습니다.
비 최종 클래스 'C'의 'copy ()'메서드
Self
는 프로토콜 'P'를 준수하도록 반환되어야합니다.
내가 접두사 class C
를 final
붙인 경우를 제외하고는 아무것도 작동 하지 않습니다.
final class C : P {
func copy() -> C {
return C()
}
}
그러나 C를 하위 클래스로 만들고 싶다면 아무것도 작동하지 않습니다. 이 문제를 해결할 방법이 있습니까?
문제는 컴파일러가 당신이 지킬 것이라는 것을 증명할 수 없다는 약속을하고 있다는 것입니다.
그래서이 약속을 만들었습니다 : 호출 copy()
은 완전히 초기화 된 자체 유형을 반환합니다.
그러나 다음과 같이 구현 copy()
했습니다.
func copy() -> Self {
return C()
}
이제 나는 재정의하지 않는 하위 클래스입니다 copy()
. 그리고 나는 C
완전히 초기화되지 않은 Self
(내가 약속 한)를 반환합니다 . 그래서 그것은 좋지 않습니다. 어때 :
func copy() -> Self {
return Self()
}
음, 그것은 컴파일되지 않을 것입니다.하지만 그렇게되었다고해도 좋지 않을 것입니다. 하위 클래스에는 사소한 생성자 D()
가 없을 수 있으므로 합법적이지 않을 수도 있습니다. (아래를 참조하십시오.)
좋습니다. 다음은 어떻습니까?
func copy() -> C {
return C()
}
예,하지만 반환되지 않습니다 Self
. 반환합니다 C
. 당신은 여전히 당신의 약속을 지키지 않고 있습니다.
"하지만 ObjC는 할 수 있습니다!" 글쎄요. 대부분은 Swift가하는 것처럼 약속을 지키더라도 상관하지 않기 때문입니다. copyWithZone:
하위 클래스에서 구현 하지 못하면 객체를 완전히 초기화하지 못할 수 있습니다. 컴파일러는 당신이 그렇게했다는 경고조차하지 않을 것입니다.
"그러나 ObjC의 대부분은 Swift로 번역 될 수 있으며 ObjC는 NSCopying
." 예, 그렇습니다. 정의 된 방법은 다음과 같습니다.
func copy() -> AnyObject!
따라서 동일한 작업을 수행 할 수 있습니다 (여기에는!에 대한 이유가 없습니다).
protocol Copyable {
func copy() -> AnyObject
}
그것은 "나는 당신이 돌려받는 것에 대해 아무것도 약속하지 않습니다."라고 말합니다. 다음과 같이 말할 수도 있습니다.
protocol Copyable {
func copy() -> Copyable
}
그것은 당신이 할 수있는 약속입니다.
하지만 우리는 잠시 동안 C ++에 대해 생각하고 우리가 할 수있는 약속이 있다는 것을 기억할 수 있습니다 . 우리와 우리의 모든 서브 클래스가 특정 종류의 이니셜 라이저를 구현할 것이라고 약속 할 수 있으며, Swift는이를 강제 할 것입니다 (따라서 우리가 진실을 말하고 있음을 증명할 수 있습니다).
protocol Copyable {
init(copy: Self)
}
class C : Copyable {
required init(copy: C) {
// Perform your copying here.
}
}
이것이 복사를 수행하는 방법입니다.
우리는 이것을 한 단계 더 dynamicType
나아갈 수 있지만를 사용하고 그것이 항상 우리가 원하는 것인지 확인하기 위해 광범위하게 테스트하지는 않았지만 정확해야합니다.
protocol Copyable {
func copy() -> Self
init(copy: Self)
}
class C : Copyable {
func copy() -> Self {
return self.dynamicType(copy: self)
}
required init(copy: C) {
// Perform your copying here.
}
}
여기서 우리는 우리를 위해 복사를 수행하는 이니셜 라이저가 있다는 것을 약속하고, 런타임에 호출 할 것을 결정할 수 있으며, 찾고 있던 메소드 구문을 제공합니다.
Swift 2에서는이를 위해 프로토콜 확장을 사용할 수 있습니다.
protocol Copyable {
init(copy:Self)
}
extension Copyable {
func copy() -> Self {
return Self.init(copy: self)
}
}
Swift의 관련 유형을 활용하여 원하는 작업을 수행하는 또 다른 방법이 있습니다. 다음은 간단한 예입니다.
public protocol Creatable {
associatedtype ObjectType = Self
static func create() -> ObjectType
}
class MyClass {
// Your class stuff here
}
extension MyClass: Creatable {
// Define the protocol function to return class type
static func create() -> MyClass {
// Create an instance of your class however you want
return MyClass()
}
}
let obj = MyClass.create()
실제로 프로토콜 ( gist )에서 필요할 때 쉽게 반환 Self
할 수있는 트릭이 있습니다 .
/// Cast the argument to the infered function return type.
func autocast<T>(some: Any) -> T? {
return some as? T
}
protocol Foo {
static func foo() -> Self
}
class Vehicle: Foo {
class func foo() -> Self {
return autocast(Vehicle())!
}
}
class Tractor: Vehicle {
override class func foo() -> Self {
return autocast(Tractor())!
}
}
func typeName(some: Any) -> String {
return (some is Any.Type) ? "\(some)" : "\(some.dynamicType)"
}
let vehicle = Vehicle.foo()
let tractor = Tractor.foo()
print(typeName(vehicle)) // Vehicle
print(typeName(tractor)) // Tractor
Rob의 제안에 따라 관련 유형 으로 더 일반적으로 만들 수 있습니다 . 접근 방식의 이점을 보여주기 위해 예제를 약간 변경했습니다.
protocol Copyable: NSCopying {
associatedtype Prototype
init(copy: Prototype)
init(deepCopy: Prototype)
}
class C : Copyable {
typealias Prototype = C // <-- requires adding this line to classes
required init(copy: Prototype) {
// Perform your copying here.
}
required init(deepCopy: Prototype) {
// Perform your deep copying here.
}
@objc func copyWithZone(zone: NSZone) -> AnyObject {
return Prototype(copy: self)
}
}
나는 비슷한 문제가 있었고 유용한 것을 생각해 냈기 때문에 이것이 해결책을 찾을 때 찾은 첫 번째 장소 중 하나이기 때문에 나중에 참조하기 위해 공유 할 것입니다.
위에서 언급했듯이 문제는 copy () 함수에 대한 반환 유형의 모호성입니다. 이것은 copy ()-> C 및 copy ()-> P 함수를 분리하여 매우 명확하게 설명 할 수 있습니다.
따라서 프로토콜과 클래스를 다음과 같이 정의한다고 가정합니다.
protocol P
{
func copy() -> P
}
class C:P
{
func doCopy() -> C { return C() }
func copy() -> C { return doCopy() }
func copy() -> P { return doCopy() }
}
이는 반환 값의 유형이 명시적일 때 예상되는 결과를 컴파일하고 생성합니다. 컴파일러가 반환 유형을 자체적으로 결정해야 할 때마다 상황이 모호하고 P 프로토콜을 구현하는 모든 구체적인 클래스에 대해 실패합니다.
예를 들면 :
var aC:C = C() // aC is of type C
var aP:P = aC // aP is of type P (contains an instance of C)
var bC:C // this to test assignment to a C type variable
var bP:P // " " " P " "
bC = aC.copy() // OK copy()->C is used
bP = aC.copy() // Ambiguous.
// compiler could use either functions
bP = (aC as P).copy() // but this resolves the ambiguity.
bC = aP.copy() // Fails, obvious type incompatibility
bP = aP.copy() // OK copy()->P is used
결론적으로 이것은 기본 클래스의 copy () 함수를 사용하지 않거나 항상 명시적인 유형 컨텍스트가있는 상황에서 작동합니다.
I found that using the same function name as the concrete class made for unwieldy code everywhere, so I ended up using a different name for the protocol's copy() function.
The end result is more like:
protocol P
{
func copyAsP() -> P
}
class C:P
{
func copy() -> C
{
// there usually is a lot more code around here...
return C()
}
func copyAsP() -> P { return copy() }
}
Of course my context and functions are completely different but in spirit of the question, I tried to stay as close to the example given as possible.
Just throwing my hat into the ring here. We needed a protocol that returned an optional of the type the protocol was applied on. We also wanted the override to explicitly return the type, not just Self.
The trick is rather than using 'Self' as the return type, you instead define an associated type which you set equal to Self, then use that associated type.
Here's the old way, using Self...
protocol Mappable{
static func map() -> Self?
}
// Generated from Fix-it
extension SomeSpecificClass : Mappable{
static func map() -> Self? {
...
}
}
Here's the new way using the associated type. Note the return type is explicit now, not 'Self'.
protocol Mappable{
associatedtype ExplicitSelf = Self
static func map() -> ExplicitSelf?
}
// Generated from Fix-it
extension SomeSpecificClass : Mappable{
static func map() -> SomeSpecificClass? {
...
}
}
To add to the answers with the associatedtype
way, I suggest to move the creating of the instance to a default implementation of the protocol extension. In that way the conforming classes won't have to implement it, thus sparing us from code duplication:
protocol Initializable {
init()
}
protocol Creatable: Initializable {
associatedtype Object: Initializable = Self
static func newInstance() -> Object
}
extension Creatable {
static func newInstance() -> Object {
return Object()
}
}
class MyClass: Creatable {
required init() {}
}
class MyOtherClass: Creatable {
required init() {}
}
// Any class (struct, etc.) conforming to Creatable
// can create new instances without having to implement newInstance()
let instance1 = MyClass.newInstance()
let instance2 = MyOtherClass.newInstance()
참고URL : https://stackoverflow.com/questions/25645090/protocol-func-returning-self
'Development Tip' 카테고리의 다른 글
Apache가 XAMPP 제어판에서 실행되고 있지 않습니다 (오류 : Apache가 예기치 않게 종료되었습니다. 포트가 차단 되었기 때문일 수 있음) (0) | 2020.11.06 |
---|---|
Rails 바로 가기에서 nil이 아니고 비어 있지 않은지 확인하십시오. (0) | 2020.11.06 |
인터페이스 구현에서 정적 변수의 의미는 무엇입니까? (0) | 2020.11.06 |
하나의 쿼리로 두 테이블에서 삭제 (0) | 2020.11.06 |
sqlite의 ALTER COLUMN (0) | 2020.11.06 |