NOTE阅读文档版本:
语言规约 Cangjie-0.53.18-Spec
具体开发指南 Cangjie-LTS-1.0.3
在阅读 了解仓颉的语言规约时, 难免会涉及到一些仓颉的示例代码, 但 我们对仓颉并不熟悉, 所以可以用 仓颉在线体验 快速验证
有条件当然可以直接 配置Canjie-SDK
WARNING博主在此之前, 基本只接触过C/C++语言, 对大多现代语言都没有了解, 所以在阅读过程中遇到相似的概念, 难免会与C/C++中的相似概念作类比, 见谅
且, 本系列是文档阅读, 而不是仓颉的零基础教学, 所以如果要跟着阅读的话最好有一门编程语言的开发经验
WARNING在阅读仓颉编程语言的开发指南之前, 已经大概阅读了一遍 仓颉编程语言的语言规约, 已经对仓颉编程语言有了一个大概的了解
所以在阅读开发指南时, 不会对类似: 类、函数、结构体、接口等解释起来较为复杂名称 做出解释
此样式内容, 表示文档原文内容
基础数据类型
整数类型
整数类型分为有符号(
signed)整数类型和无符号(unsigned)整数类型有符号整数类型包括
Int8、Int16、Int32、Int64和IntNative, 分别用于表示编码长度为8-bit、16-bit、32-bit、64-bit和平台相关大小的有符号整数值的类型无符号整数类型包括
UInt8、UInt16、UInt32、UInt64和UIntNative, 分别用于表示编码长度为8-bit、16-bit、32-bit、64-bit和平台相关大小的无符号整数值的类型对于编码长度为
N的有符号整数类型, 其表示范围为:对于编码长度为
N的无符号整数类型, 其表示范围为:下表列出了所有整数类型的表示范围:
类型 表示范围 Int8Int16Int32Int64IntNativePlatform dependentUInt8UInt16UInt32UInt64UIntNativePlatform dependent程序具体使用哪种整数类型, 取决于该程序中需要处理的整数的性质和范围
在
Int64类型适合的情况下, 首选Int64类型, 因为Int64的表示范围足够大并且 整数类型字面量 在没有类型上下文的情况下默认推断为
Int64类型, 可以避免不必要的类型转换
仓颉中整数类型根据位数和有无符号共分为10种, 其中两种IntNative和UIntNative与平台相关
仓颉中的整型字面量, 在没有上下文时, 默认为Int64类型, 即: 类似let value = 20, value就是Int64类型
整数类型字面量
整数类型字面量有
4种进制表示形式: 二进制(使用0b或0B前缀)、八进制(使用0o或0O前缀)、十进制(没有前缀)、十六进制(使用0x或0X前缀)例如, 对于十进制数
24, 表示成二进制是0b00011000(或0B00011000), 表示成八进制是0o30(或0O30), 表示成十六进制是0x18(或0X18)在各进制表示中, 可以使用下划线
_充当分隔符的作用, 方便识别数值的位数, 如0b0001_1000对于整数类型字面量, 如果它的值超出了上下文要求的整数类型的表示范围, 编译器将会报错
let x: Int8 = 128 // Error, 128 out of the range of Int8let y: UInt8 = 256 // Error, 256 out of the range of UInt8let z: Int32 = 0x8000_0000 // Error, 0x8000_0000 out of the range of Int32在使用整数类型字面量时, 可以通过加入后缀来明确整数字面量的类型, 后缀与类型的对应为:
后缀 类型 后缀 类型 i8Int8u8UInt8i16Int16u16UInt16i32Int32u32UInt32i64Int64u64UInt64加入了后缀的整数字面量可以通过以下方式使用:
var x = 100i8 // x 是 100 Int8 类型var y = 0x10u64 // y 是 16 UInt64 类型var z = 0o432i32 // z 是 282 Int32 类型
仓颉中的整型字面量支持: 二进制、八进制、十进制和十六进制
并且, 可以使用_进行分割, 不影响数值, 同时可以使用后缀明确类型:
// 二进制 需要加前缀 0b/0B0b000011110b00001111i80b00001111_i80b0000_1111_i80b0000_1111_u8
// 八进制 需要加前缀 0o/0O0o765430o76543i160o76543_i160o76_543_i160o76_543_u16
// 十进制 无前缀1234567812345678i3212345678_i3212_345_678_i3212_345_678_u32
// 十六进制 需要加前缀 0x/0X0xFE0xFEi80xFE_i80xFE_DC_i160xFE_DC_u16字符字节字面量
仓颉编程语言支持字符字节字面量, 以方便使用
ASCII码表示UInt8类型的值字符字节字面量由字符
b、一对标识首尾的单引号、以及一个ASCII字符组成, 例如:var a = b'x' // a is 120 with type UInt8var b = b'\n' // b is 10 with type UInt8var c = b'\u{78}' // c is 120 with type UInt8c = b'\u{90}' - b'\u{66}' + c // c is 162 with type UInt8
b'x'表示类型为UInt8大小是120的字面值另外还可以通过
b'\u{78}'这种转义形式表示类型为UInt8,16进制大小为0x78或10进制大小为120的字面值需要注意的是,
\u内部最多有两位16进制数, 并且值必须小于256(十进制)
仓颉中存在字符字节字面量, 不是字符字面量, 而不是字符串字面量
而是一b'ASCII'形式的字符字节字面量, ''包裹的内容必须是ASCII表中的字符, 或\u{二位十六进制 < 256}
整数类型支持的操作
整数类型默认支持的操作符包括: 算术操作符、位操作符、关系操作符、自增和自减操作符、复合赋值操作符
各操作符的优先级参见附录中的操作符
算术操作符包括: 一元负号(
-)、加法(+)、减法(-)、乘法(*)、除法(/)、取模(%)、幂运算(**)
除了一元负号(
-)和幂运算(**), 其他操作符要求左右操作数是相同的类型
*,/,+和-的操作数可以是整数类型或浮点类型
%的操作数只支持整数类型
**的左操作数只能为Int64类型或Float64类型, 并且:
当左操作数类型为
Int64时, 右操作数只能为UInt64类型, 表达式的类型为Int64当左操作数类型为
Float64时, 右操作数只能为Int64类型或Float64类型, 表达式的类型为Float64位操作符包括: 按位求反(
!)、左移(<<)、右移(>>)、按位与(&)、按位异或(^)、按位或(|)注意, 按位与、按位异或和按位或操作符要求左右操作数是相同的整数类型
关系操作符包括: 小于(
<)、大于(>)、小于等于(<=)、大于等于(>=)、相等(==)、不等(!=)要求关系操作符的左右操作数是相同的整数类型
自增和自减操作符包括: 自增(
++)和自减(--)注意, 仓颉中的自增和自减操作符只能作为一元后缀操作符使用
复合赋值操作符包括:
+=、-=、*=、/=、%=、**=、<<=、>>=、&=、^=、|=整数类型之间、整数类型和浮点类型之间可以互相转换, 整数类型可以转换为字符类型, 具体的类型转换语法及规则请参见[数值类型之间的转换]
注意:
本章所提及的某个类型支持的操作, 均是指在没有操作符重载的前提下
仓颉的整数类型、浮点类型之间可以相互显式转换, 整数类型也可以转换成目标字符类型, 但 都需要遵循类型转换的语法规则
浮点类型
浮点类型包括
Float16、Float32和Float64, 分别用于表示编码长度为16-bit、32-bit和64-bit的浮点数(带小数部分的数字, 如3.14159、8.24和0.1等)的类型
Float16、Float32和Float64分别对应IEEE 754中的半精度格式(即binary16)、单精度格式(即binary32)和双精度格式(即binary64)
Float64的精度(有效数字位)约为15位,Float32的精度(有效数字位)约为6位,Float16的精度(有效数字位)约为3位使用哪种浮点类型, 取决于代码中需要处理的浮点数的性质和范围
在多种浮点类型都适合的情况下, 首选精度高的浮点类型, 因为精度低的浮点类型的累计计算误差很容易扩散, 并且它能精确表示的整数范围也很有限
浮点数, 即小数
目前, 绝大多数的现代编程语言对于浮点数的规定都遵循IEEE 754标准
针对不同的浮点精度, 仓颉中存在三种浮点类型:Float16``Float32``Float64, 分别对应 半精度、单精度和双精度
对应的有效位精度为3位、6位和15位
这是什么意思呢?
精度的位数, 表示浮点数可靠位数, 包括整数位和小数位
如果存在一个浮点数字面量:123.1234567890123456789
那么, 将此字面量赋值到三种不同的浮点类型时, 数据位的可靠程度是不同的:
-
Float16:let half: Float16 = 123.1234567890123456789println(half.format(".20")) -
Float32:let single: Float32 = 123.1234567890123456789println(single.format(".20")) -
Float64:let double: Float64 = 123.1234567890123456789println(double.format(".20"))
这三个变量打印的结果是不同的:
打印结果截图
可以看到:
-
对于
Float16, 对于整个十进制数, 只有5位是准确的:3位整数,2位小数 -
对于
Float32, 对于整个十进制数, 有8位是准确的:3位整数,5位小数 -
对于
Float64, 对于整个十进制数, 有16位是准确的:3位整数,13位小数
为什么与文档不保持一致呢?
答案其实很简单, 因为文档的精度, 说明的是绝对准确的位数, 而打印的数据后面几位可能并不是绝对的精准, 显示只是在不精准之后, 恰好”精准”了
如果数据变了, 可能打印出来的”精度”可能就会变化, 但 前3``6``15位的精度是绝对的
所以使用浮点数时, 要按照精度进行使用
精度并不仅表示小数位精度, 而是指整个完整的浮点数, 包括整数部分和小数部分
NOTE仓颉中, 使用
println直接打印浮点类型数据, 默认最多保留6位小数:let value = 123.1234567890println(value)但可以通过
FloatN.format()接口, 调整输出小数位不过在使用前需要导入
std.convert.Formattable接口import std.convert.Formattablelet value = 123.1234567890println(value.format(".10"))
浮点类型字面量
浮点类型字面量有两种进制表示形式: 十进制、十六进制
在十进制表示中, 一个浮点字面量至少要包含一个整数部分或一个小数部分, 没有小数部分时必须包含指数部分(以
e或E为前缀, 底数为10)在十六进制表示中, 一个浮点字面量除了至少要包含一个整数部分或小数部分(以
0x或0X为前缀), 同时必须包含指数部分(以p或P为前缀, 底数为2)下面的例子展示了浮点字面量的使用:
let a: Float32 = 3.14 // a is 3.140000 with type Float32let b: Float32 = 2e3 // b is 2000.000000 with type Float32let c: Float32 = 2.4e-1 // c is 0.240000 with type Float32let d: Float64 = .123e2 // d is 12.300000 with type Float64let e: Float64 = 0x1.1p0 // e is 1.062500 with type Float64let f: Float64 = 0x1p2 // f is 4.000000 with type Float64let g: Float64 = 0x.2p4 // g is 2.000000 with type Float64在使用十进制浮点数字面量时, 可以通过加入后缀来明确浮点数字面量的类型, 后缀与类型的对应为:
后缀 类型 f16Float16f32Float32f64Float64加入了后缀的浮点数字面量可以像下面的方式来使用:
let a = 3.14f32 // a is 3.140000 with type Float32let b = 2e3f32 // b is 2000.000000 with type Float32let c = 2.4e-1f64 // c is 0.240000 with type Float64let d = .123e2f64 // d is 12.300000 with type Float64
仓颉的浮点类型字面量, 除了一般的十进制小数之外, 十进制和十六进制浮点数均可分为: 整数部分、小数部分和指数部分, 指数部分与前两部分相乘
十进制, 还可以使用e/E表示指数部分(没有小数部分时, 指数部分为必须), eN表示以10为底的N次幂, N为整数
十六进制, 则必须存在使用p/P表示指数部分, pN表示以2为底的N次幂, N为整数
浮点类型支持的操作
浮点类型默认支持的操作符包括: 算术操作符、关系操作符、复合赋值操作符
浮点类型不支持自增和自减操作符
浮点类型之间、浮点类型和整数类型之间可以互相转换, 具体的类型转换语法及规则请参见数值类型之间的转换
布尔类型
布尔类型使用
Bool表示, 用来表示逻辑中的真和假
布尔类型字面量
布尔类型只有两个字面量:
true和false下面的例子展示了布尔字面量的使用:
let a: Bool = truelet b: Bool = false
布尔类型支持的操作
布尔类型支持的操作符包括: 逻辑操作符(逻辑非
!, 逻辑与&&, 逻辑或||)、部分关系操作符(==和!=)、部分复合赋值操作符(&&=和||=)
布尔类型支持的操作, 基本都是关系和逻辑操作符
布尔类型禁止与其他类型发生类型转换