二、变量与基本类型

变量与基本类型

  • 变量
    • 定义
    • 声明和使用
  • 基本类型
    • 数字类型
      • 介绍
      • 运算
        • 算术运算符
        • 位运算符
        • 赋值运算符
        • 运算符优先级
    • 布尔类型
    • 字符类型
    • 字符串类型

变量

定义

变量,指值可以变的量。变量以非数字的符号来表达,一般用拉丁字母。变量的用处在于能一般化描述指令的方式。结果只能使用真实的值,指令只能应用于某些情况下。变量能够作为某特定种类的值中任何一个的保留器。

比如一个公式 x + 2 = 6 此时x就是一个变量,变量往往代表着某个值,比如这里的x就代表的是4这个值。在Kotlin中,我们也可以让变量去代表一个具体的值,并且变量的值是可以发生变化的,在程序中,我们也可以使用变量,并且变量具有类型。

声明和使用

要声明一个变量,我们需要使用以下格式:

var [变量名称] : [数据类型]

这里的数据类型我们会在下节课开始逐步讲解,比如整数就是Int类型,不同类型的变量可以存储不同的类型的值。后面的变量名称顾名思义,就像x一样,这个名称我们可以随便起一个,但是注意要满足以下要求:

  • 可以由大小写字母、数字、下划线(_)组成,但是不能以数字开头。
  • 如果变量名加上反引号,则可以以数字开头,字符组成也可以包含空格、$等一些特殊字符,但<>.[];等一些字符依旧不行。
  • 变量不能重复定义,大小写敏感,比如A和a就是两个不同的变量。
  • 不能有空格、@、#、+、-、/ 等符号。
  • 应该使用有意义的名称,达到见名知意的目的(一般我们采用英文单词),最好以小写字母开头。
  • 不可以是 true 和 false。
  • 不能与Kotlin语言的关键字或是基本数据类型重名

当然各位小伙伴没必要刻意去进行记忆有哪些关键字,我们会在学习的过程中逐步认识到这些关键字。新手要辨别一个单词是否为关键字,只需要通过IDEA的高亮颜色进行区分即可,比如:
在这里插入图片描述

深色模式下,关键字会高亮为橙色,浅色模式下会高亮为深蓝色,普通的代码都是正常的灰白色。

比如现在我们想要定义一个整数(Int)类型的变量a,那么就可以这样编写:

fun main() {var a : Int
}

但是这个变量一开始没有任何值,比如现在我们要让这个变量表示10,那么就可以将10赋值给这个变量:

fun main() {var a : Int = 10
}

不过由于变量在一开始就被赋值为10这个整数,此时类型是确定的,Kotlin的编译器非常聪明,它支持自动推断类型,这里会自动将变量a的类型推断为Int类型,我们可以直接省略掉后面的Int类型:

fun main() {var a = 10
}

或者我们可以在使用时再对其进行赋值:

fun main() {var a : Inta = 10
}

是不是感觉跟数学差不多?这种写法对于我们人来说,实际上是很好理解的,意思表达很清晰。为了更直观地查看变量的值,我们可以直接将变量的值也给打印到控制台:

fun main() {var a = 10println(a)
}

在这里插入图片描述

变量的值也可以在中途进行修改:

fun main() {var a = 666a = 777println(a)   //这里打印得到的就是777
}

变量的值也可以直接指定为其他变量的值:

fun main() {var a = 10var b = a //直接让b等于a,那么a的值就会给到bprintln(b) //这里输出的就是10了
}

我们还可以让变量与数值之间做加减法(运算符会在后面详细介绍):

fun main() {var a = 9   //a初始值为9a = a + 1   //a = a + 1也就是将a+1的结果赋值给a,跟数学是一样的,很好理解对吧println(a)  //最后得到的结果就是10了
}

对于那些只读的变量,我们可以将其表示为一个常量,使用val关键字:

fun main() {val a = 666 //使用val关键字,表示这是一个常量a = 777;    //常量的值不允许发生修改
}

编译时得到报错:
在这里插入图片描述

常量的值只有第一次赋值可以修改,其他任何情况下都不行:

fun main() {val a: Inta = 777;
}

基本类型

数字类型

介绍

Kotlin提供了一组表示数字的内置类型,对于整数,有四种不同大小的类型,因此,值范围:

类型大小(位)最小值最大值
Byte8-128127
Short16-3276832767
Int32-2,147,483,648 (-2^31)2,147,483,647(2^31-1)
Long64-9,223,372,036,854,775,808 (-2^63)9,223,372,036,854,775,807(2^63 - 1)

为什么不同的数据类型有着值范围呢?这是因为我们的计算机底层是采用0和1表示数据的,并且数据的表示位数有限,我们以二进制来计算,就像下面这样:

1 + 1 = 10

可能很多小伙伴会好奇,为什么1 + 1得到的结果是数字十?这是因为二进制中只有0和1,因此只要满二就进一,所以就变成这样的结果了,如果各位是初次学习,可能会不太好理解。

这里以上面的8位大小的Byte类型为例,在计算机底层存储数据时,只有8个bit位(一个bit位就可以表示一个0或1)来存储它,那么它能表示的最大值和最小值就是:

00000000 ~ 11111111 转换为十进制就是 0 ~ 255

不过为了能够表示负数,计算机一般使用补码进行表示,所以,上面的最小值和最大值就变成了-128 ~ 127了。

默认情况下,我们使用的常量数字都是Int类型,除非它的大小已经超出Int类型能够表示的最大范围,在超出Int类型可以表示的最大范围之后,默认为Long类型:

val one = 1 // Int
val threeBillion = 3000000000 // Long
val oneLong = 1L // 我们也可以在数字后面添加大写字母L来表示这是一个Long类型的数值
val oneByte: Byte = 1   //Int类型数据也可以在符合其他类型范围时自动转换

对于一些比较长的数字,我们可能需要使用类似于分隔符一类的东西来方便我们计数,比如:

银行往往把1000000000这种长数字记为1,000,000,000,这样看起来会更直观

在Kotlin中也可以像这样去编写:

val a = 1_000_000_000

数字类型不仅可以写成十进制,也可以以十六进制或是二进制表示(Kotlin不支持八进制表示)只需要添加对应的前缀即可,比如一个十六进制数据:

val a = 0xAF

因为十六进制中大于等于十的数据没有对应的阿拉伯数字可以表示,所以在计算机中就以ABCDEF来替代这无法表示的6个数字。并且我们需要在数字前面添加0x表示这是16进制的数字,接下来是2进制:

val a = 0b1001   //0b前缀表示二进制数据,后面的1010对应着十进制的9

除了整数类型外,Kotlin还为无符号整数提供以下类型:

  • UByte:一个无符号8位整数,范围从0到255
  • UShort:无符号16位整数,范围从0到65535
  • UInt:一个无符号32位整数,范围从0到2^32 - 1
  • ULong:一个无符号64位整数,范围从0到2^64 - 1

为了使无符号整数更易于使用,Kotlin同样提供了用后缀标记,该后缀表示无符号类型(类似于上面的Long类型添加L字母)

  • 使用uU字母作为后缀表示无符号整数。而具体的类型是根据前面变量的类型确定的,如果变量没有提供类型,编译器将根据数字的大小使用UIntULong

    val b: UByte = 1u  // UByte类型, 由变量提供的类型
    val s: UShort = 1u // UShort类型, 由变量提供的类型
    val l: ULong = 1u  // ULong类型, 由变量提供的类型val a1 = 42u    // UInt类型,根据数字大小自动推断得到
    val a2 = 0xFFFF_FFFF_FFFFu // ULong类型,根据数字大小自动推断得到
    
  • uLUL可以将文字直接标记为无符号Long类型:

    val a = 1UL // ULong类型,直接使用后缀标记
    

对于小数来说,Kotlin提供符合IEEE 754标准的浮点类型FloatDoubleFloat为IEEE 754标准中的单精度数据,而`Double位标准中的双精度数据,对于单双精度,本质上就是能够表示的小数位精度,双精度比单精度的小数精度更高。

这些类型的大小不同,并为不同精度的浮点数提供存储:

类型大小(位)符号与尾数位数阶码位数小数位数
Float322486-7
Double64531115-16

我们也可以直接创建小数类型的DoubleFloat变量,小数部分与整数部分由一个小数点(.)隔开,编译器默认情况下会将所有的小数自动推断为推断Double类型:

val pi = 3.1415 // 默认推断为Double类型
val one: Double = 1 // 这种写法是错误的,因为1不是小数,无法编译通过
val one: Double = 1.0 // 但是这种写法就是对的,因为这样表示就是小数,即使小数位是0

由于默认是Double类型,如果我们要明确指定值为Float类型,那么需要添加后缀fF,并且由于精度问题,如果该值包含超过6-7位小数,则会丢失一部分精度:

val e = 2.7182818284 // Double类型的数值
val e: Float = 2.7182818284f // 这里表示为Float会导致精度折损,得到2.7182817

与其他一些语言不同,Kotlin中的数字类型没有隐式转换的操作,例如,一个Double类型的变量无法将其值赋值给Int类型变量:
在这里插入图片描述

运算

算术运算符

Kotlin支持数学上标准的算术运算集,例如:+-*/% 并且这些运算符都是通过运算符重载实现的具体功能,我们会在后续的章节中讲解Kotlin的运算符重载机制,这里各位小伙伴就当做是普通的运算操作即可。

Kotlin支持运算符重载,运算符重载是一种允许程序员重新定义运算符的语言特性,通过运算符重载,您可以为自定义的类或数据类型定义一些特定操作的行为。

其中加减乘除操作这里就不做介绍了,而%符号用于取余操作,也就是计算前面的数整除后面的数得到的余数:

println(1 + 2)   //计算1加上2的结果
println(2_500_000_000L - 1L)   //计算2500000000减去1的结果
println(3.14 * 2.71)   //计算3.14与2.71的乘积
println(10.0 / 3)   //计算10除以3得到的结果
println(10 / 3)   //10除以3得到的余数为1

以上运算都比较简单,但是注意在除法运算中,只有两个操作数中出现小数,除法的结果才是小数,如果两个操作数都是整数,那么得到的结果也是整数,并且直接丢失小数位(不会四舍五入)

println(5 / 2)    //结果是2,而不是2.5

同样的,除了直接使用字面量来进行运算,我们也可以将定义的变量参与到运算中:

fun main() {val a = 10println(a / 2)
}

注意,在Kotlin中不同的算数运算符,它们的优先级也不一样:

println(1 + 2 * 3)

在数学中,乘法运算的优先级比加法运算更高,因此我们需要先计算乘法,再计算加法,而在Kotlin中是一样的,乘法和除法运算符的优先级是高于加法运算符的,所以说上面算出来的结果是7,同样的,我们数学中使用括号来提升某些运算的优先级,在Kotlin中同样可以,比如:

println((1 + 1) * 3)   //使用小括号来强制提升优先级

有些时候,我们可能想要让某个变量的值增加一定数值,比如下面这样:

var a = 10
a = a + 9   //让a等于a+9的结果

对于这种让变量本身加减乘除某个值的情况,可以使用赋值运算符简化:

a += 9   //等价于 a = a + 9
a /= 9   //等价于 a = a / 9
a %= 2   //等价于 a = a % 2

如果我们只是希望某个变量自增或自减1,那么我们可以像这样去写:

fun main() {var a = 10a++    //使用两个++表示自增1println(a)     //打印得到11a--    //使用两个--表示自减1
}

不过,这个双++符号,可以放在变量的前后,都能实现自增操作:

var a = 10
++a   //最终效果等价于a++

但是他们有一个本质区别,就是++在前面,a是先自增再得到结果,而++在后面,是a先得到结果,再进行自增,比如:

fun main() {var a = 10println(a++)   //这里++在后面,打印a的值依然是10,但是结束之后a的值就变成11了println(++a)   //这里++在前面,打印a的值是这里先自增之后的结果,就是12了
}

对于新手来说,这个很容易搞混,所以说一定要记清楚。

位运算符

Kotlin提供了一组整数的位运算操作,可以直接在二进制层面上与数字表示的位进行操作,不过只适用于IntLong类型的数据:

  • shl(bits)– 有符号左移
  • shr(bits)– 有符号右移
  • ushr(bits)– 无符号右移
  • and(bits)– 按位与
  • or(bits)– 按位或
  • xor(bits)– 按位异或
  • inv()– 取反

这里我们从按位与开始讲解,比如下面的两个数:

fun main() {val a = 9val b = 3val c = a and b //进行按位与运算println(c)
}

按位与实际上就是让这两个数每一位都进行比较,如果这一位两个数都是1,那么结果就是1,否则就是0:

  • a = 9 = 1001
  • b = 3 = 0011
  • c = 1 = 0001(因为只有最后一位,两个数都是1,所以说结果最后一位是1,其他都是0)

同样的,按位或,其实就是只要任意一个为1(不能同时为0)那么结果就是1:

fun main() {val a = 9val b = 3val c = a or bprintln(c)
}
  • a = 9 = 1001
  • b = 3 = 0011
  • c =11= 1011(只要上下有一个是1或者都是1,那结果就是1)

按位异或的意思就是只有两边不相同的情况下,结果才是1,也就是说一边是1一边是0的情况:

  • a = 9 = 1001
  • b = 3 = 0011
  • c =10= 1010(从左往右第二位、第四位要么两个都是0,要么两个都是1,所以说结果为0)

按位取反操作跟前面的正负号一样,只操作一个数,最好理解,如果这一位上是1,变成0,如果是0,变成1:

  • 127 = 01111111
  • -128 = 10000000

所以说计算的结果就是-128了。

除了以上的四个运算符之外,还有位移运算符,比如:

fun main() {val c = 1 shl 2 //shl表示左移运算println(c)
}
  • 1 = 00000001
  • 4 = 00000100(左移两位之后,1跑到前面去了,尾部使用0填充,此时就是4)

我们发现,左移操作每进行一次,结果就会x2,所以说,除了直接使用*进行乘2的运算之外,我们也可以使用左移操作来完成。

同样的,右移操作就是向右移动每一位咯:

fun main() {val c = 8 shr 2  //shr表示右移运算println(c)
}

跟上面一样,右移操作可以快速进行除以2的计算。对于负数来说,左移和右移操作不会改变其符号位上的数字,符号位不受位移操作影响:

fun main() {val c = -8 shr 2   //这里得到的依然是个负数println(c)
}

我们也可以使用考虑符号位的右移操作,一旦考虑符号位,那么符号会被移动:

fun main() {val c = -1 ushr 1 //无符号右移是ushr,移动会直接考虑符号位println(c)
}

比如:

  • -1 = 11111111 11111111 11111111 11111111
  • 右移: 01111111 11111111 11111111 11111111(无符号右移使用0填充高位)

此时得到的结果就是正数的最大值 2147483647 了,注意,不存在无符号左移操作。

赋值运算符

除了之前提到的三种赋值运算符外,算术运算符都可以与等于号组合为赋值运算符。所有赋值运算符如下:

  1. =:简单赋值运算符
  2. +=:加法赋值运算符
  3. -=:减法赋值运算符
  4. *=:乘法赋值运算符
  5. /=:除法赋值运算符
  6. %=:取余赋值运算符
运算符优先级

最后我们再总结一下不同运算符的优先级,对应的优先级从上往下依次减弱:

  1. 一元运算符:例如 ++、–、+、-、!、~
  2. 乘法和除法运算符:*、/、%
  3. 加法和减法运算符:+、-
  4. 位移运算符:shl、shr、ushr
  5. 按位与运算符:and
  6. 按位或运算符:or
  7. 按位异或运算符:xor
  8. 逻辑运算符:&&、||
  9. 比较运算符:>、>=、<、<=、==、!=
  10. 区间运算符:…
  11. 赋值运算符:=、+=、-=、*=、/=、%=

布尔类型

布尔类型是Kotlin中的一个比较特殊的类型,它并不是存放数字的,而是状态,它有下面的两个状态:

  • true - 真
  • false - 假

布尔类型(boolean)只有truefalse两种值,也就是要么为真,要么为假,布尔类型的变量通常用作流程控制判断语句(不同于C语言,C语言中一般使用0表示false,除0以外的所有数都表示true)

val a: Boolean = true

如果给一个其他的值,会无法编译通过:

布尔值除了可以直接赋值得到,也可以通过一些关系运算得到,常见的关系运算有大于、小于以及等于,所有的关系运算在下方:

  • 判断两个数/对象的值是否相等:a == ba != b
  • 判断两个数/对象的引用是否相等:a === b 和 a !== b
  • 判断数之间大小:a < ba > ba <= ba >= b
  • 判断数是否在指定范围中:a..bx in a..b(相当于x>=a && x<=b),x !in a..b

比如我们想判断变量a和变量b的值是否相同:

fun main() {val a = 10val b = 8println(a == b)  //判断a是否等于b(注意等号要写两个,因为单等号为赋值运算)println(a >= b)   //判断a是否大于等于bprintln(a < b)   //判断a是否小于bval c: Boolean = a != b   //判断a是否不等于b并将结果赋值给变量c
}

可以看到,通过逻辑运算得到的结果,都是true或false,也就是我们这里学习的Boolean类型值。在Kotlin中,我们为了快速判断某个数是否在一个区间内,可以直接使用 a..b 来表示一个数学上[a, b]这样的闭区间,比如我们这里要判断变量a的值是否在1~10之间:

fun main() {val a = 10println(a in 1..10)   //这里1..10表示1~10这个闭区间,使用in关键字来进行判断println(a in 1..<10)   //这里1..<10表示1~10这个前闭后开区间,使用in关键字来进行判断// a in 1 until 10 == a in 1..<10println(a !in 1..10)   //相反的,使用!in判断是否不在这个区间
}

对于Boolean类型的变量之间,也有一些逻辑运算符用于进行组合条件判断:

  • ||– 逻辑或运算
  • &&– 逻辑与运算
  • !– 取反运算

其中取反运算最好理解,它可以让true变成false,false变为true,比如:

fun main() {val a = 10val b = 20val c = a > b   //这里很明显c应该为falseprintln(!c)   //这里进行了取反操作并打印,那么结果就是true了
}

对于逻辑与和逻辑或运算,我们可以像这样去使用:

fun main() {val a = 10val b = 0println(100 >= a && b >= 60)  //我们可以使用与运算符连接两个判断表达式,只有两边都为true结果才是trueprintln(100 >= a || b >= 60)  //我们可以使用或运算符连接两个判断表达式,只要两边任意一个为true结果就是true
}

与运算符要求左右两边同时为真,得到的结果才是真,否则一律为假,而或运算就是要求两边只要有一边为真,结果就是真,除非两边同时为false,那么就没戏了。

不过需要注意的是,在与运算中,第一个判断表达式得到了false之后,此时不会再继续运行第二个表达式,而是直接得到结果false(逻辑运算符会出现短路的情况,只要第一个不是真,就算第二个是真也不可能了,所以说为了效率,后续就不用再判断了,在使用时一定要注意这一点)同样的,或运算下当发现第一个判断表达式为true时,也不会继续向后执行了,因为结果已经是真了。

字符类型

字符类型也是一个重要的基本数据类型,它可以表示计算机中的任意一个字符(包括中文、英文、标点等一切可以显示出来的字符)字符由Char类型表示,字符值用单引号:'1'囊括:

val c: Char = 'A'
println(c)

注意,字符只能表示一单个字符,我们之前遇到的字符串跟字符不一样,关于字符串我们会在下节课进行介绍。

我们打印出来的也是单个字符:
在这里插入图片描述

那么可能会有小伙伴好奇,字符类型在计算机底层是怎么进行存储的呢?实际上每个字符在计算机中都会对应一个字符码,首先我们需要介绍ASCII码:
在这里插入图片描述

比如我们的英文字母A要展示出来,那就是一个字符的形式,而其对应的ASCII码值为65,我们可以使用.code来获取某个字符对应的ASCII码,比如下面这样:

fun main() {val c: Char = 'A'println(c.code)   //这里就会打印字符对应的ASCII码
}

得到结果为:
在这里插入图片描述

字符型占据2个字节的空间用于存放数据:

  • char 字符型(16个bit,也就是2字节,它不带符号)范围是0 ~ 65535

不过,这里的字符表里面不就128个字符吗,那char干嘛要两个字节的空间来存放呢?我们发现表中的字符远远没有我们所需要的那么多,这里只包含了一些基础的字符,中文呢?那么多中文字符(差不多有6000多个),用ASCII编码表那128个肯定是没办法全部表示的,但是我们现在需要在电脑中使用中文,这时,我们就需要扩展字符集了。

Unicode是一个用于表示文本字符的标准字符集。它包含了世界上几乎所有的已知字符,包括不同国家和地区的字母、数字、标点符号、符号图形以及特殊的控制字符。

与Unicode不同,ASCII(American Standard Code for Information Interchange)是一个只包含128个字符的字符集。它最初是为了在计算机系统中传输基本英语字符而设计的。ASCII字符集包含了常见的拉丁字母、数字、标点符号以及一些特殊字符。

Unicode采用了一个更加广泛的字符编码方案,包括了不同的字符集编码,比如UTF-8和UTF-16等。UTF-8是一种可变长度的编码方案,它可以用来表示Unicode中的任意字符,且向后兼容ASCII字符集。而UTF-16则是一种固定长度的编码方案,它使用两个字节来表示一个Unicode字符。

与ASCII相比,Unicode的主要优势在于它能够表示各种不同的语言和字符,而不仅仅限于英语字符。这使得Unicode成为全球通用的字符编码标准,为不同国家和地区的语言提供了统一的编码方式。

所以,一个Char就能表示几乎所有国家语言的字符,这样就很方便了。

接着我们来介绍一下转译字符,对于一些我们平时很难直接通过键盘或是输入法打出来的字符,比如一些特殊符号:
在这里插入图片描述

这些符号我们没办法直接打出来,但是现在我们又想要表示它们,该怎么做呢?我们可以使用转义来将这些字符对应的Unicode编码转换为对应的字符,只需要在前面加上\u即可,比如✓这个符号:

fun main() {val c = '\u2713'   //符号✓对应的Unicode编码为10003,这里需要转换为16进制表示,结果为0x2713println(c)
}

除了能像这样表示一个特殊字符,我们也可以使用一些其他的转义字符来表示各种东西:

  • \t – 选项卡
  • \b – 退格
  • \n – 换行(LF)
  • \r – 回车(CR)
  • \' – 单引号
  • \" – 双引号
  • \\ –反斜杠
  • \$ – 美元符号

这些转义字符都是为了防止在特殊情况下无法表示某些字符,而给我们的替代方案,后续各位小伙伴在使用时可以回来参考一下。

字符串类型

字符串类是一个比较特殊的类型,它用于保存字符串。我们知道,基本类型Char可以保存一个2字节的Unicode字符,而字符串则是一系列字符的序列,它的类型名称为String

字符串通常由双引号""囊括,它可以表示一整串字符:

val str: String = "Hello World"

注意,字符串中的字符一旦确定,无法进行修改,只能重新创建。

如果我们需要再字符串中换行,需要用到转义字符,字符串中同样支持使用转义字符:

fun main() {val text = "Hello\nWorld"println(text)
}

不过,字符串只能写一行,有时候有点不太够用,可能我们想要打印多行文本,我们除了用\n转义字符来换行之外,也可以直接使用三个双引号"""来表示一个原始字符串,但是原始字符串无法使用转义字符:

fun main() {val text = """这是第一行这第二行别\n了,没用真牛逼啊,这功能隔壁Java15才有"""println(text)
}

效果如下:
在这里插入图片描述

可以看到确实是够原始的,把我代码里面的缩进都给打印出来了,这样肯定不是我们希望的样子,我们希望的仅仅是一个简单换行而已,那这里该怎么去处理呢?(可以使用trimIndent方法)后面我们在讲解函数之后,会额外补充这里的内容。

有时候为了方便,我们可以将不同的字符串拼接使用:

fun main() {val str1 = "Hello"val str2 = "World"val str = str1 + str2println(str)   //使用 + 来拼接两个字符串,得到的结果就是两个字符串合在一起的结果
}

字符串除了和字符串拼接之外,也可以和其他类型进行拼接:

fun main() {val a = 10val text = "这是拼接的值" + aprintln(text)   //打印出来就是与其他类型的拼接结果
}

但是我们需要注意字符串拼接的顺序,只能由字符串拼接其他类型,如果是其他类型拼接字符串,可能会出现问题:
在这里插入图片描述

但是现在我们就是希望其他类型的数据拼在最前面,这里应该怎么做呢?我们可以使用字符串模版来完成:

fun main() {val a = 10val text = "这是拼接的值$a"  //这里的$为模版表达式,可以直接将后面跟着的变量或表达式以字符串形式替换到这个位置println(text)
}

如果要添加到前面:

val text = "$a 这是拼接的值" //注意这里$a之后必须空格,否则会把后面的整个字符串认为这个变量的名字

出现这种情况除了用空格去解决之外,我们也可以添加一个花括号:

val text = "${a}这是拼接的值"  //添加花括号就可以消除歧义了
val text = "${a > 0}这是拼接的值"  //花括号中也可以写成表达式

由于美元符用于模版表达式了,所以说如果我们希望在字符串中仅仅表示$这个字符,那么我们需要用到转义:

val text = "\$这是美元符"   //普通字符串直接使用\$表示
//原始字符串要套个娃
val str = """${'$'}这是美元符    """

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/54365.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MongoDB集群模式详解及应用实战

目录 本节课内容&#xff1a; 集群搭建 1.创建3个目录&#xff1a; 2.编辑配置文件 ​编辑 3.启动&#xff1a; 4.看看&#xff1a; 5.另外&#xff0c;两个如上1&#xff0c;2&#xff0c;3步骤操作 &#xff0c;但是日志目录&#xff0c;端口什么的需要改一下即可。 …

10以内数的分解

// 10以内数的分解.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 //#include <iostream> using namespace std; int main(int argc, char* argv[]){for (int i 2; i < 10; i){for (int j 1; j < i; j){printf("%d%d%d ",j…

操作系统学习笔记---文件管理

文件系统基础 概念 文件&#xff1a;以计算机硬盘为载体的存储在计算机上的信息集合 文件的属性 文件具有一定的属性&#xff0c;系统不同&#xff0c;属性也会有所不同&#xff0c;但通第都包括如下属性&#xff1a;名称、标识符、类型、位置、大小、保护、时间、日期和用…

vue3+vite@4+ts+elementplus创建项目详解

1、第一步创建项目cnpm init vite4 2、设置vue3.2局域网可访问配置&#xff1a; 找到项目路径下的package.json目录下找到script对象下面添加一下代码&#xff1a; "serve": "vite --host 0.0.0.0" 启动项目命令不在是dev而是&#xff1a;cnpm run serve 3…

《深度学习》OpenCV 摄像头OCR 过程及案例解析

目录 一、摄像头OCR 1、含义 2、一般操作步骤 1&#xff09;安装OpenCV库 2&#xff09;设置摄像头 3&#xff09;图像采集 4&#xff09;图像预处理 5&#xff09;文本识别 6&#xff09;文本处理 7&#xff09;结果显示 二、案例实现 1、定义展示图像函数 2、定…

深入理解 JavaScript 事件循环机制:单线程中的异步处理核心

深入理解 JavaScript 事件循环机制&#xff1a;单线程中的异步处理核心 JavaScript 是一门单线程的编程语言&#xff0c;也就是说它在同一时间只能执行一个任务。然而&#xff0c;现代 Web 应用经常需要处理大量的异步操作&#xff0c;如用户输入、网络请求、定时器等。为了确…

《迁移学习》—— 将 ResNet18 模型迁移到食物分类项目中

文章目录 一、迁移学习的简单介绍1.迁移学习是什么&#xff1f;2.迁移学习的步骤 二、数据集介绍三、代码实现1. 步骤2.所用到方法介绍的文章链接3. 完整代码 一、迁移学习的简单介绍 1.迁移学习是什么&#xff1f; 迁移学习是指利用已经训练好的模型&#xff0c;在新的任务上…

鸿蒙开发(NEXT/API 12)【状态查询与订阅】手机侧应用开发

注意 该接口的调用需要在开发者联盟申请设备基础信息权限与穿戴用户状态权限&#xff0c;穿戴用户状态权限还需获得用户授权。 实时查询穿戴设备可用空间、电量状态。订阅穿戴设备连接状态、低电量告警、用户心率告警。查询和订阅穿戴设备充电状态、佩戴状态、设备模式。 使…

初识Django

前言: 各位观众老爷们好&#xff0c;最近几个月都没怎么更新&#xff0c;主要是最近的事情太多了&#xff0c;我也在继续学习Django框架&#xff0c;之前还参加了一些比赛&#xff0c;现在我会开始持续更新Django的学习&#xff0c;这个过程会比较久&#xff0c;我会把我学习的…

MySQL--三大范式(超详解)

目录 一、前言二、三大范式2.1概念2.2第一范式&#xff08;1NF&#xff09;2.3第二范式&#xff08;2NF&#xff09;2.3第三范式&#xff08;3NF&#xff09; 一、前言 欢迎大家来到权权的博客~欢迎大家对我的博客进行指导&#xff0c;有什么不对的地方&#xff0c;我会及时改进…

嘴尚绝卤味:健康美味的双重奏

在当今快节奏的生活中&#xff0c;人们对美食的追求不再仅仅停留于味蕾的满足&#xff0c;更加注重食物的健康与营养。在这一背景下&#xff0c;"嘴尚绝卤味"以其独特的健康理念与精湛的制作工艺&#xff0c;成为了市场上备受瞩目的卤味品牌。本文将从"嘴尚绝卤…

Kotlin基本知识

Kotlin是一种现代的静态类型编程语言&#xff0c;由JetBrains公司在2010年推出&#xff0c;并被Google在2019年宣布为Android开发的首选语言。 超过 50% 的专业 Android 开发者使用 Kotlin 作为主要语言&#xff0c;而只有 30% 使用 Java 作为主要语言。 70% 以 Kotlin 为主要语…

文章解读与仿真程序复现思路——电力自动化设备EI\CSCD\北大核心《考虑光伏不确定性的配电网谐波监测优化配置方法 》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

Azure DevOps Server:不能指派新增的用户

Contents 1. 概述2. 解决方案 1. 概述 近期和微软Azure DevOps项目组解决了一个“无法指派开发人员”的问题&#xff0c;在此分享给大家。问题描述&#xff1a; 在一个数据量比较大的Azure DevOps Server的部署环境中&#xff0c;用户发现将新用户的AD域账户添加到Azure DevOps…

《15分钟轻松学 Python》教程目录

为什么要写这个教程呢&#xff0c;主要是因为即使是AI技术突起的时代&#xff0c;想要用好AI做开发&#xff0c;那肯定离不开Python&#xff0c;就算最轻量级的智能体都有代码块要写&#xff0c;所以不一定要掌握完完整整的Python&#xff0c;只要掌握基础就能应对大部分场景。…

数据看板如何提升决策效率?

数据看板作为一种直观、高效的数据可视化工具&#xff0c;在这一过程中发挥着至关重要的作用。以一家中型制造企业为例&#xff0c;每天面临着生产计划的安排、原材料的采购、产品质量的把控以及市场销售的策略制定等诸多业务场景。在生产线上&#xff0c;需要确保设备的高效运…

【隐私计算篇】多方安全计算之函数秘密共享(FSS)

1. 函数秘密共享(FSS)定义 秘密共享是一种将一个值拆分为多个份额的方法&#xff0c;形式有多种&#xff0c;可以参考《安全多方计算(MPC)矩阵乘法算子的原理分析》。这里主要提及加法秘密共享&#xff0c;使得&#xff1a;这些份额可以重新组合以还原出秘密值&#xff1b;任…

【HTML并不简单】笔记1-常用rel总结:nofollow、noopener、opener、noreferrer,relList

文章目录 rel"nofollow"rel"noopener"与rel"opener"rel"noreferrer"relList对象 《HTML并不简单&#xff1a;Web前端开发精进秘籍》张鑫旭&#xff0c;一些摘要&#xff1a; HTML&#xff0c;这门语言的知识体系非常庞杂&#xff0c;涉…

Python数据结构与算法问题详解

Python数据结构与算法问题详解 Python 作为一种高级编程语言&#xff0c;凭借其简洁的语法和强大的内置库&#xff0c;成为了数据结构与算法学习的绝佳工具。本文将深入解析几种常见的数据结构&#xff0c;并结合具体的算法&#xff0c;展示如何在实际问题中高效解决问题。通过…

《PMI-PBA认证与商业分析实战精析》第7章 解决方案评价

第7章 解决方案评价 本章主要内容&#xff1a; 评价的建议思维 解决方案的评价计划 确定评价什么 何时以及如何验证解决方案的结果 评价验收标准和解决缺陷 促进通过/不通过的决策 获得解决方案的签字确认 评价解决方案的长期绩效 解决方案替换/淘汰 本章涵盖的考试…