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);
//运行时溢出异常
}
浙公网安备 33010602011771号