Cannot use args (type []string) as type []interface {}

go
14,037

The error is pretty clear, the function expects type []interface{} but you're passing in a value of type []string. You have to first convert []string to []interface{} before passing it to Exec. And the way to do that is to loop over the strings and add each one to a new slice of interface{}.

https://golang.org/doc/faq#convert_slice_of_interface


As an alternative approach, you can change the Insert argument types.

func Insert(query string, args ...interface{}) (err error) {
    db, err := sql.Open("sqlite3", "sqlite.db")
    if err != nil {
        return err
    }
    q, err := db.Prepare(query)
    if err != nil {
        return err
    }
    _, err = q.Exec(args...)
    return err
}

func main() {
    err := Insert("INSERT INTO table(first,last) VALUES(?,?)", "Nantha", "nk")
    if err !=nil{
        fmt.Println(err.Error())
        return
    }
}

Please note that you're using the database/sql package incorrectly. Many of the objects returned from that package's functions/methods need to be closed to release the underlying resources.

This is true for *sql.DB returned by Open, *sql.Stmt returned by Prepare, *sql.Rows returned by Query, etc.

So your function should look closer to something like this:

func Insert(query string, args ...interface{}) (err error) {
    db, err := sql.Open("sqlite3", "sqlite.db")
    if err != nil {
        return err
    }
    defer db.Close()

    q, err := db.Prepare(query)
    if err != nil {
        return err
    }
    defer q.Close()

    _, err = q.Exec(args...)
    return err
}

Also note that sql.DB is reusable, that means that you don't have to sql.Open a new instance every time you need to talk to the database.

From the docs on Open:

The returned DB is safe for concurrent use by multiple goroutines and maintains its own pool of idle connections. Thus, the Open function should be called just once. It is rarely necessary to close a DB.

If you keep doing it the way you're doing it, openning a new DB every time you call Insert or any other function that needs to talk to the DB, your program will perform worse than if you had a single DB and have your functions reuse that.

Share:
14,037

Related videos on Youtube

Ram
Author by

Ram

:)

Updated on June 04, 2022

Comments

  • Ram
    Ram almost 2 years

    my golang sqlite insert function. i'm using this package "github.com/mattn/go-sqlite3"

    func Insert(args ...string)(err error){
      db, err:=sql.Open("sqlite3","sqlite.db")
      if err !=nil {
        return
      }
      q, err := db.Prepare(args[0])
      if err !=nil{
        return
      }
      _,err = q.Exec(args[1:]...)
      return
     }
    main (){
      err := Insert("INSERT INTO table(first,last) VALUES(?,?)","Nantha","nk")
      if err !=nil{
      fmt.Println(err.Error())
        return
      }
    }
    

    i'm getting this error

    cannot use args (type []string) as type []interface {} in argument to q.Exec

    • mkopriva
      mkopriva over 4 years
      You have to convert []string to []interface{} before passing it to Exec. And the way to do that is to loop over the strings and add each one to a new slice of interface{}.
    • Peter
      Peter over 4 years
    • Ram
      Ram over 4 years
      any other solution without using loop
    • mkopriva
      mkopriva over 4 years
      No, there isn't.
    • Volker
      Volker over 4 years
      @mkopriva He could use a recursive solution which formally isn't a loop ;-)
  • Ram
    Ram over 4 years
    v:= []interface{}{"nantha","nk"} -> Insert(q,v) i'm getting unsupported type []interface {}, a slice of interface
  • mkopriva
    mkopriva over 4 years
    @Nantha You don't need to do that, Insert(q, "Nantha", "nk") will still work, even after you change the Insert to Insert(query string, args ...interface{})
  • mkopriva
    mkopriva over 4 years
    @Nantha and if you want to use v := []interface{}{"nantha","nk"}, you can do it like this Insert(q, v...).
  • Ram
    Ram over 4 years
    it's working :) thank you so much