好的我有一个名为 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 回答
不,我不这么认为 . 您说
getEnvironment
将返回T
,它可以是客户端代码指定的任何类型,只要它实现Environment
即可 . 但是,该方法的实现不会这样做 . 它只返回两种Environment
,它返回的类型不是由客户端代码决定的 . 返回的类型取决于retreiveEnvironmentFromLocalStore
返回的内容 . 因此,在这种情况下,泛型不适合 .由于它返回的环境类型是由方法的实现决定的,而不是客户端代码,你应该在这里使用多态 - 让它返回一个
Environment
代替:我建议您尝试以明确,可理解的代码方向移动,无论时尚方向如何 .
这是你的函数声明:
func getEnvironment() - > T其中T:Environment
这表示
getEnvironment()
将返回某种类型的对象T
,其中T
基于调用getEnvironment()
的代码推断 at compile time .T
可以是哪些类型?它可以是Production
或Development
. 例如,你可以写:这使得编译器推断
getEnvironment()
在此调用站点返回Production
(这是Environment
) .但是有一个问题:
getEnvironment()
可能会尝试返回Development
,基于retreiveEnvironmentFromLocalStore
内的随机数生成器 . 然后,当它无法将Development
强制转换为Production
时,您将收到崩溃 at run time .为什么你认为
getEnvironment()
需要是通用的?根据你问题中的代码,它不应该是 .风格说明:Swift API Design Guidelines建议我们
除非
Settings
中的方法具有重要的副作用,否则更好的名称将是environment()
和rawEnvironmentFromLocalStore()
.