0
点赞
收藏
分享

微信扫一扫

d作者:d的新特性


概述

更好可读的函数

●八进制字面
●0结尾无需分配的串
●隐藏类型
●避免内存分配的链
●避免返回错误
●替换goto的嵌套函数

已有技术

● 半浮点数
● 用​​​CTFE​​​初化数组
● 用枚举生成​​​域名​​​列表
● 从C​​​对接​​D

八进制字面

●0755
●18位字的PDP-10
今天仅用于​​​文件权限​​​,但它们仍然很适合.十进制的​​0755​​是什么.

模板字面

// RX 为有写.
enum RX = octal!755;
pragma(msg, RX);//十进制:493

template octal(int i) {
enum octal = convert(i);
}

int convert(int i) {
return i ? convert(i / 10) * 8 + i % 10 : 0;
}

不用内置字面

● 像​​binary!1100_1111​​​的模板​​字面​​​.
● ​​​无需​​​扩展编译器
● 用户可根据需要​​​添加​​它们

●不分配0终止串

● ​​切片​​​是描述长度的,不是​​0终止​​​ ● 如何​​不分配内存​​的调用需要​​0终止​​的​​C函数​​?
● 在堆栈上分配​​stringz!​​,但是​​如何​​?

auto toCStringThen(alias dg)(const(char)[ ] src) nothrow
{
import dmd.common.string :;

const len = src.length + 1;
char[512] small = void;
auto sb = SmallBuffer!char(len, small[]);
scope ptr = sb[];
ptr[0 .. src.length] = src[];
ptr[src.length] = '\0';
return dg(ptr);
}
char[ ] name = ... ;
int fd = name.toCStringThen!(
(fname) => open(fname.ptr, O_RDONLY)
);

隐藏类型

auto range(int i, int j) {
struct Result {
int i, j;
bool empty() { return i == j; }
int front() { return i; }
void popFront() { ++i; }
}
return Result(i, j);
}

void main() {
foreach (x; range(3, 6))
printf("%d\n", x);
}
//打印:3,4,5

避免内存分配链

一般:

char[ ] path = "include/";
char[ ] name = "file";
char[ ] ext = ".ext";
char[ ] filename = path ~ name ~ ext;

不分配方式:

import std.stdio;
import std.range :;
import std.algorithm.iteration :;
import std.array :;
import std.utf :;

void main() {
string path = "include/";
string name = "file";
string ext = ".ext";

auto filename = chain(path, name, ext);
writeln(filename); // "include/file.ext"
string f = filename.byChar.array();
writeln(f.length); // 17
writeln(f); // "include/file.ext"
//注意注释.
}

​​链链接​​

避免返回错误

● ​​异常​​​昂贵且复杂
● ​​​错误代码​​​混乱且容易​​被忽略​​​ ● ​​可选​​返回类型仍然​​很难看​​ ● ​​因而...​​:定义不存在的​​错误​​!

搜索子串,但未发现

返回​​空集​​​,如​​零​​长度串.

NaN方法

● 浮点表示包含​​NaN​​​(​​非数​​​)模式
● ​​​IEEE754​​​规范的一部分
● ​​​NaN​​​的任何操作都产生​​NaN​​​结果
● 这样不必检查​​​代码错误​

NaN变量

● 有​​NaN​​​时​​发出​​​错误消息
● ​​​NaN​​​的任何操作都会产生​​NaN​​​结果
1,​​​D​​​编译器从​​错误​​​中"​​恢复​​​"时使用此方法.
2,防止无意义的串联​​​错误消息​​.

替换char变量

发现无效​​Unicode​​​时,​​D​​​倾向于​​抛异常​​​.
1,这通常是因为​​​Unicode​​​数据混乱,2不希望​​退出​​​处理,如​​渲染​​​待显示文本.
● 我的方法是​​​定义​​​所有代码点,因此​​没有错误​​​ ● 相反,用​​U+FFFD​​替换​​无效代码点​​.

嵌套函数替换Goto

void plan(int i) {
switch (i) {
case 1:
a();goto L3;
case 2: goto L4;
case 3:e();
L3:b();
L4:
c();
return;
}
}

这样:

void plan(int I){
void doc(){c();}
void dobc(){b();doc();}

switch (i) {
case 1:
a();return dobc();
case 2: return doc();
case 3:e();return dobc();
}
}

半浮点数

● 16位浮点类型
● 16位用于经济存储
● 请求​​​按内置类型​​​,麻烦的是有很多​​16位​​​浮点格式
合理的​​​库解决方案​​可能吗?

半浮点用法

HalfFloat h = hf!27.2f;
HalfFloat j = cast(HalfFloat)( hf!3.5f + hf!5 );
HalfFloat f = HalfFloat(0.0f);

半浮点,指数表示为​​1(符号),5(指数),10(分数)​​.

半浮点实现

● 存储为​​short​​​ ● 隐式转换​​HalfFloat​​为​​float​​.
● 显式转换​​float​​为​​HalfFloat​​.

struct HalfFloat {
@property float toFloat() { return shortToFloat(s); }
alias toFloat this;//隐式转换`HalfFloat`为`float`
//模板避免隐式转换`参数`到`浮点`
this(T : float)(T f) {
static assert(is(T == float));
s = floatToShort(f);
}
ushort s = EXPMASK | 1;//.init是HalfFloat.nan

static @property {
HalfFloat min_normal() { HalfFloat hf = void;hf.s=0x04;return hf;}
HalfFloat max() { HalfFloat hf = void; hf.s = 0x7BFF; return hf; }
HalfFloat nan() { HalfFloat hf = void; hf.s = EXPMASK | 1; return hf; }
HalfFloat infinity() { HalfFloat hf = void; hf.s = EXPMASK; return hf; }
HalfFloat epsilon() { HalfFloat hf = void; hf.s = 0x14 ; return hf; }
}

enum dig = 3;
enum mant_dig = 11;
enum max_10_exp = 5;
enum max_exp = 16;
enum min_10_exp = -5;
enum min_exp = -14;

ushort s = EXPMASK | 1;//.init是HalfFloat.nan
}

//半浮点字面
template hf(float v)
{
enum hf = HalfFloat(v);
}

HalfFloat h = hf!27.2f;

​ShortToFloat()​​​和​​floatToShort()​​​实现
●浮点优点:​​​圆整-保护位-粘性位-隐藏位​

用CTFE初始化数组

int[20] squares=[0,1,4,9,16,25,36,49,64,81,1,121,144,169,196,225,256,289,324,361,];

旧方法:

import core.stdc.stdio;

void main()
{
enum N = 20;
printf("module table;\n");
printf("int[%d] squares = [", N);
foreach (i; 0 .. N) {
printf("%d,", i * i);
}
printf("];\n");
}
//使用:
import table;

新方法

组合​​λ​​​和​​CTFE​​:

enum N = 20;
int[N] squares = () {
int[N] squares;
foreach (i; 0 .. N)
squares[i] = i * i;
return squares;
}();//应该很有用吧.

用枚举生成域内名列表

感谢​​Dennis Korpel​​.

struct S
{
bool square : 1,
circle : 1,
triangle : 1;
}

得到想要的:

struct S
{
enum Flags { Square = 1, Circle = 2, Triangle = 4 }

bool square() { return !!(flags & Flags.Square); }
bool circle() { return !!(flags & Flags.Circle); }
bool triangle() { return !!(flags & Flags.Triangle); }

bool square(bool b) { b ? (flags |= Flags.Square)
: (flags &= ~Flags.Square); return b; }
bool circle(bool b) { b ? (flags |= Flags.Circle)
: (flags &= ~Flags.Circle); return b; }
bool triangle(bool b) { b ? (flags |= Flags.Triangle)
: (flags &= ~Flags.Triangle); return b; }

private ubyte flags;
}

会这样写:

void main()
{
enum F { square, circle, triangle }

static struct S
{
mixin(generateFlags!(F, ubyte));
}//生成标志.
S s;
s.square = true;
s.circle = false;
s.triangle = true;
assert(s.square == true);
assert(s.circle == false);
assert(s.triangle == true);
}

生成位标志:

string generateBitFlags(E, T)() {
string result = "pure nothrow @nogc @safe final {";
enum enumName = __traits(identifier, E);

foreach (size_t i, mem; __traits(allMembers, E)) {
static assert(i < T.sizeof * 8, "字段太多");
enum mask = "(1 << "~i.stringof~")";
result ~= "

bool "~mem~"() const scope { return !!(flags & "~mask~"); }

bool "~mem~"(bool v) {
v ? (flags |= "~mask~") : (flags &= ~"~mask~");
return v;
}";
}
return result ~ "}\n private "~T.stringof~" flags;\n";
}

导入C

__import stdio;

int main()
{
printf("你好,世界\n");
return 0;
}

如果导入的是D模块?

__import stdio;
__import daction;

int main() {
printf("D函数返回%d\n", action(value)); // 1
return 0;
}
//
module daction;

enum value = 7;
int action(int i) { return 3 + i; }

重载函数:

__import stdio;
__import daction;

int main()
{
printf("D函数返回%d\n",action(1.0f));//5
return 0;
}
//
module daction;

int action(int i) { return 3; }
int action(float f) { return 5; }

模板?

__import stdio;
__import daction;

int main()
{
printf("D函数返回%d\n",action(1));//4
return 0;
}
//
module daction;

int action(T)(T t) { return cast(int)t.sizeof; }

导入​​D​​​模板,补全了​​循环圈​​​,即​​C​​​也可对接​​D函数​​!

​D​​​的细节使​​编程​​更圆滑!


举报

相关推荐

0 条评论