D语言和C#,java类似,是一门区分值类型和引用类型的语言。
概念和区分:
(注:没有找到权威的定义,维基百科没有,只有勉强链接到百度百科了)
- 值类型:百度百科 , 说下个人理解:默认在栈中分配的,传递时默认(自定义赋值函数可以做其他实现)是占用的内存的copy的。
- 引用类型:百度百科 ,说下个人理解:默认在堆中分配,使用的时候都是其引用,也就是其指针。所谓的赋值也就是引用(指针)更新。
D中的分类:
(注:非官方分类,个人区分,如有错误请指出)
值类型:
- 基础类型:字符类型([u]byte,[d/w]char),数字类型([u]short,[u]int,[u]long,[u]cent,[i/c]float,[i/c]double,[i/c]real,),布尔类型(bool),空类型(void)
- 结构
- 指针(引用本质也可以理解为指针)
- 静态数组
- function 和 delegate
引用类型:
- 类和接口
- 动态数组(不单单一个元素指针,还有长度)
注:function 本质就是一个指针,对应C中的函数指针。delegate 本质是两个指针,一个函数指针,一个上下文指针,传递的时候是复制两个指针的。
函数传參方式:
注: 如果不是C/C++系列出身,可能晕。
在C/C++ 中对于一个函数参数传递方式,区分值传递和址传递。其他语言中一般很少谈,但是其是还是存在的。在D语言中虽然区分值类型和引用类型,但是函数传参还是要注意传值和传址,还有别名传递。
- 默认情况下(函数参数没有修饰符的情况):值类型传值,引用类型传址。
- 传递指针:对于指针,传递的是值,但是对于指针指向的,则是传址
- 传递引用类型:对于引用类型的实体是传址。
- ref 修饰 :别名传递。 函数参数只是会被当成 alias 的一个别名。
- out 修饰 : 传递方式来说和ref修饰一样,只是其在传递前会把参数重置为 T.init 也就是原来的数据被重新初始化为 T.init。
- 传递指针:传递规则同ref,但是不管指针有没有指向地址,传递到函数的时候指向都是null
- 传递引用类型:传递规则同ref,但是不管引用(指针)有没有引用,其都会被重置为null
- 其他修饰: 默认的传值和传址规则
- scope : 如果参数是个引用类型,那么不能被赋值给超出作用域的变量(例如全局变量)
- in : in = scope + const
- lazy : 懒惰执行,放到参数传递后执行,传递的可以是语句。非我们说的值或者址传递,编译时特殊处理的。
- shared / const / immutable / inout : 参数隐式转换为 shared / conast/immutable / inout。
别名传递和址传递区别:地址传递传递的是指针,其指针还是会被复制的,但是别名传递不会有任何新的分配,只是制定一个新的别名。
下面是例子:
import std.stdio; void handle(T)(T obj) { writeln("\t # dee in ", &obj); } void handleref(T)(ref T obj) { writeln("\t # handle ref in ", &obj); } void main() { auto obj = new Object(); writeln("&obj : ", &obj); handle(obj); handleref(obj); }
执行的结果(每个人输出是不一样的:):
>rdmd delegate.d &obj : 7FFD2BFB49D8 // 原始的引用(指针的)的地址 # dee in 7FFD2BFB49B8 // 地址传递后新指针(引用)的地址 # handle ref in 7FFD2BFB49D8 // 别名传递,本质还是原来的变量
One thought on “D语言中的值类型,引用类型和函数传递方式”