如何在 swift 中使用泛型类型处理不同类型?

2024-01-21

我正在尝试编写一个类,它允许我轻松地在两个值之间进行插值。

class Interpolation
{
    class func interpolate<T>(from: T, to: T, progress: CGFloat) -> T
    {
        // Safety
        assert(progress >= 0 && progress <= 1, "Invalid progress value: \(progress)")

        if let a = from as? CGFloat, let b = to as? CGFloat
        {
        }
        if let a = from as? CGPoint, let b = to as? CGPoint
        {

        }
        if let from = from as? CGRect, let to = to as? CGRect
        {
            var returnRect = CGRect()
            returnRect.origin.x     = from.origin.x + (to.origin.x-from.origin.x) * progress
            returnRect.origin.y     = from.origin.y + (to.origin.y-from.origin.y) * progress
            returnRect.size.width   = from.size.width + (to.size.width-from.size.width) * progress
            returnRect.size.height  = from.size.height + (to.size.height-from.size.height) * progress
            return returnRect // Cannot convert return expression of type 'CGRect' to return type 'T'
        }

        return from
    }
}

不幸的是,它给了我一个错误return returnRect:无法将类型“CGRect”的返回表达式转换为返回类型“T”。也许我不明白如何使用泛型...我只想有一个函数来处理各种类型之间的插值,而不是有一堆像这样的函数func interpolate(from: Int, to: Int), func interpolate(from: CGPoint, to: CGPoint), etc.


问题是T是一个通用占位符 - 这意味着你无法知道实际的具体类型是什么T来自函数内部。因此,尽管你可以有条件地施放from and to to a CGRect(从而确定T == CGRect),Swift 无法推断出此信息,因此禁止尝试返回CGRect当它期望回报时T.

因此,粗略的解决方案是将返回结果强制转换回T为了弥合信息与类型系统之间的差距:

if let from = from as? CGRect, let to = to as? CGRect {

    // ...

    return returnRect as! T
}

然而,这种类型转换实际上表明您正在与类型系统作斗争,并且没有利用泛型提供的静态类型,因此不建议这样做。

更好的解决方案,如@Wongzigii 已经说过了 https://stackoverflow.com/a/38653299/2976878,就是使用协议。例如,如果您定义一个Interpolate正如他在回答中所示的协议 - 然后您可以使用此协议来约束您的通用占位符T在你的interpolate功能:

class Interpolation {
    class func interpolate<T:Interpolate>(from: T, to: T, progress: CGFloat) -> T {

        // Safety
        assert(progress >= 0 && progress <= 1, "Invalid progress value: \(progress)")

        return T.interpolate(from: from, to: to, progress: progress)
    }
}

这解决了您的许多问题 - 它消除了运行时类型转换,而是使用协议约束来调用专门的interpolate功能。协议约束还阻止您传递任何不符合协议的类型Interpolate在编译时,因此也解决了类型转换失败时该怎么办的问题。

尽管如此,我实际上很喜欢这个解决方案@JoshCaswell 在他的回答中建议 https://stackoverflow.com/a/38687308/2976878回答你的另一个问题——重载运算符以实现此功能。与前面的解决方案一样,关键是定义一个协议来封装您在每种类型上定义的功能,然后将通用函数限制为该协议。

一个简单的实现可能如下所示:

protocol Interpolatable {
    func +(lhs:Self, rhs:Self) -> Self
    func -(lhs:Self, rhs:Self) -> Self
    func *(lhs:Self, rhs:CGFloat) -> Self
}

func +(lhs:CGRect, rhs:CGRect) -> CGRect {
    return CGRect(x: lhs.origin.x+rhs.origin.x,
                  y: lhs.origin.y+rhs.origin.y,
                  width: lhs.size.width+rhs.size.width,
                  height: lhs.size.height+rhs.size.height)
}

func -(lhs:CGRect, rhs:CGRect) -> CGRect {
    return CGRect(x: lhs.origin.x-rhs.origin.x,
                  y: lhs.origin.y-rhs.origin.y,
                  width: lhs.size.width-rhs.size.width,
                  height: lhs.size.height-rhs.size.height)
}

func *(lhs:CGRect, rhs:CGFloat) -> CGRect {
    return CGRect(x: lhs.origin.x*rhs,
                  y: lhs.origin.y*rhs,
                  width: lhs.size.width*rhs,
                  height: lhs.size.height*rhs)
}

extension CGRect : Interpolatable {}
extension CGFloat : Interpolatable {}

class Interpolation {
    class func interpolate<T:Interpolatable>(from: T, to: T, progress: CGFloat) -> T {
        assert(progress >= 0 && progress <= 1, "Invalid progress value: \(progress)")
        return from + (to - from) * progress
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何在 swift 中使用泛型类型处理不同类型? 的相关文章

随机推荐

  • C中int默认是long int吗?

    为什么我发现 int 和 long int 的大小显示为 4 个字节 难道int默认是long int吗 sizeof short lt sizeof int lt sizeof long 这就是您可以信赖的一切 其余的完全取决于实施 在早
  • iTextSharp 字段重命名不适用于合并

    这是后续另一个问题 https stackoverflow com questions 44003264 itextsharp merge method produces empy form fields now duplicate val
  • 访问 DOM 或 Shadow DOM 的 Web 组件的父上下文

    Context 我正在不同的上下文中进行有关 Web 组件组合的测试 特别是 我试图通过在以下位置中的搜索过程从另一个 Web 组件访问其中一个组件来关联多个 Web 组件 DOM Shadow DOM所涉及的组件 Problem 假设我们
  • 有角材料。鼠标悬停时突出显示表格行

    我们在我们的应用程序中使用 Angular Material 表 https material angular io components table overview https material angular io component
  • 导入 com.google.android.maps.geopoint 无法解析

    我有 Java GoogleMAP 项目 这不是 android 项目 我之前使用 KML 完成过这个项目 现在Google已经改用JSON XML了 我需要将坐标保存在数据库 postgresql 中的 2 个位置内 然后根据这个我将在M
  • 我有一个多模块 Maven 2 POM,它有两个 WAR,我如何配置它以在运行测试之前部署这两个 War?

    粗略地说 我有 比如说 项目 A pom 包装 它有两个模块 M1 和 M2 比如说 每个模块都有 war 包装 M2 有集成测试 但 M2 战争对 M1 战争进行了服务调用 这确实应该 将相同的数据加载到数据库中 部署 M1 的 WAR
  • 无法从类型 Two 对非静态方法 fxn(int) 进行静态引用 [重复]

    这个问题在这里已经有答案了 可能的重复 无法从静态上下文引用非静态方法 背后的原因是什么 https stackoverflow com questions 290884 what is the reason behind non stat
  • EF代码首先不创建数据库

    这是我的代码 public void ConfigureServices IServiceCollection services services AddDbContext
  • itunesconnect 处理失败

    I had archieved the xcode project and uploaded it into itunes connect This is 5 time uploading for internal testing It s
  • 为什么 window.addEventListener('scroll', this.someScrollHandler, false) 在 IE 10 上不起作用?

    我目前正在构建一个带有滚动处理程序的 React 应用程序 用于在无限滚动组件中加载更多数据 我在用着window addEventListener scroll this someScrollHandler false 带限制 适用于除
  • 如何在本地设置多个NPM用户?

    我使用两个 NPM 帐户 公共帐户和私人帐户 我该如何设置才能不需要npm login每次我在不同的帐户上发布模块时 UPD 寻找 NPM 内置解决方案 因此没有 shell 脚本等 这就是我使用 4 个不同的 NPM 登录解决该问题的方法
  • 工作簿已打开,但我仍然收到 VBA 下标超出范围错误

    我正在尝试通过我的宏脚本打开工作簿 每次尝试打开工作簿时都会重复出现此错误 我面临的问题是当我使用 Workbooks Open strFilePath where strFilePath genericfilepath FileDupli
  • 使用强分类器进行 boosting 的效果

    使用强 而不是弱 错误率接近随机 分类器进行 boosting 会产生什么效果 一个强分类器单独使用是否会比在 adaboost 中与一堆弱分类器一起使用时表现更好 对的 这是可能的 一切都取决于您的学习数据集 看看没有免费的午餐定理 总是
  • CSS溢出:隐藏剪切阴影

    现在是这样的 当我禁用时overflow hidden 阴影通常遍布四周 但当它打开时 它会在左侧和顶部被切割 我不知道为什么它只切割这两侧 但目前看起来仍然不太好 如何摆脱它 Code toolong width 80 overflow
  • django 错误 - ImportError:没有名为 apps 的模块

    我正在尝试创建第一个名为 mysite 的 django 项目 我的项目的结构是 mysite manage py mysite init py settings py urls py wsgi py polls init py admin
  • 应用程序关闭前的 Ionic 运行功能

    是否有某种我可以调用的函数来侦听应用程序是否即将退出 关闭或进入后台 基本上任何意味着 用户已停止使用该应用程序 的事件 我是我的应用程序 我建立了一个 用户日志 用于跟踪用户在应用程序中导航时的情况 我不想在这些事件发生时不断向服务器发送
  • Django 标签云插件 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • RavenDb - 递归查询/索引,用于分层文档

    我知道这可能是一个有点愚蠢的问题 可能会这样做 错了 但我会以任何方式询问 假设我有一组层次结构文档 它们包含的关于其在层次结构中的位置的唯一信息 是他们的家长 ID 如果它为空 我们就到达了顶部 吸引父母和孩子是最容易的部分 我想做的是查
  • Jenkins + Github Pull 请求构建器显示名称

    对于我们的项目 我们使用 GitHub 我们启用了 TravicCI 因为这是我们项目使用所必需的 除此之外 我们还有一个与拉取请求构建器一起运行的 Jenkins 完整实例 Now this all works fine and in t
  • 如何在 swift 中使用泛型类型处理不同类型?

    我正在尝试编写一个类 它允许我轻松地在两个值之间进行插值 class Interpolation class func interpolate