crystal-lang - 如何强制返回值与 Crystal 中的参数值类型相同?
问题描述
如果我有一个接受多种类型参数的函数,我如何强制返回必须与输入的值匹配?
当我想要一种方法与父类型的任何子代一起工作时,尤其会出现这种情况。为了演示,考虑一些“barlike”的东西:
abstract struct Barlike
property bar: Int32
def initialize(@bar); end
end
abstract def make_clang_sound
abstract def serve_drinks
end
现在任何结构都可以实现这两种方法,并存储该值
struct Bar1 < Barlike
def make_clang_sound
puts "bing bang bong"
end
def serve_drinks
puts "your drink sir"
end
end
struct Bar2 < Barlike
def make_clang_sound
puts "kling klang"
end
def serve_drinks
puts "here are your drinks"
end
end
现在,如果我有一个方法想要使用 bar 并返回一个带有更新值的新方法(毕竟这些是结构):
def foo(arg : Barlike)
new_bar = arg.bar + 2
arg.class.new(new_bar)
end
这将返回 a Bar1
if aBar1
传入和 a Bar2
if that 传入但不能保证:
def foo(arg : Barlike)
"howdy"
end
我也将把我foo
放入一个抽象结构中,所以我需要保证foo
返回的实现者与Barlike
给定的类型相同。
我试过了
def foo(arg : Barlike) : arg.class
end
但这是一个编译时错误(arg 不能在那里使用)
我也试过
def foo(arg : Barlike) : typeof(arg)
end
它通过了,但这里的 typeof 只是 Barlike 而我真的需要它只是传入的东西,只有 Bar1 或 Bar2 等等。
宏可以帮助吗?
解决方案
用于此的工具是自由变量。这本质上是针对单个方法的泛型。
# This method returns the same type as its argument
def foo(arg : T) : T forall T
arg
end
这已经解决了您问题的主要部分。
但是,目前无法对自由变量应用类型限制,例如限制T
为Barlike
.
不过,有一些解决方法:
- 使用宏来验证参数类型:
def foo(arg : T) : T forall T
{% raise "arg must implement Barlike" unless T < Barlike %}
arg
end
- 委托给另一个具有类型限制的方法:
def foo(arg : T) : T forall T
foo_impl(arg)
end
private def foo_impl(arg : Barlike)
arg
end
两种解决方法都会影响方法的实现。没有办法为 a 指定这样的类型限制abstract def
。数字 2 可能是可行的,如果你做foo_impl
抽象并需要继承类来实现这个,而不是foo
. 但也可以只使用自由变量的初始示例,没有Barlike
限制。在实践中,您可能不会获得太多收益。
推荐阅读
- algorithm - 为什么基于优先级队列的 Dijkstra 最短路径算法不适用于负权图?
- python - 如何将 pandas DataFrame 的行合并到列表中并将此 DataFrame 转换为 dict
- materialize - 在物化 css 中创建两个侧导航
- css - CSS 线性渐变,三角形起始 46%
- python - XML 中的 odoo 11 日期比较 (qweb)
- android - 在我的应用程序中管理多个密码帐户的最佳做法是什么?
- c# - 如何在 Xamarin Forms 上触发浮动操作按钮 OnClicked EventHandler
- python - 在 TensorFlow 中,我如何知道哪些行已编入索引?
- javascript - twilio.AccessToken 是 TypeScript on Firebase Functions 中的“不是构造函数”
- mysql - Mysql事件不运行