I have represented the results of my API requests using Result Enum with generic type as follow Result<T: Resource, Error>
In some cases I do not want to discuss whether the request has succeed or failed but I still need the returned resource as nullable value.
I tried to write the extension as the code below:
extension Result<T, Error> where T: Resource {
var value: Any? {
switch self {
case .success(let resource):
return resource.value
case .failure:
return null
}
}
}
However I got these compiler errors:
Constrained extension must be declared on the unspecialized generic type 'Result' with constraints specified by a 'where' clause
Use of undeclared type 'T'
You can simply create extension as below,
extension Result {
var value: Any? {
switch self {
case .success(let resource):
return resource
case .failure:
return nil
}
}
}
As in the enum definition, T is always Resource so you don't need to specify in the extension.
But if Resource is some protocol and you want to put a constraint on value variable in declaration then you can specify that in the extension using where clause as below,
extension Result where T == someSubTypeOfResource {
var value: Any? {
switch self {
case .success(let resource):
return resource
case .failure:
return nil
}
}
}
Write the type constraint as follows:
enum Result<T, Error> {
case success(T)
case failure(Error)
}
struct Resource {
let value: String
}
extension Result where T == Resource {
var value: Any? {
switch self {
case .success(let resource):
return resource.value
case .failure:
return nil
}
}
}
You can simply do it like,
enum Result<T> where T: Resource {
case success(T)
case failure(Error?)
}
Create the enum Result with case success accepting a generic associated value of type Resource and another case failure with Error? as its associated value.
Since you're using the generic param of type Resource, I assume Resource is a protocol having value as one of its properties.
protocol Resource {
var value: String {get set}
}
Now, the extension Result goes like,
extension Result {
var value: Any? {
switch self {
case let .success(resource):
return resource.value
case let .failure(error):
return error
}
}
}
Now return error in case failure and resource.value for case success.
There is no need to specify the generic parameter T with where clause in the extension again since you did that already while defining the enum Result.
Usage:
struct R1: Resource {
var value: String
}
let r1 = R1(value: "R1 is of type Resource")
let result = Result<R1>.success(r1)
print(result.value)
Related
I want to make an enum that returns a class type that conforms to the codable protocol for Networking Layer.
enum SearchQueryType : String, CaseIterable{
case podcast
case episode
var classType: Any {
switch self {
case .podcast:
return PodcastSearchResponse.self
case .episode:
return EpisodeSearchResponse.self
}
}
static func objectForType <T> (type: String) -> T {
return self.allCases.first{$0.rawValue == type}!.classType as! T
}
}
the problem is when assigning the generic type from objectForType function I get an error says "Generic parameter 'T' could not be inferred"
func search (for query: String, type: String, sortByDate: Bool) {
let endpoint = SearchResultRequest.searchFor(query: query, type: type, sortByDate: sortByDate)
var objectType = SearchQueryType.ObjectForType(type: type)
NetworkManger.shared.callRequest(objectType: objectType , endpoint: endpoint) { (result) in
switch result{
}
}
}
I tried to return a type that conforms to the codable protocol, but I get an error from the search function that says the expected T.type is not codable.
is there any way to make a function or enum that returns a class type that works with my case?
I'm new to Swift and decided to write my own Optional enum.
enum MyOptional<Type> {
case none
case some(Type)
func get() -> Type {
switch self {
case .some(let x):
return x
case .none:
fatalError()
}
}
}
var test: MyOptional<String> = MyOptional.some("testString")
test.get().append("#")
But in case I put some struct that have mutating function and call that function - the compiler, obviously, tells me:
error: cannot use mutating member on immutable value: function call
returns immutable value test.get().append("#")
How does Swift's Optional returns struct by reference unwrapping them?
The Swift compiler has quite a bit of built-in support for Optional; including for the postfix operators ! and ? which can produce l-values (values which reside at known locations in memory; therefore allowing for mutations of that memory if the expression is mutable).
Unfortunately I don't believe it's possible to implement your own l-value returning operators (or functions in general), although constructs that allow you to define getters and setters (such as computed properties and subscripts) can be treated as l-values when they have setters:
enum MyOptional<Type> {
case none, some(Type)
var forceUnwrapped: Type {
get {
switch self {
case .some(let x):
return x
case .none:
fatalError()
}
}
set {
self = .some(newValue)
}
}
// just for demonstration; don't actually implement this as a subscript!
subscript() -> Type {
get {
switch self {
case .some(let x):
return x
case .none:
fatalError()
}
}
set {
self = .some(newValue)
}
}
}
var test = MyOptional.some("testString")
test.forceUnwrapped.append("#")
test[].append("#")
Here, test.forceUnwrapped and test[] can be treated as l-values. When mutating through them, the compiler will create a temporary variable from calling the getter, mutate this temporary, and then call the setter with the mutated value.
Although it's worth noting in both cases that when used with assignment (i.e test.forceUnwrapped = ... & test[] = ...), the getter won't be called; only the setter, which gives them slightly different semantics to Optional's postfix !, which will crash on the optional being nil even on assignment (i.e someOptional! = ...).
As an alternative, you could also define a method that takes a closure with an inout parameter, allowing the caller to mutate the force-unwrapped value:
enum MyOptional<Type> {
case none
case some(Type)
mutating func forceMutate<R>(_ body: (inout Type) throws -> R) rethrows -> R {
switch self {
case .some(var x):
defer {
self = .some(x)
}
return try body(&x)
case .none:
fatalError()
}
}
}
var test = MyOptional.some("testString")
test.forceMutate { $0.append("#") }
You can use non-mutating operations, and reassign the result back into the variable:
enum MyOptional<Type> {
case none
case some(Type)
func forceUnwrap() -> Type {
switch self {
case .some(let x):
return x
case .none:
fatalError()
}
}
static func ?? (lhs: MyOptional, rhs: #autoclosure () -> Void) {
}
}
var test: MyOptional<String> = .some("testString")
print(test)
test = .some(test.forceUnwrap() + "#")
print(test)
It might also be useful to have functions like map and flatMap:
extension MyOptional {
func map(_ transform: (Wrapped) -> Wrapped) -> MyOptional<Wrapped> {
switch self {
case .some(let x):
return .some(transform(x))
case .none:
return .none
}
}
mutating func mapInPlace(_ transform: (Wrapped) -> Wrapped) {
self = self.map(transform)
}
}
test = test.map{ $0 + "#" }
print(test)
test.mapInPlace{ $0 + "#" }
print(test)
How can I access an enum value for a specific case without having to implement an enum function for each case?
I'm thinking something like this:
enum Result<S, F> {
case success(S)
case failure(F)
}
let resultSuccess = Result<Int, String>.success(1)
let resultFailure = Result<Int, String>.failure("Error")
let error: String? = case let .failure(error) = resultFailure
Something like this would also be acceptable:
let error: String? = (case let .failure(error) = resultFailure) ? error : ""
Obviously this doesn't even compile, but that's the gist of what I want.
Is that possible?
EDIT: explaining why my question is not the same as Extract associated value of enum case into a tuple
It's very simple, that answer access the values inside the if statement, rather than as an Optional like in my question. To specify a little more, imagine I have to extract values from multiple enums, and maybe enums inside enums, for that I'd need nested if's, or guard's, but with guard I wouldn't be able to continue the flow, since it forces a return.
Add two computed properties for success case and failure case respectively.
enum Result<S, F> {
case success(S)
case failure(F)
var successValue: S? {
switch self {
case .success(let value):
return value
case .failure:
return nil
}
}
var failureValue: F? {
switch self {
case .failure(let value):
return value
case .success:
return nil
}
}
}
let resultSuccess = Result<Int, String>.success(1)
let resultFailure = Result<Int, String>.failure("Error")
if let error = resultFailure.failureValue {
// do something
print(error)
}
I'm afraid this is the most you can get:
let error: String?
if case .failure(let e) = resultFailure {error = e}
This technique from the question "Accessing an Enumeration association value in Swift" will do it:
enum Result<S, F> {
case success(S)
case failure(F)
}
let resultFailure = Result<Int, String>.failure("Error")
var error: String?
if case let Result.failure(value) = resultFailure {
error = value
}
print(error) // Optional("Error")
This will also work in place of the "if case let =" construct:
switch resultFailure {
case let Result.failure(value): error = value
default : error = nil
}
Here you go, 1 line and uses let:
let error: String? = { if case let .failure(value) = resultFailure { return value }; return nil }()
'emun' seems to me like a keyword or a primitive type.
And obviously following code does not compile:
if self is enum {
}
But how can I be able to check if certain protocol is implemented by any enum?
protocol Enumatable {
}
extension Enumatable {
func isEnum() -> Bool {
return self is enum //it does not compile
}
}
But what I really want is to set some kind of constraint in the protocol to force the adopting class to be an enum. Is that possible?
Thanks!
I'm not sure how performant it is to use Mirrors. But here you go:
enum SomeEnum {
case one
case two
}
let mirror = Mirror(reflecting: SomeEnum.one)
if let displayStyle = mirror.displayStyle {
switch displayStyle {
case .enum:
print("I am an enum")
default:
print("not an enum")
}
}
I have tried to boil this issue down to its simplest form with the following.
Setup
Xcode Version 6.1.1 (6A2008a)
An enum defined in MyEnum.swift:
internal enum MyEnum: Int {
case Zero = 0, One, Two
}
extension MyEnum {
init?(string: String) {
switch string.lowercaseString {
case "zero": self = .Zero
case "one": self = .One
case "two": self = .Two
default: return nil
}
}
}
and code that initializes the enum in another file, MyClass.swift:
internal class MyClass {
let foo = MyEnum(rawValue: 0) // Error
let fooStr = MyEnum(string: "zero")
func testFunc() {
let bar = MyEnum(rawValue: 1) // Error
let barStr = MyEnum(string: "one")
}
}
Error
Xcode gives me the following error when attempting to initialize MyEnum with its raw-value initializer:
Cannot convert the expression's type '(rawValue: IntegerLiteralConvertible)' to type 'MyEnum?'
Notes
Per the Swift Language Guide:
If you define an enumeration with a raw-value type, the enumeration automatically receives an initializer that takes a value of the raw value’s type (as a parameter called rawValue) and returns either an enumeration member or nil.
The custom initializer for MyEnum was defined in an extension to test whether the enum's raw-value initializer was being removed because of the following case from the Language Guide. However, it achieves the same error result.
Note that if you define a custom initializer for a value type, you will no longer have access to the default initializer (or the memberwise initializer, if it is a structure) for that type. [...]
If you want your custom value type to be initializable with the default initializer and memberwise initializer, and also with your own custom initializers, write your custom initializers in an extension rather than as part of the value type’s original implementation.
Moving the enum definition to MyClass.swift resolves the error for bar but not for foo.
Removing the custom initializer resolves both errors.
One workaround is to include the following function in the enum definition and use it in place of the provided raw-value initializer. So it seems as if adding a custom initializer has a similar effect to marking the raw-value initializer private.
init?(raw: Int) {
self.init(rawValue: raw)
}
Explicitly declaring protocol conformance to RawRepresentable in MyClass.swift resolves the inline error for bar, but results in a linker error about duplicate symbols (because raw-value type enums implicitly conform to RawRepresentable).
extension MyEnum: RawRepresentable {}
Can anyone provide a little more insight into what's going on here? Why isn't the raw-value initializer accessible?
This bug is solved in Xcode 7 and Swift 2
extension TemplateSlotType {
init?(rawString: String) {
// Check if string contains 'carrousel'
if rawString.rangeOfString("carrousel") != nil {
self.init(rawValue:"carrousel")
} else {
self.init(rawValue:rawString)
}
}
}
In your case this would result in the following extension:
extension MyEnum {
init?(string: String) {
switch string.lowercaseString {
case "zero":
self.init(rawValue:0)
case "one":
self.init(rawValue:1)
case "two":
self.init(rawValue:2)
default:
return nil
}
}
}
You can even make the code simpler and useful without switch cases, this way you don't need to add more cases when you add a new type.
enum VehicleType: Int, CustomStringConvertible {
case car = 4
case moped = 2
case truck = 16
case unknown = -1
// MARK: - Helpers
public var description: String {
switch self {
case .car: return "Car"
case .truck: return "Truck"
case .moped: return "Moped"
case .unknown: return "unknown"
}
}
static let all: [VehicleType] = [car, moped, truck]
init?(rawDescription: String) {
guard let type = VehicleType.all.first(where: { description == rawDescription })
else { return nil }
self = type
}
}
Yeah this is an annoying issue. I'm currently working around it using a global-scope function that acts as a factory, i.e.
func enumFromString(string:String) -> MyEnum? {
switch string {
case "One" : MyEnum(rawValue:1)
case "Two" : MyEnum(rawValue:2)
case "Three" : MyEnum(rawValue:3)
default : return nil
}
}
This works for Swift 4 on Xcode 9.2 together with my EnumSequence:
enum Word: Int, EnumSequenceElement, CustomStringConvertible {
case apple, cat, fun
var description: String {
switch self {
case .apple:
return "Apple"
case .cat:
return "Cat"
case .fun:
return "Fun"
}
}
}
let Words: [String: Word] = [
"A": .apple,
"C": .cat,
"F": .fun
]
extension Word {
var letter: String? {
return Words.first(where: { (_, word) -> Bool in
word == self
})?.key
}
init?(_ letter: String) {
if let word = Words[letter] {
self = word
} else {
return nil
}
}
}
for word in EnumSequence<Word>() {
if let letter = word.letter, let lhs = Word(letter), let rhs = Word(letter), lhs == rhs {
print("\(letter) for \(word)")
}
}
Output
A for Apple
C for Cat
F for Fun
Add this to your code:
extension MyEnum {
init?(rawValue: Int) {
switch rawValue {
case 0: self = .Zero
case 1: self = .One
case 2: self = .Two
default: return nil
}
}
}