跳到主要内容

类型

在 nature 中每一个变量都有一个数据类型,不同的类型在内存中占用的大小是不相同的。类型分为简单类型与复合类型。

简单类型

关键字存储大小 byte说明
int-有符号整型,与运行平台的 cpu 位宽一致,比如 64 位下 int 占用 8byte = 64bit
i81有符号整型
i162有符号整型
i324有符号整型
i648有符号整型
uint-无符号整型,与目标平台 cpu 位宽 一致
u81无符号整型
u162无符号整型
u324无符号整型
u648无符号整型
float-浮点数,与执行平台的 cpu 位宽一致,比如 64 位 cpu 下占用 8byte, 与 f64 一致
f324单精度浮点数
f648双精度浮点数
bool1布尔类型,值有 true 和 false

bool 类型的值是小写的 true 和 false。

警告

在 64 位系统下,c 语言的 float = f32, 而 nature 中 float = f64

由于简单类型在堆外存储,所以其在各种赋值操作,函数参数传递等操作时都是值传递

复合类型

复杂类型可以理解为由简单类型组合并内置在 nature 中的结构,其不需要手动定义,比如 string 类型,其就是由多个 u8 类型组成。

大部分复合类型的主体都存储在了堆中,堆外存储的是指针。存储在 heap 中类型在各种赋值操作,函数参数传递等操作时都是引用传递,也就是传递了指针,不会修改或复制堆上的数据

类型名称存储位置关键字示例说明
stringheapstringstring str = 'hello world'
vecheap[T][int] list = [1, 2, 3, 4]
mapheap{T:T}{int:string} map = {1: 'a', 2: 'b'}key 类型仅支持 integer/float/string
setheap{T}{int} set = {1, 2, 3, 4}
tupheap(T)(int, bool) t = (1, true)
fnheapfn(T):Tfn(int,int):int f = fn(int a, int b):int {}
structstackstruct {}
arrstackarr<T,len>arr<u8,12> array = [1, 2, 3, 4]
信息

这里主要演示类型的定义方式,具体使用将会在后续章节说明。另外如果是变量声明的话推荐用 var 关键字进行类型推导,上面是演示示例所以直接使用了类型声明。

特殊类型

self

在结构体中直接声明函数时,用来引导结构体自身,示例

type square = struct {
int length
int width
var area = fn(self s):int {
return s.length * s.width
}
}

此时 self 等同于 ptr<square>

ptr

安全指针,nature 中目前不支持对变量的取指针操作,所以使用的场景有限,主要用于和 c 语言进行交互。使用示例

type person = struct {}
ptr<person> = new person // v 通过 new 关键字进行实例化 person, 此时 person 将会在堆中进行初始化
ptr<person> = null // x, 安全指针不允许赋值为 null

any

语法示例

int foo = 1
int bar = 2
any car = foo // v 这里发生累隐式类型转换,将 int 类型的 foo 转换成了 any 类型
int baz = car // x any 时复合类型,不能赋值给 int 类型的 baz 变量,这里需要借助类型断言来进行赋值
int baz = car as int // v as 此时表示 assert 类型断言,其与类型转换共用关键字 as

bool isint = car is int // v 使用 is 关键字可以对 any/联合类型当前的实际存储类型进行判断

联合类型

int|null foo = null
foo = 1

联合类型本质就是 any,只是具有更小的选择范围。再范围包含的情况下,可以允许大范围的联合类型赋值给小范围的联合类型,如

int|float foo = null
int|float|null bar = foo // v bar 的类型范围大于 foo

int|null baz = bar // x bar 的类型范围大于 baz, 所以不允许赋值

any car = baz // v any 包含所有类型,所以可以接受任意值

null

null 的类型定义和值都是关键字 null

cptr

一种通用的指针类型,指针的本质就是 uint64 类型。ctpr 和 c 语言的 void* 是类似的东西,所以常用于与 c 语言进行交互。 比如

string s = 'hello world'
cptr p = s.ref() // 得到的就是一个 cptr

cptr a = 0 as cptr // 任何类型都可以转换为 cptr 类型

null 指针 cptr<T>

cptr<T>ptr<T> 的特殊形式,其支持赋值为 null, 其本质类似与 ptr<T>|null 但是在内存结构上与 union type 不同。其至占用 8byte 长度。

type person = struct {
string name
}

ptr<person> p = new person{}
cptr<person> p2 = null // v
cptr<person> p3 = p // v

println(p2.name) // v
println(p3.name) // x, cptr 需要经过 as 断言才能够使用

let p3 as ptr<person> // v
println(p3.name) // v

let p3 as null // v, 但是会出现运行时错误

类型别名

type myint = int

使用关键字 type 可以定义类型别名,一般与 struct 组合使用。类型别名同样也支持参数,如

type nullable<t0> = t0|null

后续在泛型中会再次见到类型参数的使用。

类型转换

nature 暂时不支持隐式类型转换。请使用 expr as type 的方式进行显示的类型转换。如 bool a = 12 as bool

字面量类型

var foo = 1 // 字面量 1 默认为 int 类型
u8 bar = 1 // 由于字面量 1 在赋值时判断到 bar 为 u8 类型,且字面量范围符合 u8 范围,所以此时 1 默认为 u8 类型,并不需要进行类型转换。

u8 bar = 0x1A // 16 进制字面量

var car = 1.1 // 字面量浮点型默认为 float 类型

var baz = true // bool 类型
var baq = false // bool 类型

💡 暂时不支持 2 进制字面量与 8 进制字面量

字符串

nature 可以通过单引号或者双引号来包裹字符串,推荐使用单引号更加简洁。

这是声明一个字符串字面量的示例

var str = 'hello world' // 此时 str 是 string 类型, 等同于 string str = 'hello world'

字符串转义

无论是单引号还是双引号都会对字符串进行转义操作, 例如 println('hello\nworld') 编译输出将会得到

> ./main
hello
world#

目前支持的转义字符有

\': 单引号字符
\": 双引号字符
\\: 反斜杠字符
\n: 换行符
\r: 回车符
\t: 制表符(Tab键)
\b: 退格符(光标左移一格)
\f: 换页符
\v: 垂直制表符
\a: 响铃符(发出一声“哔”)
\0: 空字符(NULL字符,ASCII码为0)

字符串运算

可以通过逻辑运算符号与比较运算符操作字符串

string s = 'hello world'
string s2 = s + ' one piece'
println(s2) // hello world one piece


// 字符串比较操作
println('hello world' == 'hello world') // true
println('hello world' != 'hello world') // false
println('a' < 'b') // true
println('a' > 'b') // false

字符串处理

字符串和 vec 具有相同的数据解构,所以可以直接对 string 进行类似 vec 的操作,也可以通过 as 进行类型转换。

string s = 'hello world'
(s[1], s[2]) = (s[2], s[1]) // 字符串交换

println(s[0], s[1]) // 可以直接访问 string 中的 item
var l = s as [u8] // 将 string 转换成 [u8] 类型
l[0] = 110 // ascii 编码 n

在与 c 语言交互时,通常需要一个 c 类型的字符串,也就是 \0 结尾的字符串,且不包含 header 信息。可以调用字符串属性方法 ref() 得到 c 语言字符串。其返回一个通用指针类型 cptr

string s = 'hello world'

cptr p = s.ref()

s.ref() 得到的是对原有字符串数据的引用,所以在 c 中修改 p 指针中的数据也会影响字符串 s 中的数据