如何在Swift中使用Self作为方法返回类型?

时间:2018-04-12 15:19:07

标签: swift protocols swift4.1

此代码生成Xcode错误消息,引导您进入一个圆圈。假设我有一个名为static string GetBuildMonthDay() { var version = typeof(Test).GetTypeInfo().Assembly.GetName().Version; var buildDateTime = new DateTime(2000, 1, 1) .AddDays(version.Build) .AddSeconds(version.Revision * 2); return buildDateTime.ToString("Mdd", CultureInfo.InvariantCulture); } 的协议,我想让Markers复制自己。这是第一次猜测......

Marker

(我不确定如何正确使用protocol Marker { func copy() -> Self } class Marker1 : Marker { func copy() -> Self { return Marker1() // error here } } ,因为我无法在 Swift编程语言文档中找到它。如果你知道它在哪里记录,请包括回答。)

该代码在标记的行上显示错误:Self并且它建议修复:Cannot convert return expression of type 'Marker1' to return type 'Self'

我接受修复:

Insert ' as! Self'

这会导致另一个编译器错误:... return Marker1() as! Self ...

如果我接受“修复”,则会返回原始错误。我称之为Xcode中的一个错误。我们试试别的:

'Self' is only available in a protocol or as the result of a method in a class; did you mean 'Marker1'?

另一个错误:func copy() -> Marker1 { return Marker1() }

使类Method 'copy()' in non-final class 'Marker1' must return `Self` to conform to protocol 'Marker'确实可以修复错误。但有没有办法在没有上课的情况下做到这一点? final在哪里记录?

2 个答案:

答案 0 :(得分:3)

使用这样的层次结构,您必须使该类符合协议final

protocol Marker {
    func copy() -> Self
}
final class Marker1 : Marker {
    func copy() -> Marker1 {
        return Marker1()
    }
}

需要final,因为当您不申请final并创建子类Marker2: Marker1时,复制将不再返回正确的类Self

您可以通过创建required初始化程序并始终创建正确的实例来解决此问题:

protocol Marker {
    init()
    func copy() -> Self
}
class Marker1 : Marker {
    required init() {
    }
    func copy() -> Self {
        let copy = type(of: self).init()
        return copy
    }
}

(删除原始代码,因为不起作用)

相关:Implementing copy() in Swift

答案 1 :(得分:1)

当前实现的问题是Self是一种抽象类型,因此您不能简单地从返回类型为Marker1的函数中返回具体类型,例如Self 。如果将返回类型更改为Marker1,则需要使类最终确保没有子类可以覆盖该方法,因为在子类中,Self将对应于子类类型。但是,这仍然不好,因为在这种情况下子类将不符合协议,因为在Marker1的子类中,Marker1的返回类型与{{1}不同}。

您可以通过使用self获取当前类的元类型来解决此问题,然后在元类型上调用指定的初始化程序,这将确实返回类型为type(of: self)的实例。最后一步是为您的类创建一个必需的初始化程序,以确保所有子类都需要实现在Self方法中调用的相同初始化程序,以使copy()也适用于子类。

copy