《Kotlin项目实战开发》第3章+类型系统与可空类型

所需积分/C币:8 2017-09-30 16:28:16 701KB PDF

《Kotlin项目实战开发》 第3章 类型系统与可空类型 跟Java、C和C ++ 一样, Kotlin也是“静态类型编程语言”。 通常,编程语言中的类型系统中定义了  如何将数值和表达式归为不同的类型  如何操作这些类型  这些类型之间如何互相作用 我们在编程语言中使用类型的目的是为了让编译器能够确定类型所关联的对象需要分配多少空间。 在每一个编程语言中,都有一个特定的类型系统。静态类型在编译时期时,就能可靠地发现类型错误。因此通常能增进最终程序的可靠性。 类型系统在各种语言之间有非常大的不同,主要的差异存在于编译时期的语法,以及运行时期的操作实现方式。 本章我们简单介绍一下Kotli
313 Kotlin的类型系统 Jaⅵa是一个近乎纯洁的面向对象编程语言,但是为了编程的方便还是引入了基本数据类 型,为了能够将这些基木数据类型当成对象操作,Java为每一个基木数据类型都引入了对应 的包装类型( wrapper class),例如int的包装类就是 Integer从Java5开始引入了自动装 箱/拆箱机制,使得二者可以相互转换。Java为每个原始类型提供了包装类型: 原始类型: boolean,char,byte, short;,int,long,foat, double 包装类型: Boolean, Character,Byte, Short, Integer,Iong, Float, Double Kotlin中去掉了原始类型,只有“包装类型”,编译器在编译代码的时候,会自动优化性 能,把对应的包装类型拆箱为原始类型, Kotlin系统类型分为可空类型和不可空类型。 Kotlin中引入了可空类型,把有可能为null 的值单独用可空类型来表示。这样就在可空引用与不可空引用之间划分出来条明确的显式的 界线” Kotlin类型层次结构如图3-2所示: Any? An String? Int? MyClass? String Int M class Nothing? Nothing 图3-2 Kotl in类型层次结构 通过这样显式地使用可空类型,并在编译器作类型检查,大大降低了出现空指针异常的概 率 对于 Kotlin的数字类型而言,不可空类型与Java中的原始的数宇类型对应。如表3-1所 小 表3-1 Kotlin的不可空数字类型与Java的数字类型映射 Kotlin Java Int long ng Float float Double double Kotlin中对应的可空数字类型就相当于Java中的装箱数字类型。如表3-2所示 表3-2 Kotlin的可空数字类型与Java的数字类型映射 Kotlin Java Int? Integer Long ng Float? Float Double? Double 在Jaa中,从基本数字类型到引用数字类型的转换就是典型的装箱操作,例如int转为 Integer。同理,在 Kotlin中,非空数字类型到可空数组类型需要进行装箱操作。 >>>vala:Int=1000//不可空Int >>>Va1b:int=1000 >>>a===b t¥ue true 上面返回的都是true,因为a,b它们都是以原始类型存储的,类似于Java中的基本数字 类型 >>>va1a:int?=1000//可空Int >>>val b: Int?=1000 七rue >>>a===b false 我们可以看出,当a,b都为可空类型时,a跟b的引用是不等的。 这里的“等于”号简单说明如表3-3所示: 表3-3 Kotlin中的“等于”号 等于符号 功能说明 赋值,在逻辑运算时也有效 等于运算,比较的是值,而不是引用 完全等于运算,不仅比较值,而且还比较引用,只有两者 一致才为真 另外,Java中的数组也是个较为特殊的类型。这个类型是T,这个方括号让我们觉得 不人优雅。 Kotlin中摒弃了这个数组类型声明的语法。 Kotlin简单直接地使用 array类型代表 数组类型。这个 Array中定义了get,set算子函数,同时有一个size属性代表数组的长度 还有一个返回数组元素的迭代子 Iterator<T>的函数 iterator Kotlin数组Aray完整的定义如下: public class Array<ro i public in1 ane constructor(size:Int,init:(Int)->里)//构造函数 public operator fun get( index:int):T//get操作符,等价于 Array[ index] public operator fun set( index:nt, value:):Unit//set操作符,等价于 Array[index]=value pub1 ic val size:Int//数组长度,不可变Int pub1 ic operator fun iterator(): Iterator<T>//数组元素达代了 其中,构造函数我们可以这么用 >>> val square= Array(5,{i->i*i})//创建一个长度是5的数组,i对应数组的下标,值是 >> square forEach(::println) 014916 我们在编程过程中常用的 boolean, charl], byteL], shortL,int,long, float, doublel], Kotlin直接使用了8个新的类型来对应这样的编程场景: BooleanArray ByteArray charArray DoubleArray FloatArray IntArray 工 angAra ShortArray 32可空类型T 我想Java和 Android开发者肯定早已厌倦了空指针异常( Null Pointer Exception)。这 个讨厌的空指针异常在运行时总会在某个你意想不到的地方忽然出现,让我们感到措手不及。 自然而然地,人们会想刭为何不能在编译时就提前发现这类空指针异常,并大量修复这些 问题?现代编程语言正是这么做的。 Kotlin自然也不例外。 在ava8中,我们可以使用 Optional类型来表达可空的类型。 package com. easy. kotlin import java.util. optional mport static java. lang System. outi public class Java8optionalDemo I public static void main(String[ ]args)t out, print1n( strEngth( optiona1,of("abc"));// optiona1.of("abc")创建一个可空 的 optiona1< string>类型的变量 out println(strLength(optional. ofNullable(null)))i static Integer strEngth(optional<string> s)f turn sorElse( ).length( 运行输出: 但是,这样的代码,依然不是那么地优雅。 在 Groovy中提供了一种安全的属性/方法访问操作符(?) user?. getUsername()?. toUppercase() swit也有类似的语法,只作用在 Optional的类型上。 Kotlin中使用了 Groovy甲面的安全调用符,并简化了 Optional类型的使用,直接通过 在类型T后面加个?,这个类型T?就表达了 Optional<T>的意义。 上面Java8的例子,用 Kotlin米写就显得更加简单优雅了 package com. easy, kotlin fun main (args: Array<string>)( println(strEngth(null)) println(strEngth( abc)) fun strength(s: String?): Int return s2. length2:0//安全调用符和 Elvis操作符 其中,我们使用 String?同样表达了 Optional< String>的意思。相比之下,哪个更简单 呢?想必是一目了然啦 3.3安全操作符 让我们赶紧扔掉Jaa中的一堆nul防御式样板代码吧 当我们使用Java开发的时候,我们的代码大多是防御性的。如果我们不想遇到 NullPointerException,我们就需要在使用它之前不停地去判断它是否为null 有了安全调用符(?.),Elis操作符(2:)和let函数,我们就可以完全抛弃掉Java中冗 长的if-null和 IT-not-nu ll语句 本节我们来学习一下在 Kotlin中如何优雅正确地使用安全操作符。 3.3.1可空类型与nul 在Jaa中,如果我们访问一个空引用的成员变量或者方法,可能会导致空指针异常 NullPointerException (NPE) Kotlin正如很多现代编程语言一样一—是空安全的。 Kotlin中引入了可空类型。在 Kotlin 中,类型系统将可空类型和不可空类型进行了区分,例如, String为不可空类型, String?为可 空类型,如果将不可空类型赋值为nul将会编译不通过。 我们通过一个可空类型符号T?来明确地指定一个对象类型T是否能为空。 我们可以像这样去写 >>> val str: string=nu11//nu11不能赋值给不可空的 String类型 error: null can not be a value of a non-null type string val str: string null 我们可以看到,这里不能通过编译, String类型不能是null 个可以赋值为null的 String类型的正确姿势是: String?,代码如下所示 >>> var nu1 lablestr: string?=nu11//nu11可以赋值给可空的字符串类型 String? >> nullablestr null 我们再来看一下 Kotlin中关于null的一些有趣的运算。 null跟null是相等的: >>>nu11==nu11 true >>>nu11!=nu11 false null这个值比较特殊,null不是Any类型 >> null is Any false 但是,nu是Any?类型: >> null is Any? true 我们来看看nu对应的类型是什么: >>>vara=nu11//隐式声明变量a,并初始化值为nu11 >>> a is Nothing?//a是 Nothing?类型 t¥ue >>> a is Nothing//a不是 Nothing类型 false >>>a mull >>>a=1//1不能赋值给a, Nothing?类型只有一个值nu11 error: the integer literal does not conform to the expected type Nothing? a=1 从报错信息我们可以看出,null的类型是 Nothing?。关于 nothing?我们将会在下面的小 节中介绍。 33.2安全调用符 我们不能直接使用可空的 nullablestr来调用其属性或者方法 >> var nullablestr: string? null >> nullablestr length error: only safe(?,)or non-null asserted(!!.) calls are allowed on a nullable receiver of type String? nullablestr length 上面的代码无法编译, nullablestr可能是nul我们需要使用安全调用符(?.)来调用 >>>nu1 l ablest?,1 ength//如果nu11 ablest为空,则返回nu11。这个表达式的类型是Int? null nullablestr =abc >>>nu11 ablest2,1 ength//如果nu1 ablest非空,就返回nu1 ablest,1 ength。这个表达式的 类型是Int? 只有在 nullablestr}=null时才会去调用其 length属性 333非空断 如果我们想只冇在确保 nullablestr不是nu的情况下才能这么调用,否则抛岀异常,我 们可以使用断言操作符(!!) >>>nullablestr null >> nullablestr!! length kotlin. KotlinNullPointerException 非空断言符!!似Java中调用 assert语句。非空断言可以用在你需要拋出异常时(一般情况下,不建 议使用) Kotlin中对于不可空类平的对象变量,我们可以直接调用它的成员变量或者函数。而对可空类型,直接 调用成员变量或者函数将会直接编译不通过,直接在语法层面倣出了限制。这样可以最大限度的去避免空指 针异常 334 Elvis运算符 Java8中 Optional提供了 orElse方法,我们可以如下使用 E1se("")·1 ength(); 这个东东,在 Kotlin是最最常见不过的 Elvis运算符(:?)了: s? length ? 0 相比之下,还有什么理由继续用Java8的 Optional呢? 我们也可以使用 Elvis操作符来给定一个在是nul的情况下的替代值 >> nullablestr >>>vars=nu1lab1estr?:"NULL”//如果nu11ab1estx是nu11,表达式的值返回“NULL” NUL工 10 3.3.5let函数 let函数是一个 inline函数,它的定义如下 dkotlin.internal. Inlineonly pub1 ic inline fun<,R>,1et( block:(T)->R):R= block(this)//默认以当前这个对象里 作为闭包的b1ock参数 如果一个List中有空null元素和非空 String元素,而只要对非空值执行某个操作,我们 就可以使用let操作符 >> val listwithNulls= listof(a"b"",null,null,D") >>> listwithNulls [A, B, C, null, null, D] >> listwithNulls forEach it? leti println(it)1] ABCD 我们再举个简单的例子。例如,我们想要在 Textview和text都不为null时,在消息框 ( toast)中显示text消息,代码如下 textview?. text? leti toast(it)I 是不是相当简洁、易懂? 34特殊类型 本节我们介绍 Kotlin中的特殊类型:Unit, Nothing,Any以及其对应的可空类型 Unit?, Nothing?, Any? 34.1Unt类型 Kotlin也是面向表达式的语言。在 Kotlin中所有控制流语句都是表达式(除了变量赋值、 异常等)。 Kotlin中的Unit类型实现了与Java中的void一样的功能。 总的来说,这个Unit类型并没有什么特别之处。它的定义是 package kotlin public object Unit i override fun tostring()=" kotlin,Unit"// object对象Uni的 tostring()函数回定返 口"kot1in.Unit"这个字符串 不同的是,当个函数没有返回值的时候,我们用Unit来表示这个特征,而不是null 大多数时候,我们并不需要显式地返回Unit,或者声明一个函数的返回类型为Unit。编 译器会推断出它。 代码示例: > fun unitExample (println( Hello, Unit

...展开详情
img
  • 签到新秀

    累计签到获取,不积跬步,无以至千里,继续坚持!

关注 私信 TA的资源

上传资源赚积分,得勋章
    最新推荐