d@nogc仍应允许分配合同串

原文

void foo(string s) @safe pure nothrow @nogc
in (s != "hello", "Invalid " ~ s) {
}

void main() {}

错误:不能在@nogcdeneme.foo函数中使用~符号.
但是该符号仅在即抛错误时使用,即不应继续执行该程序.所以,只分配一点GC不会有什么坏处,对吧?😅
否则,必须丢弃@nogc注解或提供有用错误消息功能.

如果GC完全禁止甚至没有初化怎么办?是你想要使用@nogc的环境.

如果完全禁止GC(就像在BetterC中一样),甚至不会首先编译"Invalid"~s表达式.因此,需要其他方式创建错误消息(可能使用malloc)

避免GC的主要动机之一是防止低延迟代码遭受GC"停止世界"的暂停.
通过在函数级别而不是整个程序级别操作,@nogc可帮助编写正确程序,其中可承受延迟代码可用GC,而低延迟代码可在单独线程中运行来避免它,这些线程收集时不会停止.简单从程序中完全删除GC会强制所有内容而不仅是延迟敏感部分,都变为@nogc.
(话虽如此,@nogc仍是非常不完整和不安全的方法,因为它没有阻止程序中使用GC的部分,通过参数或共享内存传递GC内存的所有权@nogc线程,也没有阻止使用有GC依赖的模块,线本构造器的模块.)

@nogc在合同中仍应允许分配串.

诀窍是,不是在那儿立即创建错误串,而是抛包含一些数据的错误.稍后在使用错误数据时使用GC.如果data有需要GC复制构造器,那么祝你好运.:p

工作原理:
程序员使用区分串定义错误.SumType定义必须列举此类错误可携带的所有类型数据.(幸好,编译时错误会告诉你缺少需要添加的元组类型.)

mixin NoGcError!("Foo", SumType!(Tuple!(Foo, int, int), Tuple!(string), Tuple!()));

尽管"Foo"可以是任何东西,但同结构关联是有意义的:

struct Foo {
  int i;

用户在生成错误串时必须指定"Foo":

void bar(int i, int j) @safe pure nothrow @nogc
  in (i == 42, error!"Foo"("一些错误", this, i, j)) {
    // ...
  }

注意此处不同类型的错误数据:

void zar(string str, double d) @safe pure nothrow @nogc
  in (!isNaN(d), error!"Foo"("不能为Nan", str)) {
    // ...
  }
}

error!"Foo"也可以用来合约外内容.

void main() {
  auto f = Foo(1);
  // f.bar(42, 44);
  // f.zar("hello world", double.init);
  error!"Foo"("错误!");
}

完整草稿:

import std; // Sorry :(

mixin NoGcError!("Foo",SumType!(Tuple!(Foo,int,int),Tuple!(string),Tuple!()));

struct Foo {
  int i;

  void bar(int i, int j) @safe pure nothrow @nogc
  in (i == 42, error!"Foo"("一些错", this, i, j)) {
    // ...
  }

  void zar(string str, double d) @safe pure nothrow @nogc
  in (!isNaN(d), error!"Foo"("不能为nan", str)) {
    // ...
  }
}

void main() {
  auto f = Foo(1);
  // f.bar(42, 44);
  // f.zar("hello world", double.init);
  error!"Foo"("错误!");
}

mixin template NoGcError(string tag, Data) {
  class NoGcError : Error {
    string msg;
    Data data;

    enum noDataString = Tuple!()().to!string;

    this() {
      super(tag ~ " Error");
    }

    // 从object.Throwable.toString适配
    override
    void toString(scope void delegate(in char[]) sink) const {
      sink(file); sink(":"); sink(line.to!string); sink(": ");
      sink(tag); sink(" Error: "); sink(msg);
      const dataStr = data.to!string;
      if (dataStr != noDataString) {
        sink("\n  数据: "); sink(dataStr);
      }

      if (info) {
        try {
          sink("\n----------------");
          foreach (t; info) {
            sink("\n"); sink(t);
          }

        } catch (Throwable) {
          // 忽略更多错误
        }
      }
    }
  }

  static ref error_(string t)()
  if (t == tag) {
    static NoGcError err_;
    return err_;
  }

  static this() {
    error_!tag = new NoGcError();
  }
}

string error(string tag, Data...)(string msg, Data data, string file = __FILE__, size_t line = __LINE__) @safe pure nothrow @nogc {

  static auto thrower(string msg, Data data, string file, size_t line) @trusted nothrow @nogc {
    static assert (__traits(compiles, error_!tag.data = tuple(data)),format!`NoGcError的和类型!"%s"必须包括Tuple!%s`(tag, Data.stringof));

    error_!tag.msg = msg;
    error_!tag.data = tuple(data);
    error_!tag.file = file;
    error_!tag.line = line;
    throw error_!tag;
  }

  // 从std/regex/internal/ir.d适配
  static assumePureFunction(T)(T t) @trusted pure nothrow @nogc {
    enum attrs = functionAttributes!T | FunctionAttribute.pure_;
    return cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t;
  }

  assumePureFunction(&thrower)(msg, data, file, line);

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