在Rust Programming Language一书中,在Structs一章中我们介绍了元组结构.
在哪些情况下我应该使用元组结构而不是正常的元组(除了书中提到的例子)?
Luk*_*odt 13
在以下情况下使用元组结构:
你会发现这种情况并非经常发生.如果是,你通常只是试图总结正好一个其他类型的到一个新的类型,给它不同的行为.这是一种已知的模式,称为"新类型"模式.如果结构中有多个字段,通常需要为它们命名.
作为快速提醒:
我们来看看[T]::split_at()
:
fn split_at(&self, mid: usize) -> (&[T], &[T])
Run Code Online (Sandbox Code Playgroud)
他们这个函数的作者选择在这里返回一个元组.让我们看看,我们会从...获得任何东西吗?
SplitSlice
,SliceParts
,...?我们可以给出的每个名字都是多余的,因为该功能已经恰当地命名.left
并且right
会更清楚地说明哪一方是哪一方.但在这里我们假设程序员有正确的直觉.英语是从左到右书写的,在英语文化中,数组通常是从左到右绘制的([0 | 1 | 2 | 3 ]
),因此对大多数人来说都是有意义的.⇒只是一个元组很好!
另一个例子:假设你正在编写一个以某种方式与文本文件(编译器,文本编辑器......)一起工作的应用程序.当您在讨论文本文件中的某个区域(例如,搜索结果)时,您希望通过给出字节偏移来指定该区域.让我们看看元组是否适合我们:
fn find_first_occurence(file: &TextFile, needle: &str) -> (usize, usize)
Run Code Online (Sandbox Code Playgroud)
返回类型是否适合自己?而不是......即使你知道文件中的区域是由字节偏移指定的,返回值仍然是不明确的:要么是(start, end)
它的(start, stuff)
,要么是东西可以是任何其他搜索指标(函数不需要返回end
,因为我们已经知道它的长度,needle
因此可以计算它).所以,我希望你同意,我们想要命名返回类型.我们称之为Span
- 这是Rust编译器中使用的名称.
下一个问题:struct或tuple struct?命名字段是否有意义?同样,没有明确的答案,但我认为我们确实想要命名字段.什么更容易阅读:span.1 - span.0
或span.high - span.low
?另外,我们可以为命名字段编写文档; 例如,记录这high
是独占的.
⇒结构
现在想象您想要向用户报告行号.特别重要的是返回给定跨度的相应行号的函数(为简单起见,我们假设此跨度从不跨越多行).
fn get_line_number(file: &TextFile, span: Span) -> ???
Run Code Online (Sandbox Code Playgroud)
那么我们又回来了什么?在这个函数的上下文中,一个简单u32
的可能就好了!毫无疑问,这u32
代表了什么.虽然:行号计数是从0还是1开始?叹
当然,我们可以在函数上记录这个属性......并且每个其他函数都使用行号.那么如何创建一个新类型并将其记录在那里呢?这也有助于获取多个数字的函数,包括行号:
print_snippet(&file, 57, 63, 80);
Run Code Online (Sandbox Code Playgroud)
等等,现在的行号是多少?确切地说:不是采用u32
s,而是采用LineNumber
s - 类型系统是文档.
我们现在同意创建一种新类型.但是:struct或tuple struct?让我们试试struct:
struct LineNumber {
line_number: u32, // uhm...
}
Run Code Online (Sandbox Code Playgroud)
那么,怎么称呼这个领域?唯一合适的名称分为两类:
line_number
,number
,line
,...inner
,value
,data
,...命名该领域并没有什么好处.所以,让我们不要使用......
⇒元组结构
使它成为一个自己的类型的决定有一些很好的结果:我们可以在我们的源代码中使用基于0的数字,但永远不必担心错误地打印它:
impl fmt::Display for LineNumber {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
(self.0 + 1).fmt(f)
}
}
Run Code Online (Sandbox Code Playgroud)
我们可以在一个地方将基于0的数字调整为基于1的数字(对于那些该死的人类!)!
另请注意,我们正在谈论上面的字节偏移.而不是使用usize
,我们还应该创建一个新类型,以区别于char偏移,例如!