月报 Vol.02:新增条件编译属性 cfg、#alias属性、defer表达式,增加 tuple struct 支持


                                                                                                                                                <h2>语言更新</h2> 
  • 新增条件编译属性 cfg。可以根据后端等条件进行文件内的条件编译。

    #cfg(any(target="js", target="wasm-gc"))
    let current_target = "js | wasm-gc"
    
  • 新增#alias属性,目前可以给方法或函数创建别名,并支持标注废弃。后续支持更多场景。

    #alias(combine, deprecated="use add instead")
    fn Int::add(x : Int, y : Int) -&gt; Int {
      x + y
    }
    
    test {
      let _ = Int::add(1, 2)
      let _ = Int::combine(1, 2)
    }
    
  • 新增 defer表达式。提供了一个基于词法作用域的资源清理功能。当程序以任何方式离开 defer expr; body 中的 body 时,expr 都会被运行

    fn main {
      defer println("End of main")
      {
        defer println("End of block1")
        println("block1")
      }
      for i in 0..&lt;3 {
        defer println("End of loop \{i}")
        if i == 2 {
          break // `break` 等也能触发 `defer`
        }
        println("Looping \{i}")
      }
      return
    }
    
    block1
    End of block1
    Looping 0
    End of loop 0
    Looping 1
    End of loop 1
    End of loop 2
    End of main
    

      目前,defer exprexpr 里不能抛出错误或调用 async 函数。expr 里不能使用 return/break/continue 等控制流跳转构造

  • Native 后端的 Bytes 的末尾现在永远会有一个额外的 '\0' 字节,因此现在 Bytes 可以直接当作 C string 传给需要 C string 的 FFI 调用。这个额外的 '\0' 字节不计入 Bytes 的长度,因此现有代码的行为不会有任何变化

  • 调整可选参数的语法,默认参数现在可以依赖前面的参数(之前这一行为被废弃了,因为它和 virtual package 不兼容,但现在我们找到了在兼容 virtual package 的前提下支持这种复杂默认值的方式)。另外,我们统一了有默认值(label~ : T = ..)和没有默认值(label? : T)的可选参数:现在,对于函数的调用者来说,这两种默认参数不再有区别,并且都支持下列调用方式:

    • 不提供参数,使用默认值

    • 通过 label=value 的形式显式提供参数

    • 通过 label?=opt 的形式调用,语义是:如果 optSome(value),等价于 label=value。如果 optNone,等价于不提供这个参数

  • 调整自动填充参数的语法,改用 #callsite(autofill(...)) 属性替代原有语法

    // 原版本
    pub fn[T] fail(msg : String, loc~ : SourceLoc = _) -&gt; T raise Failure { ... }
    // 现版本
    #callsite(autofill(loc))
    pub fn[T] fail(msg : String, loc~ : SourceLoc) -&gt; T raise Failure { ... }
    
  • 废弃 newtype,增加 tuple struct 支持

    // 旧语法,运行时等价于 Int
    type A Int
    fn get(a : A) -&gt; Int {
      a.inner()
    }
    
    // 新语法,运行时依然等价于 Int
    struct A(Int)
    fn get(a : A) -&gt; Int {
      a.0
    }
    
    struct Multiple(Int, String, Char)
    fn use_multiple(x: Multiple) -&gt; Unit {
      println(x.0)
      println(x.1)
      println(x.2)
    }
    fn make_multiple(a: Int, b: String, c: Char) -&gt; Multiple {
      Multiple(a, b, c)
    }
    
    • 当 tuple struct 中类型数量为 1 个的时候,tuple struct 等价于原有的 newtype。因此,当 newtype 的 underlying type 不是 tuple 的时候,formatter 目前会自动将旧语法迁移至新语法。为了便于迁移,这种情况下的 tuple struct 也提供了一个 .inner() 方法,之后会 deprecated 掉并移除

    • 当 tuple struct 中类型数量超过 1 个的时候,tuple struct 和原有的 tuple newtype 的区别在于:

      • tuple struct 不能由直接通过 tuple 构造

      • tuple struct 不能通过 .inner() 方法得到一个 tuple

    • 如果需要可以直接和 tuple 互相转换的 tuple struct,可以使用:

    struct T((Int, Int))
    
    fn make_t(x: Int, y: Int) -&gt; T {
      (x, y)
    }
    
    fn use_t(t: T) -&gt; (Int, Int) {
      t.0
    }
    
未经允许不得转载:紫竹林-程序员中文网 » 月报 Vol.02:新增条件编译属性 cfg、#alias属性、defer表达式,增加 tuple struct 支持

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
关于我们 免责申明 意见反馈 隐私政策
程序员中文网:公益在线网站,帮助学习者快速成长!
关注微信 技术交流
推荐文章
每天精选资源文章推送
推荐文章
随时随地碎片化学习
推荐文章
发现有趣的