【问题标题】:Array of generic classes and subclassing泛型类和子类的数组
【发布时间】:2020-09-24 01:14:57
【问题描述】:

我很难理解泛型。我想要的是拥有一组泛型类,每个类都有自己的关联类型,并相应地调用一个函数。它看起来像这样:

class SomeGenericClass<U> {
    func addCallback(callback: (U)->() ) { ... }
}

var array: [SomeGenericClass] // compile error

最后一行产生了一个错误,所以我发现我需要一个超类。我尝试过这样的事情:

class SuperClass {
    func addCallback<V>(callback: (V)->() ) { ... }
}

class SomeGenericClass<U> {
    func addCallback<V: U>(callback: (V)->() ) { ... } // compile error
}

var array: [SuperClass] // no compile error

这会产生错误Type 'V' constrained to non-protocol, non-class type 'U'

基本上我希望能够做到:

array.append(SomeGenericClass<UIImage>()) // array[0]
array.append(SomeGenericClass<Int>()) // array[1]

// Since array[0] is effectively of type SomeGenericClass<UIImage>, the compiler should understand that the close added if of type (UIImage)->(), and therefore that value is of type UIImage
array[0].addCallback { value in
   someImageView.image = value
}

在这种情况下使用超类是正确的方法吗?应该如何实现?

【问题讨论】:

  • 感谢您提供您的最终目标。那是不可能的。 value 必须有一个在编译时已知的类型。您不必写下类型这一事实并不意味着编译器不必知道它是什么。鉴于您对它的类型一无所知,您接下来会编写哪行代码使用 value?尝试编写一个真正适用于此的回调块,并且做的不仅仅是调用print(value),记住我可以将array[0] 更改为我想要的任何东西,并且您的代码仍然必须工作。
  • 了解泛型的最佳方法是从有重复的具体代码开始。然后研究如何使用泛型删除重复项。从泛型开始,然后试图找到如何使用它们几乎总是会让你陷入困境。所以在一个没有泛型的世界里,你只需要为每种类型复制代码,你会在这里写什么?
  • 感谢您的评论。我更新了我想要的代码。这根本不可能吗?我们有什么可能的解决方法?
  • 我认为重要的是还要注意我的数组是恒定的,它在惰性变量中定义并且不会改变 - 实际上,它是一个字典。因此,当我访问一个元素时,我肯定知道它将是什么类型。也许我们可以利用它,改变结构类型?
  • 但是如果array[0] 元素是SomeGenericClass&lt;Int&gt; 那么你为什么需要someImageView.image = value。在这种情况下,value 将是 Int 类型。

标签: arrays swift generics inheritance


【解决方案1】:

我通过将数组成员存储在他们自己的变量中来解决这个问题。也就是说,而不是像这样定义我的数组:

lazy var array: [SuperClass] = [
    SomeGenericClass<UIImage>(),
    SomeGenericClass<Int>(),
    //etc...
]

我是这样定义的:

lazy var genericFirst: SomeGenericClass<UIImage> = SomeGenericClass<UIImage>()
lazy var genericSecond: SomeGenericClass<Int> = SomeGenericClass<Int>()
// etc...

lazy var array: [SuperClass] = [
    genericFirst,
    genericSecond,
    //etc...
]

这样,我可以像这样访问我想要的泛型:

genericFirst.addCallback { value in
    // value is indeed of type UIImage
    someImageView.image = value
}

【讨论】:

  • 这里array的目的是什么?什么代码消耗它? (根据您的问题,这可能是一个完全正确的解决方案,所以当您说它不正确时,我不确定您的意思。也就是说,我不明白为什么这些是懒惰的。这看起来很浪费。)
  • 这个数组存储了一个视图列表,它是一种组织长滚动视图的方法,它作为一个表单,具有不同的单元格和控件,并有一种通用的方法来用来自一个视图的值填充视图输入对象,并监听这些控件的变化。
  • 好的;如果这些是 UIViews 并且您只是要遍历它们并在它们上执行addSubview 之类的操作以使它们进入滚动视图,那么您的解决方案是理想的,并且您应该如何编写它(我已经构建了类似的系统多年来)。您需要直接访问的内容的属性,以及保存所有内容的数组。本质上与故事板充满视图的方式相同,并且您希望特定访问权限的视图为其创建 IBOutlet 属性。
  • 很高兴听到这个消息!我当时接受了答案。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-14
  • 2018-05-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多