2013-05-30 2 views
0

Если у меня есть гипотетическая-структура:Определить, если структура инициализируются

type Config struct { 
     Server struct { 
       Host string 
       Port uint16 
       Timeout uint32 
     } 
} 

Я хочу знать, является ли хост и порт установлены или недобросовестными (Host к «» и порту или Таймаут 0). Есть ли эффективный способ сделать это? Потенциально использовать библиотеку отражений?

Кроме того, я предполагаю, что «» и 0 являются допустимыми.

Некоторое основание: я использую библиотеку gcfg для чтения файла конфигурации стиля INI и хочу знать, не установил ли кто-либо один из записей конфигурации.

+0

В принципе, вы пытаетесь отличить значение по умолчанию от значения? – creack

+1

Есть ли что-нибудь, что мешает вам делать что-то вроде 'if (Config.Server.Host ==" "&& Config.Server.Port == 0)'? Я не думаю, что вам нужно * использовать рефлексию, но если вы это сделаете, посмотрите http://golang.org/pkg/reflect/#DeepEqual. – Intermernet

+0

Я могу сделать вышеприведенный оператор if, однако я думаю, что с большим конфигурационным файлом это выйдет из-под контроля. Мой друг придумал http://play.golang.org/p/9g2OMLdgYq как хороший способ проникнуть в глубокие структуры (которые я мог бы использовать для сравнения тех, которые устанавливаются по сравнению с теми, которые находятся в структуре cfg) –

ответ

2

Вы не можете этого сделать. По крайней мере, если мое понимание вашей проблемы верное:

Вы хотите знать, например. если кто-то намеренно установил Timeout = 0, или время ожидания равно нулю, потому что время ожидания инициализировало Timeout до нулевого значения uint32?

Если 0 хранится в этом uint32, вы не можете различить «Это 0 был установлен некоторым пользователем, выполнив Timeout = 0». и «Это значение 0 было задано временем выполнения во время инициализации структуры». Существует только один 0, и этот 0 не имеет истории.

Если нужно сказать разницу вы могли бы изменить Timeout uint32 к Timeout *uint32: Среда инициализирует Timeout всухую. Если Timeout не равен нулю, он был установлен. (Но это приходит с очевидной ценой нулевых чеков везде, дополнительной обработкой ошибок и сложной обработкой.)

+0

Я предположил, что это так, но просто подумал, что я проверю. Я не думаю, что код выиграет от дополнительной сложности, но я буду помнить об этом! Большое спасибо. –

0

Не прямой ответом, но общая альтернатива такого рода проблемы:

Используйте нилъ-указатель для представления ссылка на неинициализированную структуру. Вам понадобится указатель в любом случае, если вы планируете передать структуру в ini-парсер.

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

http://play.golang.org/p/VkkXSuqbhi

package main 

import "fmt" 

type Config struct { 
    Server struct { 
     Host string 
     Port uint16 
     Timeout uint32 
    } 
} 

func main() { 
    var c *Config 
    fmt.Println(nil == c) 
    c = &Config{} 
    fmt.Println(nil == c) 
} 
+0

К сожалению, это скажет мне, не была ли затронута структура Config в целом, а не то, что Config.Server.Host по умолчанию. В принципе, если в моем файле конфигурации отсутствовал 1 элемент. –

2

Я предполагаю, что вы используете gcfg - У меня был очень похожий вопрос, когда я начал использовать gcfg. Мое решение заключалось в том, чтобы загружать мои значения по умолчанию явно, а затем загружать файлы (файлы) поверх них.

Here's mine; наслаждаться.

+0

, хотя и не был прямым ответом на мой вопрос (что было связано с рефлексией), я считаю, что именно так я собираюсь решить эту проблему. Большое спасибо за Вашу помощь! –

0

Следующая, вероятно, добавить больше сложности, чем вы хотите, но только так вы в курсе всех вариантов:

требования к документации Gcfg (в самом деле я не сделал это сам), что обеспечивает еще одну альтернативу , через интерфейс fmt.Scanner. Любой именованный тип, который вы объявляете, может быть проанализирован из файла INI, если он реализует fmt.Scanner.

Имея это в виду, вы могли бы, если бы вы чувствовали себя, как это, сделать что-то вдоль линий следующее:

package main 
import (
    "fmt" 
    "strconv" 
    "strings" 
) 
type OptionalInt struct { 
    IsSet bool 
    Value int 
} 

//This method definition is rather impromptu and may not be the best way to scan an int 
func (optInt *OptionalInt) Scan (state fmt.ScanState, verb rune) (err error) { 
    var token []byte 
    var n int 
    token, err = state.Token(true, nil) 
    if err==nil { 
     n, err = strconv.Atoi(string(token)) 
     if err==nil{ 
      optInt.Value = n 
      optInt.IsSet = true 
     } 
    } 
    return 
} 

type Config struct { 
    Port OptionalInt 
    TimeOut OptionalInt 
} 

func main(){ 
    //whatever... 
} 

Если вы сделаете это, то после того, как вы загрузили все данные из INI в вашу конфигурационную структуру, данные появятся в наборе полей OptionalInt. И для каждого такого поля вы сможете проверить IsSet, а также значение внутри.

Если этот подход обращается к вам, и вы в конечном итоге его пытаетесь, возможно, вы можете оставить комментарий здесь, чтобы все остальные знали, как это работает.

-1

Избавьтесь от gcfg и используйте стандартные флаги go с iniflags. Это позволит вам удалить кучу хакерского кода, упомянутого в других ответах, и сделать ваш код более идиоматичным, поддерживая значения и описания по умолчанию для каждого значения конфигурации из коробки.

Смежные вопросы