Фильтровать массив в категории / расширении

#ios #arrays #swift

#iOS #массивы #swift

Вопрос:

Для удобства в рамках небольшого эксперимента, который я провожу, я хотел бы расширить массив, чтобы предоставить некоторые функции, специфичные для приложения. Это конкретное расширение не является необходимой передовой практикой, но мне просто интересно решить возникающие у меня проблемы со Swift.

Учитывая раздел пользовательского класса, мое расширение (с частично расширенным закрытием) является:

 extension Array {

    func onlyFullSection() -> Array<Section> {

        return self.filter {
            (a:Section) -> Bool in
            return a.isFullSection()
        }
    }
}
  

Я получаю ошибку: «T» не является подтипом «Section».

Я пытался исправить это со всеми соусами (изменение типов, приведение и т.д.), Но все равно получаю похожие ошибки.

Этот другой вариант:

 extension Array {

    func onlyFullSection() -> Array<Section> {

        return (self as Array<Section>).filter {
            (a:Section) -> Bool in
            return a.isFullSection()
        } as Array<Section>
    }
  

выдает: Cannot convert the expression's type 'Array<Section>' to type 'Array<Section>'

Есть какие-нибудь подсказки о том, что я делаю неправильно? Спасибо!

Ответ №1:

Это потому, что вы расширяете T[], а не Section[] . Это означает, что у Int[] также будет ваш дополнительный метод. Это может быть не лучшей идеей (поскольку это приведет к серьезному сбою).

В настоящее время Swift не позволяет расширять специализированный универсальный тип, такой как Section[].

Но если вы действительно, действительно хотите это сделать, вот один из способов принудительного приведения, используйте reinterpretCast , который Apple описывает следующим образом

 /// A brutal bit-cast of something to anything of the same size
func reinterpretCast<T, U>(x: T) -> U
  

Вы можете использовать его следующим образом:

 extension Array {
    func onlyFullSection() -> Section[] {
        let sections : Section[] = reinterpretCast(self)
        return sections.filter{ $0.isFullSection() }
    }
}
  

Но, пожалуйста, не делайте этого.

Ответ №2:

Проблема в том, что, поскольку Array класс на самом деле является универсальным Array<T> , вы расширяете Array<T> . И, по-видимому, вы не можете выполнять преобразование между универсальными типами (т. Е. <T> в <Section> ), поэтому я полагаю, вам придется создать новый массив и просто вставить в него соответствующие объекты.

  17> extension Array {
 18.     func onlyFullSection() -> Array<Section> {
 19.         var ary = Array<Section>()
 20.         for s in self {
 21.             if (s as Section).isFullSection() {
 22.                 ary.append(s as Section)
 23.             }
 24.         }
 25.         return ary
 26.     }
 27. }
  

Вы также могли бы создать вспомогательный метод для преобразования между универсальными типами для вас, но в данном случае это просто создало бы ненужный временный объект.

Помните, что язык все еще сильно меняется, поэтому возможно, что это изменится. Я думаю, маловероятно, что мы получим возможность выполнять приведение между универсальными типами, но я надеюсь, что мы, по крайней мере, сможем расширить определенные универсальные типы.