import sun.invoke.empty.Empty

//----泛型定义----
//类
class Box<T>(t: T) {
    var value = t

}
//接口
interface IBox<T>{
    fun dragBox(t:T)

}
//函数
fun <T> singletonList(item: T): List<T> {
    println(item)
    return listOf(item)
}

fun <T> T.basicToString(): String {  // 扩展函数

    return this.toString()+"!"
}
//---泛型约束---
//单上限约束
fun <T : Comparable<T>> sort(list: List<T>) {  }
//多上限约束
fun <T> copyWhenGreater(list: List<T>, threshold: T): List<String>
        where T : CharSequence,
              T : Comparable<T> {
    return list.filter { it > threshold }.map { it.toString() }
}

//---类型擦除---
fun isArray(a: Any) {
    if (a is Array<*>){
    //  if (a is Array<Int>) {  报错，由于运行时泛型具体类型信息被擦除，所以在运行时无法检测一个实例是否是带有某个类型参数的泛型类型
        println("is array")
    }
}
fun sumArray(a: Array<*>) {
    val intArray = a as? Array<Int> ?: throw IllegalArgumentException("Array的泛型类型必须是Int类型")
    println(intArray.sum())
}

//这样就能保留泛型参数的具体类型了
inline fun <reified T> test(param: Any) {
    if (param is T){
        println("$param ---param type is match!")
    }
}

//---型变---
//协变：内部操作只读
class Producer<out T> {
    val something : T      //只读属性
    constructor(somthing:T){
        this.something=somthing
    }
    fun produce() : T {    //函数返回值
        println("producing......")
        return something
    }
}
//逆变：内部操作只写
class Consumer<in T>{
    fun consume(value:T) { //函数的形参
        println("consuming......$value")
    }
}

//使用处型变：在一个类中既有方法参数使用泛型，又有方法返回值使用泛型，该类则无法使用声明处型变，如Array类
fun <T> copy(from: Array<out T>, to: Array<in T>) {
    for (i in from.indices) {
        to[i] = from[i]
    }
}

fun main(){
    val box1: Box<Int> = Box<Int>(1)
    println(box1.value)
    val box2 = Box(2)
    println(box2.value)
    val box3 = Box("Hello")

    class myBox:IBox<String>{
        override  fun dragBox(t:String){
            println(t)
        }
    }
    myBox().dragBox("Genenric Interface")

    singletonList<Int>(1)
    (2020.basicToString())
    println(
        with("Hello") {
            basicToString()
        }
    )

    //类型擦除
    sumArray(arrayOf(1,2,3,4))
    //类型保留
    test<String>("Hello Kotlin")

    //型变--协变
    var producer1=Producer<Any>(20)
    println(producer1.produce())
    var producer2=Producer<String>("Kotlin")
    println(producer2.produce())
    producer1=producer2       //可以安全地将Producer<父类>赋值给Producer<子类>
    println(producer1.produce())
    //型变--逆变
    var consumer1=Consumer<Any>()
    consumer1.consume(20)
    var consumer2=Consumer<String>()
    consumer2.consume("Kotlin")
    consumer2=consumer1       //可以安全地将Consumer<子类>赋值给Consumer<父类>
    consumer2.consume(20)
    //使用处型变
    var arr1:Array<out Int> = arrayOf(1,2,3,4)      //out可以用Number的子类
    var arr2:Array<in Any> = Array(4){0.0f}    //in可以用Number的超类
    copy(arr1,arr2)
    arr2.forEach { println(it)}

    //星投影，适合那些泛型参数的类型不重要的场景
    // Foo<*>等价于Foo<out Upper>（读值时）或Foo<in Nothing>（写值时）
    val array1: Array<String> = arrayOf("a","b","c")
    val array2: Array<*> = array1
    array2.forEach { println(it)}
    //array2[0]="1"  报错，只可读不可写
}