You met generic structs in the Types track. Generic functions are the same idea applied to behavior: write the logic once, run it for every type that fits.
A type parameter on a function
fn first<T>(list: &[T]) -> &T works for a slice of any type T. The <T> after the name introduces the type parameter, exactly like a lifetime or a generic struct. At each call, the compiler figures out what T is from the arguments — you rarely write it explicitly.
Monomorphization, again
Generics cost nothing at runtime. The compiler generates a specialized copy of the function for each concrete type you actually call it with — one for i32, one for &str, each as fast as if hand-written. You get the reuse of a generic with the speed of a specialized function and no runtime dispatch.
The catch that needs traits
A bare T is almost useless — you can move it, but you can't compare, add, or print it, because not every type supports those operations. To say 'this T can be compared,' you constrain it with a trait bound — the very next lesson. Generics give you the parameter; traits give it capabilities.