Use @ when you want to bind the entire matched type to a value, but also want to bind individual elements inside the type. This means that:
case b @ Cls(i) =>
Will assign b to the reference of Cls, such that you can access the i value via b.i. It will also bind i to the first argument of the constructor pattern, which is of type Int. This is useful when you need to evaluate individual values of the type but also need the entire reference to the class, i.e:
case b @ Cls(i) => if (i > 10) b else b.copy(i = 10)
If you only want to bind the entire reference of Cls to a fresh value, use :
case e: Cls =>
This binds the reference to Cls to e.
If we want to get a bit more formal, case f @ Cls is called Pattern Binders:
A pattern binder x @ p consists of a pattern variable x and a pattern
p. The type of the variable x is the static type T of the pattern
p. This pattern matches any value v matched by the pattern p,
provided the run-time type of v is also an instance of T, and it
binds the variable name to that value.
And case c: Cls is called Typed Patterns:
A typed pattern x:T consists of a pattern variable x and a type
pattern T. The type of x is the type pattern T, where each type
variable and wildcard is replaced by a fresh, unknown type. This
pattern matches any value matched by the type pattern T; it binds the
variable name to that value