Swift 的新手 - 可失败的初始值设定项
New to Swift - failable initializers
我正在尝试将 Java class 转换为 Swift:
// Card class with only a main function
public class Card {
// fields
private int numvalue;
// constructor(s)
public Card(int v) {
if (v > 0 && v < 11) {
this.numvalue = v;}
else {
System.out.println("Error: Card value is outside the allowed range.
Value must be between 1 and 10 inclusive.")
}
如果我尝试使用值不在 1 到 10 之间的构造函数来初始化 Card 对象,则初始化失败,并在终端中打印一条声明,说明该值不在可接受的范围内.我试图在 Swift.
中重新创建它
class Card {
var numValue : Int?
init(numValue:Int) {
if (numValue > 0 && numValue < 11) {self.numValue = numValue}
else {print("Card value must be between 0 and 11")}
}
func setNumValue(value:Int) -> () {
self.numValue = value
}
func getNumValue() -> Int {
return self.numValue!
}
}
以上在适当的情况下有效,但即使传递了不可接受的值,它似乎仍会创建一个 Card 实例,因为我仍然可以使用 setNumValue(value:) 方法来更改值。
我尝试使 init(numvalue:) 方法失败,但如果初始化成功,我会得到一个 Optional(Card)。理想情况下,我希望任何成功初始化的 Card 对象都是 Card 对象,而不是包含 Card 的 Optional。这可能吗?
嗯,你必须检查返回的 Optional 是否为 nil,然后将其解包成 non-Optional:
class Card {
var numValue : Int
init?(numValue:Int) {
guard (numValue > 0 && numValue < 11) else {
print("Card value must be between 0 and 11")
return nil
}
self.numValue = numValue
}
func setNumValue(value:Int) -> () {
guard (numValue > 0 && numValue < 11) else {
print("Card value must be between 0 and 11")
return
}
self.numValue = value
}
func getNumValue() -> Int {
return self.numValue
}
}
let cOk = Card(numValue:1)
let cFails = Card(numValue:-1)
if let c = cOk {
// now work with c because it's a Card,
// not an Optional<Card>
}
Ideally, I'd like for any successfully initialized Card object to be a Card object, not an Optional containing a Card. Is this possible?
Swift 中可用的标准初始化方案无法做到这一点。如果您的初始化在某些情况下失败,您最终将得到 Optional<Card>
。
初始化失败
您可以通过在 init
关键字的末尾添加 ?
来使您的初始化程序可失败。即init?
.
这表明初始化程序可能会失败 (return nil)。
在您的初始化程序中,当不满足创建实例的条件时,您可以 return nil。
在本例中,我使用的是 guard
语句,但您也可以使用 if
语句。
class Card {
var numValue : Int?
init?(numValue: Int) {
guard numValue > 0 && numValue < 11 else {
print("Card value must be between 0 and 11")
return nil
}
self.numValue = numValue
}
func setNumValue(value:Int) -> () {
self.numValue = value
}
func getNumValue() -> Int {
return self.numValue!
}
}
由于您现在正在 returning 一个 Card
的可选实例,您可以使用 if let
安全地解包可选并对实例做一些事情,或者处理这样一个事实一个实例没有成功创建(你有一个 nil)。
let card = Card(numValue: 12)
if let card = card {
print(card)
} else {
print("Unable to create a Card instance")
}
在上面的示例中,将打印 "Unable to create a Card instance" 字符串(除了 "Card value must be between 0 and 11")。
有关 Swift 中可失败初始化如何工作的更多信息,请参见 here。
如果您的对象类型不需要持久化,您应该使用 Struct。顺便说一句,无需将值 属性 设为变量并创建方法来仅更改其属性。您只需创建一个新的 Card 对象来替换它而不是更改旧的。
您的 Card 结构应该如下所示:
struct Card {
let value: Int
init?(value: Int) {
guard 1...10 ~= value else {
print("Card value is out of range 1...10")
return nil
}
self.value = value
}
}
let card = Card(value: 2) // returns an object of optional type (Card?) "optional Card(value: 10)\n"
let nilCard = Card(value: 11) // valus out of the range 1...10 will return nil
if let card = Card(value: 10) {
print(card) // "Card(value: 10)\n"
}
I'd like for any successfully initialized Card object to be a Card
object, not an Optional containing a Card. Is this possible?
是的,这是可能的。只需向您的初始化程序添加一个前提条件并使其不可失败:
struct Card {
let value: Int
init(value: Int) {
precondition(1...10 ~= value, "Card value is out of range 1...10")
self.value = value
}
}
let card = Card(value: 2) // returns an object of type (Card) "Card(value: 2)\n"
let cantInitCard = Card(value: 11) // won't execute (precondition not met range 1...10)
您还可以为您的卡片初始值设定项添加第二个参数范围(可选,因为您可以设置默认值)并向您的卡片添加一个范围 属性,这样您就可以检查您可能的卡片值是什么:
struct Card {
let value: Int
let range: ClosedRange<Int>
init(value: Int, range: ClosedRange<Int> = 1...10) { // you can set a default range for yor cards
precondition(range ~= value, "Card value is out of range: " + range.description)
self.value = value
self.range = range
}
}
let card = Card(value: 5) // returns an object of type (Card) "Card(value: 5, range: 1...10)\n"
print(card.value, card.range) // "5 1...10\n"
如果您想要一张具有不同范围 1...13 值的卡片,只需传递范围
let newCard = Card(value: 11, range: 1...13) // ok to execute (precondition met range 1...13)
print(newCard.value, newCard.range) // "11 1...13\n"
我正在尝试将 Java class 转换为 Swift:
// Card class with only a main function
public class Card {
// fields
private int numvalue;
// constructor(s)
public Card(int v) {
if (v > 0 && v < 11) {
this.numvalue = v;}
else {
System.out.println("Error: Card value is outside the allowed range.
Value must be between 1 and 10 inclusive.")
}
如果我尝试使用值不在 1 到 10 之间的构造函数来初始化 Card 对象,则初始化失败,并在终端中打印一条声明,说明该值不在可接受的范围内.我试图在 Swift.
中重新创建它class Card {
var numValue : Int?
init(numValue:Int) {
if (numValue > 0 && numValue < 11) {self.numValue = numValue}
else {print("Card value must be between 0 and 11")}
}
func setNumValue(value:Int) -> () {
self.numValue = value
}
func getNumValue() -> Int {
return self.numValue!
}
}
以上在适当的情况下有效,但即使传递了不可接受的值,它似乎仍会创建一个 Card 实例,因为我仍然可以使用 setNumValue(value:) 方法来更改值。
我尝试使 init(numvalue:) 方法失败,但如果初始化成功,我会得到一个 Optional(Card)。理想情况下,我希望任何成功初始化的 Card 对象都是 Card 对象,而不是包含 Card 的 Optional。这可能吗?
嗯,你必须检查返回的 Optional 是否为 nil,然后将其解包成 non-Optional:
class Card {
var numValue : Int
init?(numValue:Int) {
guard (numValue > 0 && numValue < 11) else {
print("Card value must be between 0 and 11")
return nil
}
self.numValue = numValue
}
func setNumValue(value:Int) -> () {
guard (numValue > 0 && numValue < 11) else {
print("Card value must be between 0 and 11")
return
}
self.numValue = value
}
func getNumValue() -> Int {
return self.numValue
}
}
let cOk = Card(numValue:1)
let cFails = Card(numValue:-1)
if let c = cOk {
// now work with c because it's a Card,
// not an Optional<Card>
}
Ideally, I'd like for any successfully initialized Card object to be a Card object, not an Optional containing a Card. Is this possible?
Swift 中可用的标准初始化方案无法做到这一点。如果您的初始化在某些情况下失败,您最终将得到 Optional<Card>
。
初始化失败
您可以通过在 init
关键字的末尾添加 ?
来使您的初始化程序可失败。即init?
.
这表明初始化程序可能会失败 (return nil)。
在您的初始化程序中,当不满足创建实例的条件时,您可以 return nil。
在本例中,我使用的是 guard
语句,但您也可以使用 if
语句。
class Card {
var numValue : Int?
init?(numValue: Int) {
guard numValue > 0 && numValue < 11 else {
print("Card value must be between 0 and 11")
return nil
}
self.numValue = numValue
}
func setNumValue(value:Int) -> () {
self.numValue = value
}
func getNumValue() -> Int {
return self.numValue!
}
}
由于您现在正在 returning 一个 Card
的可选实例,您可以使用 if let
安全地解包可选并对实例做一些事情,或者处理这样一个事实一个实例没有成功创建(你有一个 nil)。
let card = Card(numValue: 12)
if let card = card {
print(card)
} else {
print("Unable to create a Card instance")
}
在上面的示例中,将打印 "Unable to create a Card instance" 字符串(除了 "Card value must be between 0 and 11")。
有关 Swift 中可失败初始化如何工作的更多信息,请参见 here。
如果您的对象类型不需要持久化,您应该使用 Struct。顺便说一句,无需将值 属性 设为变量并创建方法来仅更改其属性。您只需创建一个新的 Card 对象来替换它而不是更改旧的。
您的 Card 结构应该如下所示:
struct Card {
let value: Int
init?(value: Int) {
guard 1...10 ~= value else {
print("Card value is out of range 1...10")
return nil
}
self.value = value
}
}
let card = Card(value: 2) // returns an object of optional type (Card?) "optional Card(value: 10)\n"
let nilCard = Card(value: 11) // valus out of the range 1...10 will return nil
if let card = Card(value: 10) {
print(card) // "Card(value: 10)\n"
}
I'd like for any successfully initialized Card object to be a Card object, not an Optional containing a Card. Is this possible?
是的,这是可能的。只需向您的初始化程序添加一个前提条件并使其不可失败:
struct Card {
let value: Int
init(value: Int) {
precondition(1...10 ~= value, "Card value is out of range 1...10")
self.value = value
}
}
let card = Card(value: 2) // returns an object of type (Card) "Card(value: 2)\n"
let cantInitCard = Card(value: 11) // won't execute (precondition not met range 1...10)
您还可以为您的卡片初始值设定项添加第二个参数范围(可选,因为您可以设置默认值)并向您的卡片添加一个范围 属性,这样您就可以检查您可能的卡片值是什么:
struct Card {
let value: Int
let range: ClosedRange<Int>
init(value: Int, range: ClosedRange<Int> = 1...10) { // you can set a default range for yor cards
precondition(range ~= value, "Card value is out of range: " + range.description)
self.value = value
self.range = range
}
}
let card = Card(value: 5) // returns an object of type (Card) "Card(value: 5, range: 1...10)\n"
print(card.value, card.range) // "5 1...10\n"
如果您想要一张具有不同范围 1...13 值的卡片,只需传递范围
let newCard = Card(value: 11, range: 1...13) // ok to execute (precondition met range 1...13)
print(newCard.value, newCard.range) // "11 1...13\n"