C++ 为什么使用元组而不是对象?
我工作的代码库有一个名为Pair的对象,其中A和B是Pair中第一个和第二个值的类型。我发现这个对象令人反感,因为它被用来代替一个成员名称明确的对象。所以我发现:C++ 为什么使用元组而不是对象?,c++,tuples,C++,Tuples,我工作的代码库有一个名为Pair的对象,其中A和B是Pair中第一个和第二个值的类型。我发现这个对象令人反感,因为它被用来代替一个成员名称明确的对象。所以我发现: List<Pair<Integer, Integer>> productIds = blah(); // snip many lines and method calls void doSomething(Pair<Integer, Integer> id) { Integer product
List<Pair<Integer, Integer>> productIds = blah();
// snip many lines and method calls
void doSomething(Pair<Integer, Integer> id) {
Integer productId = id.first();
Integer quantity = id.second();
}
List productIds=blah();
//剪断许多行和方法调用
无效剂量测定(对id){
整数productId=id.first();
整数数量=id.second();
}
而不是
class ProductsOrdered {
int productId;
int quantityOrdered;
// accessor methods, etc
}
List<ProductsOrderded> productsOrdered = blah();
类产品排序{
int-productId;
整数数量有序;
//存取器方法等
}
List productsOrdered=blah();
在代码库中,该对的许多其他用法也同样难闻
我在谷歌上搜索了元组,它们似乎经常被误解或以可疑的方式使用。是否有令人信服的理由支持或反对使用它们?我很欣赏不想创建巨大的类层次结构,但是如果不使用元组,类层次结构是否会在现实的代码库中爆炸?首先,元组是快速而简单的:不是每次你想把两个东西放在一起时都要编写一个类,而是有一个模板为你做这件事 其次,它们是通用的。例如,在C++中,STD::MAP使用STD::GAND键和值对。因此,可以使用任何一对,而不必为两种类型的每一个置换生成某种带有访问器方法的包装类 最后,它们对于返回多个值很有用。实际上没有理由专门为函数的多个返回值创建一个类,如果它们不相关,则不应将它们视为一个对象
平心而论,您粘贴的代码对一对代码的使用是不好的。这只是原型质量的代码,很可能是拼凑在一起的,从未被重构过。不解决它只是懒惰
元组的真正用途是通用功能,它实际上不关心组件是什么,只在元组级别上运行。元组在Python中一直被使用,它们被集成到语言中,非常有用(它们允许初学者使用多个返回值)
有时候,你真的只需要把事情配对,创造一个真实的、对上帝诚实的班级,这是过分的。另一方面,当你真的应该使用一个类的时候,使用元组和使用相反的概念一样糟糕。一个明显的例子是坐标对(或三元组)。标签是不相关的;使用X和Y(和Z)只是一种惯例。将它们统一起来可以清楚地表明,它们可以以同样的方式处理。无论如何,OP中的代码是一团乱麻,不是因为它使用元组,而是因为元组中的值类型太弱。比较以下各项:
List<Pair<Integer, Integer>> products_weak = blah1();
List<Pair<Product, Integer>> products_strong = blah2();
列出产品_弱=blah1();
列出产品_strong=blah2();
如果我的开发团队传递ID而不是类实例,我也会感到不安,因为整数可以表示任何东西
话虽如此,元组在正确使用时非常有用:
- 元组用于将临时值分组在一起。它们当然比创建过多的包装类要好
- 当需要从函数返回多个值时,out/ref参数的有用替代方法
val of_list : ('key * 'a) list -> Map<'key,'a>
val of_list:('key*'a)list->Map
我可以使用以下方法创建地图实例:
(* val values : (int * string) list *)
let values =
[1, "US";
2, "Canada";
3, "UK";
4, "Australia";
5, "Slovenia"]
(* val dict : Map<int, string> *)
let dict = Map.of_list values
(*val值:(int*string)列表*)
设值=
[1,“美国”;
2、“加拿大”;
3、“英国”;
4.“澳大利亚”;
5,“斯洛文尼亚”]
(*val dict:Map*)
设dict=Map.of_列表值
C#中的等价代码很可笑:
var values = new Tuple<int, string>[] {
new Tuple<int, string>(1, "US"),
new Tuple<int, string>(2, "Canada"),
new Tuple<int, string>(3, "UK"),
new Tuple<int, string>(4, "Australia"),
new Tuple<int, string>(5, "Slovenia")
}
var dict = new Dictionary<int, string>(values);
var值=新元组[]{
新元组(1,“US”),
新元组(2,“加拿大”),
新元组(3,“英国”),
新元组(4,“澳大利亚”),
新元组(5,“斯洛文尼亚”)
}
var dict=新字典(值);
原则上,我不认为元组有什么问题,但C#的语法太麻烦,无法充分利用它们。已经提到了很多东西,但我认为还应该提到,有一些编程风格不同于OOP,对于这些元组来说非常有用
例如,像Haskell这样的函数式编程语言根本没有类。代码示例有一些不同的味道:
- 重塑车轮
KeyValuePair
结构。Dictionary
类使用它来存储对,但您可以在任何适合的地方使用它。(并不是说它适合这种情况……)
- 制作方轮
KeyValuePair
结构,而不要使用具有相同用途的类,因为这样会减少内存分配
- 隐瞒意图
带有属性的类清楚地显示了值的含义,而
对
类不会告诉您值表示什么(只是它们可能以某种方式相关)。要使代码合理地用这样的列表来解释,您必须给列表一个非常描述性的名称,比如productIdAndQuantityPairs
…它是代码重用。与其编写另一个与我们创建的最后5个元组类结构完全相同的类,不如让。。。一个元组类,并在需要元组时使用它
如果类的唯一意义是“存储一对值”,那么我认为使用元组是一个显而易见的想法。如果您开始实现多个相同的类,只是为了重命名这两个成员,我会说这是一种代码味道(就像我讨厌这个术语一样)。如果您正在进行排序
val transformed = data map {x => (x.expensiveOperation, x)}
val sortedTransformed = transformed sort {(x, y) => x._1 < y._1}
val sorted = sortedTransformed map {case (_, x) => x}
val pair = (99, "Luftballons")
println(pair._1)
println(pair._2)