首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在8.4中工作的代码在8.6中造成崩溃,有没有更好的方法来实现这个功能?

在8.4中工作的代码在8.6中造成崩溃,有没有更好的方法来实现这个功能?
EN

Stack Overflow用户
提问于 2017-04-14 19:12:21
回答 3查看 178关注 0票数 0

我有一个Tcl实用程序,它可以很容易地确保在控制流离开当前范围( proc)时运行的代码片段。它在TCL8.6.6中崩溃,所以我想知道是否有一种“更好”的方法来实现TCL8.6中的功能?

一个示例用法是:

代码语言:javascript
复制
proc test {file} {
   set fh [open $file]
   ::Util::Defer [list close $fh]
   # ... do a bunch of stuff
   # and even if we hit an error
   # [close $fh] will be evaluated as we return
   # from the proc
}

它在TCL8.4中运行得很好,我在代码中都使用了它。

由于我仍然在提高TCL8.6中所有可用功能的速度,我在问如何编写::Util::Defer proc以最好地利用TCL8.6?

以下是8.4的实现:

代码语言:javascript
复制
namespace eval ::Util {}
proc ::Util::Defer_impl {cmd args} {
  uplevel 1 $cmd
}
proc ::Util::Defer {cmd} {
  set vname _u_defer_var
  # look for a unique variable name
  while {[uplevel 1 [list info vars $vname]] != ""} {
    set vname ${vname}_
  }
  uplevel 1 [list set $vname $cmd]
  # when the variable is unset, trigger a call to the command
  uplevel 1 [list trace add variable $vname unset [list ::Util::Defer_impl $cmd]]
  # return a chunk of code enabling the user to cancel this if desired
  return [list variable $vname unset [list ::Util::Defer_impl $cmd]]
}

编辑补充:我很感谢你的回答。老实说,我已经有了用于文件句柄的其他语法糖,如下:

代码语言:javascript
复制
proc test {file} {
   set fh [::Util::LocalFileHandle $file]
   # do stuff
}

我只是对::Util::Defer的通用解决方案寄予更多的期望--因为我偶尔会在同一个proc中有两到三个用途(在不同的位置)。是的,如果不存在或不可读的话,我就忽略了错误处理。

注意:我已经向ActiveState报告了这个bug,并提交了一个core.tcl.tk上的bug

编辑以添加buggy代码:这是对我造成崩溃的Tcl代码,它稍微缩小到本质(而不是完全成熟的::Util::Defer)。

代码语言:javascript
复制
# ---------------begin script-------------------
package require Itcl

proc ::try_uplevel {} {
  return [uplevel 1 [list ::info vars _u_defer_var]]
}

itcl::class ::test_class {
  constructor {} {}

  public proc test_via_proc {} {
    ::try_uplevel
  }
}

::test_class::test_via_proc
# ---------------end script-------------------
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-04-17 15:19:22

周末,我想到了这个重量级的解决方案。它利用itcl::local功能实现同样的效果。它确实依赖于Itcl --但由于问题是与Itcl的交互,这似乎是一个合理的解决方案,尽管它并不是纯粹的Tcl。

代码语言:javascript
复制
itcl::class Defer_impl {
  constructor {cmd} {} {
    set _to_eval $cmd
  }
  destructor {
    uplevel 1 $_to_eval
  }
  private variable _to_eval {}
}

proc ::Util::Defer {cmd} {
  uplevel 1 [list itcl::local ::Defer_impl #auto $cmd]
}
票数 0
EN

Stack Overflow用户

发布于 2017-04-15 08:20:59

您描述的模式是受支持的;它不应该崩溃(实际上,我无法用8.6.3或8.6支持分支的尖端再现崩溃)。它唯一的问题是,如果在close (或任何其他延迟脚本)期间出现错误,它不会报告它,从这个片段中可以看到(%是提示符):

代码语言:javascript
复制
% apply {{} {
    ::Util::Defer [list error boo]
    puts hi
}}
hi
% 

这就是为什么我花了不少精力在8.6中提供一个try命令的原因之一。有了这个,你就可以做到:

代码语言:javascript
复制
proc test {filename} {
    set f [open $filename]
    try {
        # Do stuff with $f
    } finally {
        close $f
    }
}

它还处理一些棘手的事情,比如将抛入正文中的错误与finally子句放在一起( body异常信息在finally子句的错误异常信息的-during选项中),这样如果两者都出现错误,您就可以发现这两个错误。

代码语言:javascript
复制
% catch {
    try {
        error a
    } finally {
        error b
    }
} x y
1
% puts $x
b
% puts $y
-errorstack {INNER {returnImm b {}}} -errorcode NONE -errorinfo {b
    while executing
"error b"} -errorline 5 -during {-code 1 -level 0 -errorstack {INNER {returnImm a {}}} -errorcode NONE -errorinfo {a
    while executing
"error a"} -errorline 3} -code 1 -level 0

就我个人而言,我更倾向于这样写:

代码语言:javascript
复制
proc withreadfile {varName filename body} {
    upvar 1 $varName f
    set f [open $filename]
    try {
        return [uplevel 1 $body]
    } finally {
        close $f
    }
}

proc test {file} {
    withreadfile fh $file {
        # Do stuff with $fh
    }
}

你的里程可能会不同。

票数 1
EN

Stack Overflow用户

发布于 2017-04-15 03:39:33

未经测试的代码(确切的代码段,我多次使用此模式):

代码语言:javascript
复制
proc test file {
    try {
        open $file
    } on ok fh {
        # do stuff with fh
        # more stuff 
    } finally {
        catch {close $fh}
    }
}

应该是一样的。无论您是否使用try结构处理错误,(或者您是否得到错误),finally子句中的代码在结束时都会运行。如果您想要取消该操作,请在子句中使用一个简单的if

编辑

如果您希望看到通道关闭时生成的任何错误,那么只将其包装到catch中是个坏主意,如果不能打开文件,并且没有创建通道id变量,这是必要的。备选办法包括:

  • 检查是否存在:if {[info exists fh]} {close $fh}
  • 传播关闭错误:使用resultoptions变量名称参数到catch
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43417795

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档