当前位置: 首页 > 知识库问答 >
问题:

能否在Swift中将返回类型指定为特定类型的任何集合?

通和裕
2023-03-14

我已经实现了一个自定义队列对象,我想用它在控制器中存储以前的项目。我希望将此类型用作控制器中的私有变量,并仅将其作为符合CollectionType的对象对外公开,以便客户端可以在不知道任何特定于类的详细信息(例如clear()函数)的情况下迭代或索引该对象。

Swift协议不能是通用的,所以不幸的是,我不能简单地定义一个getter来返回一个集合

class AnyCollectionOf<MemberT, IndexT: ForwardIndexType>: CollectionType {
    // Sequence Type
    func generate() -> GeneratorOf<MemberT> {
        fatalError("must override")
    }

    // Collection Type
    typealias Index = IndexT
    typealias Element = MemberT

    subscript (index: Index) -> Element {
        get {
            fatalError("must override")
        }
    }

    var startIndex: Index {
        get {
            fatalError("must override")
        }
    }

    var endIndex: Index {
        get {
            fatalError("must override")
        }
    }
}

共有3个答案

阴禄
2023-03-14

例如,我有一个堆栈视图,有2个标签和1个图像视图,并成功地使用了这个:

open var labels: [UILabel] {
        return views.filter({ $0 is UILabel }).flatMap({ $0 }) as! [UILabel]
    }

如果您想使其通用化:filterflatMapcompactMap,来自Swift 4)和downforced可选

班高明
2023-03-14

从Swift 5.1开始,这最终可以通过some关键字实现:

func upNext() -> some Collection { ... }
卢开济
2023-03-14

不幸的是,您的标题问题的答案是否定的:没有办法将CollectionType绑定为可以用作变量或返回类型的独立类型。

像SequextType和集合类型这样的协议要求实现它们的类提供类型别名来填充实现细节,比如元素类型,就像上面所做的那样。一旦协议添加了这些要求,它就再也不能作为独立类型使用了。您只能根据符合它的特定类声明接口。(如果您试图解决这个问题,您可能记得看到了关于“关联类型需求”的不太有用的编译器错误。)

这就是你不能写作的基本原因

func countItems(collection: CollectionType) -> Int { ... }

但我必须写

func countItems<T: CollectionType>(collection: T) -> Int { ... }

后一种形式确保编译器能够访问实现CollectionType协议的对象(T)的实际类型。

然而,如果您从封装而不是继承的角度考虑,您想要做的事情可能还有一个更干净的实现。您可以使用一个简单的包装器来阻止对所有内容的访问,但核心的集合类型方法除外:

struct ShieldedCollection<UCT: CollectionType> : CollectionType
{
    private var underlying: UCT

    func generate() -> UCT.Generator { return underlying.generate() }
    subscript(index: UCT.Index) -> UCT.Generator.Element { return underlying[index] }
    var startIndex: UCT.Index { return underlying.startIndex }
    var endIndex: UCT.Index { return underlying.endIndex }
}

var foo = [1, 2, 3]
var shieldedFoo = ShieldedCollection(underlying: foo)

(此处,UCT=“基础集合类型”。)

ShieldedCollection仍然具有所有常用的TypeAlias作为CollectionType,但由于这些别名可以从上下文推断,因此不必显式指定它们。

这种泛型方法的缺陷是,底层类型仍然泄漏到API中,不幸的是,这是一个相当大的缺陷。在上面的例子中屏蔽的类型是

ShieldedCollection<Array<Int>>

由于您的基础集合是一个自定义对象,因此即使客户端无法直接访问该类,其名称仍可能在API中泄漏。但是请注意,这不是一个功能问题,因为不可能通过ShieldedCollection包装器访问底层对象。此外,使用者将永远不必自己编写类型-他们可以将previousItems()的结果用作CollectionType,编译器将解开所有问题。

如果您真的想要掩盖对基础集合类型的所有提及,您可以通过在ShieldedCollection中移动UCT定义来编写上面包装器的特定任务模拟:

struct ShieldedCollection<T> : CollectionType    // Changed!
{
    typealias UCT = [T]                          // Added!

    private var underlying: UCT                  // Everything else identical

    func generate() -> UCT.Generator { return underlying.generate() }
    subscript(index: UCT.Index) -> UCT.Generator.Element { return underlying[index] }
    var startIndex: UCT.Index { return underlying.startIndex }
    var endIndex: UCT.Index { return underlying.endIndex }
}

var foo = [1, 2, 3]
var shieldedFoo = ShieldedCollection(underlying: foo)

在这里,您放弃了全部通用性,从而使返回类型变得整洁——此版本的ShieldedCollection将仅适用于作为数组的底层CollectionType。(当然,您只需将typealias中自己的自定义集合类型替换为UCT。)

 类似资料:
  • 注意:这是一个理论性的问题,我并不试图修复任何东西,也不试图为了实际目的达到任何效果 在Scala中使用<code>(参数)创建lambda时= Lambdas与方法没有什么不同,它们都被指定为表达式,但就我的理解,方法的返回类型很容易用< code > def name(arguments):return type = expression 语法来定义。 考虑这个(说明性的)例子:

  • 我正在尝试有一个通量通用转换器使用通用类型在Java 8。我把我的代码建立在这个答案的基础上。其思想基本上是实现这个特定的转换器->: 类型转换器->转换为我想要的任何类型。因此,我正在使用构造函数创建一个类型为的类,并返回一个方法。我想在调用上创建类似这样的多个条目:,但类类型不同。但它甚至对整数也不起作用。 当我使用此单元测试进行测试时,我得到错误:。

  • 使用Python3的函数注释,可以指定同构列表(或其他集合)中包含的项的类型,以便在PyCharm和其他IDE中进行类型暗示? int列表的伪python代码示例: 我知道使用Docstring是可能的... ... 但如果可能的话,我更喜欢注释样式。

  • 下面对getHighest()和getLowest()的调用返回Comparable类型的对象,而不是T类型的对象,这正是我们想要的。为什么,我该如何改进这段代码,使这些调用返回T(这样T的字段和方法就可用了)? 下一行生成编译器错误: 错误:找不到符号符号:方法getName()位置:接口java.lang.Comparable 我想employee.getHighest()返回一个员工(而不仅

  • 假设我有一个函数: 如何指定可以为的返回类型?

  • 问题内容: 假设我有一个函数: 如何为可以指定的东西指定返回类型? 问题答案: 您正在寻找。 由于您的返回类型可以是(从返回),也应该使用: 在有关打字的文档中,是以下内容的简写: 等价于。 其中表示类型或的值。 如果由于担心别人可能偶然发现而没有意识到它的含义而希望变得露骨,则可以始终使用: 但是我怀疑这是一个好主意,是一个指示性名称,它确实节省了几次击键。 正如@ Michael0x2a的注释