我想写一个函数返回一个数组,其所有子数组的长度必须为2。例如,返回将是[[1,2],[3,4]]
。
我定义:
(1)子集TArray的数组在哪里{. all~~子集:: 在哪里[Int, Int]}
;
和
sub fcn(Int $n) of TArray is export(:fcn) {
[[1, 2], [3, 4]];
}
我觉得(1)太复杂了。有更简单的吗?
如果你想对函数的参数(而不是它的返回类型)施加这种约束,你可以这样做:
sub fcn(@a where {all .map: * ~~ [Int, Int]}) {...}
正如其他答案所提到的,目前没有很好的语法来类似地约束返回类型,但有一个建议是为返回类型添加对类似语法的支持。事实上,正如在那个问题中提到的,有人自愿致力于实现,但据我所知还没有取得任何进展。(我想我应该知道,因为我是那个志愿者...哎呀)
因此,就目前而言,子集是最好的选择,但希望未来会有更好的方法来编写它。
我想目标是将内部数组的类型限制为[Int, Int]...我能得到的最接近的是声明两个子集,一个基于另一个...
subset IArray where * ~~ [Int, Int];
subset TArray where .all ~~ IArray;
否则,您使用的匿名子集形式似乎是最简单的,尽管@raiph指出您可以删除“of Array”部分。
subset TArray of Array where { .all ~~ subset :: where [Int, Int] };
有更简单的吗?
在我们去那里之前,让我们后退一步。即使仅仅看一眼代码就忽略了代码的“过于复杂”性质,它也有潜在的问题和复杂性,原因可能不太明显。我将强调三点:
>
该子集将接受一个包含数组的数组,其中每个数组都包含两个Int,但它不强制使用数组。外部数组的类型可能只是一个通用数组,而不是一个数组。事实上,除非您有意引入强类型值,否则它将是。我将在这个答案的最后一部分介绍强输入。
空数组怎么样?您的子集将接受该选项。这是你的意图吗?如果没有,那么至少需要一对Int如何?
外部where
子句使用了形式为. all~~...
的常见Raku习语,在~~
智能匹配运算符的左侧有一个连接。令人惊讶的是,根据我刚刚提交的问题,这可能是一个问题。有什么替代方案?
Raku在保持简单方面做得很好。如果我们抛开对强类型的任何人为渴望,专注于用于收紧代码的简单工具,那么我过去会建议的一个简单子集是:
subset TArray where .all == 2; # BAD despite being idiomatic???
这具有原始代码的所有问题,此外它还接受具有整数所属的非整数的数据。
但它确实具有一些弥补性的特性,即它可以进行有用的检查(内部数组每个都有两个元素),而且它比您的代码要简单得多。
现在我提醒自己,我需要将~~
左侧的. all
视为可能的问题,我会将其改为:
subset TArray where 2 == .all; # Potentially the new idiomatic.
这个版本读起来更差,但是,虽然可读性很重要,但基本的正确性更重要。
以下是我提出的两种变体:
subset TArray where all .map: * ~~ (Int,Int);
subset TArray where .elems == .grep: (Int,Int);
这两者都避免了连接/智能匹配问题。(第一个表达式在智能匹配的左侧有一个连接,但它不是问题的示例。)
第二个版本显然不太正确(可以将其视为检查子数组的计数是否与匹配的子数组的计数相同(Int,Int)),但如果子数组为零,则它很好地解决了匹配问题,如果需要解决的话:
subset TArray where 0 < .elems == .grep: (Int,Int);
迄今为止的解决方案不处理强类型。也许这是可取的。也许不是。
为了理解我的意思,让我们先看看字面意思:
say WHAT 1; # (Int)
say WHAT [1,2]; # (Array)
say WHAT [[1,2],[3,4]]; # (Array)
>
这些值的类型由其文字构造函数确定。
最后两个是数组,在它们的元素上是通用的。
(第二个不是Array[Int]
,这可能是意料之中的。同样,最后一个不是Array[Array[Int]]
。)
复合类型(数组和哈希)的当前内置Raku文字形式都构造通用Array
s,它们不约束其元素的类型。
请参阅PR介绍[1,2,3]: Int
语法#4406,了解有关元素类型复合文字的提案/PR以及我刚刚在此处回复您关于该PR的替代和/或补充方法的问题。(多年来一直在讨论类型系统的这一方面,但似乎是时候让Rakoons考虑解决它了。)
如果您想构建一个强类型数据结构作为从例程返回的值,并让返回类型检查该值,该怎么办?
有一种方法可以构建这样一个强类型的值:
my Array[Array[Int]] $result .= new: Array[Int].new(1,2), Array[Int].new(3,4);
超级冗长!但是现在你可以为你的子的返回类型检查编写以下内容,它会起作用的:
subset TArray of Array[Array[Int]] where 0 < .elems == .grep: (Int,Int);
sub fcn(Int $n) of TArray is export(:fcn) {
my Array[Array[Int]] $result .= new: Array[Int].new(1,2), Array[Int].new(3,4);
}
构建强类型值的另一种方法是,不仅在变量的类型约束中指定强类型,还指定强制类型,以便将松散类型的值连接到强类型的目标。
我们保留完全相同的子集
(建立强类型目标数据结构并添加“细化类型”检查):
subset TArray of Array[Array[Int]] where 0 < .elems == .grep: (Int,Int);
但是,我们没有使用详细的按构造更正的初始化值,而是使用完整的类型名和新的,我们引入了额外的强制类型,然后只使用普通的文本语法:
constant TArrayInitialization = TArray(Array[Array[Int]()]());
sub fcn(Int $n) of TArray is export(:fcn) {
my TArrayInitialization $result = [[1,2],[3,4]];
}
(我本可以将TArray开始化
声明编写为另一个子集
,但这样做会有点过度。常量
可以轻松完成这项工作。)
(这是《Raku rebless不再处理继承类》的后续内容) 我试图想出一个更复杂的用例,但无法让代码正常工作。 这个想法是一个Person类,带有儿童和成人的混音子类。我们有一个UNICEF对象,当年龄超过18岁时将类型更改为Adult。 这一点显然是失败的,因为成年人是父母而不是孩子的混合体: 但它部分运行: 用一个类和一个混音来设置它是这样的: 但它不起作用: 我明白了。rebless系列指
我有一个任务,我们要创造一个石头,纸,剪刀的游戏。它指定我们必须创建一个抽象的“工具”类,其中有三个子类:“ToolRock”、“ToolPaper”、“ToolScissors”。抽象类应该有一个“+getFeagnet():tool”函数(用斜体写成)。 我的假设是做一个像这样的抽象函数: RockTool类被指定为具有函数“+get弱点():tool”(不是用斜体写的),我的想法是创建一个覆
假设我已经包装了我的C类和,并且可以通过SWIG生成的模块从Python访问它们: 在Python中,我创建了面向用户的类,它是一个浅层代理,主要添加docstring,并允许IDE对参数名称进行制表符补全: 问题在于,返回类型为,它没有docstring,也不显示参数名称(swig将所有参数公开为)。相反,我希望它提供我自己的浅代理
我有下面的课,我试图测试。我遇到问题的方法是,因为我试图存根/模拟行为,然后在测试中验证行为。
我正试图从使用observable转换下面的observable代码。使用可管道操作符创建到。 我已经尝试了下面的方法,但是我得到了一个转换错误,无法转换可观察的类型。看不见的。如有任何帮助,我们将不胜感激。
对于一堆带有泛型的包装类,我的继承结构遇到了一些麻烦。这基本上是结构: 这将与当前代码一起编译和工作,但是,这似乎很危险。如果调用方像这样使用这个方法:,它将很好地编译,但是如果findMiddle尝试返回SubBWrapper,则在运行时会有一个ClassCastException。我以为行得通却行不通的是: 所以我的问题基本上是,有没有正确的方法来编写编译、运行并遵循最佳实践的方法findMi