d为何to管用,转换不管用

原文
我写了些代码,做了一些转换实验.我发现有时,对比转换(cast),仅std.conv.to!工作,我不知道为什么,因为我假设他们是一样的.我有如下接口:

interface ICustomDrawable {
    void render(sfRenderWindow* renderWindow);
}

及实现该接口的以下类:

class Button : ICustomDrawable {
    ...
    override void render(sfRenderWindow* renderWindow) {
        ...
    }
}

及使用自定义的(ICustomDrawable)类:

class StackLayout : ICustomDrawable {
   ...
    void addChild(T)(T child) {
        static assert(is(T : ICustomDrawable), "Invalid type T for child");
        ...
    }
    ...
    ICustomDrawable[] _children;
}

有时,想要转换子(属性),则只有第二个示例有效:

foreach (Button button; cast(Button[])(_boardSizeRow.children)) {
    button.update(event, _renderWindow);
}
//第1,第2
foreach (Button button; to!(Button[])(_boardSizeRow.children)) {
    button.update(event, _renderWindow);
}

运行第一个代码示例时,得到了一个黑屏,而第二个没有.这很奇怪,因为向控制台写入"type"时,他们是相同的.为什么?

你需要知道两件事:
1.隐式转换接口引用为兼容类引用时,生成指针略有不同.

interface I {}
class C : I {}
void main()
{
    C c = new C;
    I i = c;
    import std.stdio;
    writeln(cast(void*) c); /*如:7F3C140A7000*/
    writeln(cast(void*) i); /*如:7F3C140A7010*/
}

2.从A数组类型到B数组类型的转换是"按绘画类型"完成的.是重新解释而不是转换数组元素.

但是不能按类引用重新解释引用接口,因为指针会错.你需要转换数组的每个元素(因而用'to').

但,记住,可在不使用转换std.conv就,仅通过省略正在迭代的变量类型来完成foreach:

import std.stdio, std.conv;

interface IDog {
    void bark();
}

class Dog: IDog{
    string s;
    this(string _s){s = _s;}
    void bark(){writeln(s);}
}

class List{
    IDog[] dogs;
    void add(T)(T d){ dogs ~= d;  }
}

void main(){
    auto d1 = new Dog("meaw!");
    auto d2 = new Dog("wof!");
    auto l = new List();
    l.add(d1);
    l.add(d2);

    foreach(d; l.dogs){ // 未标记d类型
        d.bark();
    }
}

'foreach'适合该情况,因为'bark''IDog'的方法.但'update'不是,因此需要转换为'Button[]'.
此时,你可如下转换类型:

import std.stdio, std.conv;

interface IDog {
    void bark();
}

class Dog: IDog{
    string s;
    this(string _s){s = _s;}
    void bark(){writeln(s);}
    void update(string _s){ s ~= " - " ~ _s; }
}

class List{
    IDog[] dogs;
    void add(T)(T d){ dogs ~= d;  }
}

void main(){
    auto d1 = new Dog("meaw!");
    auto d2 = new Dog("wof!");
    auto l = new List();
    l.add(d1);
    l.add(d2);

    foreach(i,d; l.dogs){//用i来显示每次更新
        (cast(Dog)d).update(to!string(i));
        d.bark();
    }
}

解释如下.

转换仅改变"观察到的类型",而"to"则是深度转换.观察:

import std.stdio;
import std.conv;

void main()
{
    int[] ints  = [1, 2, 3];
    auto bytes1 = cast(ubyte[])(ints);
    auto bytes2 = to!(ubyte[])(ints);
    writeln(bytes1);
    writeln(bytes2);
}
//结果:
[1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0]
[1, 2, 3]

to"真正"类型转换非常有用.可改变串宽.最后,"to"可解释串.如:

import std.stdio;
import std.conv;

void main()
{
    int[] ints  = to!(int[])("[1, 2, 3]");
    writeln(ints);
}
//结果
[1, 2, 3]

To非常方便,因为这是"一站式商店":不管你想做什么:"to"就可了.不需要混合/匹配的调用atoi/itoa/encode/decode等的.此外,它是安全的:如果失败,to会抛.如果溢出,它也会抛:

import std.conv;

void main()
{
    int a = 500;
    ubyte b = cast(ubyte)(a); 
//无问题,静默溢出
    ubyte c = to!ubyte(a);
//运行时溢出异常
}
posted @   zjh6  阅读(15)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示