使Swift数组符合协议

17

假设某些项目可以出现在 Feed中,只要它们实现了 Feedable 协议定义的必要属性。也让我们说 Photo 对象值得出现在Feed中:

extension Photo: Feedable { }

是否有可能说这些照片的Array也可以作为Feedable?

extension [Photo] : Feedable

我是否总是需要某种包装对象,比如PhotoAlbum,才能符合Feedable的要求?

编辑

再次强调,我想知道是否可以只创建 Photo 对象的数组来实现 Feedable。不是将任何内容类型的 Array 变为 Feedable,也不是将 Feedable 数组本身变为 Feedable(如果您需要这样的解决方案,则下面提供了这两个解决方案)。

换句话说,一种(我怀疑不存在的)解决方案将允许我定义一个类型为 Feedable 的变量,并具有以下结果:

var feedable: Feedable

//photo is feedable, so this is fine
feedable = Photo() //ok

//arrays of photos are feedable
let photo1 = Photo()
let photo2 = Photo()
feedable = [photo1, photo2]

//arrays of other things are not
feedable = ["no", "dice"] //nope

//even if the contents of an array are themselves Feedable, that's not sufficient. E.g. Video is Feedable, but Array of Videos is not.
let video1 = Video()
let video2 = Video()
feeble = video1 //fine
feedable = [video1, video2] //nope

或许这个代码片段(尽管不能编译)更能清晰地表达意图。


3
extension Array where Element: Feedable { ... } 的翻译是:当元素为Feedable时,对数组进行扩展 { ... } - Leo Dabus
@LeoDabus 我想为 Photo 对象数组提供一个特定的 Feedable 协议实现,而不是其他 Feedable 类型的数组。例如,与 Video 对象数组不同,Photos 数组可能提供不同的 feedDescription - Ben Packard
@matt Feedable协议将为Photo和一组Photo提供不同的feedDescription实现。例如,“添加了一张照片”与“添加了5张照片”。假设我只提供了适合于Feed的项目(照片、视频或其中任何一组)。 - Ben Packard
1
@BenPackard extension _ArrayType where Generator.Element == Photo { ... }@BenPackard extension _ArrayType where Generator.Element == 照片 { ... } - Leo Dabus
你不能覆盖它。 - Leo Dabus
显示剩余16条评论
6个回答

13

你可以通过以下方式实现你的目标:

Swift 4:

protocol Feedable {
    func foo()
}

extension String: Feedable {
    func foo() {    
    }
}

extension Array: Feedable where Element: Feedable {
    func foo() {    
    }
}
// or in more generic way to support Array, Set and other collection types
extension Collection: Feedable where Element: Feedable {
    func foo() {    
    }
}

1
这很不错,但我认为它并没有满足所有的要求。具体来说,我的代码片段中最后一个例子:“即使数组的内容本身是Feedable,这也是不够的。例如,Video是Feedable,但是Videos数组不是。”在你的实现中,字符串数组之所以是可馈送的,仅仅是因为字符串本身是可馈送的。 - Ben Packard

3
如果有一个包含PhotoVideo的数组,你想成为哪个元素?
1.每个元素都表现出它所代表的意义。
extension Array where Element : Feedable {
    func foo() {
        if Element.self == Photo.self {

        } else {

        }
    }
}

2. 整个数组的表现形式为“视频”。

extension Array where Element : Photo {
    func foo() {

    }
}

我想要前者,但不想允许所有类型的数组都是可馈送的。 - Ben Packard
@BenPackard Element是一个数组的泛型类型。当你的数组符合所有条件时,带有条件的扩展才能生效。 - Lumialxk
@ben-packard 提出的解决方案中的 "where" 子句意味着此扩展仅适用于数组,其中数组中的元素类型符合 Feedable 协议,而不是“任何类型的所有数组”。 - Scott Thompson
@ScottThompson 这不是我想问的。我想知道如何将照片数组变成可供馈送,而不是将馈送数组变成可供馈送。我认为这是不可能的。 - Ben Packard

1
我认为目前还不可能。在我的项目中,我也遇到了ModelProducer的同样问题。
protocol M: ModelType {}
protocol ModelProducerType {
    associatedtype M: ModelType
    var model: M? { get }
    func produce()
}

struct Test: ModelType {}
class TestProducer: ModelProducerType {
    var model: Test?
    func produce() {
        model = Test()
    }
}

我使用ModelType作为一种虚拟协议。问题在于我无法创建一个可以生成多个ModelType的模型生产者,因为你发现的同样的原因。在这种情况下的解决方案如下:
protocol M: ModelType {}
protocol ModelProducerType {
    associatedtype M: ModelType
    var model: [M] { get }
    func produce()
}

struct Test: ModelType {}
class TestProducer: ModelProducerType {
    var model: [Test] = []
    func produce() {
        model = [Test()]
    }
}

这种方法从一开始就更加灵活。我摆脱了可选变量,而且单个模型生产者只需在数组中有一个项目。也许你可以采用类似的方法。


0

这里的答案几乎满足了你想要做的事情。具体来说,this one,只需进行一个更改,就可以将其限制为符合type而不是符合protocol的元素。

Swift 5.8

extension Array: Feedable where Element == Photo {
   
}

使用这个扩展程序,问题中发布的代码显示了预期的错误,在其他地方一切正常。

Xcode displaying the code from the question


0
你可以创建一个数组来符合这样的协议:
typealias PhotoArray = [Photo]

extension PhotoArray: Feedable {}

-5

我没有在 playground 中尝试过,但也许你可以简单地创建一个 Feedable 的数组:

var myPhotosArray = [Feedable]()

那么实现Feedable协议的所有内容都将被允许在数组中。如果您只想要一个照片数组,您仍然可以子类化您的照片对象以创建一个FeedablePhoto对象。

请在Playground中尝试此操作,而不是没有测试就进行投票否决。 严肃地说,三个投票否决却没有任何理由和解释...

import UIKit

protocol Tree: class {
  func grow()
}

class BigTree: Tree {
  internal func grow() {
    print("Big tree growing")
  }
}

class SmallTree: Tree {
  internal func grow() {
    print("Small tree growing")
  }
}

class Car {
  //not a tree
}

var manyTrees = [Tree]()

manyTrees.append(BigTree())
manyTrees.append(SmallTree())
manyTrees.append(Car()) //This makes an error "Car doesn't conform to expected type 'Tree'"

你在给这篇文章点负分之前有没有尝试过?我试了,它可行。 - Mikael
我自己没有将其减1,但这并没有回答问题。我认为这就是它被投票降低的原因。 - Ben Packard
据我理解,是这样的。只有实现Feedable协议的类才能添加到数组中。问题是:“是否可能说这些照片的数组也可以是Feedable?” 我想我的答案不容易理解,我没有尝试过Swift 3,但是在Swift 2中,只需让Photo类实现该协议即可。 - Mikael

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接