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)

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

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

 

时间: 2025-01-28 02:17:45

Nim教程【十四】的相关文章

Android简明开发教程十四:Context Menu绘制几何图形

上下文相关菜单(Context Menu)类同PC上按鼠标右键显示的菜单,在Android平台上是长按来激活Context Menu,Context Menu一般用来显示和当前UI内容相关的菜单. Context Menu的用法和Option Menu非常类似: 首先是创建 菜单资源,在res/menu 下新建menu_context_shape.xml,用来显示Oval,Pear,Shape2D: <?xml version="1.0″ encoding="utf-8″?>

Nim教程【四】

这是国内第一个关于Nim的系列教程 先说废话 不得不说Rust也是门不错的语言,园子里 有人曾经说: Rust语言除了library或keyword缩写比较恶心以外其他所有地方完爆go 还有人曾这样评价Rust语言 Rust 可以说是 D 语言二代目,  没有 D 里的一些经验主义设计,  而且更函数式,  作为 a better C++ 当之无愧.  Pattern matching, Block, Generic 这些东西, Go 有么?  不好的地方是集成 feature 略贪心,  指针

Flash MX 2004 编程(AS2.0)教程(十四)

编程|教程 2.6事件监听 事件有一个习气,就是"拉帮结派",正常情况下,某些对象是接收不到某些事件的,比方说一个动态文本就不能接受鼠标事件.如果我们编写这样的代码为一个动态文本指定事件处理代码: myTextField_txt.onMouseDown = function(){ } 当我们在它上面单击鼠标时,代码并不会执行,因为它压根就不会接收到鼠标事件.要想让它正确接受鼠标事件,必须再加上这样的代码: Mouse.addListener(myTextField); 这个语句就是让m

Flash MX 2004 ActionScript图文教程(十四)

教程 2.6事件监听 事件有一个习气,就是"拉帮结派",正常情况下,某些对象是接收不到某些事件的,比方说一个动态文本就不能接受鼠标事件.如果我们编写这样的代码为一个动态文本指定事件处理代码: myTextField_txt.onMouseDown = function(){ } 当我们在它上面单击鼠标时,代码并不会执行,因为它压根就不会接收到鼠标事件.要想让它正确接受鼠标事件,必须再加上这样的代码: Mouse.addListener(myTextField); 这个语句就是让myTe

FrontPage 2003基础教程(十四) 新建自定义链接

默认链接有时不够用,可以建自定义链接,独立于默认.在插入链接时有两个选项:一个是默认,另一个是自定义链接. 自定义链接可以放在主页下面,也可以放在独立的地方.下图一中的"娱乐"就是放在主页下的.图二中的新建成链接栏是独立的.   当然你还可以在自定义下面添加下层链接. 查看全套FrontPage 2003基础教程

PostgreSQL教程(十四):数据库维护_PostgreSQL

一.恢复磁盘空间:     在PostgreSQL中,使用delete和update语句删除或更新的数据行并没有被实际删除,而只是在旧版本数据行的物理地址上将该行的状态置为已删除或已过期.因此当数据表中的数据变化极为频繁时,那么在一段时间之后该表所占用的空间将会变得很大,然而数据量却可能变化不大.要解决该问题,需要定期对数据变化频繁的数据表执行VACUUM操作.     VACUUM命令存在两种形式,VACUUM和VACUUM FULL,它们之间的区别见如下表格:   无VACUUM VACUU

Redis教程(十四):内存优化介绍_Redis

一.特殊编码:     自从Redis 2.2之后,很多数据类型都可以通过特殊编码的方式来进行存储空间的优化.其中,Hash.List和由Integer组成的Sets都可以通过该方式来优化存储结构,以便占用更少的空间,在有些情况下,可以省去9/10的空间.     这些特殊编码对于Redis的使用而言是完全透明的,事实上,它只是CPU和内存之间的一个交易而言.如果内存使用率方面高一些,那么在操作数据时消耗的CPU自然要多一些,反之亦然.在Redis中提供了一组配置参数用于设置与特殊编码相关的各种

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十四)

C#开发WPF/Silverlight动画及游戏系列教程(Game Tutorial):(四十四)制作主角属性面板及加点器 游戏中会使用大量的菜单面板,而这些面板往往都带有选项卡.如果用Silverlight工具中的TabControl,则需要通过复杂的xaml重写模板来实现自定义样式,这一点时常让开发者头疼,毕竟界面的东西应该属于美工的范畴,这也是我所发现在目前Silverlight中唯一一处只能通过xaml而无法用代码实现的地方.当然,如果您对此特别感兴趣,同样可以到http://www.c

C#开发WPF/Silverlight动画及游戏系列教程(Game Course):(三十四)

C#开发WPF/Silverlight动画及游戏系列教程(Game Course):(三十四)地图编辑器诞生啦! 到目前为止,教程示例游戏中虽然实现了A*,但是还无法轻松的为地图设置障碍物:并且游戏所有地图均为一张整的大图片,主角的移动会导致窗体对地图的不停切割,越大的地图带来的负面性能损耗越明显.对地图进行切片处理则可达到性能的最大优化:载入的时候按需加载,地图根据主角的位置仅显示特定部份:并且如果还能配上任意勾勒的遮挡物,那么这一切的一切将更能完美的诠释我们的游戏.开发制作地图编辑器已迫在眉

C#开发WPF/Silverlight动画及游戏系列教程(Game Course):(二十四)

C#开发WPF/Silverlight动画及游戏系列教程(Game Course):(二十四) Be careful!前方怪物出没 游戏的精灵框架到此为止算告一段落,让我们一同来体验它带来的神奇效应. 一个安静的黄昏,主角悠闲的甩着它帅气的毛发独跑于林阴大道.怎知天色已晚即将进入月亮的领地,嘿嘿,我们的故事就从这里开始:Be careful,前方怪物出没! 实在不忍心让主角空有一身武艺而无处施展,本节为了不再让它孤单,我将向游戏中加入可爱的妖精妹妹与之为伴: 好象在哪见过呢?对,就是她了,可爱吧