我应该如何在Swift中写这个?

时间:2017-02-05 18:31:17

标签: swift

有关详细信息,请参阅编辑#2,如果有任何问题尚未明确,请在评论中提问:)

让我们说我创建了这样的协议:

protocol A {
 associatedtype T
 func computeSomething(with:T) -> Double
}

在我的泛型类中,我想做类似的事情:

class B<U> {
 var doSomething:A<U>
}  

这是因为这会产生错误,但我想接受任何支持类型U上的computeSomething的类型,但我根本不知道如何做到这一点?

编辑为CLARITY:基本上如果A是一个通用的结构或类,那是可能的,但是如果没有默认实现(由类或结构提供)在这里有意义并且我唯一想要的是确保类型做我想要的?

谢谢

编辑#2(具体示例)
我想过度简化我的问题,这使得它很难理解,所以这里是一个仍然简化和虚构的问题,可能更好地匹配我遇到的问题: 我正在编写一个处理其泛型类型T的通用类:

class Process<T> { ... }

Process本身包含处理T的代码,但为了使此代码有效,需要T符合某些协议,例如:

protocol A {
    func mixWith(other:A) -> A
}

protocol B {
    var isFoo:Bool { get set }
}

所以我的第一种方法是简单地要求T符合这些协议:

class Process<T:<A,B>> { ... }

这看起来像最简单的方法,可能在很多情况下,但在我的情况下,我认为这实际上是有问题的,因为这个原因:

首先,我可能需要以多种不同方式处理相同类型,并且更改正在处理类型的方式通常需要更改协议AB的实际实现,例如例如,fooProcessbarProcess都属于Process类型,其类型为MyType

let fooProcess = Process<MyType>()
let barProcess = Process<MyType>() 

但我希望fooProcessbarProcess执行不同的操作,这些操作在很多情况下需要更改{{1} AB协议的实现键入,这根本不可能。

所以我的第一个想法是简单地要求定义一些闭包和变量,以便我不再需要协议,并且只在我的MyType类中定义数据的处理方式,有点像这样:

Process

所有处理都将直接在我的class Process<T> { // var mix:(_ lhs:T, _ rhs:T)->(T) var isFoo:(_ a:T)->(Bool) ... } 课程中实施,再次这看起来就像是正确的解决方案但现在又出现了另一个问题,这导致了我的关联类型方法:事实证明,在许多情况下,我的Processing类的用户想要获得我的框架实现的一些默认行为,例如,我可以自动实现协议Process和{{1}对于他们来说,只要他们的类符合协议A,这就是它如何做到的:

B

通过使用这种方法,我会让我的用户直接选择他们想要实现的东西,通过符合协议X他们只需要编写一些代码并让我的框架到所有的如果他们想要实现自己的A或B他们仍然可以。

所以如果我是对的,我的闭包实现就无法做到这一点。

因此,我认为相关的类型协议将是一个很好的解决方案,因为在这里我可以让我的用户轻松获得一些默认行为或编写自己的行为,所以现在我们回到我原来的问题:

protocol X:A,B {
...
}

extension protocol X {
   // Here was my default implementation of A and B, which enabled my user to directly get A and B implemented as long as their type conformed to X
}

然后做那样的事情:

X

这里与闭包相比的优势在于我可以编写一个符合AProcessing的特殊类,它可以提供默认实现,这样:

protocol AProcessing {
    associatedtype U
    func mix(_ lhs:U, _ rhs:U) -> U 
}

protocol BProcessing {
   associatedtype U
   func isFoo(_ a:U) -> Bool
}

这会使我的用户能够这样:

class Process<T> {
var aProcessor:AProcessing<T>
var bProcessor:BProcessing<T>
}

这不仅在Swift中不可能,而且感觉我使用的太多了&#34; hacks&#34;为了完成工作,应该有一个更简单的语言功能,不幸的是我不知道我应该使用什么......任何想法?

谢谢。

3 个答案:

答案 0 :(得分:0)

我认为这是不可能的,因为协议的泛型类型是在实现它的类中指定的。

你可以这样写:

class B<U, P: A> where P.T == U {
    var someVar: P?
}

但是,您需要为特定类指定第二个参数。例如:

class C: A {
    typealias T = String

    func computeSomething(with: String) -> Double {
        return 0.0
    }
}

let b = B<String, C>()
let c = b.someVar

但它无法在associatedtype

中返回具有特定类型的协议

答案 1 :(得分:0)

一种方法是从一个空的通用结构开始,然后在有意义的类型上扩展它:

struct A<T> {}

extension A where T: Base {
  func computeSomething(with: T) -> Double {
    return 1
  }
}

用法:

protocol Base {}

class B<U: Base> {
  let doSomething = A<U>()

  func foo(x: U) -> Double {
    return doSomething.computeSomething(with: x)
  }
}

class Z : Base {}

let x = B<Z>()
let y = x.foo(x: Z())
print(y)

答案 2 :(得分:0)

编辑#2:

删除相关类型,它应该可行:

{{ post.blocks_content_~myNumber~_title }}
{{ post['blocks_content_'~myNumber~'_title'] }}

然后,你的处理器:

protocol A {}
protocol B {}

protocol AProcessing {
  func mix(_ lhs: A, _ rhs: A) -> A
}

protocol BProcessing {
  func isFoo(_ a: B) -> Bool
}

用法:

class Process<T: A & B> {
  var aProcessor: AProcessing!
  var bProcessor: BProcessing!

  func foo(_ a: T) -> Bool {
    let x = aProcessor.mix(a, a)
    guard let b = x as? B else { return false }
    return bProcessor.isFoo(b)
  }
}