TclOO: разница между объявлением переменной на уровне класса или в конструкторе - PullRequest
2 голосов
/ 24 сентября 2019

Я не совсем понимаю, где использовать variable myVar и когда требуется использовать my variable myVar

Если я определю такой класс, ошибок не будет:

oo::class create Foo {
    variable bar

    constructor {input} {
        set bar $input
    }

    method twoBar {} {
        return [expr {2 * $bar}]
    }
}

затем

% set f [Foo new 42]
::oo::Obj12
% $f twoBar
84

Но если я переместу variable bar в конструктор:

oo::class create Foo {
    constructor {input} {
        variable bar
        set bar $input
    }

    method twoBar {} {
        return [expr {2 * $bar}]
    }
}

, тогда

% set f [Foo new 42]
::oo::Obj12
% $f twoBar
can't read "bar": no such variable

Это решается добавлением my variable bar вtwoBar метод.

Что происходит?

1 Ответ

3 голосов
/ 24 сентября 2019

Внутри метода variable - это просто известная вам обычная команда Tcl, а текущее пространство имен - это пространство имен экземпляра (которое есть у каждого объекта).

На уровне объявления variable отличается. (Это совершенно другая команда.) Он настраивает переменный преобразователь для настроенного объекта (в данном примере класса Foo), чтобы иметь имя переменной, которое, если ононе найден в локальной области (метода), будет найден в пространстве имен экземпляра;решатель фактически сделает это для списка имен переменных.Переменный преобразователь применяется ко всем методам, определенным этим классом - но не его подклассы или суперклассы (я пробовал другой способ; это отстой) - или экземпляр, если в контексте, определяющем экземпляр.1013 * В ваших примерах это означает, что:

  1. В первом случае и конструктор, и метод twoBar имеют bar на самом деле ссылаются на переменную ::oo::Obj12::bar (при обычных предположенияхоб именах пространств имен в реализации TclOO).
  2. Во втором случае, когда bar относится к ::oo::Obj12::bar в конструкторе (технически, только после вызова variable), в twoBarМетод bar всегда относится только к локальной переменной, которую вы никогда не устанавливали.Это означает, что чтение из bar завершается неудачно (из-за стандартной семантики чтения переменных).

Вызов my variable bar имеет тот же эффект, что и variable bar внутри этого метода.Разница заключается в том, что один из них может быть вызван как вызываемый извне объекта, а другой может связывать и устанавливать несколько переменных одновременно;оба они используются редко, но принципиально различаются.


На уровне байт-кода единственное заметное различие между двумя методами twoBar заключается в следующем (в первой версии):

% tcl::unsupported::disassemble method Foo twoBar
ByteCode 0x0x7ff5a2845810, refCt 1, epoch 17, interp 0x0x7ff5a2808010 (epoch 17)
  Source "\n        return [expr {2 * $bar}]\n  ..."
  Cmds 2, src 38, inst 6, litObjs 1, aux 0, stkDepth 2, code/src 0.00
  Proc 0x0x7ff5a2835f10, refCt 1, args 0, compiled locals 1
      slot 0, scalar, resolved, "bar"
  Commands 2:
      1: pc 0-5, src 9-32        2: pc 0-4, src 17-31
  Command 1: "return [expr {2 * $bar}]..."
  Command 2: "expr {2 * $bar}..."
    (0) push1 0     # "2"
    (2) loadScalar1 %v0     # var "bar"
    (4) mult 
    (5) done 

Переменная bar (в слоте 0) помечена как «resolved» (что делает махинации под крышками).В остальном они полностью идентичны.Конструкторы имеют серьезные различия в последовательности команд, поэтому их сложно сравнивать, но мы все еще можем видеть, что там происходит.

% tcl::unsupported::disassemble constructor Foo
ByteCode 0x0x7ff5a2845c10, refCt 1, epoch 17, interp 0x0x7ff5a2808010 (epoch 17)
  Source "\n        set bar $input\n  ..."
  Cmds 1, src 28, inst 5, litObjs 0, aux 0, stkDepth 1, code/src 0.00
  Proc 0x0x7ff5a2835d90, refCt 1, args 1, compiled locals 2
      slot 0, scalar, arg, "input"
      slot 1, scalar, resolved, "bar"
  Commands 1:
      1: pc 0-3, src 9-22
  Command 1: "set bar $input..."
    (0) loadScalar1 %v0     # var "input"
    (2) storeScalar1 %v1    # var "bar"
    (4) done 

Опять же, bar - это resolved

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...