2017-01-25 6 views
2

私はスウィフトにJavaクラスを変換しようとしています:新 - failable初期化子

// 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.") 
    } 

Iは1と10の間にない値で、コンストラクタを使用して、カードオブジェクトを初期化しようとすると、初期化が失敗し、その値が許容範囲内にないことを説明する文がターミナルに印刷されます。私は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! 
    } 
} 

適切な例では上記の作品が、私はまだsetNumValue(値:)値を変更する方法を使用することができますので、受け入れられない値が渡された場合でも、まだカードのインスタンスを作成するために表示されます。

私はinit(numvalue :)メソッドを利用可能にしようとしましたが、初期化が成功した場合はOptional(Card)を取得しました。理想的には、正常に初期化されたCardオブジェクトがCardオブジェクトであり、Cardを含むOptionalではないことが望ましいです。これは可能ですか?

+2

あなたのJavaクラスdoesnの範囲を渡します't faiあなたが無効な番号を入力した場合、lは単に 'numvalue'を設定しません。コンストラクタから 'Card'インスタンスを取得します。 Swiftでは、オプションで成功するかどうかを知るために、オプションの初期化子から戻ってくるオプションを条件付きで* unwrap *したいでしょう。言語ガイドの[オプション]セクション(https://developer.apple.com/library/prerelease/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html#//apple_ref/doc/uid)を読むことを強くお勧めします。/TP40014097-CH5-ID330)を参照してください。 – Hamish

+2

@LouisDeVesto Hamishのコメントに追加するには:Javaのコンストラクタには、Swiftの利用可能なイニシャライザと同等の機能はありません。代わりに、Javaでは、新しいオブジェクトを返すか、 'null'を返すコンストラクタを呼び出す静的メソッドを使用します。 – Alexander

+0

また、btwの場合、値が範囲内にあるかどうかを確認することができます。 'if 1 ... 10〜= numValue {... ' – Alexander

答えて

2

さて、あなたはそれがゼロであるか否かが返されたオプションを確認し、非オプションにそれをアンラップする必要があります:

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> 
} 
+3

このようなクラスは本当に構造体として優れています。オブジェクトの主な機能が単一の「Int」値を格納することであると考えると、不必要なオーバーヘッドがたくさんあります。 –

+1

完全には同意しますが、質問の背後にある可能性があります。サンプルコードが単純になりました。あなたは、決して知らない... –

0

理想的には、私はすべての成功したためたいCardオブジェクトはCardオブジェクトに初期化され、Cardを含むOptionalは初期化されません。これは可能ですか?

これは、Swiftで利用可能な標準的な初期化方式では不可能です。特定の条件下で初期化が失敗する場合は、最終的にOptional<Card>になります。


Failable初期

あなたはinitキーワードの末尾に?を追加して、初期化子failableを作ることができます。つまり、init?です。

これは、初期化子が失敗する可能性がある(nilを返す)ことを示します。

インスタンスを作成するための条件が満たされていない場合、初期化子で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! 
    } 
} 

あなたは今、あなたが安全に、オプションをアンラップし、インスタンスで何かをするif letを使用し、またはインスタンスが正常に作成されていなかったという事実を扱うことができ、Cardのオプションのインスタンスを返すされているので、(あなたはnilを持っています)。上記の例で

let card = Card(numValue: 12) 
if let card = card { 
    print(card) 
} else { 
    print("Unable to create a Card instance") 
} 

、「カードのインスタンスを作成できません」の文字列(「カード値は0〜11でなければならない」に加えて)印刷されます。

Swiftでのfusing初期化の詳細については、hereを参照してください。

1

オブジェクトタイプを永続化する必要がない場合は、構造体を使用する必要があります。BTWは、valueプロパティを変数にしてそのプロパティを変更するメソッドを作成する必要はありません。古いものを変更する代わりに、新しい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" 
} 

私はカード オブジェクトではなく、カードを含むオプションすべき正常に初期化カードのオブジェクトのためにしたいと思います。これは可能ですか?

はい可能です。ちょうどあなたの初期化子に前提条件を追加し、それ以外failableます

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" 
関連する問題