Swift 中采用类型名称的通用函数

2024-02-28

在 C# 中,可以通过指定类型来调用泛型方法:

public T f<T>()
{
   return something as T
}

var x = f<string>()

Swift 不允许您在调用泛型方法时对其进行专门化。编译器想要依赖类型推断,所以这是不可能的:

func f<T>() -> T? {
    return something as T?
}

let x = f<String>() // not allowed in Swift

我需要的是一种使用泛型将类型传递给函数并且该函数返回该类型的对象的方法

这可行,但不太适合我想做的事情:

let x = f() as String?

编辑(澄清)

我可能不太清楚问题实际上是什么,这都是关于调用返回给定类型(任何类型)的函数的更简单的语法。

举一个简单的例子,假设您有一个 Any 数组,并且创建了一个返回给定类型的第一个元素的函数:

// returns the first element in the array of that type
func findFirst<T>(array: [Any]) -> T? {
    return array.filter() { $0 is T }.first as? T
}

你可以这样调用这个函数:

let array = [something,something,something,...]

let x = findFirst(array) as String?

这非常简单,但是如果返回的类型是带有方法的某种协议并且您想在返回的对象上调用该方法怎么办:

(findFirst(array) as MyProtocol?)?.SomeMethodInMyProtocol()
(findFirst(array) as OtherProtocol?)?.SomeMethodInOtherProtocol()

这种语法很尴尬。在 C#(与 Swift 一样强类型)中,您可以执行以下操作:

findFirst<MyProtocol>(array).SomeMethodInMyProtocol();

遗憾的是,这在 Swift 中是不可能的。

所以问题是:有没有一种方法可以用更清晰(不那么尴尬)的语法来完成此任务。


不幸的是,您无法显式定义泛型函数的类型(通过使用<...>语法)。然而,你can提供通用元类型(T.Type)作为argument到函数中,以便 Swift 推断出函数的泛型类型,如罗曼曾说过 https://stackoverflow.com/a/37216835/2976878.

对于您的具体示例,您希望您的函数如下所示:

func findFirst<T>(in array: [Any], ofType _: T.Type) -> T? {
  return array.lazy.compactMap { $0 as? T }.first
}

这里我们使用的是compactMap(_:)为了获得成功转换为的元素序列T, 进而first获取该序列的第一个元素。我们也在使用lazy这样我们就可以在找到第一个元素后停止评估元素。

用法示例:

protocol SomeProtocol {
  func doSomething()
}

protocol AnotherProtocol {
  func somethingElse()
}

extension String : SomeProtocol {
  func doSomething() {
    print("success:", self)
  }
}

let a: [Any] = [5, "str", 6.7]

// Outputs "success: str", as the second element is castable to SomeProtocol.
findFirst(in: a, ofType: SomeProtocol.self)?.doSomething()

// Doesn't output anything, as none of the elements conform to AnotherProtocol.
findFirst(in: a, ofType: AnotherProtocol.self)?.somethingElse()

请注意,您必须使用.self为了引用特定类型的元类型(在本例中,SomeProtocol)。也许不像您想要的语法那样光滑,但我认为它与您将获得的一样好。

尽管在这种情况下值得注意的是,该函数最好放置在Sequence:

extension Sequence {
  func first<T>(ofType _: T.Type) -> T? {
    // Unfortunately we can't easily use lazy.compactMap { $0 as? T }.first
    // here, as LazyMapSequence doesn't have a 'first' property (we'd have to
    // get the iterator and call next(), but at that point we might as well
    // do a for loop)
    for element in self {
      if let element = element as? T {
        return element
      }
    }
    return nil
  }
}

let a: [Any] = [5, "str", 6.7]
print(a.first(ofType: String.self) as Any) // Optional("str")
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Swift 中采用类型名称的通用函数 的相关文章

随机推荐

  • Python 脚本错误地删除了 .xlsx 文件中创建的图表

    我尝试使用 Python 编写一个脚本 该脚本从存储在文件夹层次结构中的所有 csv 文件中获取一些特定值 这些值将复制到已创建的目标文件 xlsx 中的某些特定单元格 目标文件还有一些现有的空图表 在单独的工作表中 这些图表将使用脚本提供
  • CGPath Scale 出现问题

    我正在使用绘制多边形CGPath并添加到CAShapeLayer 我想扩大我的规模CGPath当用户点击它时 我知道如何扩展CGPath 但是当我点击我的CGPath my CGPath当我在中心绘制多边形时 绘制远离中心 CGAffine
  • 在Python中获取特定JSON元素的值

    我对 Python 和 JSON 很陌生 所以如果我听起来一无所知 我很抱歉 我从 Google Translate API 获得以下结果 并希望解析出 translatedText 的值 data translations transla
  • AngularJS 将焦点移动到回车时的下一个控件

    最好的方法是什么 当在表单中按 Enter 键时 焦点转到下一个输入 而不是使用 AngularJS 提交表单 我有一个包含很多字段的表单 客户习惯于按 Enter 移动到下一个输入 来自桌面应用程序 当用户按 Enter 键时 Angul
  • 使用 Oracle 数据库链接,无需不可读的动态 SQL

    如何编写可以针对给定数据库链接执行的简洁 PL SQL 存储过程 写起来真的很混乱 PROCEDURE my proc aDbLink IN VARCHAR2 IS BEGIN EXECUTE IMMEDIATE SELECT mycolu
  • TAwImageGrid - 如果删除最后一个图像,程序会泄漏内存

    使用 Delphi XE7更新1 图像网格 https stackoverflow com q 8853378 1992767 在 Intel Core i7 2820QM 上运行的 Windows 10 Professional 此代码将
  • Bundler 正在弃用捆绑控制台,转而使用 bin/console。任何人都可以更清楚地说明 bin/console 应该如何工作吗?

    我有一个定制的红宝石宝石 它严重依赖bundle console 没什么特别或奇特的 只是一个交互式控制台 其中包含由 Gemfile 定义的一组 gem 我们在开发过程中经常使用控制台 目前 当我运行该命令时 我收到以下弃用消息 已弃用
  • 在 Docker 环境中运行 R 包 reticulate

    在之前的工作中 我使用 reticulate 包在 R 中运行 Autogluon autoML 库 该代码在我当前的配置 Ubuntu 20 4 R 4 10 reticulate v 125 中运行良好 然而 这段代码在 Docker
  • 一般问题:着色语言/着色器是面向对象的吗?

    我目前正在接受学徒培训 其中一位培训师说 着色器是面向对象的 作为面向对象编程的示例 对我来说 这意味着 HLSL 和 GLSL 是面向对象的语言 我从来没有认为着色器是面向对象的 但现在当我看到这个时 https www khronos
  • Python 纯虚函数可能和/或值得吗?

    我可能有不同的心态 主要是一名 C 程序员 这个问题与 Python 中的 OOP 有关 更具体地说 与纯虚拟方法有关 所以采用我改编的代码这个问题 https stackoverflow com questions 4714136 pyt
  • 在 R 中使用 ggmap 和 Stamen 地图进行映射:标记点和比例

    我正在尝试使用 ggmap 和 Stamen 地图制作我的研究地点的地图 我见过一些类似的问题 但还没有找到将解决方案合并到我的 Stamen 地图代码中的方法 对此我有两个问题 1 如何自定义标记地图上的点 2 如何在Stamen地图中为
  • 在 Eloquent 中使用 withTrashed 处理关系

    有没有办法使用withTrashed与 Eloquent 中的关系 我需要的是这个 我有桌子和模型Mark和另一张桌子User User有很多Mark and Mark属于User 所以我在 Eloquent 模型中定义了它 现在我需要获取
  • Postgres 中的多语句查询

    我希望向 Postgres 数据库发送多个读取查询 以减少需要前往令人痛苦的远程数据库的次数 有什么东西在libpq支持这种行为 是的 您可以使用异步处理函数 http www postgresql org docs current sta
  • 更改为 .gitattributes 后 Git 重新签出文件

    我有一个存储库 其中包含一个错误地以 LF 行结尾提交的文件 但它需要有 CRLF 行结尾 为了解决这个问题 我添加了一个 gitattributes 文件以在签出时强制执行正确的行结尾 这似乎解决了签出新存储库时的问题 但现有的签出拒绝更
  • 使用 webpack 在 Laravel 5 中将插件安装到 CKEditor 5

    我在将插件安装到集成到 Laravel 5 6 的 CKEditor 时遇到了一个小问题 根据 CKEditor 文档的集成指南 我能够添加 ckeditor ckeditor5 build classic https www npmjs
  • WordPress wp_enqueue_script 不工作

    我正在开发一个主题并尝试让 wp enqueue script 工作 奇怪的是 什么也没有出现 它没有任何作用 这是我的设置 在functions php中我有 function named scripts global named opt
  • VBA创建对象

    自 1 月 10 日起 我就被困在这条代码线上 我在一封电子邮件中收到了它 我发现我必须学习课程模块 所以我做了 现在又回来询问新的基础 代码行是 严重警告 您必须转到 VBE 中的 工具 gt 参考 并激活Microsoft WinHTT
  • SSIS 顺序处理

    我在同一数据流任务中有 5 个独立的数据流 每个数据流都有源和目的地 我怎样才能让它们按顺序运行 它们似乎并行运行 我可能会在不同的数据流任务中执行此操作 但我怎样才能在单个数据流任务中做到这一点 同一任务中不要有独立的数据流 我知道导入
  • 如何使用 scanf() 获取任意数量的整数? [关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 该程序采用任意数量的整数作为输入 并
  • Swift 中采用类型名称的通用函数

    在 C 中 可以通过指定类型来调用泛型方法 public T f