类型和造型
基本类型
即原子类型
类型
可以用type来查看任意q实体的类型(用short数值类型表示),原子数的返回值都是负数,简单列表的返回值是正数(原子数的类型值跟其简单列表的类型值一样,只是正负数的差别)。普通列表的返回值是0h
q)type `42 -11h q)type (`42;`a;`b) 11h q)type (42;`42) 0h
变量的类型
在q里,不需要显示的声明变量的类型,变量的类型是它的值的类型,重新赋值后类型也会跟值类型变化而变化。
造型($)
$是一个二元操作符,右参是要被转换的原子数,左参是要转换到的类型,左参可以用以下四种方式:
- 类型的短整型值,如整型是6h
- 类型的字符值,如整型是"i"
- 类型的名称符号,如整型是`int
q)6h$4.2 4i q)"i"$4.2 4i q)`int$4.2 4i
$支持左右参数的智能列表处理
q)"b"$0 1 2 011b q)5 6 7h$42 42h 42i 42 q)5 6 7h$4.2 5.2 6.2 4h 5i 6 q)5 6 7h$4.2 5.2 'length
将整数型的无穷数转换成更大范围的类型时,按它们的实际值处理,无穷数只是该类型的最大数,在更大范围的类型里,它也只是个普通值
q)"i"$0Wh 32767i q)"j"$-0Wi -2147483647
字符串、字符->符号
用空符号(`)来作为左参。对于包含空格和特殊字符的符号,无法使用直接定义的方式赋值,而是要通过符号->字符串的方式赋值。
q)`$"z" `z q)`$"Happy Birthday" `Happy Birthday
在转换的过程中,字符串的左右空白会被移除
q)`$" abc " `abc
字符串->数据类型
使用大写的类型的字符名称
q)"I"$"4267" 4267i q)"T"$"23:59:59.999" 23:59:59.999
对于代表日期的字符串,可以支持不同的格式
q)"D"$"2007-04-24" 2007.04.24 q)"D"$"12/25/2006" 2006.12.25 q)"D"$"07/04/06" 2006.07.04
Coercing Types
简单列表的子元素赋值不能更改其类型
q)c:10 20 30 40 q)c[1]:42h 'type
我们可以使用列表的类型来转换值后再赋值
q)c[1]:(type c)$42h q)c 10 42 30 40 q)c[0 1 3]:(type c)$(1.1;42j;0x21) q)c 1 42 30 33
实际上type c=7h,跟我们指定7h作左参没有区别,只不过它是动态的,事先不需要知道它的类型。同样也可用于原子数,但是要将类型转换成正数,因为原子数的type返回值是负的
q)a:10 q)a:(type a)$10i 'type q)a:(neg type a)$10i q)a 10
创建指定类型的空列表
我们可以用()定义一个空列表,但是它是一个普通列表,没有指定任何子元素类型
q)type () 0h
我们可以使用造型来创建指定类型的空列表
q)type `int$() 6h q)type `$() 11h
当我们需要强制类型匹配的时候,指定类型的空列表很有用
q)L:`int$() q)L,:4.2 'type q)L,:4 q)L ,4i
枚举
在造型时,左参是一个代表某种类型的字符型、短整型或者符号。在这一节里,造型将被扩展到用户定义的目标域,提供枚举类型的函数版本。
传统的枚举
传统的枚举的目的是:
- 用一个描述性的名称代替含糊不清的数字,例如"blue"代替3
- 强类型检查,保证只使用允许的值
- 命名空间,同一个名字可以在不同的地方(代表不同的含义)使用而不会造成混淆
数据规范化
数据规范化可以减少重复并保留最少的数据量。例如,有一个文本列表,其文本来自一个固定的数量较少的文本集合,存储这个文本会带来如下问题:
- 每个文本长度的不同使得列表的存储管理更复杂
- 列表里很可能存在大量重复的文本
枚举可以解决以上问题。
q)v:`c`b`a`c`c`b`a`b`a`a`c q)u:distinct v q)u `c`b`a q)k:u?v q)k 0 1 2 0 0 1 2 1 2 2 0 q)u[k] `c`b`a`c`c`b`a`b`a`a`c q)v~u[k] 1b
u和k规范化了v。这样做的目的是空间压缩和速度。假定u的大小是a,u里的符号子元素的最大占用空间是b(个人疑问,不确定kdb+里是symbol列表按固定长度还是实际长度存储symbol?)。对于长度是x的v,其存储空间是
b*x而对于规范化后的u和k,存储空间是
a*b+4*x当x远大于a的时候,后者更节约空间。尤其是子元素占用空间很大的时候
q)v:`ccccccc`bbbbbbb`aaaaaaa`ccccccc`ccccccc`bbbbbbb q)u:distinct v q)u `ccccccc`bbbbbbb`aaaaaaa q)k:u?v q)k 0 1 2 0 0 1另外,从磁盘读写索引列表k是非常快的块操作。
枚举
枚举封装了上述的任意symbol列表的因子分解,其语法是
`u$v
u是一个symbol类型的唯一列表,v是一个原子类型或者原子类型的列表。
使用枚举
定义枚举,实际上保存的是索引列表
q)u:`c`b`a q)v:`c`b`a`c`c`b`a`b`a`a`a`c q)ev:`u$v q)ev `u$`c`b`a`c`c`b`a`b`a`a`a`c
使用枚举的时候就跟使用v一样
q)v[3] `c q)ev[3] `u$`c q)v[3]:`b q)v `c`b`a`b`c`b`a`b`a`a`a`c q)ev[3]:`b q)ev `u$`c`b`a`b`c`b`a`b`a`a`a`c q)v=`a 001000101110b q)ev=`a 001000101110b q)v in `a`b 011101111110b q)ev in `a`b 011101111110b
如果比较v和ev,=和~有不同的结果,=支持智能列表处理而~仅比较本身
q)v=ev 111111111111b q)v~ev 0b
更新枚举
在使用枚举的地方更新同一个值只需要一个操作就可以了,可以大大提高有很多重复的大列表的性能
q)u[1]:`x q)ev `u$`c`x`a`x`c`x`a`x`a`a`a`c q)v `c`b`a`b`c`b`a`b`a`a`a`c
如果要在v上达到同样的效果,需要变更每个地方
q)v[where v=`b]:`x q)v `c`x`a`x`c`x`a`x`a`a`a`c
往枚举里添加新值
往v里添加新值是一个简单的操作而在ev里则不一样,你不能直接添加一个新值(新值指的是不在u里面的值),必须先加到u里才能再加到ev里。但是我们往ev里加一个值的时候并不知道它是否是新值,这时候我们可以用?操作符来解决这个问题,该操作符只有在值不在列表里才会将值加入列表
q)u:`c`b`a q)v:`c`b`a`c`c`b`a`b`a`a`a`c q)ev:`u$v q)v,:`d q)v `c`b`a`c`c`b`a`b`a`a`a`c`d q)ev,:`d 'cast q)u,:`d q)ev,:`d q)ev `u$`c`b`a`c`c`b`a`b`a`a`a`c`d q)u `c`b`a`d q)`u?`a `u$`a q)u `c`b`a`d q)`u?`e `u$`e q)u `c`b`a`d`
还原枚举
可以使用value来还原枚举
q)u:`c`a`b q)v:`c`b`a`c`c`b`a`b`a`a`a`c q)ev:`u$v q)ev `u$`c`b`a`c`c`b`a`b`a`a`a`c q)value ev `c`b`a`c`c`b`a`b`a`a`a`c q)v~value ev 1b
枚举的类型
每个枚举都会被授予一个新的从20开始的数字表示的类型
q)u1:`c`b`a q)u2:`2`4`6`8 q)u3:`a`b`c q)u4:`c`b`a q)type `u1$`c`a`c`b`b`a 22h q)type `u1$`a`a`b`b`c`c 22h q)type `u4$`c`a`c`b`b`a 23h q)type `u2$`8`8`4`2`6`4 24h q)type `u3$`c`a`c`b`b`a 25h
上面从22开始是因为前面已经有枚举了。基于同一个列表的枚举其类型相同,如上述代码里两个基于u1的枚举类型都是22,。另外枚举类型的数字顺序跟列表定义的顺序无关,跟定义枚举的顺序有关,例如u2在u4之前定义但是在u4之后应用于枚举,因此u4的枚举是23而u2的枚举是22。如果右参是一个原子类型,类型是负数
q)type `u1$`a -22h
注意,同一个值基于不同域的枚举是不一样的,即使它们的域是相等的
q)u1~u4 1b q)v:`c`a`c`b`a q)(`u1$v)~`u4$v 0b