欧美一区二区三区老妇人-欧美做爰猛烈大尺度电-99久久夜色精品国产亚洲a-亚洲福利视频一区二区

C++TpeScript系列的泛型有什么用途

這篇文章主要介紹“C++ TpeScript系列的泛型有什么用途”,在日常操作中,相信很多人在C++ TpeScript系列的泛型有什么用途問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”C++ TpeScript系列的泛型有什么用途”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!

成都做網(wǎng)站、成都網(wǎng)站建設(shè)介紹好的網(wǎng)站是理念、設(shè)計和技術(shù)的結(jié)合。創(chuàng)新互聯(lián)擁有的網(wǎng)站設(shè)計理念、多方位的設(shè)計風(fēng)格、經(jīng)驗豐富的設(shè)計團隊。提供PC端+手機端網(wǎng)站建設(shè),用營銷思維進行網(wǎng)站設(shè)計、采用先進技術(shù)開源代碼、注重用戶體驗與SEO基礎(chǔ),將技術(shù)與創(chuàng)意整合到網(wǎng)站之中,以契合客戶的方式做到創(chuàng)意性的視覺化效果。

一、模版

說起泛型,不得不提一下泛型的鼻祖,模版。C++中的模版以燒腦殼和強大著稱,并被各類大牛津津樂道多年。就現(xiàn)在而言,Java、.NET或TS中的泛型都可以被認(rèn)為是實現(xiàn)了C++模版的子集。對于子集的說法,我不敢茍同。因為就存在的目的而言,TS和C++模版完全不一樣。

C++模版的出現(xiàn)是為了產(chǎn)生類型安全的通用容器。我們先來說一下通用容器,比如我寫了個鏈表或者數(shù)組,這個數(shù)據(jù)結(jié)構(gòu)不太關(guān)心存在里面的具體數(shù)據(jù)是什么類型,它都可以實現(xiàn)對應(yīng)的操作。但js本身不關(guān)注類型和大小,所以js中的數(shù)組本來就是通用容器。對于TS而言,泛型的出現(xiàn)就可以解決這個問題。另一個值得對比的是產(chǎn)生,C++模版最終產(chǎn)出的是對應(yīng)的類或函數(shù),但對于TS而言,TS無法產(chǎn)生任何東西。有的同學(xué)可能要問了,TS不是最終產(chǎn)生JS代碼嗎?這樣說有點不嚴(yán)謹(jǐn),因為TS最終是分離出了JS代碼,而沒有對原有邏輯做任何處理。

C++模版的另一個目的就是元編程。這個元編程相當(dāng)?shù)貜姶?,它主要通過編譯時的程序設(shè)計構(gòu)造來優(yōu)化程序的執(zhí)行。就TS而言,目前它只做了一處類似的優(yōu)化,就是const enum可以內(nèi)聯(lián)在執(zhí)行的地方,僅此而已。關(guān)于這類優(yōu)化,上篇結(jié)束的位置也提到了基于類型推導(dǎo)的優(yōu)化,但目前而言,TS還沒有這個功能。倘若這類簡單的優(yōu)化都不支持,那對于更為復(fù)雜的元編程而言,就更不可能了(元編程需要對泛型參數(shù)進行邏輯推導(dǎo),并最終內(nèi)聯(lián)到使用到的地方)。

二、泛型

我認(rèn)為TS中的泛型主要有3個主要用途:

  • 聲明泛型容器或組件。比如:各種容器類Map、Array、Set等;各種組件,比如React.Component

  • 對類型進行約束。比如:使用extends約束傳入?yún)?shù)符合某種特定結(jié)構(gòu)。

  • 生成新的類型

關(guān)于第二、三點,因為之前文章已經(jīng)很清楚地提到過,這里不再贅述。關(guān)于第一點,我這里舉兩個例子:

第一個例子是關(guān)于泛型容器,假如我想實現(xiàn)一個簡單的泛型鏈表,代碼如下:

class LinkedList<T> { // 泛型類
  value: T;
  next?: LinkedList<T>; // 可以使用自身進行類型聲明
  constructor(value: T, next?: LinkedList<T>) {
    this.value = value;
    this.next = next;
  }
  log() {
    if (this.next) {
      this.next.log();
    }
    console.log(this.value);
  }
}
let list: LinkedList<number>; // 泛型特化為number
[1, 2, 3].forEach(value => {
  list = new LinkedList(value, list);
});
list.log(); // 1 2 3

第二個是泛型組件,假如我想實現(xiàn)一個通用的表單組件,可以這樣寫:

function Form<T extends { [key: string]: any }>({ data }: { data: T }) {
  return (
    <form>
      {data.map((value, key) => <input name={key} value={value} />)}
    </form>
  )
}

這個例子不止演示了泛型組件,也演示了如何使用extends定義泛型約束?,F(xiàn)實中的泛型表單組件可能比這個更為復(fù)雜,上面只是演示一下思路。

到此為止,TS的泛型就講完了!但這個文章還沒完,下面我們來看一下泛型的一些高級使用技巧。

三、泛型遞歸

遞歸簡單來說就是函數(shù)的輸出可以繼續(xù)作為輸入來進行邏輯演算的一類解決問題的思路。舉個簡單的例子,比如我們要算加法,定義了一個add函數(shù),它只能求兩個數(shù)的和,但現(xiàn)在我們有1,2,3等三個數(shù)需要計算,那我們?nèi)绾斡矛F(xiàn)有的工具解決這個問題呢?答案很簡單,首先算add(1, 2)是3,然后add(3, 3)是6。這就是遞歸的思路。

在現(xiàn)實生活中,遞歸是如此的常見,以至于我們經(jīng)常忽略它的存在。程序的世界也是如此。這里舉個例子,并用這個例子來說明TS中的遞歸如何實現(xiàn)。比如,我現(xiàn)在有個泛型類型ReturnType<T>,它可以返回一個函數(shù)的返回類型。但我現(xiàn)在有個調(diào)用層級很深的函數(shù),而且我不知道它的層級有多深,我該如何做呢?

思路一:

type DeepReturnType<T extends (...args: any) => any> = ReturnType<T> extends (
  ...args: any
) => any
  ? DeepReturnType<ReturnType<T>> // 這里引用自身
  : ReturnType<T>;

上面代碼的說明:這里定義了一個DeepReturnType的泛型類型,類型約束為接受任意參數(shù)、返回任意類型的函數(shù)。若它的返回類型是個函數(shù),則繼續(xù)用返回類型調(diào)用自身,否則返回函數(shù)的返回類型。

任何直觀、簡潔的方案背后都有一個但是。但是,這個是無法通過編譯的。主要原因是,TS暫時不支持。以后支不支持我不知道,但,官方給的理由很明確:

  • 這個有著環(huán)形的意圖不可能構(gòu)成對象圖,除非你以某種方式推遲(通過惰性或狀態(tài))。

  • 真的沒有辦法知道類型推導(dǎo)是否結(jié)束。

  • 我們可以在編譯器中使用有限類型的遞歸,但問題不在于類型是否終止,而是計算密集程度和內(nèi)存分配律如何。

  • 一個元問題:我們是否希望人們編寫這樣的代碼?這種使用場景是存在的,但這樣實現(xiàn)的類型不一定適合庫的消費者。

  • 結(jié)論:我們還沒有為這種件事做好準(zhǔn)備。

所以,我們該如何實現(xiàn)這類需求呢?方法是有的,如官方給出的思路,我們可以使用有限次數(shù)的遞歸。下面給出我的思路:

// 兩層泛型類型
type ReturnType1<T extends (...args: any) => any> = ReturnType<T> extends (
  ...args: any
) => any
  ? ReturnType<ReturnType<T>>
  : ReturnType<T>;
// 三層泛型類型
type ReturnType2<T extends (...args: any) => any> = ReturnType<T> extends (
  ...args: any
) => any
  ? ReturnType1<ReturnType<T>>
  : ReturnType<T>;
// 四層泛型類型,可以滿足絕大多數(shù)情況
type DeepReturnType<T extends (...args: any) => any> = ReturnType<T> extends (
  ...args: any
) => any
  ? ReturnType2<ReturnType<T>>
  : ReturnType<T>;
  
// 測試
const deep3Fn = () => () => () => () => "flag is win" as const; // 四層函數(shù)
type Returned = DeepReturnType<typeof deep3Fn>; // type Returned = "flag is win"
const deep1Fn = () => "flag is win" as const; // 一層函數(shù)
type Returned = DeepReturnType<typeof deep1Fn>; // type Returned = "flag is win"

這種技巧可以推廣到定義深層結(jié)構(gòu)的Exclude、OptionalRequired等等。

四、默認(rèn)泛型參數(shù)

有時候我們很喜歡泛型,但有時候我們又不希望類或函數(shù)的消費者每次都指定泛型的類型,這時候,我們可以使用默認(rèn)的泛型參數(shù)。這個在很多第三方庫中廣泛使用,比如:

// 接收P S C的泛型組件
class Component<P,S,C> {
  props: P;
  state: S;
  context:C
  ....
}
// 需要這樣使用
class MyComponent extends Component<{}, {}, {}>{}

// 但如果我的組件是個很純粹的組件,并不需要props、state和context呢
// 可以這樣定義
class Component<P = {}, S = {}, C = {}> {
  props: P;
  state: S;
  context:C
  ....
}
// 然后可以這么使用
class MyComponent extends Component {}

我覺得這個特性非常實用,它以一種js中很自然的方式實現(xiàn)了C++模版中的partial instantiation。

五、泛型重載

泛型重載在官方文檔上提過幾嘴,這種重載依賴于函數(shù)重載的一些機制,因此,我們先來看一下TS中的函數(shù)重載吧。這里,我用lodash里面的map函數(shù)來舉例。map函數(shù)的第二個參數(shù)可以接受一個string或是function,比如官網(wǎng)的例子:

const square = (n) => n * n;

// 接收函數(shù)的map
map({ 'a': 4, 'b': 8 }, square);
// => [16, 64] (iteration order is not guaranteed)
 
const users = [
  { 'user': 'barney' },
  { 'user': 'fred' }
];

// 接收string的map
map(users, 'user');
// => ['barney', 'fred']

那么,這樣的類型聲明如何在TS中表達呢?我可以使用函數(shù)重載,比如這樣:

// 這里只做演示,不保證正確性。真實場景下這里需要填充正確的類型,而不是any
interface MapFn {
  (obj: any, prop: string): any; // 當(dāng)接收string時的情況,情景一
  (obj: any, fn: (value: any) => any): any; // 當(dāng)接收函數(shù)時的情況,情景二
}
const map: MapFn = () => ({});

map(users, 'user'); // 重載情景一
map({ 'a': 4, 'b': 8 }, square); // 重載情景二

上面這段代碼使用了TS中比較奇特的一種機制,也就是函數(shù)、new等 類函數(shù)的定義可以寫在interface中。這個特性的出現(xiàn)主要是為了支持js中可調(diào)用的對象,比如,在jQuery中,我們可以直接執(zhí)行$("#banner-message"),或者調(diào)用其方法 $.ajax()。

當(dāng)然,也可以使用另一種更為傳統(tǒng)的做法,比如下面這樣:

function map(obj: any, prop: string): any;
function map(obj: any, fn: (value: any) => any): any;
function map(obj, secondary): any {}

這里,基本講清楚了函數(shù)重載。推廣到泛型,基本上是一樣的。這里舉一個知友提的問題的例子,對于這個問題,這里不再贅述。解決思路大概是這樣的:

interface FN {
  (obj: { value: string; onChange: () => {} }): void;
  <T extends {[P in keyof T]: never}>(obj: T): void;
  //  ,對于obj的類型T而言,它始終不接收其它的key。
}

const fn: FN = () => {};

fn({}); // 正確
fn({ value: "Hi" }); // 錯誤
fn({ onChange: () => {} }); // 錯誤
fn({ value: "Hi", onChange: () => ({}) }); // 正確

對于React生態(tài),這里有一個比較值得閱讀的泛型重載的實例,那就是connect函數(shù),大家可以移步到它的源碼以便了解更多。

整體而言,我不太喜歡這篇文章。究其原因,TS中的泛型使用廣泛,因其設(shè)計初衷的原因,可玩性較差。但我對這種設(shè)計理念是支持的,首先,它能夠滿足我們定義類型的要求,其次,它做到了比C++模版更為簡單易用。

到此,關(guān)于“C++ TpeScript系列的泛型有什么用途”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

網(wǎng)站名稱:C++TpeScript系列的泛型有什么用途
文章源于:http://chinadenli.net/article4/ppsdoe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供軟件開發(fā)、電子商務(wù)網(wǎng)站設(shè)計、網(wǎng)站導(dǎo)航建站公司、全網(wǎng)營銷推廣

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都定制網(wǎng)站建設(shè)
好吊一区二区三区在线看| 日韩午夜老司机免费视频| 91亚洲精品国产一区| 国产日韩精品欧美综合区| 国产原创中文av在线播放| 日韩一级一片内射视频4k| 激情五月天免费在线观看| 精品日韩av一区二区三区| 91人妻久久精品一区二区三区 | 日韩日韩欧美国产精品| 草草视频福利在线观看| 精品少妇人妻av免费看| 亚洲精品中文字幕在线视频| 插进她的身体里在线观看骚| 日韩精品一级一区二区| 日本女人亚洲国产性高潮视频| 亚洲熟女诱惑一区二区| 亚洲熟女精品一区二区成人| 日韩欧美一区二区黄色| 精品国产亚洲免费91| 五月天丁香婷婷一区二区| 开心激情网 激情五月天| 午夜激情视频一区二区| 国产成人人人97超碰熟女| 久久偷拍视频免费观看| 亚洲国产91精品视频| 国产欧美日韩精品一区二| 精品一区二区三区人妻视频| 日韩欧美综合在线播放| 国产欧美一区二区久久 | 1024你懂的在线视频| 日本午夜免费啪视频在线| 成人综合网视频在线观看| 亚洲国产丝袜一区二区三区四| 欧美尤物在线视频91| 亚洲免费视频中文字幕在线观看| 亚洲午夜福利视频在线| 日本午夜免费福利视频| 欧美日韩精品综合一区| 男人和女人黄 色大片| 免费啪视频免费欧美亚洲|