2011-11-02 12 views
13

Un paquete que estoy usando, gosqlite, tiene un método con un parámetro variadic en su tipo es la interfaz de vacío.Pass rebanada cadena a variadic parámetro de la interfaz vacío

func (s *Stmt) Exec(args ...interface{}) os.Error 

puedo llamar a este bien si pasar explícitamente los parámetros individuales:

statement := blah() 
error := statement.Exec("hello", 3.0, true) // works fine 

Sin embargo, como el parámetro variadic corresponde a los marcadores de posición en el operador de in de mi instrucción SQL de select, el número de estos marcadores de posición es no se conoce en tiempo de compilación pero cambia dinámicamente en tiempo de ejecución según lo que esté haciendo el usuario. P.ej. Termino con SQL similar a la siguiente si el usuario introduce cuatro valores:

SELECT * FROM sky WHERE name IN (?,?,?,?) 

Así que, naturalmente, me gustaría llamar al método Exec con una rodaja de cuerdas:

var values []string = getValuesFromUser() 
statement := createStatementWithSufficientNumberOfPlaceholders(len(values)) 
_ := statement.Exec(values...) // compiler doesn't like this 

Esto no compila . Puedo solucionar este problema mediante la creación de una rodaja de interfaz de vacío y la copia de las referencias sobre: ​​

values2 := make([]interface{}, len(values)) 
for index, value := range values { values2[index] = value } 
_ := statement.Exec(values2...) // compiler happy but I'm not 

Y esto funciona bien pero se siente un poco torpe. Me preguntaba si había algún truco para poder pasar el values directamente a esta función o, en su defecto, una forma más clara de convertir el segmento de cadena en uno de interfaz vacía.

Muchas gracias.

Respuesta

9

No hay forma de pasar un []string directamente a un parámetro ...interface{}. Hacer esto requiere una copia de tiempo lineal (¡con n + 1 asignaciones!). Si el lenguaje te oculta esto, sería un costo oculto significativo. Normalmente, pasar una porción a un argumento variado simplemente pasa el corte en la función.

En cuanto a otras formas de hacerlo, puede hacerlo más limpio escribiendo una función que toma un []string y devuelve el []interface{} correspondiente. Por supuesto, tendrá que volver a escribirlo para cada conversión []T ->[]interface{} que desee hacer, pero es una función bastante corta, y todo lo que cambia es la firma. Se podría utilizar reflection, que viene con un coste inherente en tiempo de ejecución, para hacer la función de "genérico", como por ejemplo en:

valuesVal := reflect.ValueOf(values) 
... 
for i := range values2 { values2[i] = valuesVal.Index(i).Interface() } 
+0

He dejado el código de conversión en línea en este momento: la función parece excesiva cuando la agregué. Supongo que el problema, en última instancia, es que Go no es compatible con matrices/divisiones covariantes de la manera en que estoy acostumbrado en Java y C#, que tal vez [no es algo malo] (http://en.wikipedia.org/wiki /Covariance_and_contravariance_(computer_science)#Arrays_in_C.23_and_Java). –

1

no tengo una respuesta. Y supongo que no hay un solo puesto que incluso incorporado y variadic copia y anexar tienen el mismo (o compatible hormigón) Tipo de elemento de "tonto", pero tengo dos sugerencias obvias:

  • no devuelva []string de getValuesFromUser() (es decir, pasar todavía sin adornos []interface{}),
  • en el otro extremo de envoltura tipo llamadas a statement.Exec() con un func haciendo []string a []interface{} conversión.

O en la misma, tercera nota obvia extienda type statement con Exec(args ...string).

P.S. No he hecho ningún punto de referencia, pero no creo que este tipo de conversión sea muy costoso ya que la interfaz {} se siente como un tipo de referencia y el compilador probablemente esté haciendo algunos trucos sucios detrás de la cortina ... y quizás otra vez no, , También sería feliz de aprender de una solución real.

+0

Gracias por las sugerencias. Sin embargo, creo que sería más incorrecto pasar '[] interfaz {}' de 'getValuesFromUser()' de lo que sería pagar el precio de la copia. En cuanto a extender el tipo: esta es una idea interesante, pero con la advertencia de que Go no admite funciones sobrecargadas, por lo que debería tener un nombre diferente. –

+0

@PaulRuane no quiero sonar demasiado filosófico, pero no veo cómo podría ser incorrecto, siempre y cuando esto permanezca oculto para el usuario final (siempre puede escribir cast/assert para referencia futura). sobre un tema similar también hay una [sugerencia] anterior (http://stackoverflow.com/questions/3839335/any-sensible-solution-to-the-lack-of-array-slice-covariance-in-go/5370177# 5370177) de SteveMcQuark que me pareció interesante. – ypb

Cuestiones relacionadas