首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将基于“MyProtocol`”的泛型函数的论点更改为使用存在的“`any”或“`some”是否会受到惩罚?

将基于“MyProtocol`”的泛型函数的论点更改为使用存在的“`any”或“`some”是否会受到惩罚?
EN

Stack Overflow用户
提问于 2022-08-14 16:45:17
回答 1查看 72关注 0票数 4

通常,在讨论像some这样的事情时,它们指的是返回类型。这个问题特别涉及在参数列表中使用anysome

例如,在String的Swift文档中,您有这个初始化器.

代码语言:javascript
复制
init<T>(_ value: T, radix: Int = 10, uppercase: Bool = false)
where T : BinaryInteger

在SWIFT5.6中,他们引入了any关键字,让我们更容易地处理存在类型。有了这个变化,我知道你理论上可以重写上面的内容。

代码语言:javascript
复制
init(_ value: any BinaryInteger, radix: Int = 10, uppercase: Bool = false)

当然,也有基于some关键字的这个版本,它也能工作.

代码语言:javascript
复制
init(_ value: some BinaryInteger, radix: Int = 10, uppercase: Bool = false)

我的问题是..。哪一个最有意义?在这样的泛型上使用存在类型有什么坏处吗?some版本呢?我最初认为是的,通用版本是最好的,因为编译器可以在编译时确定传递给它的是什么,但是同样地,存在的any,甚至some版本也是如此,因为如果您不通过BinaryInteger,它就不会编译--我不太确定如何编写测试来检查它。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-08-14 19:00:35

在Swift中将协议类型P的值传递给方法时,您目前可以使用4种可能的拼写:

  1. func f<T: P>(_ value: T) (“通用”)
  2. func f(_ value: some P) (“不透明参数”)
  3. func f(_ value: P) (“裸”存在主义)
  4. func f(_ value: any P) (“显式”存在主义)

在这些拼写中,(1)和(2)是同义词,目前(3)和(4)是同义词。在使用(1)和(2)之间没有差别,在(3)和(4)之间目前没有*没有差别;但是在(1)/(2)和(3)/(4)之间,有区别。

  1. f<T: P>(_: T)是一种传统的接受具体类型T参数的方法,保证符合P协议。获取参数的这种方式:
    • 允许您在编译时和运行时访问具体类型的T,这样就可以对T本身执行操作。
    • 没有开销,因为在编译时就知道T类型,编译器知道值的大小和布局,可以适当地设置堆栈/寄存器;它可以将任何给定的参数直接传递给方法。
    • 只能在参数的类型静态已知时(在编译时)调用;但同样,可以使用带有Self-或associatedtype需求的协议类型调用。

  2. SE-0341 (不透明参数声明)中引入的一个采用some Protocol的方法的版本完全等同于带有尖括号的泛型版本。我将避免重复提案的内容,但是导言部分详细说明了使用这种语法来简化拼写一般参数的复杂性的愿望。
  3. f(_: P)是一种传统的接受存在类型参数的方法,它保证符合协议P。获取参数的这种方式:
    • 不允许在编译时访问参数的具体基础类型;尽管这可以在运行时通过type(of:)动态访问。
    • 具有运行时开销,既可以将参数传递给方法,也可以在访问方法内的值时使用:因为参数的类型可能静态地不知道(而编译器仍然需要知道如何设置堆栈和寄存器才能调用方法),因此必须将参数装箱在“存在框”中,该框具有P接口,可以动态地将方法传递到底层的具体值。这两种方法都需要在运行时分配一个额外的" box“,以便在一致大小和布局的容器内保存实际值,以及在对方框上的方法调用必须动态地分派到基础类型时,间接的成本。
    • 无论参数的类型是否静态地已知,都可以调用;因此,不能使用带有Self-或associatedtype需求的协议类型调用。

  4. SE-0335 (存在主义任)中引入的,协议类型前面的any关键字是一个标记,它有助于指示该类型被用作存在主义。现在的与使用协议的裸名(即any P == P)完全相同,但是对于最终使用协议的裸名来代替some P,已经有了一些讨论。

因此,为了说明您的具体示例:

代码语言:javascript
复制
init(_ value: some BinaryInteger, radix: Int = 10, uppercase: Bool = false)

与原来的

代码语言:javascript
复制
init<T>(_ value: T, radix: Int = 10, uppercase: Bool = false)
where T : BinaryInteger

代码语言:javascript
复制
init(_ value: any BinaryInteger, radix: Int = 10, uppercase: Bool = false)

不是。而且,由于BinaryIntegerassociatedtype需求,所以您也不能使用any版本,因为存在类型无法提供对底层关联类型的访问。(如果你试一试,你会得到经典的error: protocol 'BinaryInteger' can only be used as a generic constraint because it has Self or associated type requirements)

一般说来,泛型在可能的情况下比存在类型更可取,因为缺乏开销和更大的灵活性;但是,它们需要知道其参数的静态类型,这并不总是可能的。

现有要素更多地接受输入,但在功能上明显受到更大的限制,而且需要付出代价。

在偏爱<T: P>some P之间,还是在Pany P之间--目前的选择是主观的,但是:

  1. 作为SE-0335的一部分,目前计划Swift 6将需要使用any关键字来表示存在的协议使用;使用该关键字的对应项是some,因此如果您希望开始对代码进行验证并保持一致,那么开始迁移到anysome可能是个好主意。
  2. 在不透明参数语法和泛型语法之间,选择由您决定,但不透明参数目前无法涵盖泛型可以使用的所有用例,特别是具有更复杂约束的用例。无论在任何地方都坚持泛型,还是喜欢不透明的参数,只在必要时才使用泛型,这都是您需要做出的代码样式选择。
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73353394

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档