How to get argument of a variant? - rust

Having these enums
pub enum Symbol {
X,
O,
}
pub enum CellContent {
Move(Symbol),
Empty,
}
and
let cell_content = CellContent::Move(Symbol::X);
how can I get the Symbol ? Of course if it's of variant Move(Symbol)
This doesn't work
if cell_0_0 == Move(a_symbol) {
return Some(a_symbol);
}
I cannot also do the following because I must do nothing (code must continue evaluation); and the following doesn't even compile at all !
match cell_0_0 {
Move(symbol) => return symbol;
_ => // do nothing;
}
// code must go on to check further conditions
| I still have some problem with basic syntax of rust, so I'm experiencing making some basic programs
So question is
How to
check if my variable is a variant of Move(Symbol)
if yes return (a copy of) symbol
else do nothing, so code can go on and do more checks
?
Edit 1: Full (not working) code
pub fn some_one_win(&self) -> Option<Symbol> {
let cell_0_0: CellContent = self.table[0][0];
let cell_0_1: CellContent = self.table[0][1];
let cell_0_2: CellContent = self.table[0][2];
if cell_0_0 == cell_0_1 && cell_0_0 == cell_0_2 {
match cell_0_0 {
Move(symbol) => return symbol;
_ => // how to 'do nothing' here ?;
}
}
let cell_1_0: CellContent = self.table[1][0];
let cell_1_1: CellContent = self.table[1][1];
let cell_1_2: CellContent = self.table[1][2];
if cell_1_0 == cell_1_1 && cell_1_0 == cell_1_2 {
match cell_1_0 {
Move(symbol) => return symbol;
_ => // how to 'do nothing' here ?;
}
}
... and so on ..
}

I cannot also do the following because I must do nothing (code must continue evaluation); and the following doesn't even compile at all !
match cell_0_0 {
Move(symbol) => return symbol;
_ => // do nothing;
}
You can do that, if you get the syntax right:
match cell_0_0 {
CellContent::Move(symbol) => {
return Some(symbol);
}
_ => {} // do nothing
}
But as PitaJ mentioned, when there’s only one pattern plus _, the if let construct is usually a cleaner alternative:
if let CellContent::Move(symbol) = cell_0_0 {
return Some(symbol);
}

Related

Refactoring variable assignment thru if let block with Enum

I'm working with the code below, which works, but is clearly not a very clever or efficient way to write a value to res.
let mut res = "";
if let Video(n) = res_info { // res_info represents reference to &Settings type
if n.pixel_width > 1920{
res = "2160p";
}
else{
res = "1080p";
}
}
Printing res_info would yield the following:
Video(Video { pixel_width: 1920, pixel_height: 1080})
The following code seems to be close, however it's not assigning &str to res. I would much prefer a codeblock like this, in which res is only declared once.
let res = if let Video(n) = res_info {
if n.pixel_width > 1920 {
"2160p";
}
else{
"1080p";
}
};
As per the unit documentation
The semicolon ; can be used to discard the result of an expression at the end of a block, making the expression (and thus the block) evaluate to ()
Removing the semicolon should stop value from being discarded so the &str is resolved from the if blocks.
let res = if let Video(n) = res_info {
if n.pixel_width > 1920{
"2160p"
} else{
"1080p"
}
}else{
panic!("res_info is not a Video")
};
or with a match statement might be cleaner
let res = match res_info {
Video(n) if n.pixel_width > 1920 => "2160p",
Video(n) => "1080p",
_ => panic!("res_info is not a Video")
};

How to use if let statement with conditions?

I know it's possible to express AND logic between if let statement and a condition like this
if let (Some(a), true) = (b, c == d) {
// do something
}
But what if I need an OR logic?
if let (Some(a)) = b /* || c == d */ {
// do something
} else {
// do something else
}
The only way I figure it out is as follows, but I think it's a little bit ugly as I have to write some code twice
if let (Some(a)) = b {
// do something
} else if c == d {
// do something
} else {
// do something else
}
If you have the same "do something" code in both cases then it must not use a. In that case you can use is_some:
if b.is_some() || c == d {
// do something
} else {
// do something else
}
In the more general case, you can use matches! to check if b matches a pattern without creating any bindings:
if matches!(b, Some(_)) || c == d {
// do something
} else {
// do something else
}

How to check if a string contains an int? -Swift

I need to know if a string contains an Int to be sure that a name the user entered is a valid full name,
for that I need to either make the user type only chars, or valid that there are no ints in the string the user entered.
Thanks for all the help.
You can use Foundation methods with Swift strings, and that's what you should do here. NSString has built in methods that use NSCharacterSet to check if certain types of characters are present. This translates nicely to Swift:
var str = "Hello, playground1"
let decimalCharacters = CharacterSet.decimalDigits
let decimalRange = str.rangeOfCharacter(from: decimalCharacters)
if decimalRange != nil {
print("Numbers found")
}
If you're interested in restricting what can be typed, you should implement UITextFieldDelegate and the method textField(_:shouldChangeCharactersIn:replacementString:) to prevent people from typing those characters in the first place.
Simple Swift 4 version using rangeOfCharacter method from String class:
let numbersRange = stringValue.rangeOfCharacter(from: .decimalDigits)
let hasNumbers = (numbersRange != nil)
This method is what i use now for checking if a string contains a number
func doStringContainsNumber( _string : String) -> Bool{
let numberRegEx = ".*[0-9]+.*"
let testCase = NSPredicate(format:"SELF MATCHES %#", numberRegEx)
let containsNumber = testCase.evaluateWithObject(_string)
return containsNumber
}
If your string Contains a number it will return true else false. Hope it helps
//Swift 3.0 to check if String contains numbers (decimal digits):
let someString = "string 1"
let numberCharacters = NSCharacterSet.decimalDigits
if someString.rangeOfCharacter(from: numberCharacters) != nil
{ print("String contains numbers")}
else if someString.rangeOfCharacter(from: numberCharacters) == nil
{ print("String doesn't contains numbers")}
//A function that checks if a string has any numbers
func stringHasNumber(_ string:String) -> Bool {
for character in string{
if character.isNumber{
return true
}
}
return false
}
/// Check stringHasNumber function
stringHasNumber("mhhhldiddld")
stringHasNumber("kjkdjd99900")
if (ContainsNumbers(str).count > 0)
{
// Your string contains at least one number 0-9
}
func ContainsNumbers(s: String) -> [Character]
{
return s.characters.filter { ("0"..."9").contains($0)}
}
Swift 2.3. version working.
extension String
{
func containsNumbers() -> Bool
{
let numberRegEx = ".*[0-9]+.*"
let testCase = NSPredicate(format:"SELF MATCHES %#", numberRegEx)
return testCase.evaluateWithObject(self)
}
}
Usage:
//guard let firstname = textField.text else { return }
let testStr1 = "lalalala"
let testStr2 = "1lalalala"
let testStr3 = "lal2lsd2l"
print("Test 1 = \(testStr1.containsNumbers())\nTest 2 = \(testStr2.containsNumbers())\nTest 3 = \(testStr3.containsNumbers())\n")
You need to trick Swift into using Regex by wrapping up its nsRegularExpression
class Regex {
let internalExpression: NSRegularExpression
let pattern: String
init(_ pattern: String) {
self.pattern = pattern
var error: NSError?
self.internalExpression = NSRegularExpression(pattern: pattern, options: .CaseInsensitive, error: &error)
}
func test(input: String) -> Bool {
let matches = self.internalExpression.matchesInString(input, options: nil, range:NSMakeRange(0, countElements(input)))
return matches.count > 0
}
}
if Regex("\\d/").test("John 2 Smith") {
println("has a number in the name")
}
I got these from http://benscheirman.com/2014/06/regex-in-swift/
let numericCharSet = CharacterSet.init(charactersIn: "1234567890")
let newCharSet = CharacterSet.init(charactersIn: "~`##$%^&*(){}[]<>?")
let sentence = "Tes#ting4 #Charact2er1Seqt"
if sentence.rangeOfCharacter(from: numericCharSet) != nil {
print("Yes It,Have a Numeric")
let removedSpl = sentence.components(separatedBy: newCharSet).joined()
print(sentence.components(separatedBy: newCharSet).joined())
print(removedSpl.components(separatedBy: numericCharSet).joined())
}
else {
print("No")
}

swift How to use enum as parameter in constructing struct?

I was doing an experiment of Swift programming book and stuck with construct a struct inner the struct itself. But the error reported the parameter is unwrapped. How could I take it value as parameter?
struct Card {
var rank: Rank
var suit: Suit
func simpleDescription() -> String {
return "The \(rank.simpleDescription()) of \(suit.simpleDescription())"
}
func FullDeck() -> Card[] {
var deck: Card[]
for i in 1...13
{
for j in 0...3
{
let rank_para = Rank.fromRaw(i)
let suit_para = Suit.fromRaw(j)
**deck.append(Card(rank: rank_para, suit : suit_para ))
//value of optional type unwrapped;did you mean to use ? or !**
}
}
return deck
}
}
enum Rank: Int {
case Ace = 1
case Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten
case Jack, Queen, King
func simpleDescription() -> String {
switch self {
case .Ace:
return "ace"
case .Jack:
return "jack"
case .Queen:
return "queen"
case .King:
return "king"
default:
return String(self.toRaw())
}
}
func compare(sec:Rank) -> Bool {
var first = 0
var second = 0
if self.toRaw() == 1 {
first = 1
} else {
first = self.toRaw()
}
if sec.toRaw() == 1 {
second = 1
} else {
second = self.toRaw()
}
return first > second
}
}
enum Suit: Int{
case Spades = 0
case Hearts, Diamonds, Clubs
func simpleDescription() -> String {
switch self {
case .Spades:
return "spades"
case .Hearts:
return "hearts"
case .Diamonds:
return "diamonds"
case .Clubs:
return "clubs"
}
}
}
the fromRaw method returns an optional value: Rank? and Suit?. That means that the value could be nil. You need to check for that:
if let aRank = rank_para {
if let aSuit = suit_para {
deck.append(Card(rank: aRank, suit: aSuit))
}
}
By using "if let", you "unwrap" the optional value into a value (aRank and aSuit) that is no longer optional (cannot be nil).
Another way to do that:
if rank_para and suit_para {
deck.append(Card(rank: rank_para!, suit: suit_para!))
}
Here, you are checking if rank_para and suit_para are nil. If they both are not, you call append and "unwrap" the optional values using !. ! means if the value is nil throw a runtime error, otherwise, treat this variable as if it cannot be nil.

Where is the Rust intrinsic called "transmute" actually implemented?

I'm trying to find the implementation for the Rust intrinsics, particularly the "transumte" intrinsic that takes one argument.
I've seen the following code in cast.rs, but as you can see, it merely delegates to some other implementation of transmute.
#[inline]
pub unsafe fn transmute<L, G>(thing: L) -> G {
intrinsics::transmute(thing)
}
Where is the actual implementation for intrinsics, especially the transmute intrinsic?
cast::transmute delegates to intrinsics::transmute. There is a module called intrinsics (now in libcore), it contains extern bindings to several functions, including transmute. As you can see from the module documentation, implementation of intrinsics is said to be located in librustc/middle/trans/foreign.rs.
However, as far as I can see, actual implementation of intrinsics is present in librustc/middle/trans/intrinsic.rs. You can search for transmute, and you will find an arm in a really big match statement which looks like this:
"transmute" => {
let (in_type, out_type) = (*substs.substs.tps.get(0),
*substs.substs.tps.get(1));
let llintype = type_of::type_of(ccx, in_type);
let llouttype = type_of::type_of(ccx, out_type);
let in_type_size = machine::llbitsize_of_real(ccx, llintype);
let out_type_size = machine::llbitsize_of_real(ccx, llouttype);
if in_type_size != out_type_size {
let sp = match ccx.tcx.map.get(ref_id.unwrap()) {
ast_map::NodeExpr(e) => e.span,
_ => fail!("transmute has non-expr arg"),
};
ccx.sess().span_fatal(sp,
format!("transmute called on types with different sizes: \
{intype} ({insize, plural, =1{# bit} other{# bits}}) to \
{outtype} ({outsize, plural, =1{# bit} other{# bits}})",
intype = ty_to_str(ccx.tcx(), in_type),
insize = in_type_size as uint,
outtype = ty_to_str(ccx.tcx(), out_type),
outsize = out_type_size as uint));
}
if !return_type_is_void(ccx, out_type) {
let llsrcval = get_param(decl, first_real_arg);
if type_is_immediate(ccx, in_type) {
match fcx.llretptr.get() {
Some(llretptr) => {
Store(bcx, llsrcval, PointerCast(bcx, llretptr, llintype.ptr_to()));
RetVoid(bcx);
}
None => match (llintype.kind(), llouttype.kind()) {
(Pointer, other) | (other, Pointer) if other != Pointer => {
let tmp = Alloca(bcx, llouttype, "");
Store(bcx, llsrcval, PointerCast(bcx, tmp, llintype.ptr_to()));
Ret(bcx, Load(bcx, tmp));
}
(Array, _) | (_, Array) | (Struct, _) | (_, Struct) => {
let tmp = Alloca(bcx, llouttype, "");
Store(bcx, llsrcval, PointerCast(bcx, tmp, llintype.ptr_to()));
Ret(bcx, Load(bcx, tmp));
}
_ => {
let llbitcast = BitCast(bcx, llsrcval, llouttype);
Ret(bcx, llbitcast)
}
}
}
} else if type_is_immediate(ccx, out_type) {
let llsrcptr = PointerCast(bcx, llsrcval, llouttype.ptr_to());
let ll_load = Load(bcx, llsrcptr);
Ret(bcx, ll_load);
} else {
// NB: Do not use a Load and Store here. This causes massive
// code bloat when `transmute` is used on large structural
// types.
let lldestptr = fcx.llretptr.get().unwrap();
let lldestptr = PointerCast(bcx, lldestptr, Type::i8p(ccx));
let llsrcptr = PointerCast(bcx, llsrcval, Type::i8p(ccx));
let llsize = llsize_of(ccx, llintype);
call_memcpy(bcx, lldestptr, llsrcptr, llsize, 1);
RetVoid(bcx);
};
} else {
RetVoid(bcx);
}
}
This seems to be code which generates code which will be inserted instead of a call to transmute. I'm no compiler expert, so please someone correct me if I'm wrong.

Resources