разница между списком tcl длины один и скаляром?

У меня есть функция c (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%, когда люди ожидают скалярное значение?

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


person pm100    schedule 29.09.2010    source источник


Ответы (2)


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

Минусов нет, только плюсы.

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

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

person Trey Jackson    schedule 29.09.2010
comment
+1: Хотя я знаю способ сделать то, о чем спрашивает спрашивающий (в 8.6), это не то, что я хочу рассказать людям, как это сделать! Это плохой стиль! Всегда возвращать список — это хороший стиль. - person Donal Fellows; 29.09.2010
comment
так что никаких ошибок, о которых нужно знать звонящим? - person pm100; 29.09.2010
comment
@ pm100 Я в это не верю, им просто нужно знать, что ваш API всегда возвращает список результатов. - person Trey Jackson; 29.09.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]
        }
    }
}

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

person RHSeeger    schedule 29.09.2010