• Kotlin基础学习笔记 (三)


    二、Kotlin 基础程序结构
     1、Val和Var
        1.1、val=value,值类型 ,类似Java的final修饰,不可以重复赋值
        ps:类似于java的中的final关键字修饰的 ,所以一般val 修饰的词为Final类型值
    val定义的是常量
     
        val FINAL_HELLO_CHINA = “hello china” //类型推导(Java中需要必须写明final和修饰关键字)
     
            在Java中含有final关键字修饰的变量,变量FINAL_HELLO_WORLD为编译期常量,在用到这个变量的时候,编译器一律把 “对这个变量的引用都会自动换成 它的值类型进行使用”,提高代码运行效率。
    public String FINAL_HELLO_WORLD =“...“;
     
    ex:
    ~运行时常量;val x =getX()
    ~编译期常量: const val x:值类型=值
        
       1.2、 var = variable 临时变量                                                                                                                                                                                                                                                                  
    ex: 
        var x = “HelloWorld “ //定义变量
            x = “ hiWolrd “  //再次赋值
     
    类型推导
        val String = “hello” //推导出String类型
        val int = 5 //Int类型
        var x = getString() + 5 //String 类型
     
     2、函数 Function
        什么是函数?
     以特定功能组织起来的代码块
        fun[函数名](参数列表):[返回值类型] { 函数体}
        fun[函数名](参数列表) =  表达式
    ex:
        fun sayFuck( name: String ) : String{  println(“fuck,$name”)  }
        fun sayFuck( name: String ) = println(“fuck,$name")
     
    什么是匿名函数?
    fun(参数列表),必须赋值给一个变量否则无法识别,如上例2
     
    值类型返回值要加参数类型 ,默认返回类型是Unit
    fun main(args: Array<String>) {
        val arg1 = args[0].toInt()
        val arg2 = args[1].toInt()
        println("$arg1+$arg2= ${sum(arg1, arg2)}")
    }
     
    fun sum(arg1: Int, arg2: Int): Int {
        return arg1 + arg2
    }
    kotlin简便写法:
       fun sum(arg1: Int, arg2: Int) = arg1 + arg2
     
    思考:方法一定有名字嘛?
        答:用一个变量接收一个方法就不需要有名字了:
                也就是一个变量的值是一个函数的返回值
            val int2 = fun(x:Int ) : Long {
                return x.toLong()
            }
    注意事项
    • 方法要功能单一
    • 函数名顾名思义
    • 参数列表不要太复杂
     
    3、类
     
    ex:
    public class JavaA {
        private int b = 0;
        public int getB() {
            System.out.println("some one tyies to get b");
            return b;
        }
        public void setB(int b) {
            System.out.println("some one tyies to set b");
            this.b = b;
        }
    }
     
    class A {
    在kotlin方法中get()、set()是默认实现的版本,想要实现必须得复写get or set方法
        var b = 0;
            get() {
                println("...")
                return field   //field 这里指代b后面真正的值,只在get/set访问器中才能访问到
            }
            set(value){
             field = value ; //相当于java中的this .b=b;
            }
    }
     
    lateinit 延时初始化 and by lazy 懒加载
    lateinit var c:String  
    延时初始化,在需要的时候进行初始化,禁止初始化之前使用
     
    lateinit val e:x  is false 
    var 可以使用 lateinit 进行延时初始化,也只能使用在var上 ,
     
       但val的延时初始化需要用下面的操作:
     val e : X by lazy {
                    … //适合于val的懒加载模式
                }
     
    当var xx:String ?= null   //初始化为null并且可空类型
    在使用的时候不可使用,因为没有向编译器保证该值不能为null
    解决办法:
     println(cc ?. length)  or  println(cc !!. length)
     
    类成员
    属性:或者说成员变量,类范围内的变量
    方法:或者说成员函数,类范围内的函数
     
    构造方法 参数中 val / var 修饰的都是属性,没有就只是构造方法的参数
     
    1、val 没有set()方法因为是不可变的final的
    2、 属性的初始化尽量在构造方法中完成。
    3、无法在构造方法中完成初始化,尝试降级为局部变量
    4、var用lateinit延迟初始化,val用lazy
    5、可空类型谨慎用null直接初始化 (!!or?)
     
    4、修饰符
     kotlin 语言的修饰符 存放在kotlin源码工程的kotlin/grammar/src/modifiers.grm 文件中,完整定义在kotlin/compiler/frontend/src/org/jetbrains/kotlin/lexer/KtToken.java源码中
    /**
    ## Modifiers
    */
     
    modifiers
      : (modifier| annotations)*
      
    typeModifiers
      : (suspendModifier| annotations)*
     
    modifier
      : classModifier
      : accessModifier
      : varianceAnnotation
      : memberModifier
      : parameterModifier
      : typeParameterModifier
      : functionModifier
      : propertyModifier
     
    classModifier 类修饰符
      : "abstract" 抽象类
      : "final" 不可被继承final类
      : "enum" 枚举类
      : "open" 可继承open类
      : "annotation" 注解类
      : "sealed" 密封类
      : "data" 数据类
      
    memberModifier
      : "override" 重写函数
      : "open" 可被重写
      : "final" 不可被重写
      : "abstract" 抽象函数
      : "lateinit" 后期初始化
      
    accessModifier 访问权限控制, 默认是public
      : "private"
      : "protected"
      : "public"
      : "internal"  整个模块内(模块(module)是指一起编译的一组 Kotlin 源代码文件: 例如,一个 IntelliJ IDEA 模块,一个 Maven 工程, 或 Gradle 工程,通过 Ant 任务的一次调用编译的一组文件等)可访问;
     
    varianceAnnotation 泛型可变性
      : "in" 
      : "out"
     
    parameterModifier
      : "noinline" 
      : "crossinline" 
      : "vararg" 变长参数
     
    typeParameterModifier
      : "reified"
      
    functionModifier
      : "tailrec" 尾递归
      : "operator"
      : "infix"
      : "inline"
      : "external"
      : suspendModifier
     
    propertyModifier
      : "const" 
     
    suspendModifier
      : "suspend"
     
    5、关键字 keywords
        一些常见的关键字:
        KtKeywordToken PACKAGE_KEYWORD          = KtKeywordToken.keyword("package");
        KtKeywordToken AS_KEYWORD               = KtKeywordToken.keyword("as");
        KtKeywordToken TYPE_ALIAS_KEYWORD       = KtKeywordToken.keyword("typealias");
        KtKeywordToken CLASS_KEYWORD            = KtKeywordToken.keyword("class");
        KtKeywordToken THIS_KEYWORD             = KtKeywordToken.keyword("this");
        KtKeywordToken SUPER_KEYWORD            = KtKeywordToken.keyword("super");
        KtKeywordToken VAL_KEYWORD              = KtKeywordToken.keyword("val");
        KtKeywordToken VAR_KEYWORD              = KtKeywordToken.keyword("var");
        KtKeywordToken FUN_KEYWORD              = KtKeywordToken.keyword("fun");
        KtKeywordToken FOR_KEYWORD              = KtKeywordToken.keyword("for");
        KtKeywordToken NULL_KEYWORD             = KtKeywordToken.keyword("null");
        KtKeywordToken TRUE_KEYWORD             = KtKeywordToken.keyword("true");
        KtKeywordToken FALSE_KEYWORD            = KtKeywordToken.keyword("false");
        KtKeywordToken IS_KEYWORD               = KtKeywordToken.keyword("is");
        KtModifierKeywordToken IN_KEYWORD       = KtModifierKeywordToken.keywordModifier("in");
        KtKeywordToken THROW_KEYWORD            = KtKeywordToken.keyword("throw");
        KtKeywordToken RETURN_KEYWORD           = KtKeywordToken.keyword("return");
        KtKeywordToken BREAK_KEYWORD            = KtKeywordToken.keyword("break");
        KtKeywordToken CONTINUE_KEYWORD         = KtKeywordToken.keyword("continue");
        KtKeywordToken OBJECT_KEYWORD           = KtKeywordToken.keyword("object");
        KtKeywordToken IF_KEYWORD               = KtKeywordToken.keyword("if");
        KtKeywordToken TRY_KEYWORD              = KtKeywordToken.keyword("try");
        KtKeywordToken ELSE_KEYWORD             = KtKeywordToken.keyword("else");
        KtKeywordToken WHILE_KEYWORD            = KtKeywordToken.keyword("while");
        KtKeywordToken DO_KEYWORD               = KtKeywordToken.keyword("do");
        KtKeywordToken WHEN_KEYWORD             = KtKeywordToken.keyword("when");
        KtKeywordToken INTERFACE_KEYWORD        = KtKeywordToken.keyword("interface");
     
        // Reserved for future use:
        KtKeywordToken TYPEOF_KEYWORD           = KtKeywordToken.keyword("typeof");
            ...
        KtKeywordToken FILE_KEYWORD    = KtKeywordToken.softKeyword("file");
        KtKeywordToken FIELD_KEYWORD     = KtKeywordToken.softKeyword("field");
        KtKeywordToken PROPERTY_KEYWORD     = KtKeywordToken.softKeyword("property");
        KtKeywordToken RECEIVER_KEYWORD     = KtKeywordToken.softKeyword("receiver");
        KtKeywordToken PARAM_KEYWORD     = KtKeywordToken.softKeyword("param");
        KtKeywordToken SETPARAM_KEYWORD  = KtKeywordToken.softKeyword("setparam");
        KtKeywordToken DELEGATE_KEYWORD  = KtKeywordToken.softKeyword("delegate");
        KtKeywordToken IMPORT_KEYWORD    = KtKeywordToken.softKeyword("import");
        KtKeywordToken WHERE_KEYWORD     = KtKeywordToken.softKeyword("where");
        KtKeywordToken BY_KEYWORD        = KtKeywordToken.softKeyword("by");
        KtKeywordToken GET_KEYWORD       = KtKeywordToken.softKeyword("get");
        KtKeywordToken SET_KEYWORD       = KtKeywordToken.softKeyword("set");
        KtKeywordToken CONSTRUCTOR_KEYWORD = KtKeywordToken.softKeyword("constructor");
        KtKeywordToken INIT_KEYWORD        = KtKeywordToken.softKeyword("init");
     
        KtModifierKeywordToken ABSTRACT_KEYWORD  = KtModifierKeywordToken.softKeywordModifier("abstract");
        KtModifierKeywordToken ENUM_KEYWORD      = KtModifierKeywordToken.softKeywordModifier("enum");
        KtModifierKeywordToken OPEN_KEYWORD      = KtModifierKeywordToken.softKeywordModifier("open");
        KtModifierKeywordToken INNER_KEYWORD     = KtModifierKeywordToken.softKeywordModifier("inner");
        KtModifierKeywordToken OVERRIDE_KEYWORD  = KtModifierKeywordToken.softKeywordModifier("override");
        KtModifierKeywordToken PRIVATE_KEYWORD   = KtModifierKeywordToken.softKeywordModifier("private");
        KtModifierKeywordToken PUBLIC_KEYWORD    = KtModifierKeywordToken.softKeywordModifier("public");
        KtModifierKeywordToken INTERNAL_KEYWORD  = KtModifierKeywordToken.softKeywordModifier("internal");
        KtModifierKeywordToken PROTECTED_KEYWORD = KtModifierKeywordToken.softKeywordModifier("protected");
        KtKeywordToken CATCH_KEYWORD     = KtKeywordToken.softKeyword("catch");
        KtModifierKeywordToken OUT_KEYWORD       = KtModifierKeywordToken.softKeywordModifier("out");
        KtModifierKeywordToken VARARG_KEYWORD    = KtModifierKeywordToken.softKeywordModifier("vararg");
        KtModifierKeywordToken REIFIED_KEYWORD   = KtModifierKeywordToken.softKeywordModifier("reified");
        KtKeywordToken DYNAMIC_KEYWORD   = KtKeywordToken.softKeyword("dynamic");
        KtModifierKeywordToken COMPANION_KEYWORD = KtModifierKeywordToken.softKeywordModifier("companion");
        KtModifierKeywordToken SEALED_KEYWORD    = KtModifierKeywordToken.softKeywordModifier("sealed");
        KtModifierKeywordToken DEFAULT_VISIBILITY_KEYWORD = PUBLIC_KEYWORD;
        KtKeywordToken FINALLY_KEYWORD   = KtKeywordToken.softKeyword("finally");
        KtModifierKeywordToken FINAL_KEYWORD     = KtModifierKeywordToken.softKeywordModifier("final");
        KtModifierKeywordToken LATEINIT_KEYWORD = KtModifierKeywordToken.softKeywordModifier("lateinit");
        KtModifierKeywordToken DATA_KEYWORD    = KtModifierKeywordToken.softKeywordModifier("data");
        KtModifierKeywordToken INLINE_KEYWORD    = KtModifierKeywordToken.softKeywordModifier("inline");
        KtModifierKeywordToken NOINLINE_KEYWORD    = KtModifierKeywordToken.softKeywordModifier("noinline");
        KtModifierKeywordToken TAILREC_KEYWORD    = KtModifierKeywordToken.softKeywordModifier("tailrec");
        KtModifierKeywordToken EXTERNAL_KEYWORD    = KtModifierKeywordToken.softKeywordModifier("external");
        KtModifierKeywordToken ANNOTATION_KEYWORD    = KtModifierKeywordToken.softKeywordModifier("annotation");
        KtModifierKeywordToken CROSSINLINE_KEYWORD    = KtModifierKeywordToken.softKeywordModifier("crossinline");
        KtModifierKeywordToken OPERATOR_KEYWORD = KtModifierKeywordToken.softKeywordModifier("operator");
        KtModifierKeywordToken INFIX_KEYWORD = KtModifierKeywordToken.softKeywordModifier("infix");
     
        KtModifierKeywordToken CONST_KEYWORD = KtModifierKeywordToken.softKeywordModifier("const");
        KtModifierKeywordToken SUSPEND_KEYWORD = KtModifierKeywordToken.softKeywordModifier("suspend");
        KtModifierKeywordToken HEADER_KEYWORD = KtModifierKeywordToken.softKeywordModifier("header");
        KtModifierKeywordToken IMPL_KEYWORD = KtModifierKeywordToken.softKeywordModifier("impl");
     
    this 关键字
    • 持有当前对象的引用,使用this来引用变量或是成员函数,亦可以使用return this,来返回某个类的引用
    • 在类的成员中,this指向的是该类的当前对象
    • 在扩展函数或者带接收者的函数字面值中,this表示在点左侧传递的 接收者参数
    • 如果this没有限定符,它指的是最内层的包含它的作用域;如果引用其他作用域中的this,可以使用this@label标签
     
    小示例:
    class Outer {
        val oh = "Oh!"
        inner class Inner {
            fun m() {
                val outer = this@Outer
                val inner = this@Inner
                val pthis = this
                println("outer=" + outer)
                println("inner=" + inner)
                println("pthis=" + pthis)
                println(this@Outer.oh)
                val fun1 = hello@ fun String.() {
                    val d1 = this // fun1 的接收者
                    println("d1" + d1)
                }
                val fun2 = { s: String ->
                    val d2 = this
                    println("d2=" + d2)
                }
                "abc".fun1()
                fun2
            }
        }
    }
     
    6、基本运算(操作)符
    • 运算符方法重载的定义,任何类可以定义或是重载基本运算符
    • 通过运算符对应的具名函数来定义,要求方法名字必须一致对的上,fun前面加上operator 关键字
    • 参数的个数对的上,类型和返回类型不作要求
    • 不能像Scala一样定义任意运算符
     
    6.1、操作符优先级
        级别由上到下 ,由高到低
            后缀 Postfix   :    “++”  , " - - “ ,”  .”  ,” ?.” ,” ?"
            前缀 Prefix    : "- "  ,"+ ", "++ ", " - - " , “!” ,”labelDefinition@"
            右手类型运算  RHS:” :" , " as " , "as?"
            乘除取余  Multiplicative :  "* “  , “ / “ , “%"
            加减     Additive :  “+” , “-"
            区间范围  Range   :  " ..”
            Infix 函数   :   给Int 定义扩展 infix fun Int .shl( x:Int ) :Int {…} —>调用 1 shl 2 ,等同于1.shl(2)
            Elvis 操作符 :“ ?:”
            命名检查符号 Named checks: “in" , "!in”, “is”, “!is"
            比较大小 Compariosn : “<“ , “>” ,”<=“ , “>="
            相等性判断 Equality  :  “==“  , “!=="
            与     Conjunction  :   “&&"
            或      DIsjunction  :    “||"
        最低 赋值 Assignment : “ = “ , “+= “ ,” -= “ , “*=“, ”/=“ , “%="       
     
    6.2 、递增 or 递减  
       inc ()  / dec () 函数必须返回一个值,用于赋值给使用 ++  or  — 操作的变量
        a ++  :  a.inc() 返回值 a
        a - - : a.dec () 返回值 a
        ++ a : a.inc() 返回值 a+1
        —a : a.dec() 返回值是 a-1   
     
    解析:
        编译器执行以下步骤来解析后缀表达式的操作符,例如:后缀形式a++ 
            1、确定a的类型 ,令其解析为T
            2、查找一个适用于类型为T的接收者的、带有operator修饰符的无参数函数inc()
            3、检查函数的返回类型是T的子类型
     
        表达式计算步骤:
            1、把a的初始值存储到临时存储a _ 中
            2、把a.inc ( ) 结果赋值给 a
            3、把a_ 作为表达式的结果返回
        对于前缀形式:
            ++a 和 —a解析步骤类似,返回值不同是取的新值来返回
                把 a.inc ()  结果赋值给a
                把 a的新值 a+1 作为表达式结果返回
     
    6.3 、算术运算符
        a + b   : a.plus ( b )
        a - b    : a.minus ( b )
        a * b    : a.times ( b )
        a / b    : a.div ( b )
        a & b   : a.rem ( b ) a.mod ( b )
        a .. b    : a .rangTo ( b )
     
    6.4 、in 操作符
        a in b   : b.contains ( a )
        a !in b  : !b.contains ( a )
     
    6.5 、计算并赋值
        a += b  : a .plusAssign ( b )
        a  -= b : a .minusAssign ( b )
        a *=  b : a .timesAssign ( b )
        a /=  b : a .divAssign ( b )
        a %= b : a.modAssign ( b )
    编译器操作 a += b : 生成a = a+b 的代码,a+b 的类型必须是a的子类
     
    6.6、相等 与 不等操作符
    •  引用相等 "===" , " !==“  ————》两个引用指向同一对象————〉不能重载!!!
    •  结构相等 “ == “ , “ != “  ————> 使用 equals() 判断
    a == b   :    a ?.equals ( b ) ?: ( b === null )
    a != b   :   ! (  a ?.equals ( b ) ?: ( b === null ) )
    在这里 == 操作符 特殊性:被翻译成一个复杂的表达式,用于筛选 null 值;
    也就是说如果 a不是null,则调用 equals ( Any )函数并返回其值 ,否则 ( a === null ) 就计算 ( b === null )的值并返回
    当与 null 显示 比较时候, a == null 会被自动转换为 a === null 
     
    6.7 、 Elvis 操作符 ?:
        在kotlin 中, Elvis 操作符 特定是跟null 比较 ,也就是说用来做null安全检查
     
            y = x ?: 0 ——>二元
    等价于==》
            val y = if ( x !== null ) x else 0  )——>kotlin 三元运算符
     
    ?:  这是一个二元运算符 ,如果第一个操作数为真,则返回第一个操作数,否则将计算并返回其第二个操作数
     
    注意:
        用( ?: ) 可以把带有默认值的if/else 结构写的精简,不用检查null,也不用重复变量
     
    6.8 、中缀操作符
        通过自定义infix函数来实现中缀操作符
    示例:       
     
     data class  Person ( val name :String .val age :Int )
            infix fun Person.grow ( years:Int ) :Person{
                    return Person ( name ,age +years )
        }
        test:
    @RunWith(Junit4::Class )
        class InfixFunctionTest {
        @Test
        fun testInfixFuntion ( ){
            val person =  Person (“son” ,25)
            println ( person .grow (2 ) )
            println ( person  grow 2 )
    }
    结果:
            name = son, /n age = 27
     
    小示例
     加法:
    class Complex(var real: Double, var imaginary: Double) {
     
        //定义一个加法函数
        operator fun plus(other: Complex): Complex {
            return Complex(real +other.real, imaginary + other.imaginary)
        }
     
        operator fun plus(other: Int): Complex {
            return Complex(real + other, imaginary)
        }
        override fun toString(): String {
            return "$real+${imaginary} i"//实部+虚部
        }
       //取模方法
    operator fun invoke() :Double{
        return Math.hypot(real, imaginary)
    }
     
    class Book {
        //中缀表达式 infix
        infix fun on(any: Any): Boolean {
            return false
        }
    }
     
        fun main(args: Array<String>) {
            val c1 = Complex(3.0, 4.0)  //3+4i
            val c2 = Complex(2.0, 7.5)  //2+7.5i
            println(c1 + c2)  //5+11.5i—>toString() 需要用到
            println(c1 + 4)
          println(c1)    //(3的平方+4的平方) 再开方
     
    //-name <Name>  //args contains name,如果包含的话就取后面的Name
    if ("-name" in args) {    //in表示Array<out T>.contains(element: T): Boolean,
        
    // 实际上返回的是indexOf >=0,如果indexOf有这个元素,返回的就是它的位置如果没有返回 -1
       
    println(args[args.indexOf("-name") + 1])//返回-name在args里面的后面一个位置的值
    }
    if(Book() on Desk()) { … }//DSL里常见 中缀表达式替换.()方法
        }
    }
     
     7、Lambda表达式 *****
    本质:匿名函数(可以赋值和传递)
    lambda表达式返回值 :表达式最后一行表达式的值
    Lambda表达式(匿名函数) 
    写法:{ [参数列表]->[函数体,最后一行时返回值] }
     
    ex: 
        普通函数表达式:fun sum( arg1:Int, arg2:Int ) = arg1 + arg2
        lambda 表达式  :  val sum ={ arg1:Int ,arg2 :Int -> arg1+arg2 }
           参数列表:arg1:Int ,arg2 :Int 
            函数体,返回值最后一行:arg1+arg2
        -> xxx :lambda表达式返回值是表达式最后一行的值
     
    val/var  xxx = {函数体} ps:arg1:Int,arg2:Int ->arg1+arg2 
    arg1:Int 表示参数返回类型
    arg1+arg2:函数返回值
    ->:用右箭头链接 
    lambda表达式可以作为参数传递!
     
    print(sum(1, 2))===  print(sum.invoke(1,3))是一个意思!—【invoke :运算符重载】
     
    在kotlin中数组的遍历两种写法:
        for( i  in  args) { … }     or for ( i in array.indices) {...}                //在Program arguments里: 添加参数中间用空格隔开
       args.forEach(  {…lambda...}  )
     
    注意:函数如果最后一个参数是lambda表达式,可以将括号内的内容移动到括号外面,若括号内无内容可直接删除。
    forEach: Array的扩展方法 ,返回值是Unit类型,使用action调用传递的Array里面的元素作为参数
    Array<out T> .forEach (action : (T) -> Unit ) :Unit {for (element in this ) action (element) }
    action : (T):参数的类型
    ->Unit :lambda 表达式返回的类型
    (action : (T) -> Unit )==lambda
     
    args.forEach( {println(it)} )  === args.forEach(){ println(it) }====>  
    注意:若参数的最后一个是lambda表达式,可以将( ) 移动到lambda表达式外面 
     
    args.forEach(::println) //[若传入的函数和lambda表达式类型完全一样]
        将println函数作为参数传递 ,println的参数是Any,接收任何对象都可以
     
    args.forEachForEach@{
     if(i=x)    return@ForEach
        println(it)
    }
    println(...)
    终断lambda表达式的迭代。以上做法可以跳出lambda表达式内的执行继续执行lambda表达式下面的内容
     
    @ForEach:接收Array<T>类型 
     
    Lambda表达式的类型举例
        main(args:Array<String>) 函数 
    ——    传入参数 Array<String> -> Unit
        println(…)
    ——传入(Any?可空的any)-> 返回Unit
    ()->Unit
    ——无参,返回值Unit
     
    (Int)->Int
    ——传入整型,返回一个整型
     
    (String,(String) ->String)->Boolean
    ——传入字符串,lambda表达式,返回一个boolean
     
    println(::printUsage is () -> Unit) :参数为0的Function0 ()————具名函数printUsage()
    invoke多少参数就是Function几,最多可以Function0-22
     
    lambda表达式的调用
    •     用()进行调用
    •     等价于invoke()
        ex : val sum = {a:Int ,b:int -> a+b}
        // in P1,in P2 out R ,传入两个int返回一个int ,Function0-22均调用invoke(参数列表)
                sum(2,3)  ——————> sum.invoke(2,3)
            
    lambda表达式的简化特点
     
    • 函数参数调用时最后一个lambda表达式可以移出去
    • 函数参数只有一个lambda,调用时小括号可以省略
    • lambda只有一个参数可默认为it
    • 入参、返回值与形参一致的函数可以用函数引用的方式作为实参传入(forEach里面传入一个printnln [::println])
     
    8、表达式 -中缀表达式、分支表达式、when表达式
        8.1、中缀表达式
    只有一个参数,且用infix修饰的函数
        ex: 
            class Book { 
                infix fun on ( place :String){
                    …}
            }
            Book() on “My desk”()
     
       8.2、 分支表达式
     
    传统的分支使用方法:
        var max = a
            if ( a < b )
                max = b 
        搭配else 的使用:
        var max : Int
            if ( a > b )
                max = a
            else
                max = b 
     
    kotlin 中的分支表达式: 
        8.2.1 、if表达式 :
        if…else :
    •    表达式与完备性
    •   if(boolean)
        var x = if (b <0) 0 else b 
       var x = if (b <0) 0//错误 ,赋值时,分支必须完备
     
     if max = if ( a >b ) {
            a
        }
        else {
            b
        }
     
    val mode = if (args.isNotEmpty() && args[0] == "1") {
        //if表达式有返回值所以可以做为代码块,每个分支里面的最后一句话是其段的返回值
        DEBUG
    } else {
        USER
    }
     
    注意:
        1、在kotlin中没有没有 java中的这一种写法: true ? 1:0 三元表达式或是说正则,对应的kotlin写法是:
        if( boolean ) 1 else 0
        2、如果if 表达式 只有一个分支, 或者分支结果返回Unit ,其值也是Unit
        3、else 和 else if 同时出现,else要再else if 之后
        4、如果有多条else if 语句同时出现,那么如果有一条else if 语句表达式测试成功,那么就会忽略掉其他所有else if 和else分支
        5、如果出现多个if ,只有一个else情形,那么else子句归属于最内层的if语句
     
     
    8.2.2 、when表达式
    •  when表达式 :
            加强版 switch,支持任意类型,不用写break
            支持纯表达式条件分支 类型if
            表达式与完备性
     
    when 既可以被当作表达式使用也可以被当作语句使用;当被当作表达式,符合条件的分支的值就是整个表达式的值,如果当作语句使用,则忽略单个分支的值
     
    fun pause() {
        when (state) {
            Player.State.BUFFERING -> {}
            Player.State.PAUSED -> {}
            Player.State.PLAYING -> {}
        }
    }
    fun main(args: Array<String>) {
        val x = 5
        when (x) {
            is Int -> println("Hello $x")
            in 1..100 -> println("$x is in 1..100")
            !in 1..100 -> println("$x is not in 1..100")
            args[0].toInt() -> println("x == args[0)
     
        }
    }
    注意: 
        1、else 在when 分支里相当于default 其他分支都不满足条会到else分支里
        2、分支处理方式相同,用逗号分隔
        3、分支条件可以是常量也可以是表达式
     
    8.3、循环表达式
      8.3.1 、for循环实例: for(element in elements 任何提供迭代器的集合) for{ :. keyword }
     
    遍历一个简单的数组 or list :
        for ( i in array.indices )
            println ( array [i] )
    等同于 下面的 i in args 
    A:
    for (arg in args) {  //for ( i in array.indices) {...}   
        println(arg)
    }
     
    B:库函数 withIndex
    for ((index, value) in args.withIndex()) {
        println("$index->$value")
        //0 -> a 1-> b 2-> c 3-> d
    }
    C:结果和B一模一样
    for (indexedValue in args.withIndex()) {
        println("${indexedValue.index}->${indexedValue.value}”)
      //0 -> a 1-> b 2-> c 3-> d
    }
     
    解析:返回一个IndexValue 类型
    public fun <T> Array<out T>.withIndex(): Iterable<IndexedValue<T>> {
        return IndexingIterable { iterator() }
    }
    public data class IndexedValue<out T>(public val index: Int, public val value: T)
     
    8.3.2、 while循环实例:while(…) / do {...} while(…)...
    var x = 5
    //1、首先判断条件,接着执行循环体
    while (x > 0) { 
        println(x)
        x--
    }
     
    //2、先执行一次循环体,再判断条件是否继续执行
    do { 
        println()
        x--
    } while (x > 0)
     
    8.3.3、 continue、break 跳出循环实例
    continue:跳过当前循环 ,直接进入循环体的下次循环;
    break:终止最近的封闭循环 用break
     
    class Student {
        fun isNotClothedProperly(): Boolean {
            return false
        }
        fun main(args: Array<String>) {
            val you = Student()
            val students = ArrayList<Student>()
            for (students in students) {
                if (students == you)  continue //当条件满足时候 ,跳过循环
                if (students.isNotClothedProperly()) {
                    break//当条件满足时候,跳出循环
                }
            }
        }
    }
    8.3.4、 return 返回
        在java,c语言中,return语句使用我们在常见不过了。虽然在Scala、groovy语言中,函数的返回值可以不需要在显示的用return 来制定,但是我们仍然认为,使用return 的编码风格更加容易阅读
        在kotlin中,除了表达式的值,有返回值的函数都要求显示使用return 来返回其值
     
    小示例:
        fun sum(a: Int ,b :Int ) :Int {
            return a + b
        }
     
    fun max ( a:Int , b:Int ) :Int {
        if ( a >b ) returna else returnb
    }
     
     
    or 在kotlin 中可以直接使用 = 符号 直接返回一个函数体的值
     fun sum ( a:Int , b :Int ) = a +b
     fun max ( a:Int , b:Int )   =  if ( a >b ) returna else b
     
     
        注意:
    •  在koltin中 return 语句会从最近的函数 或 匿名函数中 返回,但是在Lambda表达式中遇到return ,则直接返回最近的外层函数
    •  在非全局的返回只支持内部方法,如果我们只是需要跳出内部方法,就必须标记它并且返回这个标签
     
     
    ex1:
    fun return_1( ){
        val Array1 = intArrayOf( 1,2,3,4,5)
            Array1.forEach {
                if( it ==3 ) return
                    println(it)
            }
    }
    结果:在遇到3的时候会直接返回  println结果: 1 2
     
    用一个方法表达式替代内部匿名方法,在方法内部声明一个return{ :. keyword} 将从其内部返回
    ex2:
    fun return2( ){
        val intArray = intArrayOf (1,2,3,4,5)
        intArray.forEach (
           fun (a:Int ) {
                if (a == 3) return
                    println(a)
            })
    }
    结果:在运行时候遇到3会跳过它继续执行,输出结果:1 2 4 5
     
    需要在返回的时候带有一个值:
    ex3:
        return @ a1
    结果:在标签@a 上返回1,而不是“返回一个带标签的表达式(@a 1)”
     
    8.4、 标签 label
    在kotlin中 任何表达式都可以用标签来标记。标签的格式为标识符后跟 @ 符号;作用是用标签来控制 return/break/continue的跳转行为
     
         在lambda表达式开头处添加标签here@ ,可以理解为 该标签相当于记录了Lambda入口地址,然后在表达式内部使用了return@here来跳转至lambda表达式该地址处
        接收该Lambda表达式的函数是forEach ,所以可以直接使用return@ForEach,来跳转到此处执行下一轮循环;如果使用break在循环体中,是跳出最外层的循环
      
    多层循环嵌套的终止结合标签使用:
            Outter@for (…) {
                Inner@while ( i < 0) {
                    if( …) 
                   // break  :若没有@Outter 这里是把while循环给break掉,继续执行for循环
                   break@Outter  // 将for循环也给break 掉
                }
            }
     
    8.5、 throw 
    throw 用来标记无返回的函数,它的类型是特殊类型Nothing。该类没有值。和void 类似
    fun fail (msg :String) :Noting {
        throw IllegalArgumentException(msg)
    }
        throw 表达式赋值给一个变量,需要显示声明类型:Nothing
    val ex:Nothing = throw Exception(“xxxxxx")
    注意:该ex变量是Noting类型,没有任何值,无法当作参数传递给函数
     
    8.6、课后小栗子:
    自定义一个迭代器,实现数组的添加or 删除功能
     
    fun main(args: Array<String>) {
        val list=MyIntList()
        list.add(1)
        list.add(2)
        list.add(3)
    }
    class MyIterator(val iterator: Iterator<Int>) {
        operator fun next(): Int {
            return iterator.next()
        }
        operator fun hasNext(): Boolean {
            return iterator.hasNext()
        }
    }
    class MyIntList {
        private val list = ArrayList<Int>()
        fun add(int: Int) {
            list.add(int)
        }
        fun remove(int: Int) {
            list.remove(int)
        }
        //定义operator 运算符
        operator fun iterator(): MyIterator {
            return MyIterator(list.iterator())
        }
    }
     
     
    8、异常捕获
    try{…}catch(e:xxxx){...}finally{…} 表达式,可以用来赋值
     
    val result = try{ … }catch(e:xxx){ … }
     
    注意:
        先执行finally 代码在返回 return 
    return try { x/y 
            }catch (e: Exception ){
                0
            }finally{
                …
        }
     
    9、具名参数、变长参数、默认参数
     具名参数:指定实参的方式 ,在使用的时候需要赋值在括号里(...)
            fun sum( arg1: Int ,arg2: Int ) =arg1+arg2
            sum ( arg1 = 2 ,arg2 =3) //参数位置可以互换
     
    变长参数:某个参数可以接受多个值;可以不为最后一个参数;参数时候有歧义需要使用具名参数
     
            args:Array<String> —> varargargs:String 两者完全一样
       hello(1, 2, 3, 4, 5, string = "hello”)
    //将hello赋值给string,在这里使用具名参数,将1-5赋值给ints,后面复制给string
     
    ex:
    fun hello(vararg ints: Int, string: String) {
        ints.forEach(::println)
        println(string)
    }
    Spread Operator——变长参数场景
    特点:
    •  *array :表示把array展开(只支持array数组),变成一个个元素传入使用
    • 该类仅支持变长参数的实参
    • 不能重载
    • 只能使用array数组 ,不能使用list 等其他集合    
     
    val array = intArrayOf (1 ,2 ,3,4)
       hello( 3.0, *array ,string = “hello”) 
     
    默认参数:可以指定给参数列表的任意一个参数,如果把默认参数指定给一个比较靠前位置的参数,其后面的参数需要使用具名参数的形式表示
     
     
     
    一个简单的命令行计算器:
    /**
    * 一个极简的命令行计数器
    * */
    fun main(args: Array<String>) {
        while (true) {
            try {
                println("请输入算式数据,比如:1+1")
                val input = readLine() ?: break
                val splits = input.trim().split(" “) //空格分隔符,并去掉string首尾空字符
                if (splits.size < 3) {
                    throw IllegalArgumentException("参数个数异常")
                }
                val arg1 = splits[0].toDouble()
                val op = splits[1] //运算符
                val arg2 = splits[2].toDouble()
                println(
            "$arg1 $op $arg2=${
                Operator(op).invoke(arg1, arg2)
            }”
         ) //将op运算符赋值给等式
            } catch (e: NumberFormatException) {
                println("类型格式异常:" + e)
            } catch (e: IllegalArgumentException) {
                println("输入是否为三个参数的一般计算:" + e)
            }
            println("是否再来一次[Y]")
            val cmd = readLine()
            if (cmd == null || cmd.toLowerCase() == "y") {
                println("输入有误请查看")
                break
            }
        }
    }
    //定义一个运算类
    class Operator(op: String) {
        val opFun: (left: Double, right: Double) -> Double
       //初始化opFun
        init {
            opFun = when(op) {
                "+" -> { l, r -> l + r }
                "-" -> { l, r -> l - r }
                "*" -> { l, r -> l * r }
                "/" -> { l, r -> l / r }
                "%" -> { l, r -> l % r }
                else -> {//when表达式的完备性
                    throw UnsupportedOperationException(op)
                }
            }
        }
        fun invoke(left: Double, right: Double): Double {
            return opFun(left, right)
        }
    }
     
     
    Kotlin导出执行程序
    在根目录 ,build.gradle中添加依赖:
        apply plugin: ‘application'
        mainClassName = “包名.类名kt”
     
    CMD: cd build/instal/下包名
        授予权限:chmod 755 bin/下包名
        bin/下包名
  • 相关阅读:
    hdu4675 GCD of Sequence 莫比乌斯+组合数学
    hdu4746 Mophues 莫比乌斯
    BZOJ2820 YY的GCD 莫比乌斯+系数前缀和
    bzoj2005 能量采集 莫比乌斯或者普通容斥
    GCD 莫比乌斯反演 给定整数N,求1<=x,y<=N且Gcd(x,y)为素数的 数对(x,y)有多少对.
    spoj7001 Visible Lattice Points 莫比乌斯反演+三维空间互质对数
    hdu1695 GCD 莫比乌斯反演做法+枚举除法的取值 (5,7),(7,5)看做同一对
    bzoj2440 完全平方数 莫比乌斯值+容斥+二分
    Problem b 莫比乌斯反演+枚举除法的取值
    Codeforces839D Winter is here 容斥
  • 原文地址:https://www.cnblogs.com/cold-ice/p/9675497.html
Copyright © 2020-2023  润新知