In Operator
The in
operator is simply syntactic sugar for a call to the contains
function.
Similarly, !in
is a call to !contains
.
The in
operator is used to check for containment – i.e. whether a particular collection
data type contains a particular item.
Similarly, !in
is used to check for non-existence – i.e. it is true
if a particular
collection data type does not contain a particular item.
42 in array;
array.contains(42); // <- the above is equivalent to this
123 !in array;
!array.contains(123); // <- the above is equivalent to this
Built-in Support for Standard Data Types
Data type | Check for |
---|---|
Numeric range | integer number |
Array | contained item |
Object map | property name |
String | sub-string or character |
Examples
let array = [1, "abc", 42, ()];
42 in array == true; // check array for item
let map = #{
foo: 42,
bar: true,
baz: "hello"
};
"foo" in map == true; // check object map for property name
'w' in "hello, world!" == true; // check string for character
'w' !in "hello, world!" == false;
"wor" in "hello, world" == true; // check string for sub-string
42 in -100..100 == true; // check range for number
Array Items Comparison
The default implementation of the in
operator for arrays uses the ==
operator (if defined)
to compare items.
For a custom type, ==
defaults to false
when comparing it with a value of of the same type.
See the section on Logic Operators for more details.
let ts = new_ts(); // assume 'new_ts' returns a custom type
let array = [1, 2, 3, ts, 42, 999];
// ^^ custom type
42 in array == true; // 42 cannot be compared with 'ts'
// so it defaults to 'false'
// because == operator is not defined
Custom Implementation of contains
The in
and !in
operators map directly to a call to a function contains
with the two operands switched.
// This expression...
item in container
// maps to this...
contains(container, item)
// or...
container.contains(item)
Support for the in
and !in
operators can be easily extended to other types by registering a
custom binary function named contains
with the correct parameter types.
Since !in
maps to !(... in ...)
, contains
is enough to support both operators.
let mut engine = Engine::new();
engine.register_type::<TestStruct>()
.register_fn("new_ts", || TestStruct::new())
.register_fn("contains", |ts: &mut TestStruct, item: i64| -> bool {
// Remember the parameters are switched from the 'in' expression
ts.contains(item)
});
// Now the 'in' operator can be used for 'TestStruct' and integer
engine.run(
r#"
let ts = new_ts();
if 42 in ts { // this calls 'ts.contains(42)'
print("I got 42!");
} else if 123 !in ts { // this calls '!ts.contains(123)'
print("I ain't got 123!");
}
let err = "hello" in ts; // <- runtime error: 'contains' not found
// for 'TestStruct' and string
"#)?;