Blaszard Blaszard - 7 months ago 12
Swift Question

Is it possible to define [Int] * Int using custom operator in Swift?

I want to define a new operator and multiply each element of the array

[Int]
by
Int
, such as
[3, 2, 10] * 10
.

However, because
Int
is neither protocol nor class (it's struct), I first defined the following:

protocol Numeric {}
extension Int: Numeric {}
extension Double: Numeric {}
extension Float: Numeric {}


And then, I tried defining the operator, like:

func *<T: Numeric> (left: [T], right: T) -> [T] {
var newArray: [T] = []
for i in left {
newArray.append(i * right)
}

return newArray
}


However, this spits out an error:
Cannot convert value of type 'T' to expected argument type '[_]'
.

I'm not sure what the type
[_]
means, which I don't expect, but I guess the problem comes from that I don't have an operator defined that takes
T
and
T
, both of which are
Numeric
in this case.

So I defined another operator, like:

func *<T: Numeric> (left: T, right: T) -> T {
return left * right
}


However, while this has been compiled without problems, the runtime error occurred with a lot of a lot of
static * infix <A where ...> (A, A) -> A
.

enter image description here

I'm not sure why this operator was executed so many times, but now I wonder if it is possible in the first place to define a custom
*
operator, although the
Int
does already have
*
operator defined.

So is it still possible to define
[Int] * Int
operator in Swift?

Answer

You have to require the multiplication operation in the Numeric protocol:

protocol Numeric {
    func *(lhs: Self, rhs: Self) -> Self
}

Otherwise the multiplication in newArray.append(i * right) is not defined.

Your

func *<T: Numeric> (left: T, right: T) -> T {
    return left * right
}

(which calls itself recursively, resulting in a stack overflow) is then not needed.

The implementation of your new operator itself can be simplified (as already described in a now deleted answer) to

func *<T: Numeric> (left: [T], right: T) -> [T] {
    return left.map { $0 * right }
}