这里有一个玩具示例,找不到在线解决方案。
protocol Tree {
associatedtype Element
// some nice tree functions
}
class BinaryTree<T> : Tree {
typealias Element = T
}
class RedBlackTree<T> : Tree {
typealias Element = T
}
enum TreeType {
case binaryTree
case redBlackTree
}
// Use a generic `F` because Tree has an associated type and it can no
// longer be referenced directly as a type. This is probably the source
// of the confusion.
class TreeManager<E, F:Tree> where F.Element == E {
let tree: F
init(use type: TreeType){
// Error, cannot assign value of type 'BinaryTree<E>' to type 'F'
switch(type){
case .binaryTree:
tree = BinaryTree<E>()
case .redBlackTree:
tree = RedBlackTree<E>()
}
}
}
我不确定这是什么问题,还是应该寻找以便解决该问题的方法。我仍在考虑使用其他语言进行接口的协议,并且我将BinaryTree
视为Tree
的有效实现,并且对F
的唯一限制是它必须成为Tree
。为了使事情更加混乱,我不确定下面的代码片段为什么会编译,而上面的代码却没有。
func weird<F:Tree>(_ f: F){ }
func test(){
// No error, BinaryTree can be assigned to an F:Tree
weird(BinaryTree<String>())
}
任何指针或解释将不胜感激。
答案 0 :(得分:0)
我不了解这种情况的背景。但是,我提供了两种解决方案:
1:
class Bar<F:Foo> {
let foo: FooClass.F
init(){
foo = FooClass.F()
}
}
2:
class Bar<F:Foo> {
let foo: FooClass
init(){
foo = FooClass()
}
}
对于正在尝试实现的目标,您当前正在做的没有逻辑意义
答案 1 :(得分:0)
我不知道您要做什么,但是当然不可能。从您的示例中,您尝试使用Bar
创建generic
类。但这不是创建generic
对象的适当方法,因为generic
对象的创建是使该对象接受任何类型。
以下是从Wikipedia摘录的generic
的一些简要说明。
在第一段中,“ 通用编程是一种计算机编程样式,其中,算法根据 to-be-specified-later 类型进行编写,然后在作为参数提供的特定类型所需的。”
很清楚to-be-specified-later
是什么意思,对吧:)
回到您的示例:
class Bar<F: Foo> {
let foo: F
init() {
// Error, cannot assign value of type 'FooClass' to type 'F'
foo = FooClass()
}
}
根据上面的代码,类型参数F
对类型Foo
具有约束。并且,您尝试为foo
变量创建一个具有具体实现的实例,即FooClass
。这是不可能的,因为foo
变量是F
类型(抽象)。当然,我们可以像foo = FooClass() as! F
这样向下转换它,但是foo
仅限于FooClass
,那么为什么还要烦恼泛型呢?
希望有帮助:)
答案 2 :(得分:0)
类似的事情似乎是合理的。关键是要尝试使用某种逻辑来确定TreeManager
是何时使用Tree
的一种还是另一种。
protocol TreePicker {
associatedtype TreeType : Tree
func createTree() -> TreeType
}
struct SomeUseCaseA<T>: TreePicker {
typealias TreeType = RedBlackTree<T>
func createTree() -> TreeType {
return RedBlackTree<T>()
}
}
struct SomeUseCaseB<T>: TreePicker {
typealias TreeType = BinaryTree<T>
func createTree() -> TreeType {
return BinaryTree<T>()
}
}
class TreeManager<T, Picker: TreePicker> where Picker.TreeType == T {
let tree: T
init(use picker: Picker){
tree = picker.createTree()
}
这引入了另一个关心选择树实现的协议,where子句指定选择器将返回类型为T
的树。
我认为所有这些只是无法声明类型tree
的{{1}}的结果。它有些冗长,但是基本上它必须具有通用接口的外观。我想我也问得很差。我应该发布尚未编译的版本,并要求解决方案,而不是更进一步,使所有人感到困惑。
答案 3 :(得分:0)
您的处理方法是错误的。在原始示例中,除了枚举值之外,还必须指定元素(E)和容器(BinaryTree或RedBlackTree)的类型。那没有道理。
相反,您应该构造管理器以将树作为构造函数参数,从而允许Swift推断通用参数,即
class TreeManager<E, F: Tree> where F.Element == E {
var tree: F
init(with tree: F) {
self.tree = tree
}
}
let manager = TreeManager(with: BinaryTree<String>())
或者,您应该根据最终目标是在Swift 5.1中使用不透明的返回类型(这里的示例显然不是现实情况)
答案 4 :(得分:-1)
protocol Foo {
associatedtype F
}
class FooClass : Foo {
typealias F = String
}
class Bar<M:Foo> {
let foo: M
init(){
foo = FooClass() as! M
}
}