返回介绍

5.3.6. 委托给任意类型

发布于 2025-01-04 00:44:53 字数 1575 浏览 0 评论 0 收藏 0

有可能上述所有方式都无法表示你想要委托的类型。比如,可以定义一个 Mapper 类,它带有一个对象参数,并且定义了一个能够返回其他类型对象的 map 方法:

class Mapper<T,U> {               1⃣️
  final T value                 2⃣️
  Mapper(T value) { this.value = value }     
  U map(Closure<U> producer) {        3⃣️
    producer.delegate = value
    producer()
  }
}

1⃣️ Mapper 类接受两个通用类型参数:源类型与目标类型。
2⃣️ 源对象保存在一个 final 类型的对象中。
3⃣️ map 方法请求将源对象转换为目标对象。

如你所见, map 上的方法签名并不没有指明是何种对象在受闭包的控制。看看方法体,我们就了解它应该是类型 Tvalue ,但 T 并未在方法签名中,因此没有合适的选项适合 @DelegatesTo 。比如我们打算静态编译下列代码:

def mapper = new Mapper<String,Integer>('Hello')
assert mapper.map { length() } == 5

编译将失败,并且提供了以下失败信息:

Static type checking] - Cannot find matching method TestScript0#length()

在这种情况下,可以使用 @DelegatesTo 注释的 type 成员将 T 引用为类型令牌:


class Mapper<T,U> {
  final T value
  Mapper(T value) { this.value = value }
  U map(@DelegatesTo(type="T") Closure<U> producer) {    1⃣️   
    producer.delegate = value
    producer()
  }
}

1⃣️ @DelegatesTo 注释引用了一个方法签名中不存在的基本类型。

注意,这里并不局限于基本类型令牌。 type 成员可以用来表示复杂类型,比如说 List<T>Map<T,List<U>> 。 它之所以被用作最后手段的原因在于,只有当类型检查器发现使用了 @DelegatesTo 之时,类型才被检查,而不是在注释方法本身被编译时才这样做。这就意味着类型安全性只有在调用站点时才能保证。另外,编译起来也比较慢(虽然在绝大多数情况下,这一点并不容易觉察出来)。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文