Есть ли правильный способ «вырваться» из сценария переключения и остаться в процедуре, кроме зацикливания?

Я пытался не повторять один и тот же код в разных блоках переключения и не мог понять, как разбить сценарий переключения, кроме как вернуться и выйти из процедуры.

Мой вопрос: является ли перенос переключателя в цикл while просто для того, чтобы сломать его, когда это необходимо, ужасной вещью, и есть ли лучший способ?

Это заняло у меня некоторое время, но я понимаю, что перерыв не нужен, потому что можно установить переменную в catch и протестировать вне ее, чтобы определить, когда запускается остальная часть кода под opt_2 (как во втором примере кода ниже); но сделать перерыв более понятно, особенно когда реальный код немного сложнее, чем в этом примере.

Спасибо.

% proc SwitchBreak {condition valid} {
  set ui_state 1
  while { 1 } {
    switch -- $condition {
       opt_1 {
         chan puts stdout opt_1
       } opt_2 {
         chan puts stdout opt_2
         if { [info exists ui_state] && $ui_state == $valid } {
           if { [catch { throw {Database Error} {Failed to Write} } result]} {
             chan puts stdout "${result}. Rolled back"
             set rv 1
             set response {Operation Failed}
             break
           }
         }
         chan puts stdout {Opt_1 code to run only when\
            no valid ui_state or valid state succeeds.}
         set rv 0
         set response {Successful write.}
       } opt_3 {
         chan puts stdout opt_3
       } default {
         chan puts stdout opt_4
       }
    }
    break
  }
  chan puts stdout {Code after the switch.}
  chan puts stdout "rv: $rv; response: $response"
}
% SwitchBreak opt_2 1
opt_2
Failed to Write. Rolled back
Code after the switch.
rv: 1; response: Operation Failed
% SwitchBreak opt_2 0 
opt_2
Opt_1 code to run only when no valid ui_state or valid state succeeds.
Code after the switch.
rv: 0; response: Successful write.

Ни петли, ни разрыва.

proc SwitchBreak {condition valid} {
  set ui_state 1
    switch -- $condition {
       opt_1 {
         chan puts stdout opt_1
       } opt_2 {
         chan puts stdout opt_2
         set rv 0
         if { [info exists ui_state] && $ui_state == $valid } {
           if { [catch { throw {Database Error} {Failed to Write} } result]} {
             chan puts stdout "${result}. Rolled back"
             set rv 1
             set response {Operation Failed}
           }
         }
         if { $rv == 0 } {
           chan puts stdout {Opt_1 code to run only when\
              no valid ui_state or valid state succeeds.}    
           set response {Successful write.}
         }
       } opt_3 {
         chan puts stdout opt_3
       } default {
         chan puts stdout opt_4
       }
    } 
  chan puts stdout {Code after the switch.}
  chan puts stdout "rv: $rv; response: $response"
}

% % 
% Switch opt_2 1
opt_2
Failed to Write. Rolled back
Code after the switch.
rv: 1; response: Operation Failed
% SwitchBreak opt_2 0
opt_2
Opt_1 code to run only when no valid ui_state or valid state succeeds.
Code after the switch.
rv: 0; response: Successful write.

Не уверен насчет вашего случая, но в некоторых языках среди общепринятых методов обработки сложных переходов эффективным способом является перенос частей в вызовы функций.

Abel 31.03.2024 01:22

Просто слежу, чтобы посмотреть, какую помощь вы получите. За исключением нескольких тривиальных expect скриптов, я не использовал Tcl для чего-то столь же сложного, как то, что вы делаете, более 30 лет. Мне интересно, вы это делаете в рамках expect программы или независимо от нее? И если последнее, то почему, ведь почти наверняка есть варианты получше?

Kurtis Rader 31.03.2024 03:13

SQLite имеет привязки для многих популярных языков, включая Go и Python (я использовал SQLite с обоими). Я рекомендую использовать любой из этих языков, который вы предпочитаете, а не привязку Tcl.

Kurtis Rader 31.03.2024 03:51

@KurtisRader Спасибо за рекомендацию. Я никогда не использовал ни один из этих языков; и в целом у вас нет большого опыта программирования. Тем не менее (и, пожалуйста, знайте, что я не пытаюсь показаться грубым или затеять спор), Tcl мне очень понравился; и чем больше я узнаю об этом, тем больше мне это нравится. Если бы я был молодым человеком, интересующимся информатикой в ​​своей карьере, я бы изучал исходный код Tcl и SQLite.

Gary 31.03.2024 04:34

Если вы неопытный программист, изучение Tcl бесполезно. Вам следует изучать это только в том случае, если вам это абсолютно необходимо. Например, если вы собираетесь внести изменения в проект SQLite. Инвестиции в изучение современных языков, таких как Go, Rust и т. д. (все они имеют привязки к SQLite), в долгосрочной перспективе принесут вам гораздо больше пользы. Tcl был создан в 1986 году; через десять лет после того, как я начал учиться программировать. Он имеет множество недостатков и сейчас используется лишь в нескольких нишевых приложениях, таких как tkinter и SQLite. Опять же, вам лучше выучить другой язык.

Kurtis Rader 31.03.2024 04:50

Я не знаю о недостатках Tcl и индустрии программирования, но, честно говоря, Tcl, должно быть, все еще активен. Например, второе издание книги Оустерхаута (основателя Tcl) о Tcl/Tk было опубликовано в 2010 году; Ашок Надкарни написал текст большего размера только на Tcl в 2017 году; и вышло обновление до 8.6.1425 марта этого года. Это может быть ниша, поскольку объявления о вакансиях, в которых упоминается Tcl, предназначены только для компьютерных гениев, а не для новичков вроде меня.

Gary 31.03.2024 07:01

@Gary Я думаю, будет справедливо сказать, что вы можете игнорировать фразы «Я не знаю ответа на ваш вопрос, используйте библиотеку, о которой я кое-что знаю». Хотя я также не являюсь экспертом в tcl, я бы изучил сопрограммы , поскольку tcl изначально поддерживает цикл событий, я не уверен, действительно ли вам нужно зацикливаться на этом.

Thingamabobs 31.03.2024 07:27

@Gary FORTRAN и COBOL все еще активны (раньше я хорошо владел этими языками). Это не значит, что я бы порекомендовал новому программисту приложить усилия для изучения этих языков. :-) Это не имеет ничего общего с тем, что Tcl предназначен только для «компьютерных гениев, а не для новичков». Tcl — это просто интересный язык, предназначенный для определенной цели (встраиваемый в приложения для управления их поведением) и никогда не получивший широкого распространения в качестве языка общего назначения. Он, конечно, не умер, но мне кажется, что ОП было бы лучше взаимодействовать с SQLite, используя другой язык.

Kurtis Rader 31.03.2024 07:36

@Thingamabobs Будет интересно, сколько времени понадобится кому-то, чтобы ответить на вопрос ОП. Вот почему я скрываюсь и призываю ОП использовать другую языковую привязку для взаимодействия с SQLite. Кроме того, я не предлагаю ОП использовать «библиотеку, о которой я что-то знаю». Я предлагаю им использовать другую языковую привязку. Tcl — это просто одна из многих языковых привязок для библиотеки SQLite. Хотя эта привязка рассматривается проектом как особая из-за ее использования в модульных тестах.

Kurtis Rader 31.03.2024 07:47
switch не является циклом, поэтому, конечно, конструкции управления циклом, такие как break, с ним не работают. Может быть, немного меньше кода и немного больше объяснений того, чего вы пытаетесь достичь (не как; что)?
Shawn 31.03.2024 07:57

@KurtisRader Это будет не единственный вопрос, на который нет ответов по SO. Если бы OP хотел работать с огромной базой данных и имел проблемы с производительностью, а tcl просто достиг своего предела, поскольку ядро ​​tcl не предназначено для работы с огромными базами данных, и кто-то рекомендует использовать для этого Python, это было бы разумно сделать это. Поскольку ОП не достигает каких-либо пределов и просто хочет перейти к уже известной технологии ОП, просто неразумно предлагать другой язык в этом контексте.

Thingamabobs 31.03.2024 08:00

(Я бы предпочел использовать tcl для работы с базой данных sqlite, чем с Python)

Shawn 31.03.2024 08:03

@Shawn Код OP использует break внутри switch внутри while цикла. Во многих (большинстве?) языках break завершает цикл while. Разве это не относится к Tcl? Опять же, я говорю это как человек, который три десятилетия назад был минимально компетентным программистом на Tcl и с тех пор использовал его только для написания сценариев в инструменте expect. ОП также, кажется, адекватно объяснил, что они пытаются сделать. Так что меня немного смутил ваш комментарий.

Kurtis Rader 31.03.2024 08:13

@KurtisRader Да, это вырвется из цикла. Но цель ОП, похоже, состоит в том, чтобы как можно скорее завершить тело переключателя. Вопрос в том, что они делают, что заставляет их хотеть это сделать? Возможно, существует лучший способ размещения кода, но для того, чтобы сказать наверняка, нужно более четкое представление о цели. По сути, мне интересно, является ли это проблемой XY.

Shawn 31.03.2024 08:16

Есть ли правильный способ «вырваться» из сценария переключения и остаться в процедуре, кроме зацикливания? По моему мнению, это на самом деле требует сопрограмм, сохраняющих контекст при возврате. Но опять же, я не эксперт в tcl и не могу предоставить какое-либо кодовое решение для этой проблемы.

Thingamabobs 31.03.2024 08:23
catch throw кажется дорогим способом установить переменную...
Donal Fellows 31.03.2024 19:17
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
16
109
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Хотя это законно, поскольку вы можете написать это, и оно будет выполняться правильно, мне это кажется очень некрасивым; простой if...else, казалось бы, мог бы выразить намерение, но на самом деле был бы более ясным. Я бы даже сказал, что обычно я ожидаю, что это будет правдой.

# Just the bit inside the switch case
chan puts stdout opt_2
if {
    [info exists ui_state] && $ui_state == $valid
    && [catch {
        # This is a stand-in for something real, right? Right?
        throw {Database Error} "Failed to Write"
    } result]
} then {
    chan puts stdout "${result}. Rolled back"
    set rv 1
    set response "Operation Failed"
} else {
    chan puts stdout "Opt_1 code to run only when\
        no valid ui_state or valid state succeeds."
    set rv 0
    set response "Successful write."
}

Будет ли случай, когда лучше всего проделать эту запутанную вещь с помощью однократного запуска while? Я сомневаюсь в этом... но никогда не говори никогда.


Однократный запуск for будет немного лучше, если вы поместите break в предложение приращения. Таким образом, вверху будет яснее, что вы делаете.

Или вы можете использовать try с предложением on break.

Спасибо. Да, throw является заменой довольно простой транзакции upsert. Во втором примере используется if, но не так, как в вашем. Думаю, я был сосредоточен на том, при каких условиях выполнять транзакцию с базой данных, и не смог увидеть, что успех этой транзакции может быть частью этого единственного if. Если сценарий if сложнее, я попробую try с on break или просто вынесу это в отдельную процедуру; и избегайте любой формы цикла однократного запуска.

Gary 31.03.2024 23:18

Я не знал, что в операторе then есть необязательный if. Обычно я ссылаюсь на два печатных текста по Tcl, а не на Интернет; и если кто-то об этом пишет, то я это пропустил. Однако это ясно на странице руководства Tcl.

Gary 31.03.2024 23:27

Что ж, онлайн-документы и страницы руководства (обе взяты из одного и того же источника) являются исчерпывающими справочными материалами. Книги — это учебный материал, но не нормативный документ.

Donal Fellows 01.04.2024 00:03

Другие вопросы по теме