我怀疑我有一个根本性的误解需要纠正,所以将从一般概念开始,然后放大导致我这样思考的特定实例。
一般来说,是否可以编写一个类型签名具有参数化类型的函数,并根据类型参数是否属于类型类来采取不同的操作?
例如,如果你有
data MyTree a = Node { val :: a, left :: Maybe (MyTree a), right :: Maybe (MyTree a) }
prettyPrint :: MyTree a -> String
prettyPrint (Show a => ...) t = show (val t)
prettyPrint t = show "?"
Run Code Online (Sandbox Code Playgroud)
哪里prettyPrint $ Node 'x' Nothing Nothing会打印x而prettyPrint $ Node id Nothing Nothing会打印?。
引导我来到这里的是我正在处理复杂的参数化数据类型(例如MyTree)的一些实例,在我需要进行一些调试之前,它进展顺利。当我插入trace语句时,我发现自己希望我的数据类型参数派生显示,当我使用测试(可显示)数据时。但我明白,正如 LYAH 所说的那样,永远不应该在数据声明中添加类型类约束。这是有道理的,我不应该仅仅因为我想调试它就人为地限制我的数据类型。
因此,我最终将类型类约束添加到我正在调试的代码中,但很快发现它们像病毒一样传播。每个调用我正在调试的低级函数的函数也需要添加约束,直到我基本上暂时将约束添加到每个函数,以便我可以获得足够的测试覆盖率。现在我的测试代码正在污染我正在尝试开发的代码并使其偏离轨道。
我认为最好采用模式匹配并将约束排除在签名之外,或者使用多态性并定义函数的调试版本,或者以其他方式将调试跟踪包装在仅在类型参数是实例时才触发的条件中的Show。但在我的徘徊中,我找不到一种方法来做到这一点,也找不到明智的替代方案。
在 Rust 中,如何在for样式循环中执行可变大小的步骤?我可以使用此构造执行固定大小的步骤:
for i in (0..vals.len()).step_by(4)
{
println!("{}: {}", i, vals[i]);
}
Run Code Online (Sandbox Code Playgroud)
或者更合适的:
for (i,val) in vals.iter().enumerate().step_by(4)
{
println!("{}: {}", i, val);
}
Run Code Online (Sandbox Code Playgroud)
但我真正想做的是:
for i in 0..vals.len()
{
println!("{}: {}", i, vals[i]);
if vals[i] == 1 { i += 2; }
else if vals[i] == 2 { i += 4; }
}
Run Code Online (Sandbox Code Playgroud)
但当然,修改i不会影响循环迭代器。
由于主要具有 C 语言背景,现代语言对迭代器的依赖常常让人感觉像是戴着手套进行编程。通常谷歌会来救援,但我还没有找到任何解决方案来解决这个看似相当简单的问题。
我想出的最好的是
let mut i:usize = 0;
while i < vals.len()
{
println!("{}: {}", i, vals[i]);
if vals[i] == …Run Code Online (Sandbox Code Playgroud) 该问题为从索引中排除也从构建中排除的文件提供了很好的答案。一个悬而未决的问题仍然存在:如何防止作为构建一部分的文件填充代码完成功能或代码洞察功能?
我的用例是TrueSTUDIO(以前是System Workbench,当时是Eclipse)项目,其中包括另一个项目中的一些模块。它们被包装在安全使用的存根和包装中,切勿直接调用。外部模块无法编辑,因为它们必须与另一个项目保持同步,因此它们的文件名和其他符号与当前项目的名称会发生冲突。当使用代码完成来包含标题或完成函数名称时,不使用的模块的文件名和函数名称将直接显示在完成列表中。
我希望继续在我的构建中包括这些模块,但是它们的任何内容都不会出现在代码完成/洞察功能中。
我在“项目属性”->“ C / C ++常规”->“索引器”中看到,有一些选项可将索引器配置为使用其他构建配置。这是有希望的,但可能很快导致索引器与主要构建配置完全不同步。
对实用方法有什么建议吗?