如何在不破坏编译器的情况下实现MutableCollectionType ?

时间:2021-11-20 20:46:57

I'm used to an ever-crashing Swift compiler and usually there are plenty of workarounds available. This time however I'm not able to successfully make a struct conform to MutableCollectionType.

我习惯了不断崩溃的快速编译器,通常有很多可用的变通方法。然而,这一次我不能成功地使结构符合MutableCollectionType。

Pasting the attached example into a Playground works as long as you don't uncomment the MutableCollectionType conformance.
I avoided concrete implementations for all methods to narrow down the cause of the crash (thus all the fatalError()). But even when the methods are implemented properly the compiler will crash.

将所附的示例粘贴到运动场中,只要不注释mutableclecollectiontype一致性就可以。我避免了所有方法的具体实现,以缩小崩溃的原因(因此避免了所有的fatalError()))。但是,即使正确地实现了这些方法,编译器也会崩溃。

Does anybody have an idea how to work around this compiler crash?

有人知道如何处理这个编译器崩溃吗?

struct Test {}


struct TestCollection: CollectionType {

    typealias Index = Int


    private var values: [Test]


    var count: Int {
        fatalError()
    }


    var endIndex: Int {
        fatalError()
    }


    func generate() -> IndexingGenerator<Array<Test>> {
        fatalError()
    }


    var isEmpty: Bool {
        fatalError()
    }


    subscript(bounds: Range<Int>) -> ArraySlice<Test> {
        fatalError()
    }


    subscript(position: Int) -> Test {
        get { fatalError() }
        mutating set { fatalError() }
    }


    var startIndex: Int {
        fatalError()
    }
}


// uncommenting the following line crashes the compiler
// extension TestCollection: MutableCollectionType {}

1 个解决方案

#1


2  

Yeah, working around compiler crashes is pretty tough. There are a couple of techniques that are helpful, though. First of all, if you compile this and it segfaults (as this is doing for me, currently) you can still go into the error in Xcode, and it might give you more information.

是的,解决编译器崩溃是非常困难的。不过,有一些技巧是有用的。首先,如果您编译这个并它分段错误(就像我目前所做的那样),您仍然可以进入Xcode中的错误,它可能会提供更多信息。

Alternatively, you can try and reduce your crash to the minimum working example, to see which part crashes the compiler. As it happens, the minimum set of methods for MutableCollectionType conformance is actually quite small:

或者,您可以尝试将崩溃减少到最小的工作示例,以查看哪个部分导致编译器崩溃。碰巧的是,可变聚合类型一致性的最小方法集实际上相当小:

struct Test {}

struct TestCollection: MutableCollectionType {

  var startIndex: Int { fatalError() }

  var endIndex: Int { fatalError() }

  subscript(position: Int) -> Test {
    get { fatalError() }
    mutating set { fatalError() }
  }

}

So now we can add back in your extra things, one by one, until it crashes. As it happens, the typealias, count, generate(), and isEmpty, are actually better off being left out. The typealias is inferred, count and isEmpty can be calculated based on the startIndex and endIndex (and it would be just as efficient as if you wrote your own methods), and the generate() method can return an IndexingGenerator over the collection itself, rather than the array.

所以现在我们可以一个接一个地添加额外的东西,直到它崩溃。碰巧的是,将typealias、count、generate()和isEmpty排除在外实际上更好。typealias被推断出来,count和isEmpty可以基于startIndex和endIndex(并且它的效率与您编写自己的方法一样)计算,generate()方法可以在集合本身而不是数组上返回一个IndexingGenerator。

So the only thing to add back in is the ranged subscript:

所以唯一要加回来的是下标

extension TestCollection {
  subscript(range: Range<Int>) -> ArraySlice<Test> {
    fatalError()
  }
}

Looking at that a little more closely, you could possibly write this a little differently:

仔细观察一下,你可能会有不同的想法:

extension TestCollection {
  subscript(range: Range<Int>) -> ArraySlice<Test> {
    get { fatalError() }
    set { fatalError() }
  }
}

And no error!

并没有错误!

Just a small note: it looks like you're implementing a very lightweight wrapper around Array, for your Test struct. Because of the complexity involved in properly following all of the required protocols, you might be better off just extending Array to provide the functionality that you need, or extending MutableCollectionType like this:

只需要注意一点:看起来您正在为您的测试结构体实现一个关于数组的非常轻量级的包装器。由于正确地遵循所有要求的协议所涉及的复杂性,您最好只是扩展数组以提供所需的功能,或者扩展MutableCollectionType,例如:

extension MutableCollectionType where Generator.Element == Test {...

#1


2  

Yeah, working around compiler crashes is pretty tough. There are a couple of techniques that are helpful, though. First of all, if you compile this and it segfaults (as this is doing for me, currently) you can still go into the error in Xcode, and it might give you more information.

是的,解决编译器崩溃是非常困难的。不过,有一些技巧是有用的。首先,如果您编译这个并它分段错误(就像我目前所做的那样),您仍然可以进入Xcode中的错误,它可能会提供更多信息。

Alternatively, you can try and reduce your crash to the minimum working example, to see which part crashes the compiler. As it happens, the minimum set of methods for MutableCollectionType conformance is actually quite small:

或者,您可以尝试将崩溃减少到最小的工作示例,以查看哪个部分导致编译器崩溃。碰巧的是,可变聚合类型一致性的最小方法集实际上相当小:

struct Test {}

struct TestCollection: MutableCollectionType {

  var startIndex: Int { fatalError() }

  var endIndex: Int { fatalError() }

  subscript(position: Int) -> Test {
    get { fatalError() }
    mutating set { fatalError() }
  }

}

So now we can add back in your extra things, one by one, until it crashes. As it happens, the typealias, count, generate(), and isEmpty, are actually better off being left out. The typealias is inferred, count and isEmpty can be calculated based on the startIndex and endIndex (and it would be just as efficient as if you wrote your own methods), and the generate() method can return an IndexingGenerator over the collection itself, rather than the array.

所以现在我们可以一个接一个地添加额外的东西,直到它崩溃。碰巧的是,将typealias、count、generate()和isEmpty排除在外实际上更好。typealias被推断出来,count和isEmpty可以基于startIndex和endIndex(并且它的效率与您编写自己的方法一样)计算,generate()方法可以在集合本身而不是数组上返回一个IndexingGenerator。

So the only thing to add back in is the ranged subscript:

所以唯一要加回来的是下标

extension TestCollection {
  subscript(range: Range<Int>) -> ArraySlice<Test> {
    fatalError()
  }
}

Looking at that a little more closely, you could possibly write this a little differently:

仔细观察一下,你可能会有不同的想法:

extension TestCollection {
  subscript(range: Range<Int>) -> ArraySlice<Test> {
    get { fatalError() }
    set { fatalError() }
  }
}

And no error!

并没有错误!

Just a small note: it looks like you're implementing a very lightweight wrapper around Array, for your Test struct. Because of the complexity involved in properly following all of the required protocols, you might be better off just extending Array to provide the functionality that you need, or extending MutableCollectionType like this:

只需要注意一点:看起来您正在为您的测试结构体实现一个关于数组的非常轻量级的包装器。由于正确地遵循所有要求的协议所涉及的复杂性,您最好只是扩展数组以提供所需的功能,或者扩展MutableCollectionType,例如:

extension MutableCollectionType where Generator.Element == Test {...