首页 文章

协议,结构,但没有具体类型

提问于
浏览
0

好的我有一个名为 Environment 的协议

protocol Environment {
  var rootURL: String {get}
}

然后是两个结构:

struct Production: Environment {
  var rootURL = "www.api.mybackend.com/v1"
}

struct Development: Environment {
  var rootURL = "www.api.mydevelopmentbackend.com/v1"
}

具有检索环境的函数的设置对象:

class Settings {
  func getEnvironment<T>() -> T where T: Environment {
    let environmentRaw = self.retreiveEnvironmentFromLocalStore()
    switch environmentRaw {
    case 0:
        return Development() as! T
    case 1:
        return Production() as! T
    default:
        return Development() as! T
    }
  }

  func retreiveEnvironmentFromLocalStore() -> Int {
    //Realm, SQLLite, Core Date, I don't really care for this example. 
    //Let's just say it defaults to returning 1
  }
}

我真的想继续朝着Protocol Oriented Programming的方向前进,但现在当我在一个设置对象上调用这个函数并尝试使用 rootURL 属性时,编译器会抱怨它无法找出类型 . 所以,为了更好地理解并找到解决方案:

1)如果我访问由协议定义的属性,它至少知道返回类型是否符合,为什么它关心类型?

2)结构没有继承 . 我应该定义基类并忘记泛型吗?

3)我可以让我的 getEnvironment 功能更好吗?我不喜欢强制铸造,它似乎是一种代码味道 .

4)我甚至在这里正确使用泛型吗?

编辑1:

要清楚,我想要一个函数返回一个我知道将具有此属性的结构 .

2 回答

  • 3

    我甚至在这里正确使用泛型吗?

    不,我不这么认为 . 您说 getEnvironment 将返回 T ,它可以是客户端代码指定的任何类型,只要它实现 Environment 即可 . 但是,该方法的实现不会这样做 . 它只返回两种 Environment ,它返回的类型不是由客户端代码决定的 . 返回的类型取决于 retreiveEnvironmentFromLocalStore 返回的内容 . 因此,在这种情况下,泛型不适合 .

    由于它返回的环境类型是由方法的实现决定的,而不是客户端代码,你应该在这里使用多态 - 让它返回一个 Environment 代替:

    func getEnvironment() -> Environment {
        let environmentRaw = self.retreiveEnvironmentFromLocalStore()
        switch environmentRaw {
        case 0:
            return Development()
        case 1:
            return Production()
        default:
            return Development()
        }
      }
    
  • 1

    我真的想继续推进面向协议的编程方向

    我建议您尝试以明确,可理解的代码方向移动,无论时尚方向如何 .

    这是你的函数声明:

    func getEnvironment() - > T其中T:Environment

    这表示 getEnvironment() 将返回某种类型的对象 T ,其中 T 基于调用 getEnvironment() 的代码推断 at compile time .

    T 可以是哪些类型?它可以是 ProductionDevelopment . 例如,你可以写:

    let e: Production = Settings().getEnvironment()
    

    这使得编译器推断 getEnvironment() 在此调用站点返回 Production (这是 Environment ) .

    但是有一个问题: getEnvironment() 可能会尝试返回 Development ,基于 retreiveEnvironmentFromLocalStore 内的随机数生成器 . 然后,当它无法将 Development 强制转换为 Production 时,您将收到崩溃 at run time .

    为什么你认为 getEnvironment() 需要是通用的?根据你问题中的代码,它不应该是 .

    import Foundation
    
    protocol Environment {
        var rootURL: String {get}
    }
    
    struct Production: Environment {
        var rootURL = "www.api.mybackend.com/v1"
    }
    
    struct Development: Environment {
        var rootURL = "www.api.mydevelopmentbackend.com/v1"
    }
    
    class Settings {
        func getEnvironment() -> Environment {
            let environmentRaw = self.retreiveEnvironmentFromLocalStore()
            switch environmentRaw {
            case 1: return Production()
            default: return Development()
            }
        }
    
        func retreiveEnvironmentFromLocalStore() -> Int {
            return Int(arc4random())
        }
    }
    
    
    let settings = Settings()
    let e = settings.getEnvironment()
    

    风格说明:Swift API Design Guidelines建议我们

    根据副作用命名功能和方法没有副作用的人应该读作名词短语,例如: x.distance(to:y),i.successor() .

    除非 Settings 中的方法具有重要的副作用,否则更好的名称将是 environment()rawEnvironmentFromLocalStore() .

相关问题