Yak语言核心基础:语句、变量与表达式详解
前言
各位开发者朋友,大家好!今天我们正式开启Yak语言的系统学习之旅。Yak语言作为一门兼顾灵活性与高效性的编程语言,其基础语法中的语句、变量和表达式是构建各类程序的核心基石。掌握这些基础内容,是后续深入学习Yak语言并发编程、模糊测试等高级特性的前提。本文将基于官方文档,严谨、细致地为大家拆解Yak语言的语句类型、变量定义与使用、数据类型(基础类型与复合类型)以及运算符与表达式等关键知识点,助力大家夯实Yak语言基础。
从本章节开始,博主将带领大家正式开始Yak语言的学习。本章内容包含Yak语言中语句的类型、变量的定义与使用、基本数据类型的定义与使用,复合类型以及Yak语言中出现的运算符和表达式。
3.1 语句类型概览
要了解一个Yak语言基础程序,需要从基本结构开始了解:
- 文件格式 :一个标准的Yak语言程序或者脚本文件,扩展名应该为
.yak。 - 代码构成 :Yak代码由一个或者多个语句构成。其基本的语句之间可以通过"回车"来进行分隔,同时也支持
;符号分隔。
Yak语言的语句主要有十三种类型,每种类型都具有不同的功能,具体如下表所示:
| 语句类型 | 目的 | 案例描述 |
|---|---|---|
| 注释语句 | 提供按行的注释或整块儿注释 | # 号注释 // Comment 普通注释 /* Hello Yak Comment */ 多行注释 |
| 变量声明语句 | 自动或强制创建一个新的变量,对应 YakVM 编译中的一个新符号 | Golang 风格 var abc = 123 强制创建变量 abc := 123 自动创建 abc = 123 |
| 表达式语句 | 执行一个表达式,例如函数调用,数值运算,字符串运算等 | 1+1 "abc".HasPrefix("ab") |
| 赋值表达式运算 | 赋值+表达式的简易写法 | a += 1 |
| 代码块 | 主动创建一个新的定义域,执行若干行语句 | a=1; {a++; a += 12} |
| IF 控制流 | 支持 if / elif / else if / else 风格的 IF 语句编写 |
if a>1 {println("Hello V1ll4n")} |
| Switch 控制流 | 支持 Case 多值短路特性的 Switch 语句,与 break / fallthrough 配套 |
switch a {case 1,2,3: println("Hello")} |
| FOR IN 循环语句 | Python 风格的 For In 语句技术实现 | for a in [1,2,3] {println(a)} |
| FOR RANGE 循环语句 | Golang 风格的 For Range 语句技术实现 | for _, a = range [1,2,3] {println(a)} |
| FOR 循环控制 | 经典的 C 风格三语句 FOR 循环 | for i = 1; i < 10; i ++ {println(i)} for {println("无限循环")} |
| Defer 延迟执行语句 | Golang 风格的在函数或执行体结尾执行的语句块儿或者函数调用 | defer func{ if recover() != nil { println("Catched") }} |
| Go 并发语句 | Golang 风格的并发语句 | go server.Start() |
| ASSERT 断言语句 | 用以快速检查程序中是否有失败的问题 | assert 1+1 == 2, "计算失败" |
博主在后续的章节中会为大家详细介绍这些语句的使用,因此读者并不需要在这一小节完全理解各个语句的实例,有一个大概的印象即可。
3.2 变量与基本数据类型
变量和基本数据类型是编程语言的核心概念,它们对于一门编程语言的功能和表达能力至关重要。
3.2.1 变量的定义和使用
在编程中,变量是一个相当重要的概念,是存储和引用数据的标识符。它允许编程者在程序中存储值,并根据需要对这些值进行操作和更改,同时在程序中进一步跟踪和操作数据。在Yak语言中,变量的定义和使用非常简单和直观。本章将详细介绍如何在Yak语言中定义、声明和使用变量。
变量的定义
在Yak语言中,要定义一个变量,编程者可以使用var作为关键词,var后使用空格作为分隔符,再写入变量名即可完成变量的声明。变量名可以是数字,字母和下划线组合,但是必须以字母或下划线作为开头。以下是一些具体示例:
yak
var a // 声明变量a
var b, c // 声明变量b和c
var d, e = 1, 2 // 声明变量d和e,并分别赋值为1和2
根据上述示例:代码中声明了四个变量:a、b、c、d和e;用户可以选择只声明变量而不赋初值,也可以在声明时直接赋初值;根据第三行的案例,用户也可以使用一个关键字var后跟两个变量(使用,)作为分隔,可以同时声明两个变量,并同时为其赋值。
变量的赋值
在声明变量并赋值的过程中,用户使用到了本书第一个操作符"赋值操作符",写作一个=符号。这个符号的意义就是把右边的"值"传递给左边的"标识符"中。
注意 :这个
=符号并不是数学中的"等于",在计算机科学中,一般使用==作为"等于"使用。
在没有var修饰的时候,赋值符=会为左边的"标识符"自动创建一个变量。这是Yak语言的一个非常好用的特性:
yak
a = 10 // 将变量a赋值为10
b, c = 20, 30 // 将变量b赋值为20,变量c赋值为30
您可以单独给每个变量赋值,也可以同时给多个变量赋值。赋值操作符将右侧的值分配给左侧的变量。
除了=作为赋值符号的情况,在Yak语言中,:=符号组合也可以作为"赋值"功能使用,因此上述的案例可改写成新的形式:
yak
a := 10 // 将变量a赋值为10
b, c := 20, 30 // 将变量b赋值为20,变量c赋值为30
注意 :
:=的赋值和=自动赋值在某些情况下并不完全等价,我们在"定义域章节"中将会为大家详细介绍他们的区别。
变量的使用
变量的使用非常简单,只需在需要的地方使用变量名即可。例如:
yak
a = 42 // 给变量a赋值为42
result = a + 2 // 使用变量a进行计算,并将结果存储在result变量中
在上述示例中,博主使用变量a进行了计算:+ 2,并将结果存储在了result变量中。
综合讲到的完整的创建变量并赋值、使用变量的行为,我们可以再用一个案例来向大家展示变量的完整用法:
yak
var x, y = 5, 10 // 定义变量x和y,并分别赋值为5和10
sum = x + y // 使用x和y进行计算,并将结果存储在sum变量中
dump(sum) // 打印sum的值
运行上述代码将会在屏幕中输出
(int) 15
这个示例演示了如何在Yak语言中定义、赋值和使用变量,以及如何进行基本的数学计算,希望这能帮助读者更好地理解Yak语言中变量的使用方式。
3.2.2 基础数据类型
计算机在其最基础的层面上处理的数据都是由比特构成的。但为了更高效和直观地表示和处理数据,高级编程语言提供了一系列数据类型。这些数据类型可以理解为对底层比特数据的高级抽象,可以用整数、字符串等直观的方式表示数据,而不仅仅是一堆比特。
Yak语言提供了一系列内置的数据类型,这些数据类型意味着数据的灵活性和多样性,使得编程既能利用硬件的特性,又能便捷地表达多样的数据结构。在Yak语言中,数据类型分为两类:基础数据类型 和复合数据类型。
Yak语言的基本数据类型如下:
int:表示可以带正负号的整数数据类型(在Yak语言中占用的大小为64位);string:用于表示一系列字符数据的,例如:"Hello World"就是一个字符串;float:用于表示浮点数;byte:等同于"无符号8位整数",通常用来表示一个"字节";nil与undefined:一般用于表示一个未定义的变量或者空值;bool:表示"布尔值",其值只有两种情况,true或false;
为了方便用户更直观地理解Yak语言中的基本数据类型,博主创建了一个表格来对比编程语言中常见的基本数据类型:
| 对比类型 | Yak | Python | Golang |
|---|---|---|---|
| 字符串 | string | string | string |
| 二进制字符串 | []byte | b-string | []byte |
| 整数 | int | int | int8, int16, int32, int64 uint8, uint16, uint32, uint64 |
| 浮点 | float | float | float32, float64 (double) |
| 空值 | undefined/nil | 不支持 | nil |
| 布尔值 | bool | bool | bool |
通过以上对比,您可以更轻松地理解和掌握 Yak 的数据类型,并与其他语言进行比较。Yak 通过其丰富的数据类型,为开发者提供了便捷的方式来表达和处理各种数据。无论你需要表示一个简单的数字,还是一个复杂的数据结构,Yak 都能为你提供相应的工具和支持。在下面的章节中,我们将对数据类型进行详细的讲解。
整数与浮点数
Yak语言为开发者提供了简洁而强大的数字类型:整数 (int) 和浮点数 (float)。在这章里,我们将详细地探讨这些数字类型以及如何在 Yaklang 中使用它们。
为了让开发者专注于"表达逻辑",Yak语言在设计中有意避开了"整数和浮点数"的"位数"的概念,这种屏蔽的层实现的设计可以有效避免新手用户被复杂的计算机底层原理干扰。
整数声明
在Yak语言中,声明一个整数十分简单:
yak
var a = 10
实际的编程中,除了这种基础声明之外,用户往往会遇到其他的需求,例如声明一个"二进制"、"八进制"或"十六进制"的整数;在Yak语言中,用户可以直接声明一个非十进制的整数,可以参考如下案例:
yak
// 二进制声明
a = 0b10
println(a) // 输出: 2
// 八进制声明
b = 0100
println(b) // 输出: 64
// 普通整数声明(十进制)
c = 100
println(c) // 输出: 100
// 十六进制声明
d = 0x10
println(d) // 输出: 16
在声明一个非十进制整数的时候,用户只需要记住几个前缀即可:
0b:意味着声明二进制整数0x:意味着声明一个十六进制整数- 单独一个
0:意味着声明一个八进制整数
浮点数声明
与整数相似,浮点数的声明也非常直观和简单。
yak
a = 1.5
println(a) // 输出: 1.5
b = a / 0.5
println(b) // 输出: 3.0
数学运算
Yak语言提供了一整套基础的数学运算,用户可以以此对数字进行加、减、乘、除和取余等操作:
yak
println(2 + 2) // 输出: 4
println(50 - 5*6) // 输出: 20
println(8 / 5) // 输出: 1
println(17 % 3) // 输出: 2
整数与浮点的互操作
在Yak语言中,当整数和浮点数一起运算时,整数会被先转换为浮点数,再进行运算,这就意味着运算的结果将是一个浮点数:
yak
a = 5 / 2.0
println(a) // 输出: 2.5
printf("%T", a) // 输出: float64
这种设计选择的好处是保证了数值计算的准确性和一致性,无论操作数是整数还是浮点数。
布尔值类型
在Yak语言中,布尔值只有两种可能的常量:true和false。这些值通常用于表示逻辑条件的真或假。以下是一个最基本的使用:
yak
a = true
b = false
if a && b {
println("won't go here")
} else if a || b {
println("true || false == true")
}
虽然至此读者并没有正式学习if语句,但是上述代码案例并不影响读者理解true和false的含义。需要用户注意的是:与某些语言不同,Yak语言中的布尔值并不能直接与数值进行算术运算,因此true + 1在Yak语言中一般被视为"非法"。
空值:nil 与 undefined
Yak语言中引入"空值"的概念,一般来说,用户在遇到nil和undefined的时候,它们之间并没有区别,被视为等价即可,用户可以使用两个词来表示同一个概念:"这个变量没有值"。以下是一个典型案例:
yak
a = nil
println(a == undefined) // 输出: true
println(b == nil) // 输出: true
如上例所示,尝试访问一个未声明的变量将返回nil(或undefined),这为开发者提供了一个便捷的方法来检查一个变量是否被赋值。
字符声明
Yak语言可使用单引号来声明一个字符:使用单引号声明字符,双引号声明字符串,这样可以直观地区分字符和字符串,提高代码的可读性:
yak
c = 'c'
println(c) // 输出: 99 (ASCII 值)
注意 :本质上单个字符的底层类型是
uint8。
字符串
在编程语言中,字符串的处理是核心部分。Yak语言中的字符串处理吸收了众多语言的最佳实践,同时加入了一些独一无二的特性,读者可以在本节中深入理解Yak语言中的字符串处理的强大能力:
经典字符串声明
与大多数编程语言的行为一致,Yak可以使用双引号来声明字符串,这种声明方式简单直观,初学者可以轻易上手:
yak
println("Hello World")
当涉及到换行、制表符或其他特殊字符时,可以使用反斜杠\进行转义。例如\n表示换行,而\t表示制表符。此外,也支持直接输入字符的ASCII码,提供了另一种方式来插入特殊字符:
yak
println("Hello \nWorld")
/*
Output:
Hello
World
*/
文本块声明
当处理多行字符串时,经典的转义方式可能会显得冗长。为了解决这一问题,Yak语言引入反引号 ````` 作为文本块的界定符。读者可以观察如下案例:
yak
abc = `Hello World
Hello Yak`
println(abc)
/*
Output:
Hello World
Hello Yak
*/
在这个案例中,用户没有输入\n的转义符号也可以成功换行。不仅可以轻松处理多行字符串,还省去了每行的转义工作,大大增强了代码的可读性。
字节序列
除了传统的字符串处理,Yak语言还十分注重字节数据的处理。在声明一个字符串之前使用b前缀修饰,可以创建一个字节序列:
yak
name = b"Hello World\r\nHello Yak"
dump(name)
/*
OUTPUT:
([]uint8) (len=22 cap=24) {
00000000 48 65 6c 6c 6f 20 57 6f 72 6c 64 0d 0a 48 65 6c |Hello World..Hel|
00000010 6c 6f 20 59 61 6b |lo Yak|
}
*/
这种声明方式本质上是把字符串当做一个字符数组来对待,读者从dump的输出结果中就可以看出,这个字符串的原始字符编码也会被展示出来。这种声明方式非常适用于处理网络数据包,文件I/O等场景中的"原始数据"。
字符串格式化
Yak语言使用%进行基本的字符串格式化。% 是一种传统的格式化字符串的方法,称为字符串插值(string interpolation)。在Yak语言之外的许多编程语言中都有使用,例如 C、C++、Python 等。% 格式化语法允许你在字符串中插入变量的值,从而创建动态字符串。这使得字符串的格式化变得既直观又灵活,同时,还支持数组和其他数据结构的直接输入。以下是使用 % 进行格式化的基本语法:
- 在字符串中,使用
%符号作为占位符,后跟一个或多个格式说明符,例如%d(整数)、%f(浮点数)或%s(字符串)。 - 在字符串之后,使用
%符号和括号(可选,用于多个变量)包含要插入的变量。
以下是一些使用 % 进行格式化的示例:
yak
printf("Hello I am %d years old\n", 18)
println("Hello %v + %05d" % ["World", 4])
/*
OUTPUT:
Hello I am 18 years old
Hello World + 00004
*/
根据案例,Yak语言触发代码格式化的写法主要有两种:
- 使用传统的
printf函数进行触发,第一个参数为需要格式化的字符串模版,其余参数为可变参数,是格式化字符串的"材料"; - 使用
%格式化操作符来操作:%左边为需要格式化的模版,右边为一个格式化字符串的"材料",例如"Hello %v" % "World";如果有多个需要格式化的点,那么需要使用[]来包裹,并用逗号分隔元素,例如:"My name is %v, I am %d years old" % ["John", 18]。
读者可能注意到了,Yak语言在字符串模版中可以使用%v之类的组合来标记需要字符串格式化的位置和格式,以下是在编程中常用的一些案例,用户可随时查阅并动手实践:
| 项 | 解释 | 代码示例 |
|---|---|---|
%v |
根据变量的类型自动选择格式 | printf("Default format: %v\n", p) |
%T |
输出变量的类型 | printf("Type of variable: %T\n", p) |
%d |
十进制整数 | printf("Decimal integer: %d\n", 42) |
%b |
二进制整数 | printf("Binary integer: %b\n", 42) |
%o |
八进制整数 | printf("Octal integer: %o\n", 42) |
%x |
十六进制整数,使用小写字母 | printf("Hexadecimal integer (lowercase): %x\n", 42) |
%X |
十六进制整数,使用大写字母 | printf("Hexadecimal integer (uppercase): %X\n", 42) |
%f |
浮点数,不带指数部分 | printf("Floating-point number: %f\n", 3.141592) |
%c |
ASCII码对应的字符 | printf("Character: %c\n", 65) |
%q |
带引号的字符或字符串 | printf("Quoted character: %q\n", 65) |
%s |
字符串 | printf("String: %s\n", "Hello, world!") |
%p |
输出十六进制表示的内存地址或引用 | printf("Pointer: %p\n", &p) |
字符串模版字面量:f-string
Yak 语言中的 f-string(格式化字符串字面量)是一种方便的字符串插值方法,允许在字符串中直接使用表达式。这种方法可以让你轻松地将变量和表达式的值嵌入到字符串中,而无需使用复杂的字符串拼接或格式化函数。以下是一个简化的解释和示例:
-
定义变量: 在示例中,我们定义了两个变量,
a和name。a的值为"World",而name的值为"Yak"。yaka = "World" name = "Yak" -
使用f-string: 要使用f-string,需要在字符串的前面加上一个小写的
f,然后在字符串内部用${}包裹需要插入的表达式。在这个例子中,我们将在字符串中插入变量a和name的值。yakprintln(f`Hello ${a}, Hello ${name}`) -
输出结果: 这段代码将输出
"Hello World, Hello Yak"。这是因为 f-string 会将${a}替换为变量a的值,将${name}替换为变量name的值。OUTPUT: Hello World, Hello Yak
Yak语言中的f-string提供了一种简单直观的字符串插值方法,使得在字符串中嵌入变量和表达式的值变得非常简单。只需在字符串前加上一个小写的 f,并用 ${} 包裹需要插入的表达式即可。
Fuzztag快速执行:x-string
注意:本小块内容在fuzztag的专门章节中会详细介绍,此处只做简略叙述。
为了更好地支持模糊测试,Yak 语言引入了 x-string(fuzztag扩展语法)。这种独特的字符串处理方式能够快速生成一系列基于模板的字符串,大大加速了模糊测试的流程:
在这个例子中,我们使用 x-string 创建一个模板,该模板将生成一个包含 1 到 10 之间的整数的字符串:
yak
a = x"Fuzztag int(1-10): {{int(1-10)}}"
dump(a)
字符串运算
与许多编程语言相似,Yak 语言也采用加号 + 来进行字符串的连接。以下是一个简单的示例:
yak
a = "Hello, "
b = "Yak"
println(a + b) // 输出:Hello, Yak
受 Python 语言的启发,Yak 语言引入了星号 * 操作,允许将字符串重复 N 次。以下是一个示例:
yak
a = "powerful "
println(a * 5 + "yak") // 输出:powerful powerful powerful powerful powerful yak
Yak 语言使用索引和切片操作来创建字符串"切片"。通过方括号 [] 和下标,你可以轻松地获取子字符串或子元素。以下是一些示例:
yak
a = "Hello, Yak"
println(a[0]) // 输出:H
println(a[1:5]) // 输出:ello
println(a[3:0:-1]) // 输出:lle
现在,扩展这个示例,包括 a[1:] 和 a[:3] 这样的用法,以详细介绍索引操作在 Yak 语言中的应用。
省略结束索引,表示从开始索引一直到字符串末尾:
yak
a = "Hello, Yak"
println(a[1:]) // 输出:ello, Yak
省略开始索引,表示从字符串开头到结束索引(不包括结束索引):
yak
a = "Hello, Yak"
println(a[:3]) // 输出:Hel
使用负数索引,表示从字符串末尾开始计算:
yak
a = "Hello, Yak"
println(a[-3:]) // 输出:Yak
在这些示例中,我们展示了如何在 Yak 语言中连接字符串、重复字符串以及使用索引和切片来截取子字符串。这些功能使得处理字符串变得简单且直观,为学习和使用 Yak 语言的用户提供了便利。
字符串内置方法
为了使字符串处理更加高效,Yak语言引入了一系列内置方法。这些方法类似于Python,但进行了必要的优化和扩展,使其更符合Yak语言的设计哲学。
在这里,我们将介绍一些关于字符串类型的常用内置方法及示例。在这些示例中,我们将使用assert语句来确保示例代码的正确性。assert语句用于测试表达式的值,如果表达式为真,则程序继续执行;如果为假,则程序抛出异常并终止。这是一种简便的检查代码正确性的方法。
-
反转字符串:将字符串进行反序。
yakassert "abcdefg".Reverse() == "gfedcba" -
是否包含:判断字符串是否包含子字符串。
yakassert "abcabc".Contains("abc") == true assert "abcabc".Contains("qwe") == false -
替代:替代字符串中的子字符串。
yakassert "abcabc".ReplaceN("abc", "123", 1) == "123abc" assert "abcabc".Replace("abc", "123") == "123123" -
分割:将字符串根据子串进行分割,得到数组。
yakassert "abc1abc".Split("1") == ["abc", "abc"] -
连接:使用特定的字符串连接数组。
yakassert "1".Join(["abc", "abc"]) == "abc1abc" -
移除前后特定字符:
yakassert "pabcp".Trim("p") == "abc" -
转换为大写:
yakassert "hello".Upper() == "HELLO" -
转换为小写:
yakassert "HELLO".Lower() == "hello" -
计算子字符串出现的次数:
yakassert "abcabc".Count("abc") == 2 -
查找子字符串首次出现的位置:
yakassert "abcabc".Find("abc") == 0 assert "abcabc".Find("qwe") == -1
通过这些示例,读者应该大致了解Yak语言中字符串处理的大部分常用功能。这些内置方法简化了字符串操作,使其更加直观和易于理解。
包含上述描述的例子,博主把Yak语言的字符串处理方法整理成表格,以便读者随时查阅:
| 方法名称 | 代码案例 | 简要描述 |
|---|---|---|
| First | assert "hello".First() == 'h' |
获取字符串第一个字符 |
| Reverse | assert "hello".Reverse() == "olleh" |
倒序字符串 |
| Shuffle | newStr = "hello".Shuffle() |
随机打乱字符串 |
| Fuzz | results = "hello".Fuzz({"params": "value"}) |
对字符串进行模糊处理 |
| Contains | assert "hello".Contains("ell") == true |
判断字符串是否包含子串 |
| IContains | assert "Hello".IContains("ell") == true |
判断字符串是否包含子串(忽略大小写) |
| ReplaceN | assert "hello".ReplaceN("l", "x", 1) == "hexlo" |
替换字符串中的子串(指定替换次数) |
| ReplaceAll | assert "hello".ReplaceAll("l", "x") == "hexxo" |
替换字符串中所有的子串 |
| Split | assert "hello world".Split(" ") == ["hello", "world"] |
分割字符串 |
| Join | assert " ".Join(["hello", "world"]) == "hello world" |
连接字符串 |
| Trim | assert " hello ".Trim(" ") == "hello" |
去除字符串两端的cutset |
| TrimLeft | assert " hello ".TrimLeft(" ") == "hello " |
去除字符串左端的cutset |
| TrimRight | assert " hello ".TrimRight(" ") == " hello" |
去除字符串右端的cutset |
| HasPrefix | assert "hello".HasPrefix("he") == true |
判断字符串是否以prefix开头 |
| RemovePrefix | assert "hello".RemovePrefix("he") == "llo" |
移除前缀 |
| HasSuffix | assert "hello".HasSuffix("lo") == true |
判断字符串是否以suffix结尾 |
| RemoveSuffix | assert "hello".RemoveSuffix("lo") == "hel" |
移除后缀 |
| Zfill | assert "42".Zfill(5) == "00042" |
字符串左侧填充0 |
| Rzfill | assert "42".Rzfill(5) == "42000" |
字符串右侧填充0 |
| Ljust | assert "hello".Ljust(7) == "hello " |
字符串左侧填充空格 |
| Rjust | assert "hello".Rjust(7) == " hello" |
字符串右侧填充空格 |
总结
本文围绕Yak语言的核心基础展开,从语句类型、变量定义与使用,到基础数据类型的详细解析,为大家搭建了Yak语言入门的知识框架。
语句作为Yak程序的基本组成单元,涵盖了注释、变量声明、控制流等十三类核心类型,不同语句各司其职,共同支撑起程序的逻辑结构。变量作为数据的载体,其定义方式灵活多样,var声明、=自动创建、:=强制创建三种方式可适配不同的开发场景,而赋值操作的语法细节也需要大家重点区分。
基础数据类型则是Yak语言处理数据的基石,整数支持多进制声明、浮点数运算自动类型转换、布尔值严格区分逻辑与数值,这些特性都体现了Yak语言的易用性。尤其是字符串类型,融合了多种语言的优势,支持经典声明、文本块、字节序列三种定义方式,搭配格式化语法、丰富的运算操作和内置方法,能够高效应对各类字符串处理需求。
掌握这些基础内容,不仅能帮助大家编写简单的Yak程序,更是后续学习并发编程、模糊测试等高级特性的关键前提。希望大家能够通过实操加深理解,为后续的Yak语言进阶学习打下坚实的基础。