小编Bob*_*Bob的帖子

告诉,不要问和单一责任 - 在课堂上用数据做新事物

我有一个案例,"告诉,不要问"似乎与"单一责任"原则相冲突.我已经查看了有关该主题的其他讨论,但尚未能够针对这种情况找出最合适的面向对象方法.

我有一个程序,可以读取和操作各种来源的数据集合.我创建了一个类来保存和操作数据("DataSet"类).它包括对数据集执行各种操作的方法,例如比较两个数据集以生成包含差异的新数据集,以及将数据集写入文件.

我现在想对数据集执行一些分析并将结果输出到报告中.我对编码的第一次尝试询问数据集从中提取信息,然后构建报告,但这似乎违背了"告诉,不要问"的原则.那么:我应该将分析方法放在DataSet类中,并告诉数据集分析自己并生成报告吗?这会违反单一责任原则吗?如果我希望将来执行其他类型的分析怎么办-DataSet类可能变得非常臃肿,有许多不同的分析例程,这与它的核心目的无关.

有谁能建议这里最好的方法?是否有解决此问题的特定设计模式?

oop single-responsibility-principle tell-dont-ask

16
推荐指数
1
解决办法
1536
查看次数

是否有更好的功能方法来处理带错误检查的向量?

我正在学习Rust,并想知道如何改进下面的代码.

我有一个形式元组的向量(u32, String).该u32值代表行号和Strings为在相应的行中的文本.只要所有String值都可以成功解析为整数,我想返回一个Ok<Vec<i32>>包含刚刚解析的String值,但如果不是,我想返回某种形式的错误(只是Err<String>在下面的例子中).

我正在努力学习避免可变性并在适当的地方使用功能样式,如果只是需要的话,上面的功能很简单.这是我在这种情况下想出的:

fn data_vals(sv: &Vec<(u32, String)>) -> Result<Vec<i32>, String> {
    sv.iter()
        .map(|s| s.1.parse::<i32>()
                    .map_err(|_e| "*** Invalid data.".to_string()))
        .collect()
}
Run Code Online (Sandbox Code Playgroud)

但是,小问题是我想为每个无效值(而不仅仅是第一个)打印错误消息,并且错误消息应包含违规元组中的行号和字符串值.

我已设法使用以下代码执行此操作:

fn data_vals(sv: &Vec<(u32, String)>) -> Result<Vec<i32>, String> {
    sv.iter()
        .map(|s| (s.0, s.1.parse::<i32>()
                  .or_else(|e| {
                      eprintln!("ERROR: Invalid data value at line {}:  '{}'",
                                s.0, s.1);
                      Err(e)
                  })))
        .collect::<Vec<(u32, Result<i32, _>)>>() // Collect here to avoid short-circuit
        .iter()
        .map(|i| i.1
             .clone()
             .map_err(|_e| "*** Invalid data.".to_string())) …
Run Code Online (Sandbox Code Playgroud)

functional-programming rust

7
推荐指数
1
解决办法
136
查看次数

如何在类型已实现 Display 的特征对象上实现 Display

我有一些代码返回类型的特征对象MyTrait,以便它可以返回几个不同的结构之一。我想实现Display特征对象的特征,以便我可以打印该对象,并将详细信息委托给各种结构,因为它们每个都需要自己的自定义格式化程序。

我可以通过将格式化方法作为MyTrait定义的一部分,然后实现DisplayforMyTrait和委托来实现这一点 - 如下所示:

trait MyTrait {
    fn is_even(&self) -> bool;
    fn my_fmt(&self, f: &mut fmt::Formatter) -> fmt::Result;
}

impl fmt::Display for MyTrait {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        self.my_fmt(f)
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,我已经Display为每个实现的结构实现了该特征MyTrait。这意味着我最终为每个结构体提供了两个执行相同操作的方法 -直接在结构体上fmt()满足特征的方法,以及由上面的代码调用的方法。这看起来很笨拙且重复。有更简单的方法吗?Displaymy_fmt()

这是一个完整的示例程序来说明这一点。它比我想要的要长一点(它基于我之前的问题Calling functions that return different types with Shared Trait and pass to other function 的答案),但我想不出更简单的方法来说明这一点。当然,在这个玩具示例中,结构和fmt函数非常简单;在我的实际应用中它们更加复杂。

use std::fmt;

trait MyTrait {
    fn …
Run Code Online (Sandbox Code Playgroud)

traits rust

7
推荐指数
1
解决办法
4089
查看次数

在Rust中从if else条件中分配值的惯用法

在Rust中的"if - else"构造中创建或分配几个对象之一的首选方法是什么?由于范围界定,似乎变量必须在if - else之外创建.我认为的方式都不是很好.使用字符串作为示例,这是一种方式,但它会生成有关未使用的赋值的警告:

let mut s = String::new();
if condition {
    s = "first".to_string();
} else {
    s = "second".to_string();
}
Run Code Online (Sandbox Code Playgroud)

另一种选择是:

let mut s = "second".to_string();
if condition {
    s = "first".to_string();
}
Run Code Online (Sandbox Code Playgroud)

它更短并且不会产生警告,但是意味着s被分配两次,并且意味着"second".to_string()运行但是如果condition是真的则浪费.如果不是简单的字符串创建,而是昂贵的操作(可能带有副作用),这种方法就不合适了.

还有更好的选择吗?

rust

6
推荐指数
2
解决办法
519
查看次数

库箱中多个可执行文件的文件布局

我想创建一个包含两个二进制板条箱和一个包含共享代码的库的 Rust 包。我知道如何通过将二进制文件的源文件放在子目录src/bin/(例如src/bin/firstbin.rssrc/bin/secondbin.rs)中并将库代码放在src/或 中来对一个简单的程序执行此操作src/lib/

但是,如果二进制文件具有大量不属于库的非共享代码,并且我想将其源代码拆分为多个文件,则我不确定如何布局源文件。我正在考虑src/bin/firstbin/只属于第一个二进制文件和src/bin/secondbin/第二个二进制文件的文件。但是,我不确定如何从firstbin.rs和引用这些文件secondbin.rs

那么这是正确的方法吗?如果是,我如何引用这些文件?如果不是,最好的布局是什么?

rust rust-cargo

6
推荐指数
1
解决办法
6624
查看次数

State monad 是否适用于简单的递归“循环”?

我正在从“LYAH”学习 Haskell,并学习了 State monad。作为练习,我正在努力实现一个简单的“虚拟CPU”。状态单子似乎很适合这个,但我不知道如何使用它。这是我目前所拥有的一个非常精简的示例(没有状态单子):

data Instruction = Incr | Decr | Halt

data Computer = Computer { program :: [Instruction],
                           acc :: Int,
                           pc :: Int,
                           halted :: Bool
                         }

main = do
  let comp = Computer { program = [Incr, Decr, Incr, Incr, Halt]
                      , acc = 0
                      , pc = 0
                      , halted = False
                      }
  execute comp

execute :: Computer -> IO ()
execute comp = do
  let (output, comp') = step comp
  putStrLn output
  case halted …
Run Code Online (Sandbox Code Playgroud)

haskell

4
推荐指数
1
解决办法
133
查看次数

将 Eithers 列表转换为包含列表的 Eithers

我有一个返回项目列表的函数Either。如果它只包含Right项目,我想返回一个Right包含原始项目中的值列表的单个Right项目,但如果它包含任何Left项目,我想要一个Left包含原始项目中的值列表的单个Left项目。所以如果我有: [Right "a", Right "b", Right "c"] 它应该变成: Right ["a", "b", "c"] 但如果我有: [Right "a", Left "b", Right "c", Left "d"] 它应该变成: Left ["b", "d"]

注意:sequenceControl.Monad 中的函数不适合,因为它只保留第一Left项。

我想出了这个:

eitherList :: [Either a1 a2] -> Either [a1] [a2]
eitherList l = if null lefts
               then Right rights
               else Left lefts
  where f1 (Left a) (al, ar) = (a : al, ar)
        f1 (Right …
Run Code Online (Sandbox Code Playgroud)

haskell

1
推荐指数
1
解决办法
177
查看次数