当前位置: 首页 > 知识库问答 >
问题:

Raku:返回类型

岳均
2023-03-14

我想写一个函数返回一个数组,其所有子数组的长度必须为2。例如,返回将是[[1,2],[3,4]]

我定义:

(1)子集TArray的数组在哪里{. all~~子集:: 在哪里[Int, Int]}

sub fcn(Int $n) of TArray is export(:fcn) {
    [[1, 2], [3, 4]];
}

我觉得(1)太复杂了。有更简单的吗?

共有3个答案

孔星宇
2023-03-14

如果你想对函数的参数(而不是它的返回类型)施加这种约束,你可以这样做:

sub fcn(@a where {all .map: * ~~ [Int, Int]}) {...}

正如其他答案所提到的,目前没有很好的语法来类似地约束返回类型,但有一个建议是为返回类型添加对类似语法的支持。事实上,正如在那个问题中提到的,有人自愿致力于实现,但据我所知还没有取得任何进展。(我想我应该知道,因为我是那个志愿者...哎呀)

因此,就目前而言,子集是最好的选择,但希望未来会有更好的方法来编写它。

麹凯捷
2023-03-14

我想目标是将内部数组的类型限制为[Int, Int]...我能得到的最接近的是声明两个子集,一个基于另一个...

subset IArray where * ~~ [Int, Int];
subset TArray where .all ~~ IArray;

否则,您使用的匿名子集形式似乎是最简单的,尽管@raiph指出您可以删除“of Array”部分。

柯梓
2023-03-14
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文字形式都构造通用Arrays,它们不约束其元素的类型。

    请参阅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