zoukankan      html  css  js  c++  java
  • Nim教程【十四】

    网友@沉没捕鱼,赞助了一台服务器

    这个系列的教程写完之后,我们就要开始着手搭建Nim的社区了~

    异常

    Nim中的异常类型是对象类型

    根据惯例,Nim中的异常类型的命名都应该以Error后缀结尾

    在system模块中定义了异常类型的基类

    所有的异常都应该派生自system.Exception类型

    由于我们不清楚异常对象的生命周期,

    所以必须在内存堆上为异常的实例分配空间

    编译器不允许开发人员在栈上为异常分配空间

    你如果想抛出一个异常,你必须为这个异常的msg属性赋值

    按照约定,只有在非常特殊的情况下才应该引发异常

    打个比方:你不应该为打不开一个文件而引发异常,

    因为这个文件有可能是不存在的。

    raise语句引发异常

    你可以使用raise语句引发一个异常

    请看下面的代码

    var
      e: ref OSError
    new(e)
    e.msg = "the request to the OS failed"
    raise e

    如果raise关键字后面美元后跟着一个异常的实例

    那么将再次引发最后一个异常

    system模块中还为我们定义了一个newException的方法

    请看如下代码:(是不是简化了很多呢)

    raise newException(OSError, "the request to the OS failed")

    try语句捕获异常

    可以用try语句捕获异常

    # read the first two lines of a text file that should contain numbers
    # and tries to add them
    var
      f: File
    if open(f, "numbers.txt"):
      try:
        let a = readLine(f)
        let b = readLine(f)
        echo "sum: ", parseInt(a) + parseInt(b)
      except OverflowError:
        echo "overflow!"
      except ValueError:
        echo "could not convert string to integer"
      except IOError:
        echo "IO error!"
      except:
        echo "Unknown exception!"
        # reraise the unknown exception:
        raise
      finally:
        close(f)

    如果try代码块中的代码,执行的时候引发了一个异常

    那么就会执行相应的except语句

    如果后面的except语句没有明确列出这个异常

    那么就会后自行最后一个空except语句

    这看起来类似if else语句

    如果存在finally语句,

    那finally语句块内的代码无论如何都会被执行的

    如果一个异常没有得到处理

    那么这个异常会从堆栈向上传播

    这就意味着,调用链上的方法有可能不会被执行

    (如果他被执行了,那么他一定在一个finally子句中)

    如果你需要访问异常对象

    可以使用system模块中的getCurrentException方法或者getCurrentExceptionMsg方法

    来看下面的示例代码

    try:
      doSomethingHere()
    except:
      let
        e = getCurrentException()
        msg = getCurrentExceptionMsg()
      echo "Got exception ", repr(e), " with message ", msg

    在方法上做关于异常的注解

    如果你用{.raises.}对某一个方法进行了注解

    那么在编译期就会检测这个方法(或这个方法所调用到的方法)会不会抛出了某个异常

    如果会,则编译不通过

    示例代码如下:

    proc complexProc() {.raises: [IOError, ArithmeticError].} =
      ...
    
    proc simpleProc() {.raises: [].} =
      ...

    这一段我也没怎么看明白,大家自己看原文吧先

    泛型

    Nim语言的方法参数化、迭代器、等特性都是靠语言本身的泛型特性实现的

    这个特性对于强类型容器是非常有用的

    来看一下代码

    type
      BinaryTreeObj[T] = object # BinaryTree is a generic type with
                                # with generic param ``T``
        le, ri: BinaryTree[T]   # left and right subtrees; may be nil
        data: T                 # the data stored in a node
      BinaryTree*[T] = ref BinaryTreeObj[T] # type that is exported
    
    proc newNode*[T](data: T): BinaryTree[T] =
      # constructor for a node
      new(result)
      result.data = data
    
    proc add*[T](root: var BinaryTree[T], n: BinaryTree[T]) =
      # insert a node into the tree
      if root == nil:
        root = n
      else:
        var it = root
        while it != nil:
          # compare the data items; uses the generic ``cmp`` proc
          # that works for any type that has a ``==`` and ``<`` operator
          var c = cmp(it.data, n.data)
          if c < 0:
            if it.le == nil:
              it.le = n
              return
            it = it.le
          else:
            if it.ri == nil:
              it.ri = n
              return
            it = it.ri
    
    proc add*[T](root: var BinaryTree[T], data: T) =
      # convenience proc:
      add(root, newNode(data))
    
    iterator preorder*[T](root: BinaryTree[T]): T =
      # Preorder traversal of a binary tree.
      # Since recursive iterators are not yet implemented,
      # this uses an explicit stack (which is more efficient anyway):
      var stack: seq[BinaryTree[T]] = @[root]
      while stack.len > 0:
        var n = stack.pop()
        while n != nil:
          yield n.data
          add(stack, n.ri)  # push right subtree onto the stack
          n = n.le          # and follow the left pointer
    
    var
      root: BinaryTree[string] # instantiate a BinaryTree with ``string``
    add(root, newNode("hello")) # instantiates ``newNode`` and ``add``
    add(root, "world")          # instantiates the second ``add`` proc
    for str in preorder(root):
      stdout.writeln(str)

    上面的示例展示了一个泛型二叉树

    通过这个例子,您可以看到,可以用方括号来完成方法的泛型化、泛型迭代器等特性

  • 相关阅读:
    Linux 学习 step by step (2)
    公共建筑能耗监测平台的GPRS通讯服务器的开发方法分享
    幸福框架:可扩展的、动态的、万能的 编号生成器
    C++ Data Member内存布局
    .NET程序集强命名删除与再签名技术 源代码剖析
    hdu 2191(多重背包)
    五种情况下会刷新控件状态(刷新所有子FWinControls的显示)——从DFM读取数据时、新增加子控件时、重新创建当前控件的句柄时、设置父控件时、显示状态被改变时
    终于懂了:Delphi消息的Result域出现的原因——要代替回调函数的返回值!(MakeObjectInstance不会帮助处理(接收)消息回调函数的返回值)
    Firemonkey实现Mac OS程序中内嵌浏览器的功能(自己动手翻译,调用苹果提供的webkit框架)
    感悟:市场经济看得就是主观能动性,有则富贵可及,无则无限趋于零
  • 原文地址:https://www.cnblogs.com/liulun/p/4611373.html
Copyright © 2011-2022 走看看