Nimチュートリアル【14】

4936 ワード

ネットユーザー@沈没して魚を捕って、1台のサーバーを賛助しました
このシリーズのチュートリアルが終わったら、Nimのコミュニティの構築に着手します~
異常
Nimの例外タイプはオブジェクトタイプです
慣例によれば、Nimの例外タイプの名前はError接尾辞で終わるべきである.
システムモジュールで例外タイプを定義したベースクラス
すべての異常は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の句の中にいるに違いない)
例外オブジェクトにアクセスする必要がある場合
システムモジュールの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)

上の例では、汎用ツリーを示します.
この例では、メソッドの汎用化、汎用反復器などの特性をカッコで行うことができます.