Skip to content

Commit f4d85c6

Browse files
committed
update
1 parent 90710ac commit f4d85c6

File tree

5 files changed

+148
-2
lines changed

5 files changed

+148
-2
lines changed

docs/zh/quickstart/04function/03inline-function.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@ inline func add(int a, int b) -> int{
2525
return a + b;
2626
}
2727
28-
void main(){
28+
func main(){
2929
print(add(1, 2));
3030
}
3131
```
3232

3333
编译的时候,上述代码会相当于:
3434

3535
```mcfpp
36-
void main(){
36+
func main(){
3737
int a = 1;
3838
int b = 2;
3939
int ret = a + b;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
lastUpdate: true
3+
---
4+
5+
# 编译确定量
6+
7+
在编译过程中,编译器会对一些编译器可以确定的变量进行优化,例如
8+
9+
```mcfpp
10+
int i = 5;
11+
int j = 5;
12+
13+
print(i + j);
14+
```
15+
16+
这个时候,编译器就会知道`i``j`的值,因此可以直接计算出`i+j`的值为10,而且在print函数中,也可以直接输出10,而不用再转换为记分板的原始JSON文本了。
17+
18+
这种变量,在MCFPP中叫做编译确定量(`Concrete Var`)。编译确定量和普通变量是可以相互转换的,例如:
19+
20+
```mcfpp
21+
int i = 5;
22+
dynamic j;
23+
i = j;
24+
```
25+
26+
在这个例子中,虽然开始的时候编译器能追踪i的值,但是在后面的代码中,i的值被赋值为j,而j被关键字`dynamic`修饰,表示这个变量在声明的时候是不确定的,因此编译器就会丢失对i的值的追踪。
27+
28+
同理,如果一个普通变量,被赋值为了一个确定的值,或者被赋值为一个编译确定量,那么编译器就能够获取这个变量的值,这个变量也就因此成为了编译确定量。
29+
30+
值得注意的是,编译器永远不会追踪类的成员变量。即使类的成员变量被赋值为一个确定的值,编译器仍然会将它作为普通变量进行处理。

docs/zh/quickstart/07generic/01generic-param.md

Whitespace-only changes.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
---
2+
lastUpdate: true
3+
---
4+
5+
# 泛型函数
6+
7+
## 泛型参数
8+
9+
我们之前说了编译确定量的概念。在mcfpp中,可以声明一个函数需要一些编译确定量作为参数。需要使用`<>`来包围编译确定量的参数列表,从而和普通的参数区分开。在调用的时候,也要使用`<>`来包围编译确定量的参数。
10+
11+
```mcfpp
12+
13+
func test<int i>{
14+
print(i);
15+
}
16+
17+
func main(){
18+
test<5>();
19+
test<6>();
20+
}
21+
22+
```
23+
24+
在上面的例子中,`test`函数接受一个编译确定量`i`作为参数,然后打印出这个参数。在`main`函数中,我们调用了两次`test`函数,分别传递了`5``6`作为参数。这样,`test`函数就会打印出`5``6`
25+
26+
值得注意的是,编译器会在编译的时候,不会立刻将`test`函数编译,而是会等到要调用的时候,再将`test`函数的代码进行编译,并分别替换`i``5``6`。这样,`test`函数就会有两个版本,分别打印出`5``6`。而在编译好的数据包中,也只会包含编译后的`test`函数,不会包含原来的`test`函数。
27+
28+
## 类型参数
29+
30+
有一种特殊的变量,叫做类型变量。类型变量永远只能是编译时确定量,因此永远是编译器已知的。如果尝试让编译器丢失对类型变量的追踪,那么编译器会报错。
31+
32+
使用`type`关键字对类型变量进行声明。例如:
33+
34+
```mcfpp
35+
type t = int;
36+
```
37+
38+
此时,t就代表了int变量。但是这个时候,你还不能将t直接用于`t qwq = 1`这种变量声明,因为`t`并没有被注册入编译器的类型缓存中。只有当编译器作为函数的泛型参数被传入时,你才可以在这个函数中,使用这个类型变量进行变量声明。
39+
40+
```mcfpp
41+
func test<type T>(T i){
42+
print(qwq);
43+
}
44+
45+
func main(){
46+
test<int>(1);
47+
}
48+
```
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
---
2+
lastUpdate: true
3+
---
4+
5+
# 泛型类
6+
7+
和函数一样,类也可以拥有只读参数列表。这样子的类被成为泛型类。同时,只读参数列表还给泛型类带来了一些特殊的性质。
8+
9+
## 泛型类的声明
10+
11+
泛型参数在声明类的时候,在类的标识符后面,使用`<>`包裹泛型参数。
12+
13+
```mcfpp
14+
class ClassName<type T>{
15+
#类的属性和方法
16+
...
17+
}
18+
```
19+
20+
在上面的例子中,`T`是泛型参数。和函数一样,在类的内部,可以使用`T`来声明变量,这样,这个变量的类型就是泛型参数`T`
21+
22+
```mcfpp
23+
class ClassName<type T>{
24+
T value;
25+
26+
public ClassName(T value){
27+
this.value = value;
28+
}
29+
30+
func getValue() -> T{
31+
return this.value;
32+
}
33+
}
34+
35+
func main(){
36+
ClassName<int> c = ClassName(5);
37+
print(c.getValue()); //输出5
38+
}
39+
```
40+
41+
和泛型函数一样,在编译过程中,并不会立刻编译泛型类,而是会在实例化的过程中,根据传入的泛型参数,即时编译这个泛型类。同样的,在生成的数据包中也只会包含编译生成的类,不会包含泛型的原始类型。
42+
43+
从上面的例子中也可以注意到,在实例化泛型类的过程中,如果显示声明了泛型类型,那么在实例化的时候,就不需要再传入泛型参数了。
44+
45+
## 泛型类的重载
46+
47+
由于泛型类含有泛型参数,那么当然也能进行重载。根据泛型参数的不同,编译器会将其视作不同的类。
48+
49+
```mcfpp
50+
class Test<int i>{
51+
func print(){
52+
print(this.i);
53+
}
54+
}
55+
56+
class Test<int i, int j>{
57+
func print(){
58+
print(this.i + this.j);
59+
}
60+
}
61+
62+
func main(){
63+
var test = Test<5>();
64+
var test2 = Test<5, 6>();
65+
test.print();
66+
test2.print();
67+
}
68+
```

0 commit comments

Comments
 (0)