翻譯自 John Demetriou 2020年4月6日 的文章 《C# 8 Is Introducing Ranges》
我們之前討論過的 C# 中的一個特性 System.Index 結構體[1],與另一特性 System.Range 結構體 是攜手並進的。
在 C# 8.0 之前,沒有訪問集合中任意部分的範圍或切片的語法。開發人員通常不得不執行一些自定義的切片操作,或者依靠諸如 array.Skip(5).Take(2);
的 LINQ 方法。
現在 C# 新增了一個新的小特性,它可以幫助人們從一個大的陣列專案中獲取一個小範圍的專案。
讓我們來考慮一下。假設我們有一個專案陣列,我們僅需展示其中的一部分。通常情況下,我們只需要迴圈這部分,然後像下面這樣輸出它們。
var array = new string[]
{
"Item0",
"Item1",
"Item2",
"Item3",
"Item4",
"Item5",
"Item6",
"Item7",
"Item8",
"Item9"
};
for (int i = 1; i <= 5; i++)
{
Console.WriteLine(array[i]);
}
因此當我們僅需要幾個特定的項,我們通過控制索引值來獲取它們。
通過使用範圍(Range
),我們可以用以下方式來替換:
var array = new string[]
{
"Item0",
"Item1",
"Item2",
"Item3",
"Item4",
"Item5",
"Item6",
"Item7",
"Item8",
"Item9"
};
foreach (var item in array[1..5])
{
Console.WriteLine(item);
}
在這裡,第一次使用的人會注意到一個奇怪的情況——它只會列印四項。為什麼呢?這是因為範圍(Range
)包含開始,但不包含末尾。
如果想要與上面的 for
迴圈有相同的結果,我們的 foreach
迴圈應該是:
foreach (var item in array[1..6])
{
Console.WriteLine(item);
}
Range 的一些示例
1、從索引 1(包含) 到末尾(包含)
foreach (var item in array[1..])
{
Console.WriteLine(item);
}
2、從開始(包含)到索引 3(不包含)
foreach (var item in array[..3])
{
Console.WriteLine(item);
}
3、結合以上兩種,您可以得到一個語法上正確的以下版本
foreach (var item in array[..])
{
Console.WriteLine(item);
}
它的意思是獲取整個範圍。
譯者注
它也等同於下面兩種寫法:
foreach (var item in array[0..^0])
{
Console.WriteLine(item);
}
foreach (var item in array[0..array.Length])
{
Console.WriteLine(item);
}
4、從索引 1(包含)到 從末尾開始的索引 1(不包含)
foreach (var item in array[1..^1])
{
Console.WriteLine(item);
}
在這裡,它結合了[前面文章][1:1]中介紹的 Index
的 Hat 運算子(^
)。
一個快速的解釋,Hat 運算子(^
),會給您一個特定的索引。如果您寫 ^1
,也就是在請求最後一項的索引。如上所述,考慮到最後一個索引號是排除的,在一個有 10 項的序列中,請求索引項直到 ^1
,您也就是在請求索引項直到索引 9(索引從 0 開始),並且該項不包括在其中。
我希望我講清楚了。
將範圍作為變數
我們前面所做的是,將範圍(Range
)作為型別傳遞。我們也可以將範圍宣告為一個變數:
Range range = 1..9;
然後,可以在 [
和 ]
字元中使用該範圍:
var subarray = array[range];
我們還可以將其作為方法的引數傳遞、將其儲存為私有變數,或者用在任何業務邏輯所需的地方。
範圍的型別支援
範圍(Range
)不能被用在 List
或者 IEnumerable<T>
,但陣列並不是唯一支援它的型別。
您還可以將索引(Index
)和範圍(Range
) 與 String
、Span<T>
[2] 或 ReadOnlySpan<T>
[3] 一起使用。
與字串一起使用的例子基本上就是代替 Substring
方法,如下所示:
string s = "01234567";
string r = s[1..3]; // r 將會是 "12"
對於每個擔心 List
(它可能是您通常用來替代陣列的型別)不支援範圍的人來說,List
從 .Net Framework 2.0 開始就已經有 GetRange
方法了。
以下為譯者補充
索引和範圍總結
索引(Index
)和範圍(Range
)為訪問序列中的單個元素或範圍提供了簡潔的語法。
對索引和範圍的語言支援依賴於兩個新型別和兩個新運算子:
System.Index
[4] 型別表示一個序列索引。- Hat 運算子(
^
),指定一個索引與序列末尾相關,用於構造System.Index
物件。 System.Range
[5] 型別表示序列的子範圍。- 範圍運算子(
..
),用於指定範圍的開始和末尾,就像運算元一樣,用於構造System.Range
物件。
考慮陣列 sequence
, 0
索引與 sequence[0]
相同。 ^0
索引與 sequence[sequence.Length]
相同。 請注意,sequence[..^0]
不會引發異常,就像 sequence[..sequence.Length]
一樣。對於任意數字 n
,索引 ^n
與 sequence.Length - n
相同。 如下面程式碼中的註釋所示:
string[] words = new string[]
{
// index from start index from end
"The", // 0 ^9
"quick", // 1 ^8
"brown", // 2 ^7
"fox", // 3 ^6
"jumped", // 4 ^5
"over", // 5 ^4
"the", // 6 ^3
"lazy", // 7 ^2
"dog" // 8 ^1
}; // 9 (or words.Length) ^0
一個範圍指定了範圍的“開始”和“末尾”。 範圍是左閉右開的,也就是說範圍包含“開始”,不包含“末尾”。
範圍 [0..sequence.Length]
、[0..^0]
和 [..]
都表示整個範圍。
作者 : John Demetriou
譯者 : 技術譯民
出品 : 技術譯站
連結 : 英文原文
https://www.cnblogs.com/ittranslator/p/13810800.html
System.Index
結構體和 Hat 運算子(^)的全新用法 ↩︎ ↩︎https://docs.microsoft.com/zh-cn/dotnet/api/system.span-1
Span<T>
↩︎https://docs.microsoft.com/zh-cn/dotnet/api/system.readonlyspan-1
ReadOnlySpan<T>
↩︎https://docs.microsoft.com/zh-cn/dotnet/api/system.index
System.Index
↩︎https://docs.microsoft.com/zh-cn/dotnet/api/system.range
System.Range
↩︎