Generics

  1. struct Repo<T> {
  2. db DB
  3. }
  4. fn new_repo<T>(db DB) Repo<T> {
  5. return Repo<T>{db: db}
  6. }
  7. // This is a generic function. V will generate it for every type it's used with.
  8. fn (r Repo<T>) find_by_id(id int) ?T {
  9. table_name := T.name // in this example getting the name of the type gives us the table name
  10. return r.db.query_one<T>('select * from $table_name where id = ?', id)
  11. }
  12. db := new_db()
  13. users_repo := new_repo<User>(db) // returns Repo<User>
  14. posts_repo := new_repo<Post>(db) // returns Repo<Post>
  15. user := users_repo.find_by_id(1)? // find_by_id<User>
  16. post := posts_repo.find_by_id(1)? // find_by_id<Post>

At the moment only one type parameter named T is supported.

Currently generic function definitions must declare their type parameters, but in future V will infer generic type parameters from single-letter type names in runtime parameter types. This is why find_by_id can omit <T>, because the receiver argument r uses a generic type T.

Another example:

  1. fn compare<T>(a T, b T) int {
  2. if a < b {
  3. return -1
  4. }
  5. if a > b {
  6. return 1
  7. }
  8. return 0
  9. }
  10. // compare<int>
  11. println(compare(1, 0)) // Outputs: 1
  12. println(compare(1, 1)) // 0
  13. println(compare(1, 2)) // -1
  14. // compare<string>
  15. println(compare('1', '0')) // Outputs: 1
  16. println(compare('1', '1')) // 0
  17. println(compare('1', '2')) // -1
  18. // compare<f64>
  19. println(compare(1.1, 1.0)) // Outputs: 1
  20. println(compare(1.1, 1.1)) // 0
  21. println(compare(1.1, 1.2)) // -1