Разница между списком tcl длины один и скаляр? - PullRequest
1 голос
/ 29 сентября 2010

У меня есть функция переменного тока (dbread), которая читает «поля» из «базы данных».Большинство из этих полей однозначны;но иногда они многозначны.Итак, у меня был c-код, который сказал:

if valcount == 1
   return string
else
    make list
    foreach item in vals
        append to list
    return list

Потому что я думал, что большую часть времени люди хотят скаляр.

Однако это приводит к некоторым странным ошибкам синтаксического анализа.В частности, если я хочу добавить значение

set l [dbread x]            # get current c value
lappend l "extra value"     # add a value
dbwrite x {*}$l             # set it back to db

Если x имеет единственное значение, и это значение содержит пробелы, то Lappend неправильно анализирует.Я получаю список с 3 пунктами, а не с 2. Я вижу, что это происходит потому, что ему передается что-то, что не является списком, и он анализирует его в списке и видит 2 элемента.

set l "foo bar"
lappend l "next val" # string l is parsed into list -> [list foo bar]

, поэтому я получаюс [list foo bar {next val}]

В любом случае, решение состоит в том, чтобы dbread всегда возвращал список - даже если есть только один элемент.Мой вопрос - есть ли минус в этом?Есть ли сюрпризы, скрывающиеся в 90% случаев, когда люди ожидают скаляр

Альтернативой будет сделать мой собственный lappend, который проверяет llength == 1 и в особых случаях это

Ответы [ 2 ]

4 голосов
/ 29 сентября 2010

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

Нет недостатков, только потенциал роста.

Подумайте об этом, что если вы отойдете от возврата одного скаляра, и в будущем у вас будет случай, когда вы вернете значение single , которое окажется строкой с пробелом в нем. Если бы вы не создавали список из этого единственного значения, вы бы восприняли его как два значения (потому что Tcl перелистывает строку в список из двух вещей). Всегда создавая список возвращаемых значений, весь код, использующий ваш API, будет обрабатывать это правильно.

Тот факт, что Tcl не имеет строгой типизации, не означает, что это хороший стиль для возврата разных типов в разное время.

0 голосов
/ 29 сентября 2010

Один из подходов, которые я использовал в прошлом (когда данные для каждой строки могли содержать нули или пустые строки), заключался в использовании списка списков списка:

{{a b} {c d}}  ;# two rows, each with two elements
{{{} b} {c d}} ;# two rows, first element of first row is null 
               ;# llength [lindex [lindex {{{} b} {c d}} 0] 0] -> 0
{ { {{}} b } { c d } } 
               ;# two rows, first element of first row is the empty string
               ;# llength [lindex [lindex {{{{}} b} {c d}} 0] 0] -> 1

Это выглядит сложно, но на самом деле это не так, если вы рассматриваете фактические элементы данных как непрозрачную структуру данных и добавляете средства доступа для ее использования:

foreach row $db_result {
    foreach element $row {
        if {[db_isnull $element]} { 
            puts "null" 
        } elseif {![string length [db_value $element]]} {
            puts "empty string"
        } else {
            puts [db_value $element]
        }
    }
}

Конечно, гораздо сложнее, чем вы ищете, но я подумал, что стоит упомянуть.

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