Kotlin 实战(二):初步认识函数、变量、类 时间: 2018-02-15 02:06 分类: Kotlin,修仙日记 ####函数 Kotlin 是天生支持函数式编程的,所以在 Kotlin 里面,函数是“第一等公民”(first class)。 所谓"第一等公民"(first class),指的是函数与其他数据类型一样,处于平等地位,可以赋值给其他变量,也可以作为参数,传入另一个函数,或者作为别的函数的返回值(摘自[百度百科](https://baike.baidu.com/item/%E5%87%BD%E6%95%B0%E5%BC%8F%E7%BC%96%E7%A8%8B/4035031?fr=aladdin "百度百科"))。 Kotlin 函数简单声明格式如下: ```java fun max(a: Int, b: Int): Int { return if (a > b) a else b } ``` 与`java`的函数也没什么好比较,就是一种规范而已,参数以及函数返回值都写在后面,这在其他语言里也是很常见的写法。 以上可以看到,在 Kotlin 中,`if`是一个`表达式`,不是一个`声明`,两者区别就是`表达式`有值,`声明`只是一个闭合块的顶层元素,就好比上面的函数声明`fun max(a: Int, b: Int): Int`部分。在 Kotlin 中循环意外大多数的控制语句都属于表达式,也就是说可以直接用作给表达式赋值或者作为参数,而在`java`中控制语句全部属于声明。 上面的函数可以进一步简化如下: ```java fun max(a: Int, b: Int): Int = if (a > b) a else b ``` 这也是 Kotlin 特有的写法,只要记住可以这么写就行了,一个函数返回一个表达式,称之拥有一个表达式主体,如果是一对大括号,就说这个函数有一个块主体。 上面的函数还能加以简化: ```java fun max(a: Int, b: Int) = if (a > b) a else b ``` 可以看到,我们省掉了函数返回值类型的声明,这在 Kotlin 中是允许的,编译器会在编译时分析表达式的值类型,然后用作函数的返回值类型,这就是 Kotlin 中的`类型推断`。 但是需要注意的是只有表达式主体的函数才能够省去返回值类型的书写,如果是块主体的函数,则必须明确指出返回值类型声明,并且在快主体内要返回的值的前面加上`return`声明。 ####变量 以下简单声明两个变量: ```java val str = "Hello World!" val age = 24 ``` 与`java`不同,`java`声明变量时需要将变量类型写在前面,而在`Kotlin`中,都是以`val`和`var`关键字开始来声明变量的,类型放在变量名后面,在上面的声明中,和有着表达式主体的函数声明一样,我们可以省去类型的声明,当然,下面的写法也是可以的: ```java val str: String = "Hello World!" val age: Int = 24 ``` 需要注意的是,如果在声明变量的时候没有赋值,那么就必须显式指定变量类型: ```java val age: Int age = 42 ``` 上面说到`Kotlin`用`val`和`var`两个关键字来声明变量,两者的区别如下: * val:不可变的引用,初始化后不能重新分配值,相当于 Java 中的 final 变量 * var:可变的引用,初始化后的值可以再次改变,相当于 Java 中的 非 final 变量 注意,`val`不可变是指其引用地址不可变,但它引用地址所指向的对象可能是可变的,比如: ```java val list = arrayListOf("Kotlin") list.add("C++") ``` #####在字符串模板中使用变量 ```java val name = "Kotlin" println("Hello $name") ``` 和其他脚本语言非常类似,`Kotlin`字符串模板支持用`$`美元符号来使用变量,甚至是一个表达式(和`JSP`中的EL表达式非常类似): ```java val a = 2 val b = 6 println("max value is: ${if (a > b) a else b}") ``` 以上就是变量的简单使用。 ####类 首先,看一个熟悉的`Java`类写法: ```java public class Person { private final String name; public Person (String name) { this.name = name; } public String getName() { return name; } } ``` 在`Kotlin`中我们可以这样写: ```java class Person(val name: String) ``` 对比一下上面的两种写法,在`java`中构造器赋值的代码通常是完全重复的,就是将参数的变量赋值给对应名字的字段,而`Kotlin`使用如上写法就和上面的`java`代码完全是等价的。 在`Kotlin`中,类的`public`修饰器是默认的,因此可以省略掉。 #####属性 类的思想就是封装数据以及将数据转化为单一实体。 在`java`中,通常数据是存储到私有字段中的,如果需要给客户端使用的话就直接提供`getter`和`setter`方法,一般变量提供获取和设置访问器,常量只需提供`getter`获取器。这种字段和字段的访问器常被称为属性。并且,这种代码的生成对程序员来说经常是重复性的。 而在`Kotlin`中,大大简化了我们的代码,它将字段和字段的访问器结合起来了(在 Kotlin 中直接称为属性),即我们只需声明属性即可,访问器会根据声明的关键字`val`和`var`自动生成(不会显示出来,但我们可以直接使用),如下: ```java class Order(val num: String, var isFinished: Boolean) fun main(args: Array) { val o = Order("20180215000001", true) println(o.num + ", " + o.isFinished) } ``` 其实使用方式就和`java`类中的`public`字段的用法差不多,这里可能会有个疑惑:如果`java`字段直接声明为`public`,那么不就没多大区别了吗?这个疑惑我也暂且不知,这样的写法是否破话了类的封装性,在《Kotlin in Action》中并未提及,有知道的大神请帮忙讲解一下。 我测试过如下代码: ```java class Order(private val num: String, var isFinished: Boolean) ``` `num`前加上`private`修饰符,这样一来`o.num`将会报错,所以我猜测`Kotlin`上面的那种写法所声明的字段将全部默认是`public`类型的,那么是否破坏了类的封装性呢?希望学到后面能够找到答案吧。 #####自定义获取器 ```java class Rectangle(var width: Int, var height: Int) { val isSquare: Boolean get() { return width == height } } fun main(args: Array) { val rectangle = Rectangle(1, 1) println(rectangle.isSquare) rectangle.height = 2 println(rectangle.isSquare) } ``` 输出结果: > true > false 如上代码,`isSquare`属性是由自定义获取器计算获得的,虽然用`val`声明,但每次获取还是会重新计算,这里也必须用`val`关键字,用`var`关键字将会报错,书中也并未说明,总之也就一笔带过,自己尝试过在类中使用`val`和`var`声明属性,全部都要初始化设置值,这也是与`java`不同的地方。 到此,`Kotlin`中的类绝非如此简单,由于跟随《Kotlin in Action》一书学习,书中此时还并未深入讲解`Kotlin`的类,但此时心中已经存在着多个疑惑了。 ####小结 以上仅仅对`Kotlin`中的函数、变量、类有了一个初步的了解,心中疑惑甚多,加油学习从日后的学习中寻找答案吧! 标签: 无