This block has two problems:
{ (s/\s*$//)&& $_ }
The trivial problem is that it's only removing trailing spaces, not leading, which you said you wanted to remove as well.
The more insidious problem is the misleading use of &&. If the regex in s/// doesn't find a match, it returns undef; on the left side of a &&, that means the right side is never executed, and the undef becomes the value of the whole block. Which means any string that the regex doesn't match will be removed and replaced with a undef in the result array returned by map, which is probably not what you want.
That won't actually happen with your regex as written, because every string matches \s*, and s/// still returns true even if it doesn't actually modify the string. But that's dependent on the regex and a bad assumption to make.
More generally, your approach mixes and matches two incompatible methods for modifying data: mutating in place (s///) versus creating a copy with some changes applied (map).
The map function is designed to create a new array whose elements are based in some way on an input array; ideally, it should not modify the original array in the process. But your code does – even if you weren't assigning the result of map back to @a, the s/// modifies the strings inside @a in place. In fact, you could remove the @a = from your code and get the same result. This is not considered good practice; map should be used for its return value, not its side effects.
If you want to modify the elements of an array in place, your for solution is actually the way to go. It makes it clear what you're doing and side effects are OK.
If you want to keep the original array around and make a new one with the changes applied, you should use the /r flag on the substitutions, which causes them to return the resulting string instead of modifying the original in place:
my @b = map { s/^\s+|\s+$//gr } @a;
That leaves @a alone and creates a new array @b with the trimmed strings.