使用协议作为阵列类型和功能参数 swift

我想创建一个可以存储与特定协议对应的对象的类。 对象应存储在键入的阵列中。 根据文件 Swift 协议可以用作类型:

如这种类型,您可以在允许其他类型的许多地方使用该协议,包括:

作为函数,方法或初始化程序中的参数或返回类型的类型

作为一种常量,变量或属性

作为数组中的元素类型,字典或不同的容器

但是,以下导致编译器错误:

协议 'SomeProtocol' 只能用作一般限制,因为它有自己的自身或相关的类型

你是如何解决它的:


protocol SomeProtocol: Equatable {
func bla//
}

class SomeClass {

var protocols = [SomeProtocol]//

func addElement/element: SomeProtocol/ {
self.protocols.append/element/
}

func removeElement/element: SomeProtocol/ {
if let index = find/self.protocols, element/ {
self.protocols.removeAtIndex/index/
}
}
}
已邀请:

小明明

赞同来自:

您遇到了协议问题的选项 Swift, 尚无良好的解决方案。

也可以看看
https://coderoad.ru/24602595/
, 它包含关于如何绕过它的建议,这可能适合您的特定问题。 /您的问题非常一般,也许您可​​以使用这些答案找到解决方法。/.

江南孤鹜

赞同来自:

您希望使用需要的限制类型创建一个通用类 , 与他一起使用的课程
SomeProtocol

, 例如:


class SomeClass<t: someprotocol=""> {
typealias ElementType = T
var protocols = [ElementType]//

func addElement/element: ElementType/ {
self.protocols.append/element/
}

func removeElement/element: ElementType/ {
if let index = find/self.protocols, element/ {
self.protocols.removeAtIndex/index/
}
}
}


</t:>

江南孤鹜

赞同来自:

在 Swift 有一类特殊的协议,它不提供实现它的类型的多态性。 此类协议在其定义中使用关键字。
Self

或者
associatedtype

/和
Equatable

是其中之一/.

在某些情况下,您可以使用shell可擦除以使您的同性恋收集。 以下是一个例子。


// This protocol doesn't provide polymorphism over the types which implement it.
protocol X: Equatable {
var x: Int { get }
}

// We can't use such protocols as types, only as generic-constraints.
func ==<t: x="">/a: T, b: T/ -&gt; Bool {
return a.x == b.x
}

// A type-erased wrapper can help overcome this limitation in some cases.
struct AnyX {
private let _x: // -&gt; Int
var x: Int { return _x// }

init<t: x="">/_ some: T/ {
_x = { some.x }
}
}

// Usage Example

struct XY: X {
var x: Int
var y: Int
}

struct XZ: X {
var x: Int
var z: Int
}

let xy = XY/x: 1, y: 2/
let xz = XZ/x: 3, z: 4/

//let xs = [xy, xz] // error
let xs = [AnyX/xy/, AnyX/xz/]
xs.forEach { print/$0.x/ } // 1 3


</t:></t:>

董宝中

赞同来自:

我发现的有限解决方案是将协议标记为仅针对类的协议。 这将允许您使用'==='运算符进行比较对象。
我明白它不会用于结构等,但在我的情况下它足够好。


protocol SomeProtocol: class {
func bla//
}

class SomeClass {

var protocols = [SomeProtocol]//

func addElement/element: SomeProtocol/ {
self.protocols.append/element/
}

func removeElement/element: SomeProtocol/ {
for i in 0...protocols.count {
if protocols[i] === element {
protocols.removeAtIndex/i/
return
}
}
}

}

裸奔

赞同来自:

解决方案非常简单:


protocol SomeProtocol {
func bla//
}

class SomeClass {
init// {}

var protocols = [SomeProtocol]//

func addElement<t: equatable="" someprotocol="" t:="" where="">/element: T/ {
protocols.append/element/
}

func removeElement<t: equatable="" someprotocol="" t:="" where="">/element: T/ {
protocols = protocols.filter {
if let e = $0 as? T where e == element {
return false
}
return true
}
}
}


</t:></t:>

快网

赞同来自:

我理解,您的主要目标是保留与协议对应的对象集合,添加到此集合并从中删除。 这是一个功能,如您的客户所示, "SomeClass". 救世者继承需要 self, 这不是此功能的必要条件。 我们可以在阵列中做出这项工作 Obj-C, 使用功能 "index", 可以接收自定义比较器,但不支持它 Swift. 因此,最简单的解决方案是使用字典而不是数组,如下面的代码所示。 我提供了 getElements//, 谁将返回所需协议的数组。 因此,任何使用的人 SomeClass, 它甚至不会知道字典用于实现。

由于无论如何,您需要某种独特的属性来分离您的物体,我建议它 "name". 请确保你的 do element.name = "foo" 创建新副本时 SomeProtocol. 如果未指定名称,则仍然可以创建一个实例,但不会添加到集合中,并且 addElement// 多窝白 "false".


protocol SomeProtocol {
var name:String? {get set} // Since elements need to distinguished,
//we will assume it is by name in this example.
func bla//
}

class SomeClass {

//var protocols = [SomeProtocol]// //find is not supported in 2.0, indexOf if
// There is an Obj-C function index, that find element using custom comparator such as the one below, not available in Swift
/*
static func compareProtocols/one:SomeProtocol, toTheOther:SomeProtocol/->Bool {
if /one.name == nil/ {return false}
if/toTheOther.name == nil/ {return false}
if/one.name == toTheOther.name!/ {return true}
return false
}
*/

//The best choice here is to use dictionary
var protocols = [String:SomeProtocol]//


func addElement/element: SomeProtocol/ -> Bool {
//self.protocols.append/element/
if let index = element.name {
protocols[index] = element
return true
}
return false
}

func removeElement/element: SomeProtocol/ {
//if let index = find/self.protocols, element/ { // find not suported in Swift 2.0


if let index = element.name {
protocols.removeValueForKey/index/
}
}

func getElements// -> [SomeProtocol] {
return Array/protocols.values/
}
}

冰洋

赞同来自:

我发现

不是

纯净的解决方案 Swift 在这个博客中:
http://blog.inferis.org/blog/2 ... cols/
/

重点是匹配
NSObjectProtocol

, 他如何介绍
isEqual//

.
所以而不是使用协议
Equatable

及其标准使用
==

您可以编写自己的功能来查找项目并将其删除。

这是您的功能的实现
find/array, element/ -> Int?

:


protocol SomeProtocol: NSObjectProtocol {

}

func find/protocols: [SomeProtocol], element: SomeProtocol/ -> Int? {
for /index, object/ in protocols.enumerated// {
if /object.isEqual/element// {
return index
}
}

return nil
}


注意:在这种情况下,您对应的对象
SomeProtocol

, 必须继承自
NSObject

.

要回复问题请先登录注册