C 中居然也有切片語法糖,太厲害了

2021-10-22 10:20:39 字數 3736 閱讀 8324

昨天在 github 上準備找找 c# 9 又有哪些新語法糖可以試用,不覺在乙個文件上看到乙個很奇怪的寫法:foreach (var item in myarray[0..5])哈哈,熟悉又陌生,玩過python的朋友對這個[0..5]太熟悉不過了,居然在 c# 中也遇到了,開心哈,看了下是 c# 8 的新語法,諷刺諷刺,8 都沒玩熟就搞 9 了,我的探索欲比較強,總想看看這玩意底層是由什麼支撐的。

從前面介紹的myarray[0..5]語義上也能看出,這是乙個切分array的操作,那到底有幾種切分方式呢? 下面乙個乙個來介紹,為了方便演示,我先定義乙個陣列,**如下:

var myarr = new string ;
如果用 linq 的話,可以用 take(3),用切片操作的話就是 [0..3], **如下:

static void main(string args)

;//1. 獲取陣列 前3個元素

這個怎麼提取呢?在 python 中直接用 -3 表示就可以了,在c# 中需要用 ^ 來表示從末尾開始,**如下:

static void main(string args)

;//1. 獲取陣列 最後3個元素

用 linq 的話,就需要使用skip + take雙組合,如果用切片操作的話就太簡單了。。。

static void main(string args)

;//1. 獲取陣列 中 index=4,5,6 三個位置的元素

從上面的切割區間[4..7]的輸出結果來看,這是乙個左閉右開的區間,所以要特別注意一下。

從要求上來看就是獲取元素 80 和 90,如果你理解了前面的兩個用法,我相信這個你會很快的寫出來,**如下:

static void main(string args)

;//1. 獲取 array 中倒數第三和第二個元素

通過前面 4 個例子,我想大家都知道怎麼玩了,接下來就是看看到底內部是用什麼做支撐的,這裡使用 dnspy 去挖挖看。

用 dnspy 反編譯**如下:

//編譯前

var query1 = myarr[0..3];

//編譯後:

string query = runtimehelpers.getsubarray(myarr, new range(0, 3));

從編譯後的**可以看出,原來獲取切片的 array 是呼叫runtimehelpers.getsubarray得到了,然後我簡化一下這個方法,**如下:

public static t getsubarray(t array, range range)

從上面**可以看到,最後的 子array 是由buffer.memmove完成的,但是給 子array 的切割位置是由getoffsetandlength方法實現,繼續追一下**:

public readonly struct range : iequatable

public index end

public range(index start, index end)

public valuetuplegetoffsetandlength(int length)

else

index end = this.end;

int num2;

if (end.isfromend)

else

return new valuetuple(num, num2 - num);}}

看完上面的**,你可能有兩點疑惑:

1) start.isfromend 和 end.isfromend 是什麼意思。

其實看完上面**邏輯,你就明白了,isfromend 表示起始點是從左開始還是從右邊開始,就這麼簡單。

2) 我並沒有看到 start.isfromend 和 end.isfromend 是怎麼賦上值的。

這個例子的流程大概是:new range(1,3) -> operator index(int value) -> fromstart(value) -> new index(value),可以看到最後在 new 的時候並沒有對可選引數賦值。

剛才的例子是沒有對可選引數賦值,那看看本例是不是 new index 的時候賦值了?

//編譯前:

var query1 = myarr[^3..];

//編譯後:

string query = runtimehelpers.getsubarray(myarr, range.startat(new index(3, true)));

看到沒有,這一次 new index 的時候,給了 isfromend = true , 表示從末尾開始計算,大家再結合剛才的 getoffsetandlength 方法,我想這邏輯你應該理順了吧。

總的來說這個切片操作太實用了,作用於 arr 可以大幅度減少對 skip & take 的使用,作用於 string 也可以大幅減少 substring 的使用,如:"12345"[1..3]->"12345".substring(1, 2),嘿嘿,厲害了吧! 還是c# **

C 中居然也有切片語法糖,太厲害了

一 背景 講故事昨天在 github 上準備找找 c 9 又有哪些新語法糖可以試用,不覺在乙個文件上看到乙個很奇怪的寫法 foreach var item in myarray 0 5 哈哈,熟悉又陌生,玩過python的朋友對這個 0 5 太熟悉不過了,居然在 c 中也遇到了,開心哈,看了下是 c...

C 中建構函式居然是可以直接呼叫的

如下 include class a a int x a x b x 1 a int geta int getb private int a int b int main 經過編譯和執行之後,結果如下 呼叫第乙個建構函式 呼叫第二個建構函式 呼叫析構函式 5 6 呼叫析構函式 首先要知道 一 c 編...

C 中建構函式居然是可以直接呼叫的

如下 include class a a int x a x b x 1 a int geta int getb private int a int b int main 經過編譯和執行之後,結果如下 呼叫第乙個建構函式 呼叫第二個建構函式 呼叫析構函式 5 6 呼叫析構函式 首先要知道 一 c 編...