D语言中的值类型,引用类型和函数传递方式

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语言中虽然区分值类型和引用类型,但是函数传参还是要注意传值和传址,还有别名传递。

  1. 默认情况下(函数参数没有修饰符的情况):值类型传值,引用类型传址。
    1. 传递指针:对于指针,传递的是值,但是对于指针指向的,则是传址
    2. 传递引用类型:对于引用类型的实体是传址。
  2. ref 修饰 :别名传递。 函数参数只是会被当成 alias 的一个别名。
  3. out 修饰 : 传递方式来说和ref修饰一样,只是其在传递前会把参数重置为 T.init 也就是原来的数据被重新初始化为 T.init。
    1. 传递指针:传递规则同ref,但是不管指针有没有指向地址,传递到函数的时候指向都是null
    2. 传递引用类型:传递规则同ref,但是不管引用(指针)有没有引用,其都会被重置为null
  4. 其他修饰: 默认的传值和传址规则
    1. scope : 如果参数是个引用类型,那么不能被赋值给超出作用域的变量(例如全局变量)
    2. in : in = scope + const
    3. lazy : 懒惰执行,放到参数传递后执行,传递的可以是语句。非我们说的值或者址传递,编译时特殊处理的。
    4. 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语言中的值类型,引用类型和函数传递方式”

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.