프로토콜 기능이 Self를 반환합니다.
개체의 복사본을 반환하는 프로토콜 P가 있습니다.
protocol P {
func copy() -> Self
}
P를 구현하는 클래스 C:
class C : P {
func copy() -> Self {
return C()
}
}
을 을 하는지 과 하는지 을 Self
합니다:음가다다가:iet음rg.
'C' 유형의 반환 표현식을 'Self' 유형의 반환 표현식으로 변환할 수 없습니다.
저도 돌아오려고 했습니다.C
.
class C : P {
func copy() -> C {
return C()
}
}
이로 인해 다음과 같은 오류가 발생했습니다.
클래스가 '의 메서드 'copy '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()
}
그게 컴파일은 안 되겠지만 설사 컴파일이 된다고 해도 소용이 없을 겁니다.생성자가 수 위는가을수다한다수e을위는가한obeyrs .D()
합법적이지 않을 수도 있습니다.(아래 참조)
좋아요, 그럼 다음은 어떨까요?
func copy() -> C {
return C()
}
①, ②, ③을 돌려주지는 않습니다.Self
돌아옵니다. C
약속을 않고 당신은 여전히 약속을 지키지 않고 있습니다.
는 는 스위프트처럼 약속을 지키더라도 상관없기 때문입니다구현에 실패한 경우copyWithZone:
하위 클래스에서 개체를 완전히 초기화하지 못할 수 있습니다.컴파일러는 당신이 그런 짓을 했다는 것을 경고하지도 않을 겁니다.
것은 Swift로 될 수 , 는 "ObjC 로 Swift 될 ObjC 은 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.
}
}
여기서 우리는 우리를 위해 복사본을 수행하는 이니셜라이저가 있음을 약속합니다. 그러면 런타임에 당신이 찾던 메소드 구문을 제공하면서 어떤 것을 호출할지 결정할 수 있습니다.
스위프트 2를 사용하면 프로토콜 확장 기능을 사용할 수 있습니다.
protocol Copyable {
init(copy:Self)
}
extension Copyable {
func copy() -> Self {
return Self.init(copy: self)
}
}
스위프트의 관련 유형을 활용하는 것과 관련된 다른 방법이 있습니다.간단한 예는 다음과 같습니다.
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()
사실, 쉽게 돌아올 수 있는 요령이 있습니다.Self
프로토콜(protocol)에서 요구하는 경우:
/// 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
스위프트 5.1은 강제 캐스팅을 허용합니다as! Self
1> protocol P {
2. func id() -> Self
3. }
9> class D : P {
10. func id() -> Self {
11. return D()
12. }
13. }
error: repl.swift:11:16: error: cannot convert return expression of type 'D' to return type 'Self'
return D()
^~~
as! Self
9> class D : P {
10. func id() -> Self {
11. return D() as! Self
12. }
13. } //works
롭의 제안에 따라, 이것은 연관된 유형으로 더 일반적으로 만들어질 수 있습니다.접근 방식의 이점을 보여주기 위해 예제를 조금 바꿨습니다.
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() 함수에 대한 return type의 모호성이 문제입니다.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() 함수를 사용하지 않거나 항상 명시적 유형 컨텍스트가 있는 상황에서 작동합니다.
저는 모든 곳에서 다루기 힘든 코드를 위해 만들어진 콘크리트 클래스와 동일한 함수 이름을 사용하는 것을 발견하여 프로토콜의 copy() 함수에 다른 이름을 사용하게 되었습니다.
최종 결과는 다음과 같습니다.
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() }
}
물론 저의 맥락과 기능은 완전히 다르지만, 질문의 정신으로 저는 주어진 예에 최대한 가까이 다가가려고 노력했습니다.
내 모자를 여기에 던져 넣는 것 뿐입니다.우리는 프로토콜이 적용된 유형의 선택사항을 반환하는 프로토콜이 필요했습니다.우리는 또한 오버라이드가 Self만이 아닌 형식을 명시적으로 반환하기를 원했습니다.
이 방법은 'Self'를 반환 유형으로 사용하는 대신 Self와 동일하게 설정한 연관 유형을 정의한 다음 해당 연관 유형을 사용하는 것입니다.
자기를 이용하는 옛날 방식이 여기 있어요
protocol Mappable{
static func map() -> Self?
}
// Generated from Fix-it
extension SomeSpecificClass : Mappable{
static func map() -> Self? {
...
}
}
다음은 관련 유형을 사용하는 새로운 방법입니다.반환 유형이 '자체'가 아닌 현재 명시적입니다.
protocol Mappable{
associatedtype ExplicitSelf = Self
static func map() -> ExplicitSelf?
}
// Generated from Fix-it
extension SomeSpecificClass : Mappable{
static func map() -> SomeSpecificClass? {
...
}
}
에 을 하기 하기 로 답에 associatedtype
인스턴스 생성을 프로토콜 확장의 기본 구현으로 이동할 것을 제안합니다.그런 방식으로 호환되는 클래스는 이를 구현할 필요가 없으므로 코드 중복을 방지할 수 있습니다.
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
'programing' 카테고리의 다른 글
element.remove를 호출할 때 $destroy가 트리거되지 않는 이유는 무엇입니까? (0) | 2023.09.19 |
---|---|
ASP에서 *all* 예외 처리를 사용하지 않도록 설정합니다.NET Web API 2 (나만의 공간을 만들기 위해)? (0) | 2023.09.19 |
MySQL의 계층 데이터에서 깊이 기반 트리 생성(CTE 없음) (0) | 2023.09.14 |
도커 스웜은 볼륨 공유를 어떻게 구현합니까? (0) | 2023.09.14 |
SQL: Oracle - 쿼리 중인 매개 변수 (0) | 2023.09.14 |