Kotlin 泛型

文章目錄

  • 定義
    • 泛型屬性
    • 泛型函數
    • 泛型類或接口
  • where 聲明多個約束
  • 泛型具體化
  • in、out 限制泛型輸入輸出

定義

有時候我們會有這樣的需求:一個類可以操作某一類型的對象,并且限定只有該類型的參數才能執行相關的操作。
如果我們直接指定該類型Int,確實可以實現該操作,但是換一個類型就得再重新定義一個類:

class MyArray {fun add(int: Int) {}fun delete(int: Int) {}
}fun main() {val myArray = MyArray()myArray.add(1)myArray.delete(1)
}

如果我們將類型改為Any,又會導致可操作參數太過籠統,還容易出現各種問題:

class MyArray {fun add(any: Any) {}fun delete(any: Any) {}
}fun main() {val myArray = MyArray()myArray.add(1)myArray.delete("abc")
}

這時候我們需要引入泛型。泛型的定義方式如下:

<泛型名[: 泛型所屬類型], ...>

一般情況下,泛型名會是單個的大寫字母,很多時候是T,而泛型所屬類型可以指定泛型是某個類/接口或者其子類/實現(當然,單獨這樣寫做不了什么,請繼續往下看):

<T>
<T: Runnable>
<K, V>

泛型屬性

在 Kotlin 中,可以為一個類定義擴展屬性:

class MyClassval MyClass.name get() = "MyClass"

如果我們要指定是任何類都有的屬性,則可以泛型。
泛型屬性只能用在擴展,聲明時需要將泛型定義放置在val|var后,變量名前。

val <T> T.name get() = "Any"fun main() {val int = 1print(int.name)
}
Any

也可以限制該泛型是Runnable接口或其實現。

val <T: Runnable> T.name get() = "Runnable"fun main() {val int = 1// print(int.name) 不可訪問print(Runnable {  }.name)
}
Runnable

泛型函數

我們也可以為函數泛型,與泛型擴展屬性類似,泛型定義需要寫在fun和函數名之間(意外發現此時as如果無法轉換不會拋出異常,而是返回any):

fun <T> cast(any: Any) = any as Tfun main() {cast<List<Double>>(listOf(1, 2)).forEach { print(it); print(", ") }
}
1.0, 2.0, 

Note:泛型可以作為函數接收者、參數、返回值類型的一部分。如果一個泛型函數在調用時可以通過傳入的參數類型或返回值聲明確定泛型的類型,則調用時泛型的類型可以缺省,否則需要指明其類型函數名<泛型類型, ...>()(泛型類與此類似)。

聲明兩個泛型(涉及到的 Kotlin 一些便捷的習語我們將在后續文章學習):

fun <K, V> hashMap(vararg pairs: Pair<K, V>) =HashMap<K, V>().apply { putAll(pairs) }fun main() {print(hashMap("key" to 1))
}
{key=1}

泛型擴展函數:

// List 類是一個泛型類
// 可以將它的泛型指定為函數的泛型
fun <T> List<T>.print() = print(this)fun main() {listOf(1, 2, 3).print()
}
[1, 2, 3]
fun <T: Comparable<Int>> T.isGreaterZero() = this > 0fun <T: Comparable<Int>> T.isGreaterZero() = this > 0fun main() {val int = 1// Int 實現了 Comparable<Int>// 因此可以調用print(int.isGreaterZero())
}
true

作為返回值:

fun <T> Any.toType() = this as Tfun main() {// 沒有指定變量類型,無法推斷泛型的類型// 因此調用時需要聲明泛型類型val doubleList = listOf<String>().toType<List<Double>>()val intList: List<Double> = listOf<String>().toType()
}

泛型類或接口

在定義泛型類或接口時,需要將泛型定義放置在類名之后,括號之前。
泛型函數與接口是類似的,這里以類為例。

class Group<T>(vararg elements: T) {private val value = mutableListOf(*elements)fun add(element: T) = value.add(element)fun remove(element: T) = value.remove(element)// 重寫 toString,調用 print 時即可打印出列表override fun toString(): String = value.toString()
}fun main() {val group = Group(1, 2, 3) // Group<Int>(1, 2, 3)println(group)group.remove(2)println(group)group.remove(4)print(group)
}
[1, 2, 3]
[1, 3]
[1, 3]

Note:vararg用于定義數量不定的參數,vararg element: Int表示你可以傳入任意數量(0…無限大)的Int類型,在內部訪問element會獲取到一個數組Array<Int>,而使用*可以將其展開為vararg(也就是原始傳入的任意數量的Int),可以用于傳入另一個需要vararg的函數。

使用*可以指代所有泛型(下方例子中相當于Any?*無法用在函數調用上):

fun List<*>.print() = print(this)fun main() {listOf(1, 2, 3).print()println()listOf("a", "b", "c").print()
}
[1, 2, 3]
[a, b, c]

where 聲明多個約束

我們可以使用<T: 類型>來約束泛型為某一類型或其子類。但有時候我們想要將其約束于多個類型,可以使用where來實現(此時<T: 類型>中的類型也應該一并移到where處):
我們先定義一個接口和一個類,后面的例子會反復用到:

interface MyInterfaceclass MyClass : Runnable, MyInterface {override fun run() {}
}
  1. 泛型擴展屬性

    // 只有實現了 Runnable 和 MyInterface 才能擁有此擴展屬性
    val <T> T.id where T: Runnable, T: MyInterfaceget() = 123fun main() {MyClass().id
    }
    
  2. 泛型函數

    // 只有實現了 Runnable 和 MyInterface 才能擁有此擴展函數
    fun <T> T.getId() where T : Runnable, T : MyInterface = 123// 只有泛型 T 實現了 Runnable 和 MyInterface 才能使用此函數
    fun <T> getName() where T : Runnable, T : MyInterface ="Runnable&MyInterface"fun main() {MyClass().getId()getName<MyClass>()
    }
    
  3. 泛型類或接口

    // 只有實現了 Runnable 和 MyInterface 才能作為構造參數 value 傳入
    class MyContainer<T>(val value: T) where T : Runnable, T : MyInterfacefun main() {MyContainer(MyClass())
    }
    

泛型具體化

有時候我們需要判斷泛型的類型,會想到用類型::class獲取對應的KClass進行對比。而當該類型為泛型時,我們需要將其具象化reified,通常該聲明只能用于函數,并且需要與inline搭配使用:

inline fun <reified T> T.isInt() = T::class == Int::classfun main() {println(1.isInt())print(false.isInt())
}
true
false

in、out 限制泛型輸入輸出

inout修飾泛型只能用在類或接口。
當一個泛型被in修飾時,表明該類型只能作為對象屬性、方法的輸入(賦值、傳參):

class Group<in T>(vararg elements: T) {// 因為泛型聲明為 in,屬性類型中包含 T 可見性只能為 privateprivate val value = mutableListOf(*elements)fun add(element: T) {}// 因為泛型聲明為 in,不能定義返回 T 類型的方法// fun get(index: Int) = value[index]
}

當一個泛型被in修飾時,表明該類型只能作為對象屬性、方法的輸出(獲取值、函數返回):

class Group<out T>(vararg elements: T) {// 因為泛型聲明為 out,而 MutableList<T> 具有 in 和 out// 若將其公開,將會允許 in T,例如 value.add(element: T)// 屬性類型中包含 T 可見性只能為 privateprivate val value = mutableListOf(*elements)// 因為泛型聲明為 out,不能作為參數類型// fun add(element: T) {}fun get(index: Int) = value.get(index)
}

Note:注意是針對對象而言,如果是一個類聲明了out泛型,仍然可以將該泛型作為構造函數中的參數類型。

class Group<out T>(vararg elements: T)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/20432.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/20432.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/20432.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

機器人抓取檢測(Robot Grasping Detection)

目錄 前言 一、物體檢測 二、抓取點生成 三、運動規劃 四、控制 五、總結 前言 機器人抓取檢測&#xff08;Robot Grasping Detection&#xff09;是指通過計算機視覺和機器學習技術&#xff0c;自動識別并確定機器人如何抓取物體的一種技術。這個過程涉及多個步驟和關鍵…

【Python系列】Python 中方法定義與方法調用詳解

&#x1f49d;&#x1f49d;&#x1f49d;歡迎來到我的博客&#xff0c;很高興能夠在這里和您見面&#xff01;希望您在這里可以感受到一份輕松愉快的氛圍&#xff0c;不僅可以獲得有趣的內容和知識&#xff0c;也可以暢所欲言、分享您的想法和見解。 推薦:kwan 的首頁,持續學…

詳細介紹運算符重載函數,清晰明了

祝各位六一快樂~ 前言 1.為什么要進行運算符重載&#xff1f; C中預定義的運算符的操作對象只能是基本數據類型。但實際上&#xff0c;對于許多用戶自定義類型&#xff08;例如類&#xff09;&#xff0c;也需要類似的運算操作。這時就必須在C中重新定義這些運算符&#xff…

短信發送驗證碼及郵件發送驗證碼

發送短信驗證碼 阿里云發送驗證碼 public Integer sendTelCode(String tel) {String url "https://dfsns.market.alicloudapi.com/data/send_sms";String appcode "a3198282fbdf443d97aa9f3cfbe1232e";int code RandomUtil.randomInt(1000,10000);emai…

【DSP】xDAIS算法標準

1. 簡介 在安裝DSP開發支持包時&#xff0c;有名為 “xdais_7_21_01_07”文件夾。xDAIS全稱: TMS320 DSP Algorithm Standard(算法標準)。39條規則&#xff0c;15條指南。參考文檔。參考文章。 2. 三個層次 3.接口 XDAIS Digital Media。編解碼引擎。VISA&#xff08;Video&…

LeetCode前端刷題指南:探索四大領域,精通五大技能,掌握六大題型,運用七大策略

LeetCode前端刷題指南&#xff1a;探索四大領域&#xff0c;精通五大技能&#xff0c;掌握六大題型&#xff0c;運用七大策略 在前端開發的廣闊領域中&#xff0c;刷題是提高自身能力、深入理解算法和數據結構的重要途徑。LeetCode作為知名的在線刷題平臺&#xff0c;為前端開…

牛客小白月賽95VP

早上藍橋杯大寄&#xff0c;算是交了300元買了件T恤qaq 1.簽到&#xff1a;https://ac.nowcoder.com/acm/contest/83687/A 下面是AC代碼&#xff1a; #include<bits/stdc.h> using namespace std; int main() {int a,b;cin>>a>>b;if(ab) cout<<&quo…

簡述你對 SPA 單??的理解,它的優缺點分別是什么 ?

SPA&#xff08;Single-Page Application&#xff0c;單頁應用&#xff09;是一種在Web開發中廣泛使用的應用架構模式。它允許用戶通過交互操作來更新頁面的部分內容&#xff0c;而無需重新加載整個頁面。以下是關于SPA的理解、優點和缺點的簡要說明。 SPA的理解 SPA的核心思…

qi5uxeel算法分析流程記錄libmsec.so

動態注冊函數主要方法在so層。 libmsec.so 通過regsiterNative方法注冊62個函數 加殼混淆ollvm動態反調試等你還能再惡心點不 分析流程定位關鍵點 算法設計SM4以及各類自定義簽名算法 涉及到的知識包含Java C Android 完整混淆流程如下圖&#xff0c; 不得不說你開發的…

微信小程序canvas畫圖使用百分比適配不同機型屏幕達到任何屏幕比例皆可!完美適配任何機型!指定canvas尺寸適配亦可!保證全網唯一完美

錯誤代碼示例: // 在onLoad中調用 const that = this wx.getSystemInfo({success: function (res) {console.log(res)that.setData({model: res.model,screen_width: res.windowWidth/375,screen_height: res.windowHeight})} }) 我看到網上很多使用上面這種代碼去適配,其…

C語言 指針——函數指針

目錄 什么是函數指針&#xff1f; 函數指針的定義 定義函數指針時的常見錯誤 函數指針有什么用&#xff1f; 函數指針的主要應用 什么是函數指針&#xff1f; 函數指針 (Function Pointer) 就是指向函數的指針變量 數據類型 ( * 指針變量名 ) ( 形參列表 ); 例如&#x…

【回眸】牛客網刷刷刷(九) ——面試經驗篇(含參考回答)

前言 度過了忙碌的4個月&#xff0c;經歷了加班、籌備wedding、更新簡歷&#xff0c;終于有些許喘息時間。 下面的規劃比較簡單&#xff0c;一個是備考3個月后的雅思&#xff0c;一個是積累牛客網沖浪經驗&#xff0c;最后一個是記錄工作交接項。 牛客網刷刷刷這個系列也終于迎…

el-date-picker 選擇日期范圍只保存左側日期面板

需求 日期篩選&#xff0c;但限制只能選擇同一個月的數據&#xff0c;故此應該去掉右側月份面板。 實現 主要是通過 css 樣式實現&#xff1a; <style> /* 隱藏右邊日期面板 */ .el-picker-panel__content.el-date-range-picker__content.is-right .el-date-table, .…

拼多多商品信息一鍵抓取:深度解析商品詳情接口,Python實戰代碼來襲!

拼多多的商品詳情接口允許開發者通過指定的商品ID獲取商品的詳細信息&#xff0c;如商品標題、價格、描述、圖片等。接口采用HTTP請求方式&#xff0c;支持GET方法&#xff0c;返回格式為JSON。 三、接口調用 要調用拼多多的商品詳情接口&#xff0c;你需要遵循以下步驟&…

深度學習-01-作為“箱子“的變量

深度學習-01-作為"箱子"的變量 本文是《深度學習入門2-自製框架》 的學習筆記&#xff0c;記錄自己學習心得&#xff0c;以及對重點知識的理解。如果內容對你有幫助&#xff0c;請支持正版&#xff0c;去購買正版書籍&#xff0c;支持正版書籍不僅是尊重作者的辛勤勞…

6.12 Libbpf-bootstrap(三,APP)

一,APP 既然我們已經了解了最小應用以及Makefile中的編譯方式,接下來我們將通過bootstrap應用程序展示的一些額外的BPF特性。在現代BPF Linux環境中,bootstrap是我編寫可用于生產環境的BPF應用程序的方式。它依賴于BPF CO-RE(閱讀原因請點擊這里),并且需要Linux內核以CO…

Java基礎知識點(反射、注解、JDBC、TCP/UDP/URL)

文章目錄 反射反射的定義class對象反射的操作 注解注解的定義注解的應用注解的分類基準注解元注解 自定義注解自定義規則自定義demo JDBCTCP/UDP/URLTCPUDPURL 反射 反射的定義 Java Reflection是Java被視為動態語言的基礎啊&#xff0c; 反射機制允許程序在執行期間接入Refl…

[數據集][目標檢測]腦腫瘤檢測數據集VOC+YOLO格式9787張3類別

數據集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路徑的txt文件&#xff0c;僅僅包含jpg圖片以及對應的VOC格式xml文件和yolo格式txt文件) 圖片數量(jpg文件個數)&#xff1a;9787 標注數量(xml文件個數)&#xff1a;9787 標注數量(txt文件個數)&#xff1a;9787 標注…

【圖像增強處理工具】軟件使用說明書

軟件使用說明書 軟件名稱 圖像增強處理工具 軟件簡介 該軟件是一個基于 PySide6 和 OpenCV 的圖像處理工具,用戶可以通過 GUI 界面來執行圖像的旋轉、平移和鏡像操作,并將處理后的圖像保存到指定路徑。 運行軟件須知 確保 ui_form.py 文件在同一目錄下,該文件包含了通…

Bean-Searcher的使用提高查詢效率

Bean Searcher官網 添加pom.xml依賴 <dependency><groupId>cn.zhxu</groupId><artifactId>bean-searcher-boot-starter</artifactId><version>4.2.9</version> </dependency>在controller層注入 Autowiredprivate MapSearch…