Skip to content

Latest commit

 

History

History
1529 lines (1166 loc) · 43.3 KB

File metadata and controls

1529 lines (1166 loc) · 43.3 KB

目录

变量、赋值语句

概述

赋值语句用于设置变量储存的值。

变量类似于记分项,但不局限于储存分数,它可以储存所有基本数据类型允许的值,即整数、布尔值、浮点数和字符串。
赋值语句则类似于记分板设置分数的指令,该语句用于将变量储存的值设置为指定的整数、布尔值、浮点数或字符串。

赋值语句的语法如下。

变量名 = 表达式

这意味着等号的左侧是变量名,等号的右侧是表达式
变量名指的是变量的名字,它类似于记分板中虚拟玩家的名字。

在运行代码时,等号右侧的表达式会被求值,得到一个整数、布尔值、浮点数或字符串。
然后,把这个求值结果保存到变量名指向的变量中。
我们把这样的先求值,再将求值结果保存到变量的操作称为赋值操作

注意,在所有情况下,您都只能通过变量名来获取或更新变量的值。
另外,在下面给出的示例中,大多数空格都不是必须的,这只是为了让代码更美观。

示例一

将变量 a 的值设置为整数 1

a = 1

示例二

首先将变量 a 的值设置为整数 1。
然后将变量 b 的值设置为 a 加 1 的值,也就是 2

另外,您可以发现这实际上是两条赋值语句。
第一条对变量 a 进行赋值,第二条则对变量 b 进行赋值。

a = 1
b = a + 1

示例三

var_a = 0
var_b = +0
var_c = -0
var_d = 1
var_e = +1
var_f = -1

var_g = True
var_h = False

var_i = 0.0
var_j = +0.0
var_k = -0.0
var_l = 1.5
var_m = +1.5
var_n = -1.5

var_o = ''
var_p = '我想玩电脑'

在执行上面的代码后,对应变量储存了以下的数据。

变量名 储存的数据 储存的数据的数据类型
var_a 0 整数
var_b 0 整数
var_c 0 整数
var_d 1 整数
var_e 1 整数
var_f -1 整数
变量名 储存的数据 储存的数据的数据类型
var_g True 布尔值
var_h False 布尔值
变量名 储存的数据 储存的数据的数据类型
var_i 0.0 浮点数
var_j 0.0 浮点数
var_k 0.0 浮点数
var_l 1.5 浮点数
var_m 1.5 浮点数
var_n -1.5 浮点数
变量名 储存的数据 储存的数据的数据类型
var_o '' 字符串
var_p '我想玩电脑' 字符串

示例四

part_a = 'tag=回城'
part_b = 'tag=!op'
scoreboard = '音效分数'
my_score = {score, '@s['+part_a+']', scoreboard}
my_name = {selector, '@s['+part_a+','+part_b+']'}

上面的代码首先按顺序赋值了下面几个变量。

变量名 变量储存的数据 变量储存的数据的数据类型
part_a tag=回城 字符串
part_b tag=!op 字符串
scoreboard 音效分数 字符串

然后,获取 '@s['+part_a+']' 在记分板 scoreboard 的分数,
也就是 @s[tag=回城] 在记分板 音效分数 的分数。
获取到的这个分数最终将会保存在变量 my_score 中。

最后,将 '@s['+part_a+','+part_b+']' 指示的实体解析为实体名,
也就是把 @s[tag=回城,tag=!op] 指示的实体解析为实体名。
解析出的这个实体名最终会保存在变量 my_name 中。

另外,您可能发现了我们没有使用下面的写法。

my_score = {score, '@s[tag=回城]', '音效分数'}
my_name = {selector, '@s[tag=回城,tag=!op]'}

这意味着 ScoreSelector 语句都支持将表达式的求值结果作为字符串。

在上面的例子中,'@s['+part_a+']''@s['+part_a+','+part_b+']' 都是表达式,
并且这两个表达式的求值结果分别是 '@s[tag=回城]''@s[tag=回城,tag=!op]'

表达式 求值结果
'@s['+part_a+'] '@s[tag=回城]'
@s['+part_a+','+part_b+'] '@s[tag=回城,tag=!op]'

实际上,对于所有的语句,您都可以在原本填写 字符串/整数/布尔值/浮点数 的地方填写为表达式。
在实际运行代码的时候,这些表达式会被求值,然后被传入对应的语句中,如本例中的 ScoreSelector 语句。

示例五

下面的代码相对于示例三除了变量名发生了变化以外,其他的功能与示例三的是完全相同的。

aaa = 'tag=回城'
bbb = 'tag=!op'
ccc = '音效分数'
my_score = {score, '@s['+aaa+']', ccc}
my_name = {selector, '@s['+aaa+','+bbb+']'}

示例六

下面的代码是示例三的简化版本,但功能与示例三的相比,是基本相同的。
在这个例子中,我们没有像示例三那样拼接出目标选择器的字符串,而是直接写在代码里。

target_a = '@s[tag=回城]'
target_b = '@s[tag=回城,tag=!op]'
scoreboard = '音效分数'
my_score = {score, target_a, scoreboard}
my_name = {selector, target_b}

示例七

下面的代码先将变量 a 赋值为 1。
然后,计算 a+1 的值(也就是2),并把该值作为 a 的新值。
然后,计算 a+2 的值(也就是4),并把该值作为 a 的新值。
最终,变量 a 的值将是整数 4。

a = 1
a = a+1
a = a+2

示例八

下面的代码先将变量 a 赋值为 2333。
然后,计算 a*a/a 的值,得到 2333.0,然后将其作为 a 的新值。
最终,变量 a 的值将是浮点数 2333.0。

a = 2333
a = a*a/a

示例九

ak5 = 'pp' in 'pc'
gpt = 2+2>4 or (7+10)/2<0 and int('50') <= 50 or not ak5
clade = not 23 <= 60 or gpt

在执行上面的代码后,对应变量储存了以下的数据。

变量名 储存的数据 储存的数据的数据类型
ak5 False 布尔值
gpt True 布尔值
clade True 布尔值

小提示

在本编程语言中,大多数地方都可以使用赋值语句
下面列出了几乎所有可能的情况,以及对应的示例。

a0 = {selector, '@p'}               # Selector 语句
b0 = {score, '*', 'coin'}           # Score 语句
c0 = {command, 'say Hello, World!'} # Command 语句
d0 = {ref, int, 0}                  # Ref 语句
e0 = {func, math.sqrt(4)}           # Func 语句

aA = int('1')           # 强制类型转换为整数
bB = bool(1)            # 强制类型转换为布尔值
cC = float('3')         # 强制类型转换为浮点数
dD = str(3.0)           # 强制类型转换为字符串
eE = {func, int('1')}   # 通过 Func 语句强制类型转换为整数
fF = {func, bool(1)}    # 通过 Func 语句强制类型转换为布尔值
gG = {func, float('3')} # 通过 Func 语句强制类型转换为浮点数
hH = {func, str(3.0)}   # 通过 Func 语句强制类型转换为字符串

a_a = True and False    # 逻辑运算
b_b = 1+2*3*4+5         # 常规数学计算
c_c = 50 < 30           # 比较运算

A_A = 'a' + 'BB' + '?'  # 字符串拼接
B_B = 'AAA' * 3         # 字符串重复
C_C = 'a' == 'b'        # 检查字符串相同
D_D = 'a' != 'b'        # 检查字符串不同
E_E = 'a' in 'kkakk'    # 检查字符串包含

result1 = True and False or 30 <= 50        # 表达式
result2 = 1+1==2 and 2+2==4 and 9+9==0      # 表达式
answer1 = 1+(10*3)                          # 含括号的表达式
answer2 = 4*6/12==2 or(8*8==60 and 0*0==0)  # 含括号的表达式

需要说明的是,该编程语言不存在也不支持注释功能。
上方代码中 # 开头的说明仅仅是为了方便读者而设。

注意事项

并非所有的名称都可以作为变量名。

首先,变量名不能以数字开头;
其次,变量名中不能出现标点符号;
最后,变量名不能使用该编程语言的保留关键字。

下面列出了本编程语言的所有保留关键字。

  • int, bool, str, float
  • ref, selector, score, command, func
  • return
  • if, else, elif, fi
  • for, continue, break, rof
  • and, or, not, in
  • True, False

下面这些例子都是不合法的变量名。

  • 233gk5 (变量名以数字开头)
  • wo_de_!jie (变量名中包含标点符号)
  • command (变量名是保留的关键字)
  • True (变量名是保留的关键字)

下面的例子是合法的变量名。

  • command_a
  • command_b
  • True_False
  • ref_0

另外,您可能发现部分标点符号可以出现在变量名中。
这种情况下虽然没有报错,但不保证这样的变量名在未来仍然可以继续有效。

条件语句

概述

条件语句是编程中的一种控制结构,它允许程序根据不同的条件执行不同的代码块。
简单来说,它让程序依照某种方式来作出决定。因此,这赋予了程序可以作出决定的能力。

在本编程语言中,条件语句的语法如下。

if 条件1:
    代码块1
elif 条件2:
    代码块2
elif 条件3:
    代码块3
...
elif 条件N:
    代码块N
else:
    代码块Nfi

首先,条件1条件2、...、条件N 都是表达式。
并且,这些表达式的求值结果都应当是一个布尔值。

在代码被运行时,系统从 条件1 开始,按顺序地检查每个条件是否是 True,直到 条件N
在发现某个条件为 True 时,执行这个条件中的代码块。

代码块由一行或多行代码构成。在对应条件的代码块被执行完毕后,
后方所有的条件都不再被检查是否为 True,并且这些条件中的代码块都不会被执行。

因此您会发现这实际上是某种分支结构。只有其中一个条件中的代码会被执行。
特别地,如果所有这些条件都为 False,则 else 中的代码块 代码块N’ 会被执行。

例如,在上面的例子中,如果 条件1条件2 都是假,而 条件3 为真,则 代码块3 会被执行。
即便后面有条件是真,由于 条件3 已经为真,所以后方的所有条件都不会被处理,并且它们的代码块也不会被执行。

另外,这个写法也是有效的。
它与上面的区别在于它不存在 else,这意味着如果所有条件都是假,则没有代码会被执行。

if 条件1:
    代码块1
elif 条件2:
    代码块2
...
elif 条件N:
    代码块N
fi

还有一种写法是不使用 elif
这个写法指的是当 条件 为真时,执行 代码块1,否则执行 代码块2

if 条件:
    代码块1
else:
    代码块2
fi

还有一种写法是只使用 if
这个写法指的是当 条件 为真时,执行 代码块
如果它不是真,则什么都不会执行。

if 条件:
    代码块
fi

另外,我认为您有必要真正理解 if, elifelse 的中文意思。

英文 中文释义
if 如果
else 否则
elif else if 的缩写。
代表“否则如果”。

也就是说,该编程语言的条件语句实际上类似于下面的东西。

如果 条件1:
    ...
否则如果 条件2:
    ...
否则如果 条件3:
    ...
...
否则如果 条件N:
    ...
否则:
    ...

另外,您会发现上面的 4 个写法中,每个写法的最后一行都是 fi
fi 实际上用来告诉系统,这一整个条件语句已经写完了。

您可以嵌套条件语句,比如下面这个例子。

if 条件1:
    一些代码
    if 条件2:
        一些代码
    elif 条件3:
        一些代码
    fi
    一些代码
elif 条件4:
    一些代码
    if 条件5:
        一些代码
    fi
    一些代码
else:
    一些代码
    if 条件6:
        if 条件7:
            一些代码
        else:
            一些代码
        fi
    fi
    一些代码
fi

下面给出的例子可以帮助您进一步理解。

示例一

a=0
b=1
c=2

if a==0:
    a=a+20.3
fi

if b>0:
    b=b+1
elif b>0:
    b=b-1
elif b<0:
    b=b-1000
else:
    b=1000
fi

if c==0:
    c=c+10
else:
    c=c-10
fi

k=a*b*c
if k>0:
    k=233
fi

上面的代码先对变量 a, bc 进行赋值。

变量名 储存的数据 储存的数据的数据类型
a 0 整数
b 1 整数
c 2 整数

然后进行下面的条件判断。

条件 当条件成立时执行
a==0 a=a+20.3

很显然 a 为 0,因此条件成立,于是 a 会被更新为 20.3。


然后进行下面的条件判断。

条件 当条件成立时执行
b>0 (1) b=b+1
b>0 (2) b=b-1
b<0 b=b-1000
其他所有情况 b=1000

很显然 b 大于 0,因此 b>0 (1) 成立。
并且由于条件判断是按顺序的,并且只会命中一个条件,因此只有 b>0 (1) 会被命中。
因而,只有 b=b+1 被执行,所以 b 会被更新为 2。


然后进行下面的条件判断。

条件 当条件成立时执行
c==0 c=c+10
否则 c=c-10

很显然 c 等于 0 不成立,因此执行 否则 对应的代码,也就是 c=c-10
然后,变量 c 会被更新为 -8。


然后执行 k=a*b*c,使得变量 k 被设置为浮点数 -324.8。


然后进行下面的条件判断。

条件 当条件成立时执行
k>0 k=233

很显然 k 是负数,不大于 0,因此条件不成立,所以 k=233 不会被执行。


最终,在全部代码执行完成后,所有的变量的情况如下。

变量名 储存的数据 储存的数据的数据类型
a 20.3 浮点数
b 2 整数
c -8 整数
k -324.8 浮点数

示例二

time=1000
dinner=25.75
string='hello'

other1=1
other2=10
other3=20

if time > 50*2+899:
    new_str = 'hello2'
    string = string*2 + new_str
else:
    a = 0
    b = 1
    c = 2
fi

if other1 < 0:
    bbc = 0/0
    ggc = string*114514
elif other2 == 10:
    other2 = other2 * 25.25
    other3 = other2 + other3
    temp = '-----'
    string = temp + '/' + string + '/' + str(other3) + '/' + temp
else:
    new_str = 'hello3'
fi

result = str(time) + ' ' + str(dinner) + ' ' + str(string) + ' ' + str(other1+other2+other3)

上面的代码先对变量 time, dinner, string, other1, other2other3 进行赋值。

变量名 储存的数据 储存的数据的数据类型
time 1000 整数
dinner 25.75 小数
string 'hello' 字符串
other1 1 整数
other2 10 整数
other3 20 整数

然后进行下面的条件判断。

条件 当条件成立时执行
time > 50*2+899 new_str = 'hello2'
string = string*2 + new_str
否则 a = 0
b = 1
c = 2

很显然 50 乘以 2 再加上 899 为 999,它比 time 也就是 1000 更小。
因此 否则 不会被执行,而是执行下面的代码。

new_str = 'hello2'
string = string*2 + new_str

于是 new_str 被设置为字符串 'hello2',
string 被更新为字符串 'hellohellohello2'。


然后进行下面的条件判断。

条件 当条件成立时执行
other1 < 0 bbc = 0/0
ggc = string*114514
other2 == 10 other2 = other2 * 25.25
other3 = other2 + other3
temp = '-----'
string = temp + '/' + string + '/' + str(other3) + '/' + temp
其他所有情况 new_str = 'hello3'

系统首先检查 other1 < 0 是否成立。很显然 other 为 1 不小于 0,因此它不成立。
然后,系统检查 other2 == 10 是否成立。很显然 other2 就是 10,因此它成立。

所以,other2 == 10 对应的代码块,也就是下面的代码,将会被执行。

other2 = other2 * 25.25
other3 = other2 + other3
temp = '-----'
string = temp + '/' + string + '/' + str(other3) + '/' + temp

在执行完成后,截止到目前,所有变量的数据如下。

变量名 储存的数据 储存的数据的数据类型
time 1000 整数
dinner 25.75 小数
string '-----/hellohellohello2/272.5/-----' 字符串
other1 1 整数
other2 252.5 浮点数
other3 272.5 浮点数
new_str 'hello2' 字符串
temp '-----' 字符串

最后,执行了该表达式,并将其赋值给变量 result

str(time) + ' ' + str(dinner) + ' ' + str(string) + ' ' + str(other1+other2+other3)

这使得 result 最终会保存下面这个字符串。

'1000 25.75 -----/hellohellohello2/272.5/----- 526.0'

实际上,该表达式先将 time, dinner, string, other1+other2+other3 都强制转换为字符串。
其中,other1+other2+other3 指的是将 other1, other2other3 加起来的结果。

进行强制类型转换的原因是因为字符串只能跟字符串拼接,而不能跟其他数据类型的数据拼接。
在完成强制类型转换后,再将所有东西彼此拼接,并确保彼此之间由一个空格 ' ' 分隔。

示例三

year = 2025
month = 12
day = 31

if month == 1 or month == 3 or month == 5 or month == 7 or month == 8 or month == 10 or month == 12:
    if day == 31:
        if month == 12:
            year = year + 1
            month = 1
        else:
            month = month + 1
        fi
        day = 1
    else:
        day = day + 1
    fi
elif month == 2:
    if year/4==int(year/4) and not year/100==int(year/100) or year/400==int(year/400):
        if day == 29:
            month = 3
            day = 1
        else:
            day = day + 1
        fi
    else:
        if day == 28:
            month = 3
            day = 1
        else:
            day = day + 1
        fi
    fi
else:
    if day == 30:
        month = month + 1
        day = 1
    else:
        day = day + 1
    fi
fi

上面的代码用于根据当天的日期,推出第二天的日期。
例如,如果当天是 2025/12/31,则第二天应该是 2026/01/01


它首先初始化了三个变量的值。

变量名 意义 储存的数据 储存的数据的数据类型
year 表示年份 2025 整数
month 表示月份 12 整数
day 表示日期 31 整数

然后代码先解决大月,也就是 1, 3, 5, 7, 8, 10 和 12 月。
当前是否是大月可以通过下面的表达式来判断。

month == 1 or month == 3 or month == 5 or month == 7 or month == 8 or month == 10 or month == 12

然后,代码通过类似于下面的逻辑判断来确定第二天的日期。

  • 如果今天是 31 号:
    • 如果本月是 12 月:
      • 则第二天是明年的一月一日
    • 否则:
      • 则第二天是下一个月的一号
  • 否则:
    • 则第二天是本月的下一天

现在我们只需要处理小月的情况。但是需要注意的是,二月份是比较特殊的,它与闰年有关。
因此,我们先着手处理二月份的情况。

首先,我们需要了解如何判断闰年。
具体来说,只要满足下面两个中的一个条件,那么就是闰年。

  • 年份可以被 4 整除,且不被 100 整除的是闰年
  • 年份可以被 400 整除的是闰年

于是可以通过这个表达式来判断是否是闰年。
如果是闰年,该表达式的求值结果将为 True,否则为 False

year/4==int(year/4) and not year/100==int(year/100) or year/400==int(year/400)

您可能注意到了,如果一个数 A 可以被 B 整除,那么对于作商结果 C=A/B,总有:

C == int(C)

这是因为它们是整除关系,所以将 C 强制转换为整数后的值和 C 本身是完全一样的。
反之,如果 A 不能被 B 整除,则上面的关系是不成立的。

现在,我们可以判断闰年,于是我们可以计算第二天的日期。

  • 如果今年是闰年:
    • 如果今天是 29 号:
      • 则第二天是三月一号
    • 否则:
      • 则第二天是本月的下一号
  • 否则:
    • 如果今天是 28 号:
      • 则第二天是三月一号
    • 否则:
      • 则第二天是本月的下一号

现在我们处理了二月份这种棘手的情况,于是我们可以处理剩余的小月了。
也就是处理剩下来的 4, 6, 9 和 11 月。
仿照前面处理大月的方式,我们的逻辑判断如下。

  • 如果今天是 30 号:
    • 则第二天是下一个月的一号
  • 否则:
    • 则第二天是本月的下一天

最终,我们成功计算出了第二天的日期。

在本例子中,今天的日期是 20251231 日,
因此代码运行结束后,各个变量的情况如下。

变量名 储存的数据 储存的数据的数据类型
year 2026 整数
month 1 整数
day 1 整数

这意味着我们成功计算出了第二天的日期,也就是 202611 日。

循环语句

概述

正如它的名字一样,循环语句赋予了程序循环执行某段代码的能力。
在本编程语言中,循环语句有一个别名,叫做 For Loop 语句,或者 For 循环语句

下面是循环语句的语法。

for 循环变量, 循环次数:
    循环体
rof

如字面意思,循环次数 指的是代码块 循环体 需要被循环运行的次数。
应注意的是,循环次数 应是一个表达式,并且该表达式的求值结果应是一个整数。

循环变量 则是一个整数,从 0 开始,每新一轮循环开始时不断加一。
这意味着如果循环次数是 8 次,则循环变量将依次取 0, 1, 2, 3, 4, 5, 6 和 7。

循环体 是一个代码块,可以包含一行或多行的代码。
循环体 内,您可以使用 循环变量 的值,也可以通过赋值语句修改它的值。

需要说明的是,循环变量 也是一种变量。只不过它不是通过赋值语句产生的。
但无论它是如何产生的,循环变量 也只能通过它的变量名来获取它的值,也只能通过它的变量名来设置它的值。
并且,循环变量 也遵循赋值语句中提到的,针对 变量 的名称规范。

在部分情况下,循环体 执行到一部分代码时,
您希望不执行剩余的部分,直接进入下一轮循环,则您可以使用 Continue 语句。
这意味着当前轮次的循环将被跳过,剩余的代码将不被执行,而是立即进入下一轮循环。

continue

或者,如果您想终止循环,则您可以使用 Break 语句。
在循环被终止后,循环体 中剩余的代码将不被执行,并且不会有新一轮循环开始。

break

需要注意的是:

  • Continue 语句和 Break 语句都只能在循环语句中被使用
  • 您必须使用 rof 来关闭循环语句(这跟条件语句中必须使用 fi 来关闭是一个道理)

示例一

total = 0
for i, 25:
    total = total + i
rof

您可以看到上面的循环体会被执行 25 次。
在每次执行循环体时,total 的值都会被加上 i

在第一次循环时,total 被加上 0。
在第二次循环时,total 被加上 1。
在第三次循环时,total 被加上 2。
...
在第二十五次循环时,total 被加上 24。

因此,这段代码实际上是在计算 0+1+2+3+...+24 的值。
最终,这个求和的结果会被保存在变量 total 中。

示例二

r=15
a=0
b=1
total=0

for _, r*2:
    temp = a
    a = b
    b = temp + b
    total = total + a
rof

上面的代码用于计算斐波那契数列的前 31 项的和。
斐波那契数列是一个递推数列,定义为每一项等于前两项之和,通常以 0 和 1 作为起始值。
其数列为:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...


上面的代码总共循环 r 乘以 2 次,也就是 15 乘以 2 次,也就是 30 次。
在第 k 轮循环时,变量 a 的值便是斐波那契数列的第 k+1 项。

于是,我们将每次循环后得到的 a 的值加到变量 total 上,
那么在所有循环执行完毕后,total 的值便是斐波那契的前 31 项的和。


在每轮循环完成后,各个变量的结果分别如下。

循环轮次 a 的值 b 的值 total 的值
1 1 1 1
2 1 2 2
3 2 3 4
4 3 5 7
5 5 8 12
6 8 13 20
7 13 21 33
8 21 34 54
9 34 55 88
10 55 89 143
11 89 144 232
12 144 233 376
13 233 377 609
14 377 610 986
15 610 987 1596
16 987 1597 2583
17 1597 2584 4180
18 2584 4181 6764
19 4181 6765 10945
20 6765 10946 17710
21 10946 17711 28656
22 17711 28657 46367
23 28657 46368 75024
24 46368 75025 121392
25 75025 121393 196417
26 121393 196418 317810
27 196418 317811 514228
28 317811 514229 832039
29 514229 832040 1346268
30 832040 1346269 2178308

因此斐波那契的前 31 项的和为 2178308。


另外,您可能注意到了,在这个例子中,循环变量对我们的计算实际上没有帮助。
因此,这个例子使用 _ 作为循环变量,在语义上表示循环变量实际上不会被使用。

注意,这只是语义上的约定。您仍然可以获取 _ 的值,或者通过赋值语句设置它的值。
尽管您可以这么做,但是这是极其不推荐的,因为这会让您的代码失去可读性。

正如上面所说,_ 通常代表循环变量不会被使用,因此您不应该试图获取或设置它的值。

示例三

在基于示例二的基础上,我们希望只计算斐波那契数列中前 31 项中,那些是偶数的和。
实际上,我们有多种方法可以实现这样的功能,让我们观察对应的示例代码。


r=15
a=0
b=1
total=0

for _, r*2:
    temp = a
    a = b
    b = temp + b
    if a/2 == int(a/2):
        total = total + a
    fi
rof

您会观察到我在循环语句中使用条件语句来判断一个斐波那契数是否是偶数。

if a/2 == int(a/2):
    total = total+a
fi

这意味着在每次循环中,只有当变量 a 是偶数时,才会被计入到变量 total 中。


另外一种做法是使用 Continue 语句。

r=15
a=0
b=1
total=0

for _, r*2:
    temp = a
    a = b
    b = temp + b
    if a/2 != int(a/2):
        continue
    fi
    total = total + a
rof

这意味着当变量 a 不是偶数时,会立即进入下一轮循环,而不会执行后面的代码。
这意味着只有当变量 a 是偶数时,total = total+a 才会被执行,也就是把 a 计入到变量 total 中。

示例四

如果我们希望知道斐波那契数列的前多少项和会超过某个特定值呢?
比如说,我想要知道前多少项的和可以超过五万。
让我们观察对应的代码实现。


r=15
a=0
b=1

counter=0
total=1

for _, r*2:
    temp = a
    a = b
    b = temp + b
    total = total + a
    if total > 50000:
        break
    fi
    counter = counter + 1
rof

在这个代码中,我们新增了一个变量 counter,并且它的初始值是整数 1。
如果在某次循环时,代表斐波那契总和的变量 total 的值超过了五万,则终止循环。
如果循环没有被终止,则将 counter 加上一。

if total > 50000:
    break
fi
counter = counter + 1

也就是说,当变量 total 的值超过五万时,循环会被终止,于是变量 counter 就不会被加一了。
这意味着在整个代码运行结束后,counter 的最终值就是最大的能使斐波那契之和恰好不超过五万的值。
因此,在整个代码运行结束后,任何大于 counter 的整数都是我们要求的答案。

示例五

这个例子中的代码的效果和示例四中的完全相同。
唯一的区别是我们引入了一些不会影响代码逻辑的垃圾代码。
这么做的目的只是为了说明 ContinueBreak 语句的前后可以出现任何其他的代码。

r=15
a=0
b=1

counter=0
total=1

for _, r*2:
    temp = a
    a = b
    b = temp + b
    total = total + a

    if total > 50000:
        total = total + 0
        total = total + 0
        total = total + 0
        break
        total = total + 233
        total = total + 2018
        total = total + 233
    fi
    
    counter = counter + 1

    if total > 0:
        a = a + 0
        b = b + 0
        continue
        a = 233
        b = 2018
    fi
rof

其中,下面列出的代码实际上不会被执行。
因为 Continue语句会立即开始下一轮循环,而不会执行循环体中剩余的代码,
同时,Break 语句会终止当前循环,不会执行循环体剩余的代码,也不会再进入任何新一轮的循环。

total = total + 233
total = total + 2018
total = total + 233
a = 233
b = 2018

下面列出的代码虽然会被执行,但是不会有任何影响。

total = total + 0
total = total + 0
total = total + 0
a = a + 0
b = b + 0

另外,本例子中代码的空行不是必须的,但您可以发现这会增加代码的可读性。
所以,在您实际编写代码时,也要注意适当的通过空行来增加代码的可读性。

示例六

下面这段的代码将执行 10 个外层循环。并且每个外层循环中还要继续执行 10 个内层循环。
在最内层的循环中,每次将变量 result 的值加 1。

result = 0

for _, 10:
    for _, 10:
        result = result + 1
    rof
rof

因此该代码运行结束后,变量 result 的值将是整数 100。

示例七

在基于示例六的基础上,如果我们将内存循环修改为循环 20 次,
然后再在内层循环插入一条 Break 语句会发生什么?

result = 0

for _, 10:
    for _, 20:
        result = result + 1
        break
    rof
rof

实际上,这会让变量 result 最终得到整数 10。这是因为 Break 语句只会作用于其所在循环体对应的循环语句
这意味着内层循环每次在执行 result = result + 1 之后,就会执行 Break 语句,导致该内层循环被终止。
但是 Break 语句的效果不会传递到外层循环,所以外层循环仍然会执行 10 次,因此 result 的值最终是整数 10。

实际上,上面的代码与下面的代码是等效的。
虽然效果是相同的,但是下面的代码运行起来效率更高。
这是因为每次不必再进入内层循环,然后还需要执行一次 Break 语句终止内层循环,于是这节省了时间。

result = 0
for _, 10:
    result = result + 1
rof

另外,Continue 语句也是一样的,它只会作用于其所在循环体对应的循环语句
这意味 Continue 语句与 Break 语句一样,不会影响到外层的循环语句。

小提示

您可以在循环语句中嵌套多层循环语句条件语句
条件语句中亦可嵌套多层循环语句条件语句

例如,在条件语句示例三中,
实际上在条件语句中嵌套了多层的条件语句

应注意的是,如果不是必要的,您不应该嵌套多层语句。
嵌套更多的语句会让代码变的更复杂,也更难以阅读。

特别重要的是,嵌套多层循环会导致程序运行时间变得更长,从而影响效率。
在严重的情况下,您的代码可能会导致代码运行器(解释器)卡死。

返回语句

概述

返回语句对给定的表达式进行求值,并把该求值结果作为整段代码的运行结果。
返回语句执行完毕后,整个代码的运行将会立即终止,任何未执行的代码都不再会执行。
因此,返回语句的作用是“返回”代码的运行结果,然后停止运行。

例如,我们知道 rawtext 文本组件的作用是输出一段文本。在本编程语言中,文本其实是一个字符串。
因此,如果我们希望用本编程语言替代 rawtext 的话,我们其实就是在代码中通过返回语句返回一个字符串。
于是,返回的字符串就是我们最终要显示的内容,于是我们成功替代了 rawtext 的功能。

您可以通过下面的方式来执行返回语句

return 表达式

下面给出的例子可以帮助您进一步理解。

示例一

total = 0
for i, 25:
    total = total + i
rof

return total

这个示例与循环语句示例一非常相似。
唯一的不同之处就是额外增加了下面的这个语句。

return total

这意味着这段代码会把变量 total 的值作为这段代码的运行结果。
很显然 total 的值就是 0+1+2+3+...+24 的和,是个整数。
另外,本示例中的空行不是必须的,这只是为了提高可读性。

示例二

result = ''
result = result + '玩家名: ' + {selector, '@s'} + '\n'
result = result + '分数: ' + str({score, '@s', '金币'})
return result

这意味着如果 @s 指代 Steve,并且他在 金币 记分板的分数是 9931
则本代码将返回下面的这个字符串(为了便于阅读,此处已移除用于包裹字符串的单引号 ')。

玩家名: Steve
分数: 9931

实际上,上面这段代码跟下面的 rawtext 文本组件的结果是一致的。

{
    "rawtext": [
        {
            "text": "玩家名: "
        },
        {
            "selector": "@s"
        },
        {
            "text": "\n分数: "
        },
        {
            "score": {
                "name": "@s",
                "objective": "金币"
            }
        }
    ]
}

示例三

a=0
b=0

if a==0:
    a=100
    return a+25
fi

if b==0:
    b=200
    return b
fi

在这个示例中,这段代码最终会返回整数 125。
并且,在代码执行完毕后,各个变量的情况如下。

变量名 变量储存的数据 变量储存的数据的数据类型
a 100 整数
b 0 整数

这意味着在 return a+25 被执行后,变量 a 加上 25 的值被作为了整段代码的运行结果。
并且,剩余的代码并没有被执行,因为返回语句会在它完成后立即终止代码的运行。

这些就是剩余的,未被执行的代码。

if b==0:
    b=200
    return b
fi

需要再次说明的是,本例中的空行不是必要的,只是为了更高的可读性。

示例四

total = 0
for i, 25:
    total = total + i
    if total > 25:
        return total
    fi
rof

return total

该代码与示例一非常相似,但该代码在循环体额外增加了下面的代码。

if total > 25:
    return total
fi

这意味着在某次循环时,如果发现变量 total 的值大于了 25,
则整段代码将立即返回变量 total 的值,并立即终止代码的运行。

我们可以画一张表来观察代码的执行情况。
下面这张表记录了每轮循环结束时各个变量的情况。

循环轮次 i 的值 total 的值
1 0 0
2 1 1
3 2 3
4 3 6
5 4 10
6 5 15
7 6 21
8 7 28

因此,这段代码会返回整数 28 作为代码的执行结果。

小提示

在部分情况下,您可以省略返回语句,直接一个新的一行上使用单独的表达式作为程序的运行结果。
这种方式并不会终止程序的运行,并且如果之后执行到了返回语句,则也仍然是使用该返回语句的执行结果作为程序的运行结果。

例如,下面这个例子会将变量 total 的值作为程序的运行结果。
这个运行的结果是整数 300,也就是 0+1+2+3+...+24 的值。

total = 0
for i, 25:
    total = total + i
rof

total

下面的这个例子是会将示例三的变体,它会将整数 200 作为程序的运行结果。

a=0
b=0

if a==0:
    a=100
    a+25
fi

if b==0:
    b=200
    b
fi

下面的这个例子返回的结果跟示例四的是相同的。

total = 0
for i, 25:
    total = total + i
    if total > 25:
        return total
    fi
rof

total

下面的这个例子会将浮点数 2.5 作为程序的运行结果。

a = 0
2.5

下面的这个例子会将浮点数 2.5 作为程序的运行结果。

2.5

下面的这个例子返回的结果跟示例二的是相同的。

'玩家名: ' + {selector, '@s'} + '\n金币: ' + str({score, '@s', '金币'})

简写代码

在通常情况下,您不能把多行代码压缩成一行。

例如,我们有这样一段代码。

a=0
b=1
c=2

您不能压缩成这样。

a=0 b=1 c=2

但您可能希望能把一些简单的赋值操作放在一行。
我们赋予了该编程语言这样的能力,您可以这样写。

a=0 | b=1 | c=2

符号 | 与换行具有相同的作用。
它允许您将多行代码组合在一行中。

例如,对于返回语句示例三的代码:

a=0
b=0

if a==0:
    a=100
    return a+25
fi

if b==0:
    b=200
    return b
fi

您可以压缩到一行,也就是这样:

a=0 | b=0 | if a==0: | a=100 | return a+25 | fi | if b==0: | b=200 | return b | fi

这种压缩方式只是告诉您 | 到底应该如何使用。
然而,在实际编写代码时,您应该根据实际情况决定。

这意味着把所有代码都压缩在一行可能会让代码变得难以阅读。
压缩的目的是为了增强代码的可读性,而不是让阅读变得困难!

另外,上面的代码也可以简写为这样。

a=0
b=0

if a==0:
a=100
return a+25
fi

if b==0:
b=200
return b
fi

但您很容易发现这样的简写方式会让代码变得难以阅读,所以您应该尽可能避免这么做。