【问题标题】:"Dead method context" error in a function函数中的“死方法上下文”错误
【发布时间】:2019-05-11 02:58:53
【问题描述】:

我正在尝试编写一个 isBinary 函数来检查发送的行是否有任何不可打印的字符(整数值超出范围 0-127):

isBinary := [ :sline |
    'Reached isBinary fn.' displayNl.
    sline do: [ :char |           "for each character"
        i := char asInteger.      "convert to integer"
        (i < 0 | i > 127) 
        ifTrue: [^true]. ].       "return true if found unprintable"
    ^false. ].                    "if not found above, return false"

(Directory working: '.') allFilesMatching: '*.x'
do: [ :ff |
    ((ff name), ' : ') display.
    infile := FileStream open: ff name mode: FileStream read.
        firstline := infile nextLine.
        (isBinary value: firstline) 
        ifTrue: ['Binary file' displayNl.]
        ifFalse: [ 'Not a binary file' displayNl].
    infile close ].

isBinary 函数已到达,但出现以下错误(无论文件是否为二进制文件):

$ gst isbinary.st
"Global garbage collection... done"
/home/abcd/binaryfile.x : Reached isBinary fn.
Object: Character value: 16rC0 error: return from a dead method context
SystemExceptions.BadReturn(Exception)>>signal (ExcHandling.st:254)
SystemExceptions.BadReturn class(Exception class)>>signal (ExcHandling.st:151)
Character(Object)>>badReturnError (Object.st:1389)
String(SequenceableCollection)>>do: (SeqCollect.st:827)
[] in UndefinedObject>>executeStatements (isbinary.st:4)
optimized [] in UndefinedObject>>executeStatements (isbinary.st:16)
[] in Kernel.RecursiveFileWrapper(FilePath)>>filesMatching:do: (FilePath.st:903)
[] in Kernel.RecursiveFileWrapper>>namesDo:prefixLength: (VFS.st:378)
[] in File>>namesDo: (File.st:589)
BlockClosure>>ensure: (BlkClosure.st:268)
File>>namesDo: (File.st:586)
Kernel.RecursiveFileWrapper>>namesDo:prefixLength: (VFS.st:373)
[] in Kernel.RecursiveFileWrapper>>namesDo:prefixLength: (VFS.st:382)
[] in File>>namesDo: (File.st:589)
BlockClosure>>ensure: (BlkClosure.st:268)
File>>namesDo: (File.st:586)
Kernel.RecursiveFileWrapper>>namesDo:prefixLength: (VFS.st:373)
Kernel.RecursiveFileWrapper>>namesDo: (VFS.st:396)
Kernel.RecursiveFileWrapper(FilePath)>>filesMatching:do: (FilePath.st:902)
File(FilePath)>>allFilesMatching:do: (FilePath.st:775)
Directory class>>allFilesMatching:do: (Directory.st:225)
UndefinedObject>>executeStatements (isbinary.st:11)

在我的代码中用sline asArray do: 替换sline do: 也不起作用(同样的错误)。

问题出在哪里,如何解决?感谢您的帮助。

编辑: 正如答案和 cmets 中所建议的,我用类中的方法编写了以下代码,这很有效。我只想要你的 cmets 这是否是正确的方法。

Object subclass: Checker [ 
    isBinary: sline [ 
        'Reached isBinary fn.' displayNl.
        sline do: [ :char |  | i |           "for each character"
            i := char asInteger.             "convert to integer"
            i > 127
            ifTrue: [^true]     "return true if found unprintable"  
        ].       
    ^false. ]      "if no unprintable char found, return false"
].

(Directory working: '.') allFilesMatching: '*.x'
do: [ :ff |
    '------------------------------' displayNl.
    ((ff name), ' : ') displayNl.
    infile := FileStream open: ff name mode: FileStream read.
        firstline := infile nextLine.
        ((Checker new) isBinary: firstline)
        ifTrue: ['Binary file' displayNl.]
        ifFalse: [ 'Not a binary file' displayNl].
    infile close ].

【问题讨论】:

    标签: function smalltalk


    【解决方案1】:

    您的isBinary 变量绑定到一个包含所谓的非本地返回 的块,该块无法按照您想要的方式执行。原因是非本地返回的语义是从定义 de 块的方法返回(它是词法上下文)。如果这样的方法不存在或已经返回(换句话说,如果词法上下文不在调用堆栈中),则无法定义执行流应返回的位置。因此出现错误。

    要解决这个问题,只需创建一个方法#isBinary: 接收参数sline 以及您为该块编写的代码。然后调用该方法而不是评估该块。这会起作用的。

    【讨论】:

    • 如何创建#isBinary?只需将我的函数重命名为这个名称?还是我需要用这种方法创建一个单独的类?我想避免创建一个新类。您的代码示例将不胜感激。
    • 你可以写sline allSatisfy: [:char | char asInteger &gt; 127]并避免这个问题,因为你会有一个干净的块不引用外部上下文
    • @aka.nice 实际上anySatisfy 效果很好:sline anySatisfy: [:char | char asInteger &gt; 127]。谢谢。
    • @rnso 这个答案确实和我对你的其他问题(stackoverflow.com/a/56100970/383568)的回答差不多。这里增加的困难是您想从isBinary 的循环中“中断”。如果没有适当的返回方法,这是不容易实现的。 anySatisfy 是一个合适的方法,它会从它的循环中返回,并像在您的原始代码中一样以这样的非本地返回。
    • @rnso Leandro 建议您为isBinary 创建一个适当的方法(然后使用参数,因此添加了冒号)。我同意他的观点,并且由于到目前为止您似乎只从命令行运行过简单的脚本,因此建议您学习如何在 GNU Smalltalk 中创建类和方法,而不是仅仅运行简单的脚本,它们本质上是一种方法。如果你已经知道怎么做,为了简洁,你不应该避免它。
    【解决方案2】:

    以下独立方法/块代码通过创建一个返回变量来工作,如果找到不可打印的字符,则该变量的值将在循环中进行操作。然后退出循环:

    isBinary := [ :sline |            "WORKS"
        'Reached isBinary fn: ' display.
        ret := false.                 "return variable initialized to false"
        sline do: [ :char |           "loop for each character in sent line"
            i := char asInteger.      "convert to integer"
            i > 127                   "check if printable"
            ifTrue: [ret := true. exit]].   "ret becomes true if found unprintable; does not work if ^ symbol is used"  
        ret].            "if not found above, ret remains false; ret is returned value"
    

    上述方法无需按照 OP(我!)的要求创建类。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多