C# 中 System.Range 結構體


翻譯自 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) 與 StringSpan<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 對象。

考慮數組 sequence0 索引與 sequence[0] 相同。 ^0 索引與 sequence[sequence.Length] 相同。 請注意,sequence[..^0] 不會引發異常,就像 sequence[..sequence.Length] 一樣。對於任意數字 n,索引 ^nsequence.Length - n 相同。 如下面代碼中的注釋所示:

var array = new string[]
{
               // index from start    index from end
    "Item0",   // 0                   ^9
    "Item1",   // 1                   ^8
    "Item2",   // 2                   ^7
    "Item3",   // 3                   ^6
    "Item4",   // 4                   ^5
    "Item5",   // 5                   ^4
    "Item6",   // 6                   ^3
    "Item7",   // 7                   ^2
    "Item8",   // 8                   ^1
};             // 9 (or array.Length) ^0

一個范圍指定了范圍的“開始”“末尾”。 范圍是左閉右開的,也就是說范圍包含“開始”,不包含“末尾”
范圍 [0..sequence.Length][0..^0][..] 都表示整個范圍。


作者 : John Demetriou
譯者 : 技術譯民
出品 : 技術譯站
鏈接 : 英文原文


  1. https://www.cnblogs.com/ittranslator/p/13810800.html System.Index 結構體和 Hat 運算符(^)的全新用法 ↩︎ ↩︎

  2. https://docs.microsoft.com/zh-cn/dotnet/api/system.span-1 Span<T> ↩︎

  3. https://docs.microsoft.com/zh-cn/dotnet/api/system.readonlyspan-1 ReadOnlySpan<T> ↩︎

  4. https://docs.microsoft.com/zh-cn/dotnet/api/system.index System.Index ↩︎

  5. https://docs.microsoft.com/zh-cn/dotnet/api/system.range System.Range ↩︎


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM