当前位置: 首页 > news >正文

Day 2:Kotlin基础(一)

昨天搭好了 Android Studio,今天正式进入 Kotlin 语言基础。写 Android 应用本质上就是用 Kotlin 描述界面长什么样、数据怎么流转、用户操作怎么响应,这些最终都会落到变量、类型、函数和字符串拼接这四个基本功上。今天把它们逐个搞清,明天就能直接用 Kotlin 写出有逻辑的程序代码了。

变量:valvar

Kotlin 声明变量用valvar。二者的区别不在于"有没有值",而在于赋值之后还能不能改。

val声明的变量只能赋值一次,之后不能再指向其他对象。这跟 Java 里的final是同一个意思。var(variable 的缩写)声明的变量则可以反复赋值。举个例子:

funmain(){// val 声明后不可变——适合作为常量或一次性计算结果valappName="HelloAndroid"// 应用名确定之后不需要改// var 声明后可以重新赋值——适合表示会变化的状态varclickCount=0// 每次点击都要累加clickCount=clickCount+1}

如果把appName声明成var,代码也能跑,但意图就模糊了,读代码的人会预期这个值后面可能被修改,就会额外留意赋值的位置。反过来,如果clickCountval,编译器直接报错Val cannot be reassigned,逼你在声明时就明确它的角色。

Kotlin 支持类型推断,多数情况下不需要手写类型,编译器能从右边的值反推出来:

valversion=1// 推断为 Intvalratio=0.618// 推断为 Double

需要显式声明时,把类型写在变量名后面,用冒号分隔:

valuserId:Int=1varmessage:String="Hello"

类型必须显式声明的场景主要有三种,一是声明时不赋值,稍后才初始化,编译器没法猜类型,二是类型推断出的不是你想要的那个,比如你想要Long但编译器推成Int,三是作为类属性或函数参数,Kotlin 要求写明类型。

还有一种常见情况是先声明再初始化:

valcontent:String// 只声明,不赋值// ... 一些逻辑之后 ...content="result"// 唯一一次赋值机会

这里需要注意,val的"不可变"指的是变量指向的引用不可变,不是说对象内部不可变。比如val指向一个可变的列表,你仍然能往里添加删除元素,只是不能让这个变量再指向另一个列表。

数据类型

Kotlin 里的所有东西都是对象,数字、布尔值、字符,没有 Java 那种"基本类型"和"包装类型"的区分。

日常开发中最常用的数值类型就四种,Int整数、Long大整数、Double高精度小数、Float低精度小数。

类型大小字面量示例说明
Int32 位val a = 42默认整数类型
Long64 位val a = 42L注意末尾的L
Double64 位val a = 3.14默认浮点类型
Float32 位val a = 3.14f注意末尾的f

数字字面量可以用下划线分隔,提高大数可读性,1_000_0001000000完全等价。

Kotlin 有一个新手很容易踩到的坑,整数除法会丢掉小数部分,不会自动升级成浮点数。Java 开发者尤其要小心,这个行为两种语言一样,但在 Kotlin 里因为类型系统更严格,出错时定位更明显:

valhalf=5/2// 结果是 2,不是 2.5——两个 Int 相除,结果还是 Intvalcorrect=5/2.0// 结果是 2.5——其中一个操作数是 Double

第二个坑是 Kotlin 不做隐式类型转换。不能直接把Int赋给Long变量,也不能把Float传给参数类型为Double的函数:

valcount:Int=42valbigCount:Long=count// 编译错误:type mismatchvalbigCount:Long=count.toLong()// 正确做法——显式调用转换函数

对于每种数字类型都提供了toByte()toShort()toInt()toLong()toFloat()toDouble()六个转换函数。设计上之所以不做隐式转换,是为了避免精度丢失时悄无声息,凡是转换,必须在代码里写出来,让 review 的人能看见。

Boolean类型只有truefalse两个值,用在条件判断中。Char表示单个字符,用单引号括起来,val letter = 'A'String是字符串,用双引号,不可变,所有对字符串的操作都返回新字符串,不会修改原值:

valoriginal="Kotlin"valupper=original.uppercase()// 返回 "KOTLIN",original 依然是 "Kotlin"

函数

声明函数用fun关键字,后面跟函数名、括号内的参数列表、冒号后的返回值类型,然后是花括号内的函数体:

funadd(a:Int,b:Int):Int{returna+b}

Kotlin 中函数可以定义在文件顶层,不需要先写一个 class 把它包起来,这一点和 Java 不同。对于 Android 开发来说,你可能会把一个页面里的辅助逻辑,比如格式化时间、校验手机号等写成顶层函数,放在对应的包下面,外部直接按包名 import 就能用,不需要套一层 Util 类。

如果函数体只有一条表达式,可以把花括号和return都省掉,换成等号连接:

funadd(a:Int,b:Int):Int=a+b

这种单表达式函数连返回值类型都可以省略,编译器自动推断:

funadd(a:Int,b:Int)=a+b// 推断返回 Int

函数没有有意义返回值时,返回类型是Unit,相当于 Java 的void,可以省略不写:

funshowResult(value:Int){println("计算结果:$value")// 不需要 return 语句}

参数可以有默认值,这在实际项目中非常有用。比如一个网络请求函数,默认超时可以设成 5 秒,特殊场景下才传入自定义值:

fundivide(a:Double,b:Double=1.0):Double=a/bdivide(10.0)// 10.0,b 使用默认值 1.0divide(10.0,2.0)// 5.0,覆盖默认值

调用函数时可以按参数名传值,不按顺序,这就是命名参数。当一个函数有多个带默认值的参数,你只想改其中一个时,命名参数就省去了逐个补位的麻烦:

funcreateUser(name:String,age:Int=0,city:String="未知"){println("$name,$age,$city")}createUser("Tom",city="上海")// age 用默认值 0,city 覆盖为 上海

传入函数的参数在函数体内部是只读的——相当于隐式val,不能对参数重新赋值。这个约束在函数体较长、逻辑复杂时能防止无意中改掉了上游传进来的值,排错时少一个变量污染源。

字符串模板

字符串模板是 Kotlin 最顺手的语法之一,在双引号包裹的字符串里,$加变量名就能直接把变量的值嵌入到字符串中,不用再写+拼接:

valname="Tom"valscore=95println("学生:${name}, 成绩:${score}")// 学生: Tom, 成绩: 95

花括号里可以放任意 Kotlin 表达式,函数调用、算术运算甚至条件判断都可以。如果不加花括号,$只会把紧跟在它后面的那一个标识符当作变量名,所以$score等价于${score},但$score分会被解析成变量名叫score分而不是score

valbase=100println("两倍是${base*2}")// 两倍是 200println("大写:${name.uppercase()}")// 大写:TOMprintln("得分$score分")// 编译错误,找不到变量 score分println("得分${score}分")// 正确写法

需要输出一个实际的美金符号$时,写${'$'},内层是一对单引号括起来的 Char:

println("价格:${'$'}99")// 价格:$99

多行字符串用三引号"""包裹,里面也可以嵌入模板表达式,换行会原样保留,不需要\n转义:

valhtml=""" <div class="card"> <h1>${name}</h1> <p>分数:${score}</p> </div> """.trimIndent()

trimIndent()会统一去除每行前面的公共缩进,让输出看起来紧凑整齐。

字符串模板把变量、表达式和文本自然地写在一起,代码和最终输出的对应关系一目了然。用+拼接好几个变量时很容易漏掉空格或搞混引号闭合,模板写法则直接杜绝了这类低级错误。

练习

理解了这四个概念之后,用两个练习来巩固。

练习一:写计算器函数。定义加减乘除四个函数,每个接收两个Double参数,返回Double结果。在main里分别调用并打印输出。

参考实现:

funadd(a:Double,b:Double)=a+bfunsubtract(a:Double,b:Double)=a-bfunmultiply(a:Double,b:Double)=a*b// 除数为 0 时直接返回 0,避免运行时异常fundivide(a:Double,b:Double)=if(b!=0.0)a/belse0.0funmain(){valx=15.0valy=4.0println("$x+$y=${add(x,y)}")println("$x-$y=${subtract(x,y)}")println("$x*$y=${multiply(x,y)}")println("$x/$y=${divide(x,y)}")}

divide里加了对除数为零的保护——这在实际项目中是必要的,因为Double / 0.0会返回Infinity而不会直接抛异常,代码能继续执行但后续逻辑可能因此出错。更稳妥的做法是判断之后抛一个有意义的异常,这里为了让示例保持简单,直接返回零。

练习二:写 BMI 计算器。接收身高(单位米)和体重(单位千克)两个参数,计算 BMI 并打印判定结果。BMI 公式是体重除以身高的平方。判定标准参考中国标准:低于 18.5 偏瘦,18.5~23.9 正常,24.0~27.9 偏重,28.0 及以上肥胖。

funcalculateBMI(weight:Double,height:Double):Double{returnweight/(height*height)}fungetBMICategory(bmi:Double):String{returnwhen{bmi<18.5->"偏瘦"bmi<24.0->"正常"bmi<28.0->"偏重"else->"肥胖"}}funmain(){valweight=70.0// 千克valheight=1.75// 米// 保留一位小数,避免输出一长串数字valbmi=String.format("%.1f",calculateBMI(weight,height))valcategory=getBMICategory(bmi.toDouble())println("身高:${height}m,体重:${weight}kg")println("BMI:${bmi}${category})")}

这段代码把计算和分类拆成了两个函数,职责单一,各自独立可测。String.format("%.1f", ...)把 BMI 值截断到一位小数,打印结果干净——70.0 / (1.75 * 1.75)精确结果是22.857...,格式化后输出22.9,刚好落在正常范围内。when表达式的条件是从上到下依次匹配的,把区间的下界从小到大排好,就不需要写bmi >= 18.5 && bmi < 24.0这种双重条件了。

这两个练习覆盖了今天所有内容:用val声明不变的入参和计算结果,用Double做小数运算并处理类型转换,用fun定义带返回值和默认参数的函数,用字符串模板把计算结果整洁地拼进输出信息。把代码敲一遍、改几个参数跑一跑,这四个概念就真正内化了。

http://www.jsqmd.com/news/1091046/

相关文章:

  • 终极iOS激活锁绕过解决方案:applera1n完整使用指南
  • AI编程实战:如何开发一个谷歌浏览器插件,并上架 Chrome 商店?
  • GHelper:为华硕笔记本量身打造的轻量级控制工具
  • 【学习记录】Week1:Pwntools 基础——连接、接收与发送 Payload 实操
  • Simple Runtime Window Editor:三步突破游戏分辨率限制,打造专业级截图工具
  • FSearch终极指南:Linux系统极速文件搜索完整教程
  • 社论:拥抱贾子理论大厦:AI时代中国思想主权的战略觉醒
  • 降AIGC平台红黑榜:实测3款热门工具,剖析实用程度与常见陷阱,文末附攻略
  • Codex 新手入门:别急着改代码,先学会这套安全流程
  • 文件上传漏洞攻防:从原理到实战的完整攻击链解析
  • Lightweight Charts终极指南:如何在5分钟内构建高性能金融可视化应用
  • 【Springboot毕设全套源码+文档】基于springboot智能阅读推荐系统的设计与实现(丰富项目+远程调试+讲解+定制)
  • 星盾(Starshield)与星链(Starlink)系统架构差异解析:PWSA框架下的军用低轨星座独立体系与作战应用
  • 终极指南:Jellyfin Bangumi插件让动漫库管理变得简单高效
  • AI驱动移动端自动化测试:从意图理解到工程实践
  • 别再熬夜写论文了!6款一键生成论文工具,一键极速生成超长篇幅!
  • Mi-Create开源表盘设计工具:可视化操作打造个性化小米手表表盘
  • 【学习记录】Week2(一):深入 ELF 结构视图与 .got/.plt 节区作用详解
  • 如何快速掌握NDS游戏文件编辑器:Tinke的完整使用指南
  • 还在愁论文框架搭不好?9款AI论文写作软件一键生成逻辑连贯初稿!
  • 程序员真正的天花板,不是技术,是表达
  • 如何彻底解决Cursor试用限制:从设备指纹识别到一键重置的完整指南
  • 音频混音原理(MIXer)
  • 毕业生必备:9款免费AI写作辅助平台,一键生成开题报告与论文大纲
  • Ubuntu 磁盘排查必备:sudo du -sh * 与 du -shx /var/lib/docker 用法详解与实战
  • 基于STM32+FPGA的驱控一体伺服控制器:从硬件架构到FreeRTOS任务调度的设计实践
  • 2026好用的命理软件推荐给进阶用户:工具箱、学习路径和资料安全怎么选
  • 从零构建企业级iSCSI存储:Openfiler安装与基础服务配置实战
  • FreeRTOS源码详解(八)——Event
  • SGLang vs vLLM:优先级调度、限流、淘汰策略对比