In Swift can you constrain a generic to two types? String and Int
Other answers have demonstrated how to, in the general case, create a generic function constrained to two or more otherwise-unrelated types. If that general issue is what your question is really about, you're good to go.
However, if the example use case you provided resembles something you actually want to do, fooling around with generics probably isn't what you want.
The input is conceptually a "number" but it could be either a string in French, or, an integer. So the input could be a String "cent" or an Int 100. the result would be say the square root, so either String "dix" or Int 10.
This means you actually have (at least) two problems (and you didn't even use regular expressions!)...
Convert user input text to a numeric type.
(Probably your eventual type is
Float
orDouble
, because transcendental functions like square-root aren't defined onInt
in the standard library. Also note that you have to do this even if user input is "numeric" -- that is, a string containing numerals -- because that string can contain other characters which may or may not affect its "meaning" as a number.)Find the square root of the number.
(Optional, may or may not be part of your full design.) Present the answer in nice, human-readable format, possibly one resembling the format of the user's input.
Step 2 is simple, once you have a number. For Steps 1 and 3, you can at least get started with a NumberFormatter
:
guard let num = formatter.number(from: "one hundred") as? Double
else { fatalError("better error handling plz") }
let root = sqrt(num)
guard let rootText = formatter.string(from: root as NSNumber)
else { fatalError("better error handling plz") }
print(rootText) // "ten"
Set formatter.locale = Locale(identifier: "ja_JP")
and you get "十" for "百", use fr_FR
or fr_CA
and "cent" becomes "dix", etc.
However, interpreting user text is always messy. What if they enter "one hundred twenty one" instead of "one hundred twenty-one"? What about "eleventyone"? What if there are other extraneous characters? NumbeFormatter
can't recognize the entire universe of possible natural-language numeric expressions.
You have some logic to think about in your processing and output, too. What's to happen if the user-entered number doesn't have an integer square root? Do you really want to display "ten point zero four nine eight seven five six two one one two zero nine" in your UI?
Big, hairy questions like this are a good reason to factor apart the different tasks in your program instead of running all your logic through one generic function. (And there are simple reasons, too, like being able to reuse your number/text conversion code for multiple math operations.)
I was thinking something like this, although it does seem that an enumeration would be a fine answer.
protocol HasSquareRootMethod {
var squareRoot: Int { get }
}
extension Int {
var squareRoot: Int { return 0 }
}
extension String {
var squareRoot: Int { return 0 }
}
This is not a job for generics. There's nothing generic about working with a static set of two types.
This the perfect situation to use an enumeration:
enum SomeEnum { //TODO: name me
case string(String)
case int(Int)
}
func foo(input: SomeEnum) -> SomeEnum {
switch input {
case .string(let s):
print("This is a String: \(s)")
return(.string("abc"))
case .int(let i):
print("This is an Int: \(i)")
return(.int(123))
}
}
print(foo(input: SomeEnum.string("qwerty")))
print(foo(input: SomeEnum.int(5)))
You can try it here