• 华为仓颉编程语言观感



    花了半天时间,对华为新出的仓颉编程语言做了简单的了解,整体观感如下:

    • 仓颉语言看起来是一门大而全的语言,吸纳了现存的很多中编程语言的范式和语法。
    • 语法非常像Swift,有些语法又有rust的影子;
    • 静态类型语言,但编译为二进制可执行文件,无虚拟机。并发、垃圾回收与内存管理模块与java类似;
    • 支持声明式UI语法,类似于现在ArkUI使用的ArkTS语法,估计以后HarmonyOS的开发语言会从ArkTS转化为仓颉。

    目前仓颉语言只开放了文档,未开放sdk让开发者测试开发。可以申请仓颉的开发者预览版Beta招募,链接Here

    相似点(主要与Swift进行对比)

    • 类型扩展

      1. 添加函数 (swift包含)

        仓颉:
        extend String { 
            func printSize() {
                print(this.size)
            }
        }
        
        "123".printSize() // 3
        
        
        Swift:
        extension String {
            func printSize() {
                print(self.size)
            }
        }
        
        "123".printSize() // 3
        
      2. 添加属性 (swift不包含)

      3. 添加操作符重载 (swift包含)

        仓颉:
        struct Point {
            let x: Int
            let y: Int
        
            init(x: Int, y: Int) {...}
        
            operator func +(rhs: Point): Point {
                return Point(
                    this.x + rhs.x,
                    this.y + rhs.y
                )
            }
        }
        
        let a: Point = ...
        let b: Point = ...
        let c = a + b
        
        Swiftstruct Point {
            let x: Int
            let y: Int
        
            init(x: Int, y: Int) {
                self.x = x
                self.y = y
            }
        
            static func +(lhs:Point, rhs: Point) -> Point {
                return Point(x:
                    lhs.x + rhs.x,
                    y: lhs.y + rhs.y)
            }
        }
        
        let c: Point = Point(x: 1, y: 1)
        let d: Point = Point(x: 2, y: 2)
        let e = c + d
        
        
      4. 实现接口 (swift包含)

        仓颉:
        sealed interface Integer {}
        
        extend Int8 <: Integer {}
        extend Int16 <: Integer {}
        extend Int32 <: Integer {}
        extend Int64 <: Integer {}
        
        let a: Integer = 123 // ok
        
        Swift:
        protocol Integer {}
        
        extension Int8 : Integer {}
        
        let a :Integer = Int8(123)
        
        
    • 代数数据类型和模式匹配

      仓颉中的枚举定义与使用:
      
      enum BinaryTree {
          | Node(value: Int, left: BinaryTree, right: BinaryTree)
          | Empty
      }
      
      func sumBinaryTree(bt: BinaryTree) {
          match (bt) { //match关键字实际是rust语言中的模式匹配关键字。
              case Node(v, l, r) => 
                  v + sumBinaryTree(l) + sumBinaryTree(r)
              case Empty => 0
          }
      }
      
      Swift中的枚举定义与使用:
      
      indirect enum BinaryTree {
          case Node(value: Int, left: BinaryTree, right: BinaryTree)
          case Empty
      }
      
      func sumBinaryTree(bt: BinaryTree) -> Int {
          switch bt {
          case .Node(let value, let left, let right):
              return value + sumBinaryTree(bt: left) + sumBinaryTree(bt: right)
          case .Empty:
              return 0
          }
      }
      
      
    • 泛型
      泛型函数的声明方式几乎一样,尤其是针对泛型类型T的限制,两者都使用where关键字。

      仓颉:
      func lookup<T>(element: T, arr: Array<T>): Bool where T <: Equatable<T> {
          for (e in arr){
              if (element == e){
                  return true
              }
          }
          return false
      }
      
      Swift:
      func lookup<T>(element: T, arr: Array<T>) -> Bool where T : Equatable {
          for e in arr {
              if (element == e){
                  return true
              }
          }
          return false
      }
      
    • 命名参数&参数默认值

      仓颉:
      func dateOf(year!: Int64, month!: Int64, dayOfMonth!: Int64, timeZone!: TimeZone = TimeZone.Local) {
          
      }
      
      dateOf(year: 2024, month: 6, dayOfMonth: 21) // ok
      dateOf(year: 2024, month: 6, dayOfMonth: 21, timeZone: TimeZone.UTC) // ok
      
      
      Swift:
      func dateOf(year: Int64, month: Int64, dayOfMonth: Int64, timeZone: TimeZone = TimeZone.current) {
          
      }
      
      dateOf(year: 2024, month: 6, dayOfMonth: 21) // ok
      dateOf(year: 2024, month: 6, dayOfMonth: 21, timeZone: TimeZone.gmt) // ok
      
    • 尾随lambda(trailing lambda)

      仓颉:
      func unless(condition: Bool, f: ()->Unit) {
          if(!condition) {
              f()
          }
      }
      
      int a = f(...)
      unless(a > 0) {
          print("no greater than 0")
      }
      
      Swift:
      func unless(condition: Bool, f: () -> Void) {
          if !condition {
              f()
          }
      }
      
      unless(condition: true) {
          print("no greater than 0")
      }
      
      
    • 属性
      属性的get/set配置。

      仓颉:
      x和y是只读的,只有get实现,而color则是可变的,用mut prop修饰,同时具有getset实现。
      class Point {
          private let _x: Int
          private let _y: Int
          private var _color: String
      
          init(x: Int, y: Int, color: String) {...}
      
          prop x: Int {
              get() {
                  Logger.log(level: Debug, "access x")
                  return _x
              }
          }
      
          prop y: Int {
              get() {
                  Logger.log(level: Debug, "access y")
                  return _y
              }
          }
      
          mut prop color: String {
              get() {
                  Logger.log(level: Debug, "access color")
                  return _color
              }
      
              set(c) {
                  Logger.log(level: Debug, "reset color to ${c}")
                  color = c
              }
          }
      }
      
      main() {
          let p = Point(0, 0, "red")
          let x = p.x // "access x"
          let y = p.y // "access y"
          p.color = "green" // "reset color to green"
      }
      
      Swift:
      x和y是只读的,只有get实现,而color则是可变的,同时具有getset实现。
      class Point2 {
          private let _x: Int
          private let _y: Int
          private var _color: String
      
          init(_ x: Int, _ y: Int,_ color: String) {
              self._x = x
              self._y = y
              self._color = color
          }
      
          var  x: Int {
              get {
                  return _x
              }
          }
      
          var y: Int {
              get {
                  return _y
              }
          }
      
           var color: String {
              get {
                  return _color
              }
      
              set(c) {
                  _color = c
              }
          }
      }
      
          let p = Point2(0, 0, "red")
          p.x = 100 //error
          let x = p.x // "access x"
          let y = p.y // "access y"
          p.color = "green" // "reset color to green"
      
      
    • 空引用安全

      在仓颉中,对于任意类型T,都可以有对应的可选类型Option。具有Option类型的变量要么对应一个实际的具有T类型的值v,因此取值为Some(v),要么具有空值,取值为None。

      可选类型(Option)是一种 enum 类型,是一个经典的代数数据类型,表示有值或空值两种状态。
      在Swift,用来表示变量可空的关键字为Optional.

      仓颉:
      var a: ?Int = None
      a?.toString() // None
      a ?? 123 // 123
      a = Some(321)
      a?.toString() // Some("321")
      a ?? 123 // 321
      
      Swift:
      var f: Int? = nil
      print(f) //nil
      print(f ?? 123) // 123
      var g = Optional(321)
      print(g) //Optional(321)
      print(g ?? 123) // 321
      
    • 值类型
      仓颉和Swift都使用struct来实现用户自定义的值类型。

      仓颉:
      struct Point {
          var x: Int
          var y: Int
          init(x: Int, y: Int) { ... }
          ...
      }
      
      var a = Point(0, 0)
      var b = a
      a.x = 1
      print(b.x) // 0
      
      Swift:
      struct Point {
          var x: Int
          var y: Int
          init(x: Int, y: Int) { 
              self.x  = x
              self.y = y
          }
          
      }
      
      var a1 = Point3(x:0,y: 0)
      var b1 = a1
      a1.x = 1
      print(b1.x) // 0
      
    • 仓颉:
      定义一个名为 DebugLog 的宏:
      public macro DebugLog(input: Tokens) {
          if (globalConfig.mode == Mode.development) {
              return quote( println( ${input} ) )
          }
          else {
              return quote()
          }
      }
      使用 DebugLog 宏:
      @DebugLog( expensiveComputation() )
      
      Rust:
      use proc_macro;
      
      #[some_attribute]
      pub fn some_name(input: TokenStream) -> TokenStream {
      }
      
    • Actor

      使用更简洁的语法来实现异步编程、并发编程中的数据竞争问题。

      仓颉:
      actor Account {
          instance var balance: Int64
          init (x: Int64) { this.balance = f1() }
          instance func performWithdraw(amount: Int64): Unit {
              balance -= amount
          }
          receiver func withdraw(amount: Int64): Bool {
              if (this.balance < amount) {
                  return false
              } else {
                  this.performWithdraw(amount);
                  return true
              }
          }
      }
      
      Swift:
      注意:这段代码是来自于Swift的官方文档。仓颉的文档示例与swift的文档示例代码基本是一致的,看来仓颉语言应该是参考了Swift语言不少的东西。
      actor Account {
      	var balance: Int = 20// current user balance is 20
      	// ...
      	func withdraw(amount: Int) {
      		guard balance >= amount else {return}
      		self.balance = balance - amount
      	}
      }
      
    • 可变性修饰符
      可变性修饰符:let 与 var,分别对应不可变和可变属性,

    不同点

    • 垃圾收集方案

      仓颉使用追踪式垃圾回收,类似于java中的基于可达性分析的垃圾回收算法;Swift使用引用计数法。(Swift有weak关键字)

    亮点

    • 管道(Pipeline)操作符

      func double(a: Int) {
          a * 2
      }
      
      func increment(a: Int) {
          a + 1
      }
      
      double(increment(double(double(5)))) // 42
      
      5 |> double |> double |> increment |> double // 42
      
    • 类型扩展可添加属性

    • try-with-resources
      该特性应该借鉴自java.

      try (input = MyResource(),
          output = MyResource()) {
          while (input.hasNextLine()) {
              let lineString = input.readLine()
              output.writeLine(lineString)
          }
      }
      
    • 溢出检查
      这个机制使得大多数时候,整数溢出都会及时被感知,避免造成业务隐患。

      @OverflowWrapping
      func test(x: Int8, y: Int8) { // if x equals to 127 and y equals to 3
          let z = x + y // z equals to -126
      }
      
    • 并发编程

      1. 线程创建简单且占用内存量小。使用Spawn关键字来创建新线程。

        func fetch_data(url: String) {
            let response = http_get(url)
            process(response)
        }
        
        main() {
            let urls = ["https://example.com/data1", "https://example.com/data2", ...]
            let futures = ArrayList<Future<Unit>>()
            for (url in urls) {
                let fut = spawn { fetch_data(url) }  // 创建仓颉线程进行网络请求
                futures.append(fut)
            }
            for (fut in futures) {  // 等待所有仓颉线程完成
                fut.get()
            }
        }
        
      2. 无锁并发对象。
        运行时库提供了一系列的原子操作对象,尽量让开发者少使用互斥量或者锁来实现线程安全。同时提供的这些原子操作对象,针对多线程操作做了优化,其效率比单纯使用互斥量要高得多。

  • 相关阅读:
    SpringBoot项目如何引入外部jar及将外部jar打包到项目发布jar包
    自动化机器学习AutoML之flaml:利用flaml框架自动寻找最优算法及其对应最佳参数python
    bash if条件判断
    《QT从基础到进阶·三十七》QWidget实现左侧导航栏效果
    【随想】每日两题Day.10(实则一题)
    【C++初阶】三、类和对象(中)
    【乐吾乐3D可视化组态编辑器】3D场景与大屏通信
    Wpf 多指应用开发解析
    ​ 数据库约束
    字节小程序填坑说明
  • 原文地址:https://blog.csdn.net/HelloMagina/article/details/139963936